diff options
author | Richard Henderson <rth@twiddle.net> | 2011-04-13 12:57:44 -0700 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2011-04-13 12:57:44 -0700 |
commit | 0830e72f0bce29bdf1de0d67ad503a9a8b99c968 (patch) | |
tree | fac6a38690678935130280060f55427269448808 | |
parent | f907c57529209ddf51dc8d817bee266fb10784f4 (diff) | |
download | qemu-palcode-0830e72f0bce29bdf1de0d67ad503a9a8b99c968.zip qemu-palcode-0830e72f0bce29bdf1de0d67ad503a9a8b99c968.tar.gz qemu-palcode-0830e72f0bce29bdf1de0d67ad503a9a8b99c968.tar.bz2 |
Rely less on initialized data.
(1) Don't statically initialize HWRPB and PCBB.
(2) Use SwpPal at the end of do_start to install the PCBB and PTBR,
rather than setting those up in __start in PALmode.
(3) Use -mbuild-constants to prevent the compiler using static data.
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | init.c | 278 | ||||
-rw-r--r-- | pal.S | 46 | ||||
-rw-r--r-- | palcode.ld | 2 |
4 files changed, 192 insertions, 139 deletions
@@ -1,8 +1,9 @@ CROSS = alphaev67-linux- CC = $(CROSS)gcc LD = $(CROSS)ld -CFLAGS = -O -g -msmall-text -msmall-data -fvisibility=hidden \ - -mno-fp-regs -fno-strict-aliasing + +CFLAGS = -O -g -fvisibility=hidden -fno-strict-aliasing \ + -msmall-text -msmall-data -mno-fp-regs -mbuild-constants OBJS = pal.o init.o uart.o memset.o printf.o @@ -8,131 +8,44 @@ #define PAGE_SIZE (1ul << PAGE_SHIFT) #define PAGE_OFFSET 0xfffffc0000000000UL -#if 1 -#define PA(VA) ((unsigned long)(unsigned int)(VA)) -#else -#define PA(VA) ((VA) - PAGE_OFFSET) -#endif -#define VA(PA) ((PA) + PAGE_OFFSET) +#define VPTPTR 0xfffffffe00000000UL -#define HZ 1024 +#define PA(VA) ((unsigned long)(VA) & 0xfffffffffful) +#define VA(PA) ((void *)(PA) + PAGE_OFFSET) -struct pcb_struct pal_pcb __attribute__((section(".sbss"))); +#define HZ 1024 struct hwrpb_combine { struct hwrpb_struct hwrpb; struct percpu_struct processor; struct memdesc_struct md; struct memclust_struct mc[2]; -} hwrpb __attribute__((section(".data.hwrpb"))) = { - /* This is HWRPB\0\0\0. */ - .hwrpb.id = 0x4857525042000000, - - .hwrpb.size = sizeof(struct hwrpb_struct), - .hwrpb.pagesize = PAGE_SIZE, - .hwrpb.ssn = "MILO QEMU", - - /* ??? This should match TARGET_PHYS_ADDR_SPACE_BITS from qemu. */ - .hwrpb.pa_bits = 44, - - /* ??? Should we be truethful and say 1 asn, or simply pretend we - have ASNs but ignore them? */ - .hwrpb.max_asn = 127, - - /* For now, hard-code emulation of sx164. */ - .hwrpb.cpuid = PCA56_CPU, - .processor.type = PCA56_CPU, - .hwrpb.sys_type = ST_DEC_EB164, - .hwrpb.sys_variation = 15 << 10, - .hwrpb.sys_revision = 0, - - .hwrpb.intr_freq = HZ * 4096, +}; - /* ??? What the hell should we put here. Measure like the kernel will? */ - .hwrpb.cycle_freq = 400000000, +extern char stack[PAGE_SIZE] __attribute__((section(".sbss"))); +extern char _end[] __attribute__((visibility("hidden"), nocommon)); - .hwrpb.vptb = 0x200000000UL, - .hwrpb.nr_processors = 1, - .hwrpb.processor_size = sizeof(struct percpu_struct), - .hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor), +struct pcb_struct pcb __attribute__((section(".sbss"))); - .hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md), - .md.numclusters = 2, - .mc[0].usage = 2 -}; +static unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE))); -unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE))); +/* The HWRPB must be aligned because it is exported at INIT_HWRPB. */ +struct hwrpb_combine hwrpb __attribute__((aligned(PAGE_SIZE))); -extern char _end[]; -static unsigned long last_alloc = (unsigned long)_end; +static void *last_alloc; static void * alloc (unsigned long size, unsigned long align) { - unsigned long p = (last_alloc + align - 1) & ~(align - 1); + void *p = (void *)(((unsigned long)last_alloc + align - 1) & ~(align - 1)); last_alloc = p + size; - return memset ((void *)p, 0, size); + return memset (p, 0, size); } -static unsigned long -init_cpuid (void) -{ - unsigned long implver, amask; - - __asm ("implver %0" : "=r"(implver)); - __asm ("amask %1,%0" : "=r"(amask) : "r"(-1)); - amask = ~amask; - - switch (implver) - { - case 0: /* EV4 */ - return EV4_CPU; - - case 1: /* EV5 */ - if ((amask & 0x101) == 0x101) /* MAX + BWX */ - return PCA56_CPU; - if (amask & 1) /* BWX */ - return EV56_CPU; - return EV5_CPU; - - case 2: /* EV6 */ - if (amask & 4) /* CIX */ - return EV67_CPU; - return EV6_CPU; - } - return 0; -} - -static void -hwrpb_update_checksum (void) -{ - unsigned long sum = 0, *l; - for (l = (unsigned long *) &hwrpb.hwrpb; l < &hwrpb.hwrpb.chksum; ++l) - sum += *l; - hwrpb.hwrpb.chksum = sum; -} - -static void -init_hwrpb (unsigned long memsize) -{ - unsigned long pal_pages; - - hwrpb.hwrpb.phys_addr = PA((unsigned long)&hwrpb); - - pal_pages = (PA(last_alloc) + PAGE_SIZE - 1) >> PAGE_SHIFT; - - hwrpb.mc[0].numpages = pal_pages; - hwrpb.mc[1].start_pfn = pal_pages; - hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages; - - hwrpb_update_checksum (); -} - -static void -init_pcb (void) +static inline unsigned long +pt_index(unsigned long addr, int level) { - pal_pcb.ptbr = PA((unsigned long)page_dir); - pal_pcb.flags = 1; + return (addr >> (PAGE_SHIFT + (10 * level))) & 0x3ff; } static inline unsigned long @@ -149,7 +62,7 @@ build_pte (void *page) static inline void * pte_page (unsigned long pte) { - return (void *)VA(pte >> 32 << PAGE_SHIFT); + return VA(pte >> 32 << PAGE_SHIFT); } static void @@ -158,7 +71,7 @@ set_pte (unsigned long addr, void *page) unsigned long *pt = page_dir; unsigned long index; - index = (addr >> (PAGE_SHIFT+20)) % 1024; + index = pt_index(addr, 2); if (pt[index] != 0) pt = pte_page (pt[index]); else @@ -168,7 +81,7 @@ set_pte (unsigned long addr, void *page) pt = npt; } - index = (addr >> (PAGE_SHIFT+10)) % 1024; + index = pt_index(addr, 1); if (pt[index] != 0) pt = pte_page (pt[index]); else @@ -178,39 +91,156 @@ set_pte (unsigned long addr, void *page) pt = npt; } - index = (addr >> PAGE_SHIFT) % 1024; + index = pt_index(addr, 0); pt[index] = build_pte (page); } static void -init_page_table (unsigned long memsize) +init_page_table(void) { - unsigned long i, addr, max_addr, page; + /* Install the self-reference for the virtual page table base register. */ + page_dir[pt_index(VPTPTR, 2)] = build_pte(page_dir); set_pte ((unsigned long)INIT_HWRPB, &hwrpb); - /* SRM places the self-map for the VPTBR in the second entry. */ - /* MILO places the self-map for the VPTBR in the last entry. */ - page_dir[1023] = build_pte (page_dir); + /* ??? SRM maps some amount of memory at 0x20000000 for use by programs + started from the console prompt. Including the bootloader. While + we're emulating MILO, don't bother as we jump straight to the kernel + loaded into KSEG. */ +} + +static inline unsigned long +init_cpuid (void) +{ + unsigned long implver, amask; + + implver = __builtin_alpha_implver(); + amask = ~__builtin_alpha_amask(-1); + + switch (implver) + { + case 0: /* EV4 */ + return EV4_CPU; + + case 1: /* EV5 */ + if ((amask & 0x101) == 0x101) /* MAX + BWX */ + return PCA56_CPU; + if (amask & 1) /* BWX */ + return EV56_CPU; + return EV5_CPU; + + case 2: /* EV6 */ + if (amask & 4) /* CIX */ + return EV67_CPU; + return EV6_CPU; + } + return 0; +} + +static void +init_hwrpb (unsigned long memsize) +{ + unsigned long pal_pages; + + hwrpb.hwrpb.phys_addr = PA(&hwrpb); + + /* Yes, the 'HWRPB' magic is in big-endian byte ordering. */ + hwrpb.hwrpb.id = ( (long)'H' << 56 + | (long)'W' << 48 + | (long)'R' << 40 + | (long)'P' << 32 + | (long)'B' << 24); + + hwrpb.hwrpb.size = sizeof(struct hwrpb_struct); + + /* The inclusion of MILO here tells the Linux kernel that we do + not (yet) support any of the extended console support routines + that are in SRM. */ + ((int *)hwrpb.hwrpb.ssn)[0] = ( 'M' << 0 + | 'I' << 8 + | 'L' << 16 + | 'O' << 24); + ((int *)hwrpb.hwrpb.ssn)[1] = ( ' ' << 0 + | 'Q' << 8 + | 'E' << 16 + | 'M' << 24); + ((int *)hwrpb.hwrpb.ssn)[2] = ( 'U' << 0); + + /* For now, hard-code emulation of sx164. */ + hwrpb.hwrpb.cpuid = PCA56_CPU; + hwrpb.hwrpb.pagesize = PAGE_SIZE; + hwrpb.hwrpb.pa_bits = 40; + hwrpb.hwrpb.max_asn = 127; + hwrpb.hwrpb.sys_type = ST_DEC_EB164; + hwrpb.hwrpb.sys_variation = 15 << 10; + hwrpb.hwrpb.sys_revision = 0; + hwrpb.processor.type = PCA56_CPU; + + hwrpb.hwrpb.intr_freq = HZ * 4096; + + /* ??? What the hell should we put here. Measure like the kernel will? */ + hwrpb.hwrpb.cycle_freq = 400000000; + + hwrpb.hwrpb.vptb = VPTPTR; + + hwrpb.hwrpb.nr_processors = 1; + hwrpb.hwrpb.processor_size = sizeof(struct percpu_struct); + hwrpb.hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor); + + hwrpb.hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md); + hwrpb.md.numclusters = 2; + + pal_pages = (PA(last_alloc) + PAGE_SIZE - 1) >> PAGE_SHIFT; + + hwrpb.mc[0].numpages = pal_pages; + hwrpb.mc[0].usage = 1; + hwrpb.mc[1].start_pfn = pal_pages; + hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages; - /* Write the SRM vptptr. */ { - register unsigned long a0 __asm__("$16") = 0xfffffffe00000000UL; - __asm ("call_pal 0x2d" : : "r"(a0)); + unsigned long sum = 0, *l; + for (l = (unsigned long *) &hwrpb.hwrpb; l < &hwrpb.hwrpb.chksum; ++l) + sum += *l; + hwrpb.hwrpb.chksum = sum; } } +static void +init_pcb (void) +{ + pcb.ksp = (unsigned long)stack + sizeof(stack); + pcb.ptbr = PA(page_dir); + pcb.flags = 1; /* FEN */ +} + +void +do_hello(void) +{ + uart_puts(COM1, "Hello, World!\n"); + asm ("halt"); + __builtin_unreachable (); +} + void do_start(unsigned long memsize, void (*kernel_entry)(void)) { - init_page_table (memsize); - init_hwrpb (memsize); - init_pcb (); + last_alloc = _end; - uart_init (); - uart_puts (COM1, "Hello, World!\n"); + init_page_table(); + init_hwrpb(memsize); + init_pcb(); + uart_init(); - if (kernel_entry) - kernel_entry(); - asm ("halt"); + { + register int variant __asm__("$16") = 2; /* OSF/1 PALcode */ + register void (*pc)(void) __asm__("$17"); + register unsigned long pa_pcb __asm__("$18"); + register unsigned long vptptr __asm__("$19"); + + pc = (kernel_entry ? kernel_entry : do_hello); + pa_pcb = PA(&pcb); + vptptr = VPTPTR; + asm("call_pal 0x0a" : : "r"(variant), "r"(pc), "r"(pa_pcb), "r"(vptptr)); + } + __builtin_unreachable (); } @@ -182,7 +182,7 @@ __start: // Initialize GP and stack. br $gp, .+4 - ldah $gp, 0($gp) !gpdisp!1 + ldah $gp, 0($gp) !gpdisp!1 lda $gp, 0($gp) !gpdisp!1 mtpr $gp, ptPgp @@ -192,15 +192,6 @@ __start: lda t0, IPL_K_HIGH mtpr t0, qemu_ps - // Load the initial PCB and page table elements. - lda t0, page_dir($gp) !gprel - zap t0, 0xf0, t0 - mtpr t0, qemu_ptbr - - lda t0, pal_pcb($gp) !gprel - zap t0, 0xf0, t0 - mtpr t0, ptPcbb - // Make sure kernel entry points are invalid. lda t0, -1 mtpr t0, ptEntUna @@ -538,6 +529,12 @@ ENDFN CallPal_Cserve * 0 - Success (PALcode was switched) * 1 - Unknown PALcode variant * 2 - Known PALcode variant, but PALcode not loaded + * + * r26 (ra) = r27 (pv) = New PC + * Note that this is non-architected, but is relied on by + * the usage of SwpPal within our own console code in order + * to simplify its use within C code. + * */ ORG_CALL_PAL_PRIV(0x0A) CallPal_SwpPal: @@ -556,8 +553,32 @@ ENDFN CallPal_SwpPal .text 1 CallPal_SwpPal_Cont: - // YOUAREHERE - halt + rpcc p0 + mtpr a2, ptPcbb + mtpr a3, qemu_vptptr + + ldq_p $sp, PCB_Q_KSP(a2) + ldq_p t0, PCB_Q_USP(a2) + ldq_p t1, PCB_Q_PTBR(a2) + ldl_p t2, PCB_L_PCC(a2) + ldq_p t3, PCB_Q_UNIQUE(a2) + ldq_p t4, PCB_Q_FEN(a2) + + mtpr t0, ptUsp + mtpr t1, qemu_ptbr + mtpr t3, qemu_unique + + subl t2, p0, t2 + mtpr t2, qemu_pcc_ofs + + and t4, 1, t4 + mtpr t4, qemu_fen + + mtpr $31, qemu_tbia // Flush TLB for new PTBR + + mov a1, $26 + mov a1, $27 + hw_ret (a1) ENDFN CallPal_SwpPal_Cont .previous @@ -2050,6 +2071,7 @@ $laf_size = . - laf_base .size laf_base, . - laf_base .align 3 + .globl stack .type stack,@object .size stack,STACK_SIZE stack: .skip STACK_SIZE @@ -5,7 +5,7 @@ SECTIONS { . = 0xfffffc0000000000; .text : { *(.text*) } - .rodata : { *(.rodata) } + .rodata : { *(.rodata*) } .data ALIGN(8192) : { *(.data.hwrpb) *(.data*) } .got : { *(.got.plt) *(.got) } .sdata : { *(.sdata*) } |