; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > MemInfo LTORG ;---------------------------------------------------------------------------------------- ; MemorySWI ; ; In: r0 = reason code and flags ; bits 0-7 = reason code ; bits 3-31 = reason specific flags ; Out: specific to reason codes ; ; Perform miscellaneous operations for memory management. ; MemorySWI ROUT Push lr ; Save real return address. AND lr, r0, #&FF ; Get reason code. CMP lr, #(%40-%30):SHR:2 ; If valid reason code then ADDCC lr, lr, #(%30-%10):SHR:2 ; determine where to jump to in branch table, ADDCC lr, pc, lr, LSL #2 Push lr, CC ; save address so we can 10 ADRCC lr, MemReturn ; set up default return address for handler routines Pull pc, CC ; and jump into branch table. 20 ADRL r0, ErrorBlock_HeapBadReason ; Otherwise, unknown reason code. SETV ; Drop through to... MemReturn [ International BLVS TranslateError ] Pull lr ; Get back real return address. BVS SLVK_SetV ExitSWIHandler 30 B MemoryConvert ; 0 B %BT20 ; Reason codes 1-5 are reserved. B %BT20 B %BT20 B %BT20 B %BT20 B MemoryPhysSize ; 6 B MemoryReadPhys ; 7 B MemoryAmounts ; 8 B MemoryIOSpace ; 9 B MemoryFreePoolLock ; 10 B %BT20 ; Reason code 11 reserved (for PCImapping). B RecommendPage ; 12 B MapIOpermanent ; 13 B AccessPhysAddr ; 14 B ReleasePhysAddr ; 15 B MemoryAreaInfo ; 16 40 ;---------------------------------------------------------------------------------------- ; MemoryConvert ; ; In: r0 = flags ; bit meaning ; 0-7 0 (reason code) ; 8 page number provided when set ; 9 logical address provided when set ; 10 physical address provided when set ; 11 fill in page number when set ; 12 fill in logical address when set ; 13 fill in physical address when set ; 14-15 0,1=don't change cacheability ; 2=disable caching on these pages ; 3=enable caching on these pages ; 16-31 reserved (set to 0) ; r1 -> page block ; r2 = number of 3 word entries in page block ; ; Out: r1 -> updated page block ; ; Converts between representations of memory addresses. Can also set the ; cacheability of the specified pages. ; ; Declare symbols used for decoding flags (given and wanted are used ; so that C can be cleared by rotates of the form a,b). We have to munge ; the flags a bit to make the rotates even. ; ppn * 1:SHL:0 ; Bits for address formats. logical * 1:SHL:1 physical * 1:SHL:2 all * ppn :OR: logical :OR: physical given * 24 ; Rotate for given fields. wanted * 20 ; Rotate for wanted fields. ppn_bits * ((ppn :SHL: 4) :OR: ppn) logical_bits * ((logical :SHL: 4) :OR: logical) physical_bits * ((physical :SHL: 4) :OR: physical) cacheable_bit * 1:SHL:15 alter_cacheable * 1:SHL:16 flush_tlb * 1:SHL:30 ; Internal flag flush_cache * 1:SHL:31 ; Internal flag. flush_all * flush_tlb :OR: flush_cache MemoryConvert ROUT Entry "r0-r11" ; Need lots of registers!! ; MRS lr, CPSR ; Push "lr" ; ORR lr, lr, #I32_bit+F32_bit ; MSR CPSR_c, lr BIC lr, r0, #all,given ; Need to munge r0 to get rotates to work (must be even). AND r0, r0, #all,given ORR r0, r0, lr, LSL #1 ; Move bits 11-30 to 12-31. TST r0, #all,given ; Check for invalid argument (no fields provided) TEQNE r2, #0 ; (no entries in table). ADREQL r0, ErrorBlock_BadParameters BEQ %FT95 EOR lr, r0, r0, LSL #given-wanted ; If flag bits 8-10 and 12-14 contain common bits then AND lr, lr, #all,wanted ; clear bits in 12-14 (ie. don't fill in fields already given). EOR lr, lr, #all,wanted BIC r0, r0, lr LDR r6, =ZeroPage LDR r7, [r6, #MaxCamEntry] LDR r6, [r6, #CamEntriesPointer] LDR r8, =L2PT BIC r0, r0, #flush_all ; Bit set if any page is really made uncacheable (we must flush the cache). 10 SUBS r2, r2, #1 BCC %FT70 LDMIA r1!, {r3-r5} ; Get next three word entry (PN,LA,PA) and move on pointer. [ ChocolateAMB BL handle_AMBHonesty ; may need to make page honest (as if not lazily mapped) ] TST r0, #physical,wanted ; If PA not wanted BEQ %FT20 ; then skip. TST r0, #logical,given ; If LA not given (rotate clears C) then BLEQ ppn_to_logical ; get it from PN (PA wanted (not given) & LA not given => PN given). BLCC logical_to_physical ; Get PA from LA. BCS %FT80 TST r0, #logical,wanted STRNE r4, [r1, #-8] ; Store back LA if wanted. STR r5, [r1, #-4] ; Store back PA. 20 TST r0, #alter_cacheable ; If altering cacheability EORNE lr, r0, #ppn,given ; and PN not given TSTNE lr, #ppn,given TSTEQ r0, #ppn,wanted ; OR PN wanted then don't skip BEQ %FT30 ; else skip. TST r0, #physical_bits,given ; If PA not given and PA not wanted (rotate clears C) then BLEQ logical_to_physical ; get it from LA (PN wanted/not given & PA not given => LA given). BLCC physical_to_ppn ; Get PN from PA. BCS %FT80 TST r0, #ppn,wanted STRNE r3, [r1, #-12] ; Store back PN if wanted. 30 TST r0, #logical,wanted ; If LA wanted EORNE lr, r0, #physical,wanted TSTNE lr, #physical,wanted ; and PA not wanted then don't skip BEQ %FT40 ; else skip. TST r0, #alter_cacheable ; If not changing cacheability (already have PN) TSTEQ r0, #ppn_bits,given ; and PN not given and PN not wanted (rotate clears C) then BLEQ physical_to_ppn ; get it from PA (LA wanted (not given) & PN not given => PA given). BLCC ppn_to_logical ; Get LA from PN. BCS %FT80 STR r4, [r1, #-8] ; Store back LA. 40 TST r0, #alter_cacheable BEQ %BT10 CMP r7, r3 ; Make sure page number is valid (might not have done any conversion). BCC %FT80 ADD r3, r6, r3, LSL #3 ; Point to CAM entry for this page. LDMIA r3, {r4,r5} ; Get logical address and PPL. AND lr, r5, #PageFlags_TempUncacheableBits TST r0, #cacheable_bit BNE %FT50 TEQ lr, #PageFlags_TempUncacheableBits ; Make uncacheable (increment count). BEQ %BT10 ; If count has reached max then go no further (should not happen). TEQ lr, #0 ; EQ => we have to change L2. ADD r5, r5, #1:SHL:TempUncacheableShift B %FT60 50 TEQ lr, #0 ; Make cacheable (decrement count). BEQ %BT10 ; If count is already 0 then go no further (page already cacheable). SUB r5, r5, #1:SHL:TempUncacheableShift TST r5, #PageFlags_TempUncacheableBits ; EQ => we have to change L2. 60 STR r5, [r3, #4] ; Write back new PPL. BNE %BT10 ; Do next entry if we don't have to change L2. MOV r4, r4, LSR #12 ADD r4, r8, r4, LSL #2 ; Address of L2 entry for logical address. LDR r5, [r4] ; Get L2 entry (safe as we know address is valid). ORR r0, r0, #flush_tlb TST r0, #cacheable_bit BICEQ r5, r5, #L2_C ; Disable/enable cacheability. ORREQ r0, r0, #flush_cache ; If disable then we must flush cache later. ORRNE r5, r5, #L2_C STR r5, [r4] ; Write back new L2 entry. B %BT10 ; Do next entry. 70 ; *** KJB - this assumes that uncacheable pages still allow cache hits (true on all ; ARMs so far). ; *** Also, fix it up to do it page by page. TST r0, #flush_tlb EXIT EQ ; If not flush_tlb, can't have flush_cache MOV r1, r0 LDR r0, =ZeroPage ARMop TLB_InvalidateAll,,,r0 TST r1, #flush_cache ; If any page has been made uncacheable in L2 then flush! EXIT EQ LDR r0, =ZeroPage ARMop Cache_CleanInvalidateAll,,,r0 ;75 ; Pull "lr" ; MSR CPSR_c, lr EXIT 80 TST r0, #alter_cacheable ; If we haven't changed any cacheability stuff then BEQ %FT90 ; just return error. AND lr, r0, #all,wanted ; Get wanted flags. LDMIA sp, {r0,r1,r3} ; Get back original flags, pointer and count. ORR r0, r0, lr, LSR #given-wanted ; Wanted fields are now also given as we have done the conversion. BIC r0, r0, #all:SHL:11 ; Clear wanted flags, we only want to change cacheability. EOR r0, r0, #cacheable_bit ; If we made them uncacheable then make them cacheable again & v.v. SUB r2, r3, r2 SUBS r2, r2, #1 ; Change back the entries we have changed up to (but excluding) the error entry. BLNE MemoryConvert 90 ADRL r0, ErrorBlock_BadAddress 95 STR r0, [sp] SETV EXIT [ ChocolateAMB ; ; entry: r3,r4,r5 = provided PN,LA,PA triple for entry to make honest (at least one given) ; r0 bits flag which of PN,LA,PA are given ; exit: mapping made honest (as if not lazily mapped) if necessary handle_AMBHonesty ROUT Push "r0, r3-r5, lr" TST r0, #logical,given BEQ %FT10 MOV r0, r4 BL AMB_MakeHonestLA B %FT90 10 TST r0, #ppn,given BEQ %FT20 15 MOV r0, r3 BL AMB_MakeHonestPN B %FT90 20 TST r0, #physical,given BEQ %FT90 Push "r7, r9-r11" LDR r14, =ZeroPage LDR r7, [r14, #MaxCamEntry] BL physical_to_ppn Pull "r7, r9-r11" BCC %BT15 90 Pull "r0, r3-r5, pc" ] ;ChocolateAMB ;---------------------------------------------------------------------------------------- ; ppn_to_logical ; ; In: r3 = page number ; r5 = physical address if given ; r6 = CamEntriesPointer ; r7 = MaxCamEntry ; ; Out: r9 corrupted ; CC => r4 = logical address ; CS => invalid page number ; ; Convert physical page number to logical address. ; ppn_to_logical CMP r7, r3 ; Validate page number. [ No26bitCode BCC meminfo_returncs ; Invalid so return C set. | ORRCCS pc, lr, #C_bit ; Invalid so return C set. ] LDR r4, [r6, r3, LSL #3] ; If valid then lookup logical address. TST r0, #physical,given ; If physical address was given then LDRNE r9, =&FFF ANDNE r9, r5, r9 ; mask off page offset ORRNE r4, r4, r9 ; and combine with logical address. [ No26bitCode CLC MOV pc, lr | BICS pc, lr, #C_bit ; Return C clear. ] ;---------------------------------------------------------------------------------------- ; logical_to_physical ; ; In: r4 = logical address ; r8 = L2PT ; ; Out: r9 corrupted ; CC => r5 = physical address ; CS => invalid logical address, r5 corrupted ; ; Convert logical address to physical address. ; logical_to_physical MOV r9, r4, LSR #12 ; r9 = logical page number ADD r9, r8, r9, LSL #2 ; r9 -> L2PT entry for logical address MOV r5, r9, LSR #12 ; r5 = page offset to L2PT entry for logical address LDR r5, [r8, r5, LSL #2] ; r5 = L2PT entry for L2PT entry for logical address EOR r5, r5, #2_10 ; Check for valid page. TST r5, #3 [ No26bitCode BNE meminfo_returncs | ORRNES pc, lr, #C_bit ] LDR r5, [r9] ; r5 = L2PT entry for logical address EOR r5, r5, #2_10 ; Check for valid page. TST r5, #3 [ No26bitCode BNE meminfo_returncs | ORRNES pc, lr, #C_bit ] LDR r9, =&FFF ; Valid so BIC r5, r5, r9 ; mask off bits 0-11, AND r9, r4, r9 ; get page offset from logical page ORR r5, r5, r9 ; combine with physical page address. [ No26bitCode CLC MOV pc, lr | BICS pc, lr, #C_bit ] meminfo_returncs SEC MOV pc, lr ;---------------------------------------------------------------------------------------- ; physical_to_ppn ; ; In: r5 = physical address ; r7 = MaxCamEntry ; ; Out: r9-r11 corrupted ; CC => r3 = page number ; CS => invalid physical address, r3 corrupted ; ; Convert physical address to physical page number. ; physical_to_ppn ROUT LDR r9, =ZeroPage+PhysRamTable MOV r3, #0 ; Start at page 0. 10 CMP r7, r3 ; Stop if we run out of pages [ No26bitCode BCC meminfo_returncs | ORRCCS pc, lr, #C_bit ; (return with C set). ] LDMIA r9!, {r10,r11} ; Get start address and size of next block. SUB r10, r5, r10 ; Determine if given address is in this block. CMP r10, r11 ADDCS r3, r3, r11, LSR #12 ; Move on to next block. BCS %BT10 ADD r3, r3, r10, LSR #12 [ No26bitCode CLC MOV pc, lr | BICS pc, lr, #C_bit ; Return with C clear. ] ;---------------------------------------------------------------------------------------- ; Symbols used in MemoryPhysSize and MemoryReadPhys ; ; Shifts to determine number of bytes/words to allocate in table. BitShift * 10 ByteShift * BitShift + 3 WordShift * ByteShift + 2 ; Bit patterns for different types of memory. NotPresent * &00000000 DRAM_Pattern * &11111111 VRAM_Pattern * &22222222 ROM_Pattern * &33333333 IO_Pattern * &44444444 NotAvailable * &88888888 ;---------------------------------------------------------------------------------------- ; MemoryPhysSize ; ; In: r0 = 6 (reason code with flag bits 8-31 clear) ; ; Out: r1 = table size (in bytes) ; r2 = page size (in bytes) ; ; Returns information about the memory arrangement table. ; MemoryPhysSize [ HAL Entry "r0-r1,r3,sb,ip" AddressHAL MOV r0, #PhysInfo_GetTableSize ADD r1, sp, #4 CallHAL HAL_PhysInfo MOV r2, #4*1024 EXIT | MOV r1, #PhysSpaceSize :SHR: ByteShift MOV r2, #4*1024 MOV pc, lr ] ;---------------------------------------------------------------------------------------- ; MemoryReadPhys ; ; In: r0 = 7 (reason code with flag bits 8-31 clear) ; r1 -> memory arrangement table to be filled in ; ; Out: r1 -> filled in memory arrangement table ; ; Returns the physical memory arrangement table in the given block. ; MemoryReadPhys ROUT [ HAL Entry "r0-r12" AddressHAL MOV r0, #PhysInfo_WriteTable SUB sp, sp, #8 MOV r2, sp CallHAL HAL_PhysInfo ; fills in everything except DRAM LDR r0, [sp], #4 LDR r11, [sp], #4 ; r0 to r11 is DRAM or not present. LDR r1, [sp, #4] ; Get table address back ADD r1, r1, r0, LSR #ByteShift MOV r2, r0 ; Current physical address. MOV r3, #0 ; Next word to store in table. MOV r4, #32 ; How much more we have to shift r3 before storing it. MOV r5, #0 ; Current page number. LDR r6, =ZeroPage+PhysRamTable LDR r7, [r6, #CamEntriesPointer-PhysRamTable] ADD r7, r7, #4 ; Point to PPL entries. LDR r8, [r6, #MaxCamEntry-PhysRamTable] 10 LDMIA r6!, {r9,r10} ; Get physical address and size of next block. CMP r9, r0 ; If not DRAM then CMPHS r11, r9 ADDLO r5, r5, r10, LSR #12 ; adjust current page number BLO %BT10 ; and try next block. ADD r10, r10, r9 ; Add amount of unused space between current and start of block. SUB r10, r10, r2 ; size = size + (physaddr - current) 20 SUBS r4, r4, #4 ; Reduce shift. MOVCS r3, r3, LSR #4 ; If more space in current word then shift it. STRCC r3, [r1], #4 ; Otherwise, store current word MOVCC r3, #0 ; and start a new one. MOVCC r4, #28 CMP r2, r9 ; If not reached start of block then page is not present. ORRCC r3, r3, #(NotPresent :OR: NotAvailable) :SHL: 28 BCC %FT30 LDR lr, [r7, r5, LSL #3] ; Page is there so get PPL and determine if it's available or not. TST lr, #PageFlags_Unavailable ORREQ r3, r3, #DRAM_Pattern :SHL: 28 ORRNE r3, r3, #(DRAM_Pattern :OR: NotAvailable) :SHL: 28 ADD r5, r5, #1 ; Increment page count. 30 ADD r2, r2, #&1000 ; Increase current address. SUBS r10, r10, #&1000 ; Decrease size of block. BGT %BT20 ; Stop if no more block left. CMP r8, r5 ; Stop if we run out of pages. BCS %BT10 TEQ r3, #0 ; If not stored last word then MOVNE r3, r3, LSR r4 ; put bits in correct position ADDNE r2, r2, r4, LSL #BitShift ; adjust current address RSBNE r4, r4, #32 ; rest of word is not present LDRNE lr, =NotPresent :OR: NotAvailable ORRNE r3, r3, lr, LSL r4 STRNE r3, [r1], #4 ; and store word. ; End of last block of DRAM to r11 is not present. MOV r6, r0 ADD lr, r11, #1 RSBS r2, r2, lr MOVNE r0, r1 LDRNE r1, =NotPresent :OR: NotAvailable MOVNE r2, r2, LSR #ByteShift BLNE memset ; If softloaded (ie ROM image is wholely within DRAM area returned ; by HAL_PhysInfo), mark that as unavailable DRAM. LDR r0, =ZeroPage LDR r0, [r0, #ROMPhysAddr] LDR r1, [sp, #4] CMP r0, r6 ADDHS lr, r0, #OSROM_ImageSize*1024 SUBHS lr, lr, #1 CMPHS r11, lr ADDHS r0, r1, r0, LSR #ByteShift LDRHS r1, =DRAM_Pattern :OR: NotAvailable MOVHS r2, #(OSROM_ImageSize*1024) :SHR: ByteShift BLHS memset | Entry "r1-r10" ; &00000000 to OSROM_ImageSize*1024 is ROM. MOV r2, #(OSROM_ImageSize*1024-&00000000) :SHR: WordShift LDR r3, =ROM_Pattern :OR: NotAvailable BL fill_words ; OSROM_ImageSize*1024 to &02000000 is allocated to ROM but is not present. MOV r2, #(&02000000-OSROM_ImageSize*1024) :SHR: WordShift LDR r3, =NotPresent :OR: NotAvailable BL fill_words ; &02000000 to &02400000 is VRAM or not present. MOV r4, #0 LDR r4, [r4, #VRAMSize] ; Get amount of VRAM (in bytes). TEQ r4, #0 MOVNE r2, r4, LSR #WordShift ; If there is some then fill part of table. LDRNE r3, =VRAM_Pattern :OR: NotAvailable BLNE fill_words ; End of VRAM to &03000000 is not present. RSB r4, r4, #&03000000-&02000000 MOV r2, r4, LSR #WordShift LDR r3, =NotPresent :OR: NotAvailable BL fill_words ; &03000000 to &03800000 is I/O. MOV r2, #(&03800000-&03000000) :SHR: WordShift LDR r3, =IO_Pattern :OR: NotAvailable BL fill_words ; &03800000 to &08000000 is not present. MOV r2, #(&08000000-&03800000) :SHR: WordShift LDR r3, =NotPresent :OR: NotAvailable BL fill_words ; &08000000 to &10000000 is I/O (EASI space). MOV r2, #(&10000000-&08000000) :SHR: WordShift LDR r3, =IO_Pattern :OR: NotAvailable BL fill_words ; &10000000 to &20000000 is DRAM or not present. MOV r2, #&10000000 ; Current physical address. MOV r3, #0 ; Next word to store in table. MOV r4, #32 ; How much more we have to shift r3 before storing it. MOV r5, #0 ; Current page number. MOV r6, #PhysRamTable LDR r7, [r3, #CamEntriesPointer] ADD r7, r7, #4 ; Point to PPL entries. LDR r8, [r3, #MaxCamEntry] 10 LDMIA r6!, {r9,r10} ; Get physical address and size of next block. CMP r9, #&10000000 ; If not DRAM then ADDCC r5, r5, r10, LSR #12 ; adjust current page number BCC %BT10 ; and try next block. ADD r10, r10, r9 ; Add amount of unused space between current and start of block. SUB r10, r10, r2 ; size = size + (physaddr - current) 20 SUBS r4, r4, #4 ; Reduce shift. MOVCS r3, r3, LSR #4 ; If more space in current word then shift it. STRCC r3, [r1], #4 ; Otherwise, store current word MOVCC r3, #0 ; and start a new one. MOVCC r4, #28 CMP r2, r9 ; If not reached start of block then page is not present. ORRCC r3, r3, #(NotPresent :OR: NotAvailable) :SHL: 28 BCC %FT30 LDR lr, [r7, r5, LSL #3] ; Page is there so get PPL and determine if it's available or not. TST lr, #PageFlags_Unavailable ORREQ r3, r3, #DRAM_Pattern :SHL: 28 ORRNE r3, r3, #(DRAM_Pattern :OR: NotAvailable) :SHL: 28 ADD r5, r5, #1 ; Increment page count. 30 ADD r2, r2, #&1000 ; Increase current address. SUBS r10, r10, #&1000 ; Decrease size of block. BGT %BT20 ; Stop if no more block left. CMP r8, r5 ; Stop if we run out of pages. BCS %BT10 TEQ r3, #0 ; If not stored last word then MOVNE r3, r3, LSR r4 ; put bits in correct position ADDNE r2, r2, r4, LSL #BitShift ; adjust current address RSBNE r4, r4, #32 ; rest of word is not present LDRNE lr, =NotPresent :OR: NotAvailable ORRNE r3, r3, lr, LSL r4 STRNE r3, [r1], #4 ; and store word. ; End of last block of DRAM to &20000000 is not present. RSBS r2, r2, #&20000000 MOVNE r2, r2, LSR #WordShift LDRNE r3, =NotPresent :OR: NotAvailable BLNE fill_words ] EXIT fill_words STR r3, [r1], #4 SUBS r2, r2, #1 BNE fill_words MOV pc, lr ;---------------------------------------------------------------------------------------- ; MemoryAmounts ; ; In: r0 = flags ; bit meaning ; 0-7 8 (reason code) ; 8-11 1=return amount of DRAM (excludes any soft ROM) ; 2=return amount of VRAM ; 3=return amount of ROM ; 4=return amount of I/O space ; 5=return amount of soft ROM (ROM loaded into hidden DRAM) ; 12-31 reserved (set to 0) ; ; Out: r1 = number of pages of the specified type of memory ; r2 = page size (in bytes) ; ; Return the amount of the specified type of memory. ; MemoryAmounts ROUT Entry "r3" [ HAL BICS lr, r0, #&FF ; Get type of memory required (leave bits 12-31, non-zero => error). CMP lr, #6:SHL:8 ADDCC pc, pc, lr, LSR #8-2 NOP B %FT99 ; Don't understand 0 (so the spec says). B %FT10 ; DRAM B %FT20 ; VRAM B %FT30 ; ROM B %FT40 ; I/O B %FT50 ; Soft ROM 10 LDR r1, =ZeroPage LDR r3, [r1, #VRAMFlags] TST r3, #1 MOVNE r3, r3, LSR #12 ; Extract size from flags when genuine VRAM MOVNE r3, r3, LSL #12 MOVEQ r3, #0 LDR r1, [r1, #RAMLIMIT] SUB r1, r1, r3 ; DRAM = RAMLIMIT - VRAMSize B %FT97 20 LDR r1, =ZeroPage LDR r1, [r1, #VRAMFlags] TST r1, #1 MOVNE r1, r1, LSR #12 MOVNE r1, r1, LSL #12 ; VRAM = VRAMSize MOVEQ r1, #0 B %FT97 30 Push "r0, sb, ip" AddressHAL MOV r0, #PhysInfo_HardROM SUB sp, sp, #8 MOV r2, sp CallHAL HAL_PhysInfo LDMIA sp!, {r0-r1} SUB r1, r1, r0 ; ROM = ROMPhysTop - ROMPhysBot Pull "r0, sb, ip" B %FT97 40 LDR r1, =ZeroPage LDR r1, [r1, #IOAllocLimit] LDR r3, =IO SUB r1, r3, r1 ; IO = IO ceiling - IO floor B %FT97 50 Push "r0" MOV r0, #8 SWI XOS_ReadSysInfo ; Are we softloaded? Pull "r0" AND r1, r1, r2 ANDS r1, r1, #1:SHL:4 ; Test OS-runs-from-RAM flag MOVNE r1, #OSROM_ImageSize*1024 B %FT97 97 MOV r1, r1, LSR #12 ; Return as number of pages. MOV r2, #4*1024 ; Return page size. EXIT 99 ADRL r0, ErrorBlock_BadParameters [ International BL TranslateError | SETV ] EXIT | BICS lr, r0, #&FF ; Get type of memory required (leave bits 12-31, non-zero => error). BEQ %FT30 ; Don't understand 0 (so the spec says). TEQ lr, #5:SHL:8 ; Check for soft ROM BNE %FT10 LDR r1, =L1PT MOV r2, #ROM ADD r1, r1, r2, LSR #(20-2) ; L1PT address for ROM LDR r2, [r1] MOV r2, r2, LSR #12 TEQ r2, #PhysROM :SHR: 12 ; see if we have hard or soft ROM MOVEQ r1, #0 ; no soft ROM MOVNE r1, #OSROM_ImageSize*1024 ; this much soft ROM B %FT20 10 TEQ lr, #4:SHL:8 ; Check for IO space. LDREQ r1, =136*1024*1024 ; Just return 136M (includes VIDC and EASI space). BEQ %FT20 TEQ lr, #3:SHL:8 ; Check for ROM. LDREQ r1, =OSROM_ImageSize*1024 BEQ %FT20 TEQ lr, #2:SHL:8 ; Check for VRAM. MOVEQ r1, #0 ; Return amount of VRAM. LDREQ r1, [r1, #VRAMSize] BEQ %FT20 TEQ lr, #1:SHL:8 ; Check for DRAM. BNE %FT30 MOV r1, #0 LDR lr, [r1, #RAMLIMIT] LDR r1, [r1, #VRAMSize] SUB r1, lr, r1 ; Return amount of RAM - amount of VRAM. 20 MOV r1, r1, LSR #12 ; Return as number of pages. MOV r2, #4*1024 ; Return page size. EXIT 30 ADRL r0, ErrorBlock_BadParameters SETV EXIT ] ;---------------------------------------------------------------------------------------- ; MemoryIOSpace ; ; In: r0 = 9 (reason code with flag bits 8-31 clear) ; r1 = controller ID ; bit meaning ; 0-7 controller sequence number ; 8-31 controller type: ; 0 = EASI card access speed control ; 1 = EASI space(s) ; 2 = VIDC1 ; 3 = VIDC20 ; 4 = S space (IOMD,podules,NICs,blah blah) ; 5 = Extension ROM(s) ; 6 = Tube ULA ; 7-31 = Reserved (for us) ; 32 = Primary ROM ; 33 = IOMD ; 34 = FDC37C665/SMC37C665/82C710/SuperIO/whatever ; 35+ = Reserved (for ROL) ; ; Out: r1 = controller base address or 0 if not present ; ; Return the location of the specified controller. ; [ HAL MemoryIOSpace ROUT Entry "r0,r2,r3,sb,ip" AddressHAL CallHAL HAL_ControllerAddress CMP r0, #-1 MOVNE r1, r0 ADREQL r0, ErrorBlock_BadParameters STREQ r0, [sp, #0] SETV EQ EXIT | MemoryIOSpace ROUT Entry "r2" AND r2, r1, #&FF ; Get sequence number. MOV r1, r1, LSR #8 ; Get controller type. CMP r1, #6 ; Make sure it's in range. ADRCSL r0, ErrorBlock_BadParameters SETV CS EXIT CS ADR lr, controller_types LDR r1, [lr, r1, LSL #2] ; Get base address or offset to table. TEQ r1, #0 ; If not present or CMPNE r1, #1024 ; not offset to table then EXIT GE ; return. ADD lr, lr, r1 ; Point to table indexed by sequence number. LDR r1, [lr], #4 ; Get sequence number limit. CMP r2, r1 ; Make sure it's in range. BCS %FT20 LDR r1, [lr, r2, LSL #2] ; Get base address. EXIT controller_types DCD IOMD_Base + IOMD_ECTCR ; Expansion card timing control. DCD easi_space_table - controller_types DCD 0 DCD VIDC DCD IOMD_Base DCD 0 easi_space_table DCD 8 ; Maximum of 8 expansion cards. DCD PhysSpace + IOMD_EASI_Base0 DCD PhysSpace + IOMD_EASI_Base1 DCD PhysSpace + IOMD_EASI_Base2 DCD PhysSpace + IOMD_EASI_Base3 DCD PhysSpace + IOMD_EASI_Base4 DCD PhysSpace + IOMD_EASI_Base5 DCD PhysSpace + IOMD_EASI_Base6 DCD PhysSpace + IOMD_EASI_Base7 ] ; HAL ;---------------------------------------------------------------------------------------- ; MemoryFreePoolLock ; ; ; In: r0 bits 0..7 = 10 (reason code 10) ; r0 bit 8 = 1 if call is by Wimp (reserved for Acorn use), 0 otherwise ; r0 bits 9..31 reserved (must be 0) ; r1 = 0 to resume any background actions that may manipulate FreePool mapping ; (currently, this is just VRAMRescue) ; = 1 to suspend any background actions that may manipulate FreePool mapping ; all other values reserved (undefined behaviour) ; ; Out: r1 = previous state (1=suspended, 0=not suspended) ; ; A suspend call from the Wimp will be taken to mean that the whole FreePool is locked, and ; memory cannot be moved (supports Wimp_ClaimFreeMemory) ; ; VRAM rescue doesn't happen in this Kernel, but we still support the call for the Wimp. ; MemoryFreePoolLock ROUT Push "r2,r3,lr" LDR r3,=ZeroPage LDRB lr,[r3,#VRAMRescue_control] TEQ r1,#0 BNE %FT10 ;flush TLB(s) for resume - needed for Wimp resume, precaution for other - no cache flush ;since Free Pool is uncached [ HAL Push "r0" ARMop TLB_InvalidateAll,,,r3 Pull "r0" | ARM_flush_TLB r2 ] 10 TST r0,#&100 ;is it Wimp? MOVEQ r2,#VRRc_suspend MOVNE r2,#VRRc_wimp_lock TEQ r1,#0 AND r1,lr,r2 ;previous state BICEQ lr,lr,r2 ORRNE lr,lr,r2 STRB lr,[r3,#VRAMRescue_control] ;set/clear relevant bit TEQ r1,#0 MOVNE r1,#1 Pull "r2,r3,pc" ;---------------------------------------------------------------------------------------- ;PCImapping - reserved for Acorn use (PCI manager) ; ; See code on Ursula branch ;---------------------------------------------------------------------------------------- ;RecommendPage ; ; In: r0 bits 0..7 = 12 (reason code 12) ; r0 bits 8..31 = 0 (reserved flags) ; r1 = size of physically contiguous RAM region required (bytes) ; r2 = log2 of required alignment of base of region (eg. 12 = 4k, 20 = 1M) ; ; Out: r3 = page number of first page of recommended region that could be ; grown as specific pages by dynamic area handler (only guaranteed ; if grow is next page claiming operation) ; - or error if not possible (eg too big, pages unavailable) ; RecommendPage ROUT Push "r0-r2,r4-r10,lr" CMP r2,#30 BHI RP_failed ;refuse to look for alignments above 1G ; ADD r1,r1,#&1000 SUB r1,r1,#1 MOV r1,r1,LSR #12 MOVS r1,r1,LSL #12 ;size rounded up to whole no. of pages ; CMP r2,#12 MOVLO r2,#12 ;log2 alignment must be at least 12 (4k pages) MOV r0,#1 MOV r4,r0,LSL r2 ;required alignment-1 ; LDR r0,=ZeroPage+PhysRamTable MOV r3,#0 ;page number, starts at 0 LDR r5,=ZeroPage+CamEntriesPointer LDR r5,[r5] ADD r5,r5,#4 ; [r5,<page no.>,LSL #3] addresses flags word in CAM LDMIA r0!,{r7,r8} ;address,size of video chunk (skip this one) ; RP_nextchunk ADD r3,r3,r8,LSR #12 ;page no. of first page of next chunk LDMIA r0!,{r7,r8} ;address,size of next physical chunk CMP r8,#0 BEQ RP_failed ; ADD r6,r7,r4 SUB r6,r6,#1 ;round up MOV r6,r6,LSR r2 MOV r6,r6,LSL r2 SUB r6,r6,r7 ;adjustment to first address of acceptable alignment CMP r6,r8 BHS RP_nextchunk ;negligible chunk ADD r7,r3,r6,LSR #12 ;first page number of acceptable alignment SUB r9,r8,r6 ;remaining size of chunk ; ;find first available page RP_nextpage CMP r9,r1 BLO RP_nextchunk LDR r6,[r5,r7,LSL #3] ;page flags from CAM ;must not be marked Unavailable or Required TST r6,#PageFlags_Unavailable :OR: PageFlags_Required BEQ RP_checkotherpages RP_nextpagecontinue CMP r9,r4 BLS RP_nextchunk ADD r7,r7,r4,LSR #12 ;next page of suitable alignment SUB r9,r9,r4 B RP_nextpage ; RP_checkotherpages ADD r10,r7,r1,LSR #12 SUB r10,r10,#1 ;last page required RP_checkotherpagesloop LDR r6,[r5,r10,LSL #3] ;page flags from CAM TST r6,#PageFlags_Unavailable :OR: PageFlags_Required BNE RP_nextpagecontinue SUB r10,r10,#1 CMP r10,r7 BHI RP_checkotherpagesloop ; ;success! ; MOV r3,r7 Pull "r0-r2,r4-r10,pc" RP_failed MOV r3,#0 ADR r0,RP_error SETV STR r0,[sp] Pull "r0-r2,r4-r10,pc" RP_error DCD 0 DCB "No chunk available (OS_Memory 12)",0 ALIGN ;---------------------------------------------------------------------------------------- ;MapIOpermanent - map IO space (if not already mapped) and return logical address ; ; In: r0 bits 0..7 = 13 (reason code 13) ; r0 bit 8 = 1 to map bufferable space (0 is normal, non-bufferable) ; r0 bit 9 = 1 to map cacheable space (0 is normal, non-cacheable) ; r0 bits 10..12 = 0 (reserved for cache policy) ; r0 bits 13..15 = 0 (reserved flags) ; r0 bit 16 = 1 to doubly map ; r0 bit 17 = 1 if access privileges specified ; r0 bits 18..23 = 0 (reserved flags) ; r0 bits 24..27 = access privileges (if bit 17 set) ; r0 bits 28..31 = 0 (reserved flags) ; r1 = physical address of base of IO space required ; r2 = size of IO space required (bytes) ; ; Out: r3 = logical address of base of IO space ; - or error if not possible (no room) ; MapIOpermanent ROUT Push "r0-r2,r12,lr" MOV lr, r0 TST lr, #1:SHL:8 ;test bufferable bit MOVNE r0, #L1_B MOVEQ r0, #0 TST lr, #1:SHL:9 ;test bufferable bit ORRNE r0, r0, #L1_C TST lr, #1:SHL:16 ORRNE r0, r0, #MapInFlag_DoublyMapped TST lr, #1:SHL:17 ANDNE lr, lr, #2_1111:SHL:24 ADRNEL r12, PPLTransL1 LDRNE r12, [r12, lr, LSR #22] ORRNE r0, r0, #MapInFlag_APSpecified ORRNE r0, r0, r12 BL RISCOS_MapInIO MOV r3, r0 CMP r3, #0 ;MOV,CMP rather than MOVS to be sure to clear V Pull "r0-r2,r12,pc",NE ADR r0, MIp_error SETV STR r0, [sp] Pull "r0-r2,r12,pc" MIp_error DCD 0 DCB "No room for IO space (OS_Memory 13)",0 ALIGN ;---------------------------------------------------------------------------------------- ;AccessPhysAddr - claim temporary access to given physical address (in fact, ; controls access to the 1Mb aligned space containing the address) ; The access remains until the next AccessPhysAddr or until a ; ReleasePhysAddr (although interrupts or subroutines may temporarily ; make their own claims, but restore on Release before returning) ; ; In: r0 bits 0..7 = 14 (reason code 14) ; r0 bit 8 = 1 to map bufferable space, 0 for unbufferable ; r0 bits 9..31 = 0 (reserved flags) ; r1 = physical address ; ; Out: r2 = logical address corresponding to phys address r1 ; r3 = old state (for ReleasePhysAddr) ; ; Use of multiple accesses: it is fine to make several Access calls, and ; clean up with a single Release at the end. In this case, it is the old state ; (r3) of the *first* Access call that should be passed to Release in order to ; restore the state before any of your accesses. (The r3 values of the other ; access calls can be ignored.) ; AccessPhysAddr ROUT Push "r0,r1,r12,lr" TST r0, #&100 ;test bufferable bit MOVNE r0, #L1_B MOVEQ r0, #0 SUB sp, sp, #4 ; word for old state MOV r2, sp ; pointer to word BL RISCOS_AccessPhysicalAddress MOV r2, r0 Pull r3 ; old state Pull "r0,r1,r12,pc" ;---------------------------------------------------------------------------------------- ;ReleasePhysAddr - release temporary access that was claimed by AccessPhysAddr ; ; In: r0 bits 0..7 = 15 (reason code 15) ; r0 bits 8..31 = 0 (reserved flags) ; r1 = old state to restore ; ReleasePhysAddr Push "r0-r3,r12,lr" MOV r0, r1 BL RISCOS_ReleasePhysicalAddress Pull "r0-r3,r12,pc" ;---------------------------------------------------------------------------------------- ; ; In: r0 = flags ; bit meaning ; 0-7 16 (reason code) ; 8-15 1=cursor/system/sound ; 2=IRQ stack ; 3=SVC stack ; 4=ABT stack ; 5=UND stack ; 6=Soft CAM ; 7=Level 1 page tables ; 8=Level 2 page tables ; 9=HAL workspace ; 10=Kernel buffers ; 11=HAL uncacheable workspace ; 16-31 reserved (set to 0) ; ; Out: r1 = base of area ; r2 = address space allocated for area (whole number of pages) ; r3 = actual memory used by area (whole number of pages) ; all values 0 if not present, or incorporated into another area ; ; Return size of various low-level memory regions MemoryAreaInfo ROUT Entry "r0" MOV r1, #0 MOV r2, #0 MOV r3, #0 MOV lr, r0, LSR #8 AND lr, lr, #&FF CMP lr, #(MAI_TableEnd - MAI_TableStart)/4 ADDLO pc, pc, lr, LSL #2 B %FT70 MAI_TableStart B %FT70 B MAI_CursSysSound B MAI_IRQStk B MAI_SVCStk B MAI_ABTStk B MAI_UNDStk B MAI_SoftCAM B MAI_L1PT B MAI_L2PT B MAI_HALWs B MAI_Kbuffs B MAI_HALWsNCNB MAI_TableEnd 70 ADRL r0, ErrorBlock_BadParameters SETV STR r0, [sp, #Proc_RegOffset+0] EXIT MAI_CursSysSound LDR r1, =CursorChunkAddress MOV r2, #32*1024 MOV r3, r2 EXIT MAI_IRQStk [ IRQSTK < CursorChunkAddress :LOR: IRQSTK > CursorChunkAddress+32*1024 LDR r1, =IRQStackAddress MOV r2, #IRQSTK-IRQStackAddress MOV r3, r2 ] EXIT MAI_SVCStk LDR r1, =SVCStackAddress MOV r2, #SVCSTK-SVCStackAddress MOV r3, r2 EXIT MAI_ABTStk [ No26bitCode LDR r1, =ABTStackAddress MOV r2, #ABTSTK-ABTStackAddress MOV r3, r2 ] EXIT MAI_UNDStk LDR r1, =UNDSTK :AND: &FFF00000 LDR r2, =UNDSTK :AND: &000FFFFF MOV r3, r2 EXIT MAI_SoftCAM LDR r0, =ZeroPage LDR r1, [r0, #CamEntriesPointer] LDR r2, =CAMspace LDR r3, [r0, #SoftCamMapSize] EXIT MAI_L1PT LDR r1, =L1PT MOV r2, #16*1024 MOV r3, r2 EXIT MAI_L2PT LDR r0, =ZeroPage LDR r1, =L2PT MOV r2, #4*1024*1024 LDR r3, [r0, #L2PTUsed] EXIT MAI_HALWs [ HAL LDR r0, =ZeroPage LDR r1, =HALWorkspace MOV r2, #HALWorkspaceSize LDR r3, [r0, #HAL_WsSize] ] EXIT MAI_HALWsNCNB [ HAL LDR r0, =ZeroPage LDR r1, =HALWorkspaceNCNB MOV r2, #32*1024 LDR r3, [r0, #HAL_Descriptor] LDR r3, [r3, #HALDesc_Flags] ANDS r3, r3, #HALFlag_NCNBWorkspace MOVNE r3, r2 ] EXIT MAI_Kbuffs LDR r1, =KbuffsBaseAddress MOV r2, #KbuffsMaxSize LDR r3, =(KbuffsSize + &FFF) :AND: :NOT: &FFF EXIT END