📄 head.s
字号:
.ascii "HdrS" .word LINUX_VERSION_CODE .half 0x0203 /* HdrS version */root_flags: .half 1root_dev: .half 0ram_flags: .half 0sparc_ramdisk_image: .word 0sparc_ramdisk_size: .word 0 .word reboot_command .word 0, 0, 0 .word _end/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in * %g7 and at prom_vector_p. And also quickly check whether we are on * a v0, v2, or v3 prom. */gokernel: /* Ok, it's nice to know, as early as possible, if we * are already mapped where we expect to be in virtual * memory. The Solaris /boot elf format bootloader * will peek into our elf header and load us where * we want to be, otherwise we have to re-map. * * Some boot loaders don't place the jmp'rs address * in %o7, so we do a pc-relative call to a local * label, then see what %o7 has. */ mov %o7, %g4 ! Save %o7 /* Jump to it, and pray... */current_pc: call 1f nop1: mov %o7, %g3 tst %o0 be no_sun4u_here mov %g4, %o7 /* Previous %o7. */ mov %o0, %l0 ! stash away romvec mov %o0, %g7 ! put it here too mov %o1, %l1 ! stash away debug_vec too /* Ok, let's check out our run time program counter. */ set current_pc, %g5 cmp %g3, %g5 be already_mapped nop /* %l6 will hold the offset we have to subtract * from absolute symbols in order to access areas * in our own image. If already mapped this is * just plain zero, else it is KERNBASE. */ set KERNBASE, %l6 b copy_prom_lvl14 nopalready_mapped: mov 0, %l6 /* Copy over the Prom's level 14 clock handler. */copy_prom_lvl14:#if 1 /* DJHR * preserve our linked/calculated instructions */ set lvl14_save, %g1 set t_irq14, %g3 sub %g1, %l6, %g1 ! translate to physical sub %g3, %l6, %g3 ! translate to physical ldd [%g3], %g4 std %g4, [%g1] ldd [%g3+8], %g4 std %g4, [%g1+8]#endif rd %tbr, %g1 andn %g1, 0xfff, %g1 ! proms trap table base or %g0, (0x1e<<4), %g2 ! offset to lvl14 intr or %g1, %g2, %g2 set t_irq14, %g3 sub %g3, %l6, %g3 ldd [%g2], %g4 std %g4, [%g3] ldd [%g2 + 0x8], %g4 std %g4, [%g3 + 0x8] ! Copy proms handler/* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT * MMU so we can remap ourselves properly. DON'T TOUCH %l0 thru %l5 in these * remapping routines, we need their values afterwards! */ /* Now check whether we are already mapped, if we * are we can skip all this garbage coming up. */copy_prom_done: cmp %l6, 0 be go_to_highmem ! this will be a nop then nop set LOAD_ADDR, %g6 cmp %g7, %g6 bne remap_not_a_sun4 ! This is not a Sun4 nop or %g0, 0x1, %g1 lduba [%g1] ASI_CONTROL, %g1 ! Only safe to try on Sun4. subcc %g1, 0x24, %g0 ! Is this a mutant Sun4/400??? be sun4_mutant_remap ! Ugh, it is... nop b sun4_normal_remap ! regular sun4, 2 level mmu nopremap_not_a_sun4: lda [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c and %g1, 0x1, %g1 ! Test SRMMU Enable bit ;-) cmp %g1, 0x0 be sun4c_remap ! A sun4c MMU or normal Sun4 nopsrmmu_remap: /* First, check for a viking (TI) module. */ set 0x40000000, %g2 rd %psr, %g3 and %g2, %g3, %g3 subcc %g3, 0x0, %g0 bz srmmu_nviking nop /* Figure out what kind of viking we are on. * We need to know if we have to play with the * AC bit and disable traps or not. */ /* I've only seen MicroSparc's on SparcClassics with this * bit set. */ set 0x800, %g2 lda [%g0] ASI_M_MMUREGS, %g3 ! peek in the control reg and %g2, %g3, %g3 subcc %g3, 0x0, %g0 bnz srmmu_nviking ! is in mbus mode nop rd %psr, %g3 ! DO NOT TOUCH %g3 andn %g3, PSR_ET, %g2 wr %g2, 0x0, %psr WRITE_PAUSE /* Get context table pointer, then convert to * a physical address, which is 36 bits. */ set AC_M_CTPR, %g4 lda [%g4] ASI_M_MMUREGS, %g4 sll %g4, 0x4, %g4 ! We use this below ! DO NOT TOUCH %g4 /* Set the AC bit in the Viking's MMU control reg. */ lda [%g0] ASI_M_MMUREGS, %g5 ! DO NOT TOUCH %g5 set 0x8000, %g6 ! AC bit mask or %g5, %g6, %g6 ! Or it in... sta %g6, [%g0] ASI_M_MMUREGS ! Close your eyes... /* Grrr, why does it seem like every other load/store * on the sun4m is in some ASI space... * Fine with me, let's get the pointer to the level 1 * page table directory and fetch its entry. */ lda [%g4] ASI_M_BYPASS, %o1 ! This is a level 1 ptr srl %o1, 0x4, %o1 ! Clear low 4 bits sll %o1, 0x8, %o1 ! Make physical /* Ok, pull in the PTD. */ lda [%o1] ASI_M_BYPASS, %o2 ! This is the 0x0 16MB pgd /* Calculate to KERNBASE entry. */ add %o1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %o3 /* Poke the entry into the calculated address. */ sta %o2, [%o3] ASI_M_BYPASS /* I don't get it Sun, if you engineered all these * boot loaders and the PROM (thank you for the debugging * features btw) why did you not have them load kernel * images up in high address space, since this is necessary * for ABI compliance anyways? Does this low-mapping provide * enhanced interoperability? * * "The PROM is the computer." */ /* Ok, restore the MMU control register we saved in %g5 */ sta %g5, [%g0] ASI_M_MMUREGS ! POW... ouch /* Turn traps back on. We saved it in %g3 earlier. */ wr %g3, 0x0, %psr ! tick tock, tick tock /* Now we burn precious CPU cycles due to bad engineering. */ WRITE_PAUSE /* Wow, all that just to move a 32-bit value from one * place to another... Jump to high memory. */ b go_to_highmem nop /* This works on viking's in Mbus mode and all * other MBUS modules. It is virtually the same as * the above madness sans turning traps off and flipping * the AC bit. */srmmu_nviking: set AC_M_CTPR, %g1 lda [%g1] ASI_M_MMUREGS, %g1 ! get ctx table ptr sll %g1, 0x4, %g1 ! make physical addr lda [%g1] ASI_M_BYPASS, %g1 ! ptr to level 1 pg_table srl %g1, 0x4, %g1 sll %g1, 0x8, %g1 ! make phys addr for l1 tbl lda [%g1] ASI_M_BYPASS, %g2 ! get level1 entry for 0x0 add %g1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %g3 sta %g2, [%g3] ASI_M_BYPASS ! place at KERNBASE entry b go_to_highmem nop ! wheee.... /* This remaps the kernel on Sun4/4xx machines * that have the Sun Mutant Three Level MMU. * It's like a platypus, Sun didn't have the * SRMMU in conception so they kludged the three * level logic in the regular Sun4 MMU probably. * * Basically, you take each entry in the top level * directory that maps the low 3MB starting at * address zero and put the mapping in the KERNBASE * slots. These top level pgd's are called regmaps. */sun4_mutant_remap: or %g0, %g0, %g3 ! source base sethi %hi(KERNBASE), %g4 ! destination base or %g4, %lo(KERNBASE), %g4 sethi %hi(0x300000), %g5 or %g5, %lo(0x300000), %g5 ! upper bound 3MB or %g0, 0x1, %l6 sll %l6, 24, %l6 ! Regmap mapping size add %g3, 0x2, %g3 ! Base magic add %g4, 0x2, %g4 ! Base magic /* Main remapping loop on Sun4-Mutant-MMU. * "I am not an animal..." -Famous Mutant Person */sun4_mutant_loop: lduha [%g3] ASI_REGMAP, %g2 ! Get lower entry stha %g2, [%g4] ASI_REGMAP ! Store in high entry add %g4, %l6, %g4 ! Move up high memory ptr subcc %g3, %g5, %g0 ! Reached our limit? blu sun4_mutant_loop ! Nope, loop again add %g3, %l6, %g3 ! delay, Move up low ptr b go_to_highmem ! Jump to high memory. nop /* The following is for non-4/4xx sun4 MMU's. */sun4_normal_remap: mov 0, %g3 ! source base set KERNBASE, %g4 ! destination base set 0x300000, %g5 ! upper bound 3MB mov 1, %l6 sll %l6, 18, %l6 ! sun4 mmu segmap sizesun4_normal_loop: lduha [%g3] ASI_SEGMAP, %g6 ! load phys_seg stha %g6, [%g4] ASI_SEGMAP ! stort new virt mapping add %g3, %l6, %g3 ! increment source pointer subcc %g3, %g5, %g0 ! reached limit? blu sun4_normal_loop ! nope, loop again add %g4, %l6, %g4 ! delay, increment dest ptr b go_to_highmem nop /* The following works for Sun4c MMU's */sun4c_remap: mov 0, %g3 ! source base set KERNBASE, %g4 ! destination base set 0x300000, %g5 ! upper bound 3MB mov 1, %l6 sll %l6, 18, %l6 ! sun4c mmu segmap sizesun4c_remap_loop: lda [%g3] ASI_SEGMAP, %g6 ! load phys_seg sta %g6, [%g4] ASI_SEGMAP ! store new virt mapping add %g3, %l6, %g3 ! Increment source ptr subcc %g3, %g5, %g0 ! Reached limit? bl sun4c_remap_loop ! Nope, loop again add %g4, %l6, %g4 ! delay, Increment dest ptr/* Now do a non-relative jump so that PC is in high-memory */go_to_highmem: set execute_in_high_mem, %g1 jmpl %g1, %g0 nop/* The code above should be at beginning and we have to take care about * short jumps, as branching to .text.init section from .text is usually * impossible */ __INIT/* Acquire boot time privileged register values, this will help debugging. * I figure out and store nwindows and nwindowsm1 later on. */execute_in_high_mem: mov %l0, %o0 ! put back romvec mov %l1, %o1 ! and debug_vec sethi %hi(prom_vector_p), %g1 st %o0, [%g1 + %lo(prom_vector_p)] sethi %hi(linux_dbvec), %g1 st %o1, [%g1 + %lo(linux_dbvec)] ld [%o0 + 0x4], %o3 and %o3, 0x3, %o5 ! get the version cmp %o3, 0x2 ! a v2 prom? be found_version nop /* paul@sfe.com.au */ cmp %o3, 0x3 ! a v3 prom? be found_version nop/* Old sun4's pass our load address into %o0 instead of the prom * pointer. On sun4's you have to hard code the romvec pointer into * your code. Sun probably still does that because they don't even * trust their own "OpenBoot" specifications. */ set LOAD_ADDR, %g6 cmp %o0, %g6 ! an old sun4? be sun4_init nopfound_version:#ifdef CONFIG_SUN4/* For people who try sun4 kernels, even if Configure.help advises them. */ ld [%g7 + 0x68], %o1 set sun4cdm_notsup, %o0 call %o1 nop b halt_me nop#endif/* Get the machine type via the mysterious romvec node operations. */ add %g7, 0x1c, %l1 ld [%l1], %l0 ld [%l0], %l0 call %l0 or %g0, %g0, %o0 ! next_node(0) = first_node or %o0, %g0, %g6 sethi %hi(cputypvar), %o1 ! First node has cpu-arch or %o1, %lo(cputypvar), %o1 sethi %hi(cputypval), %o2 ! information, the string or %o2, %lo(cputypval), %o2 ld [%l1], %l0 ! 'compatibility' tells ld [%l0 + 0xc], %l0 ! that we want 'sun4x' where call %l0 ! x is one of '', 'c', 'm', nop ! 'd' or 'e'. %o2 holds pointer ! to a buf where above string ! will get stored by the prom. subcc %o0, %g0, %g0 bpos got_prop ! Got the property nop or %g6, %g0, %o0 sethi %hi(cputypvar_sun4m), %o1 or %o1, %lo(cputypvar_sun4m), %o1 sethi %hi(cputypval), %o2 or %o2, %lo(cputypval), %o2 ld [%l1], %l0 ld [%l0 + 0xc], %l0 call %l0 nopgot_prop: set cputypval, %o2 ldub [%o2 + 0x4], %l1 cmp %l1, ' ' be 1f cmp %l1, 'c' be 1f cmp %l1, 'm' be 1f cmp %l1, 's' be 1f cmp %l1, 'd' be 1f cmp %l1, 'e' be no_sun4e_here ! Could be a sun4e. nop b no_sun4u_here ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :)) nop1: set cputypval, %l1 ldub [%l1 + 0x4], %l1 cmp %l1, 'm' ! Test for sun4d, sun4e ? be sun4m_init cmp %l1, 's' ! Treat sun4s as sun4m be sun4m_init cmp %l1, 'd' ! Let us see how the beast will die be sun4d_init nop /* Jump into mmu context zero. */ set AC_CONTEXT, %g1 stba %g0, [%g1] ASI_CONTROL b sun4c_continue_boot nop/* CPUID in bootbus can be found at PA 0xff0140000 */#define SUN4D_BOOTBUS_CPUID 0xf0140000sun4d_init: /* Need to patch call to handler_irq */ set patch_handler_irq, %g4 set sun4d_handler_irq, %g5 sethi %hi(0x40000000), %g3 ! call sub %g5, %g4, %g5 srl %g5, 2, %g5 or %g5, %g3, %g5 st %g5, [%g4]#ifdef CONFIG_SMP /* Get our CPU id out of bootbus */ set SUN4D_BOOTBUS_CPUID, %g3 lduba [%g3] ASI_M_CTL, %g3 and %g3, 0xf8, %g3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -