/** ** Standalone startup code for Linux PROM emulator. ** Copyright 1999 Pete A. Zaitcev ** This code is licensed under GNU General Public License. **/ /* * $Id: head.S,v 1.12 2002/07/23 05:47:09 zaitcev Exp $ */ #define __ASSEMBLY__ #include #include "pstate.h" #include "lsu.h" #define NO_QEMU_PROTOS #define NO_OPENBIOS_PROTOS #include "arch/common/fw_cfg.h" #define PROM_ADDR 0x1fff0000000 #define CFG_ADDR 0x1fe02000510 #define HZ 1 * 1000 * 1000 #define TICK_INT_DIS 0x8000000000000000 .globl entry, _entry .section ".text", "ax" .align 8 .register %g2, #scratch .register %g3, #scratch .register %g6, #scratch .register %g7, #scratch /* * Entry point * We start execution from here. */ _entry: entry: ! Set up CPU state wrpr %g0, PSTATE_PRIV, %pstate wr %g0, 0, %fprs wrpr %g0, 0x0, %tl ! Extract NWINDOWS from %ver rdpr %ver, %g1 and %g1, 0xf, %g1 dec %g1 wrpr %g1, 0, %cleanwin wrpr %g1, 0, %cansave wrpr %g0, 0, %canrestore wrpr %g0, 0, %otherwin wrpr %g0, 0, %wstate ! disable timer now setx TICK_INT_DIS, %g2, %g1 wr %g1, 0, %tick_cmpr ! Disable I/D MMUs and caches stxa %g0, [%g0] ASI_LSU_CONTROL ! Check signature "QEMU" setx CFG_ADDR, %g2, %g5 mov FW_CFG_SIGNATURE, %g2 stha %g2, [%g5] ASI_PHYS_BYPASS_EC_E_L inc %g5 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2 cmp %g2, 'Q' bne bad_conf nop lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2 cmp %g2, 'E' bne bad_conf nop lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2 cmp %g2, 'M' bne bad_conf nop lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g2 cmp %g2, 'U' bne bad_conf nop ! Clear ITLB mov 6 << 3, %g1 stxa %g0, [%g1] ASI_IMMU stxa %g0, [%g1] ASI_DMMU mov 63 << 3, %g1 1: stxa %g0, [%g1] ASI_ITLB_DATA_ACCESS subcc %g1, 1 << 3, %g1 bpos 1b nop ! Clear DTLB mov 63 << 3, %g1 1: stxa %g0, [%g1] ASI_DTLB_DATA_ACCESS subcc %g1, 1 << 3, %g1 bpos 1b nop ! Get memory size from configuration device ! NB: little endian format mov FW_CFG_RAM_SIZE, %g2 dec %g5 stha %g2, [%g5] ASI_PHYS_BYPASS_EC_E_L inc %g5 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 8, %g3 or %g3, %g4, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 16, %g3 or %g3, %g4, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 24, %g3 or %g3, %g4, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 32, %g3 or %g3, %g4, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 40, %g3 or %g3, %g4, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 48, %g3 or %g3, %g4, %g4 lduba [%g5] ASI_PHYS_BYPASS_EC_E, %g3 sllx %g3, 56, %g3 or %g3, %g4, %g1 ! %g1 contains end of memory setx _end, %g7, %g3 set 0x7ffff, %g2 add %g3, %g2, %g3 andn %g3, %g2, %g3 setx _data, %g7, %g2 sub %g3, %g2, %g2 sub %g1, %g2, %g2 ! %g2 = start of private memory mov %g2, %l0 ! setup .data & .bss setx _data, %g7, %g4 sub %g3, %g4, %g5 srlx %g5, 19, %g6 ! %g6 = # of 512k .bss pages set 0xc0000000, %g3 sllx %g3, 32, %g3 or %g3, 0x76, %g3 ! valid, 512k, locked, cacheable(I/E/C), priv, writable set 48, %g7 1: stxa %g4, [%g7] ASI_DMMU ! vaddr = _data + N * 0x80000, ctx=0 or %g2, %g3, %g5 ! paddr = start_mem + N * 0x80000 stxa %g5, [%g0] ASI_DTLB_DATA_IN set 0x80000, %g5 add %g2, %g5, %g2 add %g4, %g5, %g4 deccc %g6 bne 1b nop ! setup .rodata, also make .text readable setx _data, %g7, %g5 setx _start, %g7, %g4 sub %g5, %g4, %g5 srlx %g5, 19, %g6 ! %g6 = # of 512k .rodata pages set 48, %g7 set 0x80000, %g5 setx PROM_ADDR, %l1, %l2 1: stxa %g4, [%g7] ASI_DMMU ! vaddr = _rodata, ctx=0 set 0xc0000000, %g3 sllx %g3, 32, %g3 or %g3, 0x74, %g3 or %l2, %g3, %g3 ! valid, 512k, locked, cacheable(I/E/C), priv ! paddr = _rodata + N * 0x10000 stxa %g3, [%g0] ASI_DTLB_DATA_IN add %g4, %g5, %g4 deccc %g6 bne 1b add %l2, %g5, %l2 membar #Sync setx _start, %g7, %g4 setx _rodata, %g7, %g5 sub %g5, %g4, %g5 set 0x7ffff, %g7 add %g5, %g7, %g5 ! round to 512k srlx %g5, 19, %g6 ! %g6 = # of 512k .text pages set 0x80000, %g5 set 48, %g7 setx PROM_ADDR, %l1, %l2 1: stxa %g4, [%g7] ASI_IMMU ! vaddr = _start, ctx=0 set 0xc0000000, %g3 sllx %g3, 32, %g3 or %g3, 0x74, %g3 or %l2, %g3, %g3 ! valid, 512k, locked, cacheable(I/E/C), priv ! paddr = _start + N * 0x80000 stxa %g3, [%g0] ASI_ITLB_DATA_IN add %g4, %g5, %g4 deccc %g6 bne 1b add %l2, %g5, %l2 flush %g4 mov %g1, %g3 set 8, %g2 sta %g0, [%g2] ASI_DMMU ! set primary ctx=0 ! Enable I/D MMUs and caches setx lowmem, %g2, %g1 set LSU_CONTROL_DM|LSU_CONTROL_IM|LSU_CONTROL_DC|LSU_CONTROL_IC, %g2 jmp %g1 stxa %g2, [%g0] ASI_LSU_CONTROL lowmem: /* Copy the DATA section from ROM. */ setx _data - 8, %o7, %o0 ! First address of DATA setx _bss, %o7, %o1 ! Last address of DATA setx _start, %o7, %o2 sub %o0, %o2, %o2 ! _data - _start setx PROM_ADDR, %o7, %o3 add %o3, %o2, %o2 ! PROM_ADDR + (_data - _start) ba 2f nop 1: ldxa [%o2] ASI_PHYS_BYPASS_EC_E, %g1 stx %g1, [%o0] 2: add %o2, 0x8, %o2 subcc %o0, %o1, %g0 bl 1b add %o0, 0x8, %o0 /* Zero out our BSS section. */ setx _bss - 8, %o7, %o0 ! First address of BSS setx _end - 8, %o7, %o1 ! Last address of BSS ba 2f nop 1: stx %g0, [%o0] 2: subcc %o0, %o1, %g0 bl 1b add %o0, 0x8, %o0 setx trap_table, %g2, %g1 wrpr %g1, %tba setx qemu_mem_size, %g7, %g1 stx %g3, [%g1] setx _data, %g7, %g1 ! Store va->pa conversion factor sub %g1, %l0, %g2 setx va_shift, %g7, %g1 stx %g2, [%g1] /* Finally, turn on traps so that we can call c-code. */ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate ! 100 Hz timer setx TICK_INT_DIS, %g2, %g1 rd %tick, %g2 andn %g2, %g1, %g2 set HZ, %g1 add %g1, %g2, %g1 wr %g1, 0, %tick_cmpr /* Switch to our main context. * Main context is statically defined in C. */ call __switch_context_nosave nop /* We get here when the main context switches back to * the boot context. */ bad_conf: b bad_conf nop