summaryrefslogtreecommitdiff
path: root/init.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2011-04-13 12:57:44 -0700
committerRichard Henderson <rth@twiddle.net>2011-04-13 12:57:44 -0700
commit0830e72f0bce29bdf1de0d67ad503a9a8b99c968 (patch)
treefac6a38690678935130280060f55427269448808 /init.c
parentf907c57529209ddf51dc8d817bee266fb10784f4 (diff)
downloadqemu-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.
Diffstat (limited to 'init.c')
-rw-r--r--init.c278
1 files changed, 154 insertions, 124 deletions
diff --git a/init.c b/init.c
index f0a0483..25ca743 100644
--- a/init.c
+++ b/init.c
@@ -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 ();
}