📄 head.s
字号:
jbra L(mmu_init_done)L(not16x):#endif /* CONFIG_MVME162 | CONFIG_MVME167 */#ifdef CONFIG_BVME6000 is_not_bvme6000(L(not6000)) /* * On BVME6000 we have already created kernel page tables for * 4MB of RAM at address 0, so now need to do a transparent * mapping of the top of memory space. Make it 0.5GByte for now, * so we can access on-board i/o areas. * Supervisor only access, so transparent mapping doesn't * clash with User code virtual address space. */ mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S jbra L(mmu_init_done)L(not6000):#endif /* CONFIG_BVME6000 *//* * mmu_init_mac * * The Macintosh mappings are less clear. * * Even as of this writing, it is unclear how the * Macintosh mappings will be done. However, as * the first author of this code I'm proposing the * following model: * * Map the kernel (that's already done), * Map the I/O (on most machines that's the * 0x5000.0000 ... 0x5200.0000 range, * Map the video frame buffer using as few pages * as absolutely (this requirement mostly stems from * the fact that when the frame buffer is at * 0x0000.0000 then we know there is valid RAM just * above the screen that we don't want to waste!). * * By the way, if the frame buffer is at 0x0000.0000 * then the Macintosh is known as an RBV based Mac. * * By the way 2, the code currently maps in a bunch of * regions. But I'd like to cut that out. (And move most * of the mappings up into the kernel proper ... or only * map what's necessary.) */#ifdef CONFIG_MACL(mmu_init_mac): is_not_mac(L(mmu_init_not_mac)) putc 'F' lea %pc@(L(mac_videobase)),%a0 lea %pc@(L(console_video_virtual)),%a1 movel %a0@,%a1@ is_not_040_or_060(1f) moveq #_PAGE_NOCACHE_S,%d3 jbra 2f1: moveq #_PAGE_NOCACHE030,%d32: /* * Mac Note: screen address of logical 0xF000.0000 -> <screen physical> * we simply map the 4MB that contains the videomem */ movel #VIDEOMEMMASK,%d0 andl L(mac_videobase),%d0 mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3 mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */ mmu_map_eq #0x50000000,#0x02000000,%d3 mmu_map_eq #0x60000000,#0x00400000,%d3 mmu_map_eq #0x9c000000,#0x00400000,%d3 mmu_map_tt #1,#0xf8000000,#0x08000000,%d3 jbra L(mmu_init_done)L(mmu_init_not_mac):#endif#ifdef CONFIG_SUN3X is_not_sun3x(L(notsun3x)) /* setup tt1 for I/O */ mmu_map_tt #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S jbra L(mmu_init_done)L(notsun3x):#endif#ifdef CONFIG_APOLLO is_not_apollo(L(notapollo)) putc 'P' mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 L(notapollo): jbra L(mmu_init_done)#endifL(mmu_init_done): putc 'G' leds 0x8/* * mmu_fixup * * On the 040 class machines, all pages that are used for the * mmu have to be fixed up. According to Motorola, pages holding mmu * tables should be non-cacheable on a '040 and write-through on a * '060. But analysis of the reasons for this, and practical * experience, showed that write-through also works on a '040. * * Allocated memory so far goes from kernel_end to memory_start that * is used for all kind of tables, for that the cache attributes * are now fixed. */L(mmu_fixup): is_not_040_or_060(L(mmu_fixup_done))#ifdef MMU_NOCACHE_KERNEL jbra L(mmu_fixup_done)#endif /* first fix the page at the start of the kernel, that * contains also kernel_pg_dir. */ movel %pc@(L(phys_kernel_start)),%d0 subl #PAGE_OFFSET,%d0 lea %pc@(SYMBOL_NAME(_stext)),%a0 subl %d0,%a0 mmu_fixup_page_mmu_cache %a0 movel %pc@(L(kernel_end)),%a0 subl %d0,%a0 movel %pc@(L(memory_start)),%a1 subl %d0,%a1 bra 2f1: mmu_fixup_page_mmu_cache %a0 addw #PAGESIZE,%a02: cmpl %a0,%a1 jgt 1bL(mmu_fixup_done):#ifdef MMU_PRINT mmu_print#endif/* * mmu_engage * * This chunk of code performs the gruesome task of engaging the MMU. * The reason its gruesome is because when the MMU becomes engaged it * maps logical addresses to physical addresses. The Program Counter * register is then passed through the MMU before the next instruction * is fetched (the instruction following the engage MMU instruction). * This may mean one of two things: * 1. The Program Counter falls within the logical address space of * the kernel of which there are two sub-possibilities: * A. The PC maps to the correct instruction (logical PC == physical * code location), or * B. The PC does not map through and the processor will read some * data (or instruction) which is not the logically next instr. * As you can imagine, A is good and B is bad. * Alternatively, * 2. The Program Counter does not map through the MMU. The processor * will take a Bus Error. * Clearly, 2 is bad. * It doesn't take a wiz kid to figure you want 1.A. * This code creates that possibility. * There are two possible 1.A. states (we now ignore the other above states): * A. The kernel is located at physical memory addressed the same as * the logical memory for the kernel, i.e., 0x01000. * B. The kernel is located some where else. e.g., 0x0400.0000 * * Under some conditions the Macintosh can look like A or B. * [A friend and I once noted that Apple hardware engineers should be * wacked twice each day: once when they show up at work (as in, Whack!, * "This is for the screwy hardware we know you're going to design today."), * and also at the end of the day (as in, Whack! "I don't know what * you designed today, but I'm sure it wasn't good."). -- rst] * * This code works on the following premise: * If the kernel start (%d5) is within the first 16 Meg of RAM, * then create a mapping for the kernel at logical 0x8000.0000 to * the physical location of the pc. And, create a transparent * translation register for the first 16 Meg. Then, after the MMU * is engaged, the PC can be moved up into the 0x8000.0000 range * and then the transparent translation can be turned off and then * the PC can jump to the correct logical location and it will be * home (finally). This is essentially the code that the Amiga used * to use. Now, it's generalized for all processors. Which means * that a fresh (but temporary) mapping has to be created. The mapping * is made in page 0 (an as of yet unused location -- except for the * stack!). This temporary mapping will only require 1 pointer table * and a single page table (it can map 256K). * * OK, alternatively, imagine that the Program Counter is not within * the first 16 Meg. Then, just use Transparent Translation registers * to do the right thing. * * Last, if _start is already at 0x01000, then there's nothing special * to do (in other words, in a degenerate case of the first case above, * do nothing). * * Let's do it. * * */ putc 'H' mmu_engage/* * After this point no new memory is allocated and * the start of available memory is stored in availmem. * (The bootmem allocator requires now the physicall address.) */ movel L(memory_start),availmem#ifdef CONFIG_AMIGA is_not_amiga(1f) /* fixup the Amiga custom register location before printing */ clrl L(custom)1:#endif#ifdef CONFIG_ATARI is_not_atari(1f) /* fixup the Atari iobase register location before printing */ movel #0xff000000,L(iobase)1:#endif#ifdef CONFIG_MAC is_not_mac(1f) movel #~VIDEOMEMMASK,%d0 andl L(mac_videobase),%d0 addl #VIDEOMEMBASE,%d0 movel %d0,L(mac_videobase)1:#endif#ifdef CONFIG_HP300 is_not_hp300(1f) /* * Fix up the custom register to point to the new location of the LEDs. */ movel #0xf0000000,L(custom) /* * Energise the FPU and caches. */ movel #0x60,0xf05f400c1:#endif#ifdef CONFIG_SUN3X is_not_sun3x(1f) /* enable copro */ oriw #0x4000,0x610000001:#endif#ifdef CONFIG_APOLLO is_not_apollo(1f) /* * Fix up the iobase before printing */ movel #0x80000000,L(iobase)1:#endif putc 'I' leds 0x10/* * Enable caches */ is_not_040_or_060(L(cache_not_680460))L(cache680460): .chip 68040 nop cpusha %bc nop is_060(L(cache68060)) movel #CC6_ENABLE_D+CC6_ENABLE_I,%d0 /* MMU stuff works in copyback mode now, so enable the cache */ movec %d0,%cacr jra L(cache_done)L(cache68060): movel #CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0 /* MMU stuff works in copyback mode now, so enable the cache */ movec %d0,%cacr /* enable superscalar dispatch in PCR */ moveq #1,%d0 .chip 68060 movec %d0,%pcr jbra L(cache_done)L(cache_not_680460):L(cache68030): .chip 68030 movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0 movec %d0,%cacr jra L(cache_done) .chip 68kL(cache_done): putc 'J'/* * Setup initial stack pointer */ lea SYMBOL_NAME(init_task_union),%curptr lea 0x2000(%curptr),%sp putc 'K' subl %a6,%a6 /* clear a6 for gdb *//* * The new 64bit printf support requires an early exception initialization. */ jbsr SYMBOL_NAME(base_trap_init)/* jump to the kernel start */ putc '\n' leds 0x55 jbsr SYMBOL_NAME(start_kernel)/* * Find a tag record in the bootinfo structure * The bootinfo structure is located right after the kernel bss * Returns: d0: size (-1 if not found) * a0: data pointer (end-of-records if not found) */func_start get_bi_record,%d1 movel ARG1,%d0 lea %pc@(SYMBOL_NAME(_end)),%a01: tstw %a0@(BIR_TAG) jeq 3f cmpw %a0@(BIR_TAG),%d0 jeq 2f addw %a0@(BIR_SIZE),%a0 jra 1b2: moveq #0,%d0 movew %a0@(BIR_SIZE),%d0 lea %a0@(BIR_DATA),%a0 jra 4f3: moveq #-1,%d0 lea %a0@(BIR_SIZE),%a04:func_return get_bi_record/* * MMU Initialization Begins Here * * The structure of the MMU tables on the 68k machines * is thus: * Root Table * Logical addresses are translated through * a hierarchical translation mechanism where the high-order * seven bits of the logical address (LA) are used as an * index into the "root table." Each entry in the root * table has a bit which specifies if it's a valid pointer to a * pointer table. Each entry defines a 32KMeg range of memory. * If an entry is invalid then that logical range of 32M is * invalid and references to that range of memory (when the MMU * is enabled) will fault. If the entry is valid, then it does * one of two things. On 040/060 class machines, it points to * a pointer table which then describes more finely the memory * within that 32M range. On 020/030 class machines, a technique * called "early terminating descriptors" are used. This technique * allows an entire 32Meg to be described by a single entry in the * root table. Thus, this entry in the root table, contains the * physical address of the memory or I/O at the logical address * which the entry represents and it also contains the necessary * cache bits for this region. * * Pointer Tables * Per the Root Table, there will be one or more * pointer tables. Each pointer table defines a 32M range. * Not all of the 32M range need be defined. Again, the next * seven bits of the logical address are used an index into * the pointer table to point to page tables (if the pointer * is valid). There will undoubtedly be more than one * pointer table for the kernel because each pointer table * defines a range of only 32M. Valid pointer table entries * point to page tables, or are early terminating entries * themselves. * * Page Tables * Per the Pointer Tables, each page table entry points * to the physical page in memory that supports the logical * address that translates to the particular index. * * In short, the Logical Address gets translated as follows: * bits 31..26 - index into the Root Table * bits 25..18 - index into the Pointer Table * bits 17..12 - index into the Page Table * bits 11..0 - offset into a particular 4K page * * The algorithms which follows do one thing: they abstract * the MMU hardware. For example, there are three kinds of * cache settings that are relevant. Either, memory is * being mapped in which case it is either Kernel Code (or * the RamDisk) or it is MMU data. On the 030, the MMU data * option also describes the kernel. Or, I/O is being mapped * in which case it has its own kind of cache bits. There * are constants which abstract these notions from the code that * actually makes the call to map some range of memory. * * * */#ifdef MMU_PRINT/* * mmu_print * * This algorithm will print out the current MMU mappings. * * Input: * %a5 points to the root table. Everything else is calculated * from this. */#define mmu_next_valid 0#define mmu_start_logical 4#define mmu_next_logical 8#define mmu_start_physical 12#define mmu_next_physical 16#define MMU_PRINT_INVALID -1#define MMU_PRINT_VALID 1#define MMU_PRINT_UNINITED 0#define putZc(z,n) jbne 1f; putc z; jbra 2f; 1: putc n; 2:func_start mmu_print,%a0-%a6/%d0-%d7 movel %pc@(L(kernel_pgdir_ptr)),%a5 lea %pc@(L(mmu_print_data)),%a0 movel #MMU_PRINT_UNINITED,%a0@(mmu_next_valid) is_not_040_or_060(mmu_030_print)mmu_040_print: puts "\nMMU040\n" puts "rp:" putn %a5 putc '\n'#if 0 /* * The following #if/#endif block is a tight algorithm for dumping the 040 * MMU Map in gory detail. It really isn't that practical unless the * MMU Map algorithm appears to go awry and you need to debug it at the * entry per entry level. */ movel #ROOT_TABLE_SIZE,%d5#if 0 movel %a5@+,%d7 | Burn an entry to skip the kernel mappings, subql #1,%d5 | they (might) work#endif1: tstl %d5 jbeq mmu_print_done subq #1,%d5 movel %a5@+,%d7 btst #1,%d7 jbeq 1b2: putn %d7 andil #0xFFFFFE00,%d7 movel %d7,%a4 movel #PTR_TABLE_SIZE,%d4 putc ' '3: tstl %d4 jbeq 11f subq #1,%d4 movel %a4@+,%d7 btst #1,%d7 jbeq 3b4: putn %d7 andil #0xFFFFFF00,%d7 movel %d7,%a3 movel #PAGE_TABLE_SIZE,%d35: movel #8,%d26: tstl %d3 jbeq 31f subq #1,%d3 movel %a3@+,%d6 btst #0,%d6 jbeq 6b7: tstl %d2 jbeq 8f subq #1,%d2 putc ' ' jbra 91f8: putc '\n' movel #8+1+8+1+1,%d29: putc ' ' dbra %d2,9b movel #7,%d291: putn %d6 jbra 6b31: putc '\n' movel #8+1,%d2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -