summaryrefslogtreecommitdiff
path: root/init.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2011-04-06 16:02:23 -0700
committerRichard Henderson <rth@twiddle.net>2011-04-10 10:25:15 -0700
commit0ea286dc681fe3690fc4bb8007144190e03b8d51 (patch)
tree8f6462f8d6e270a7766e05392b7bee05caf0c28b /init.c
parente00c70db6ec09b5015ba5602a781d282134d3fcd (diff)
downloadqemu-palcode-0ea286dc681fe3690fc4bb8007144190e03b8d51.zip
qemu-palcode-0ea286dc681fe3690fc4bb8007144190e03b8d51.tar.gz
qemu-palcode-0ea286dc681fe3690fc4bb8007144190e03b8d51.tar.bz2
TEMP: finished through init_page_tables
Diffstat (limited to 'init.c')
-rw-r--r--init.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/init.c b/init.c
new file mode 100644
index 0000000..70b6297
--- /dev/null
+++ b/init.c
@@ -0,0 +1,206 @@
+#include <string.h>
+#include <stddef.h>
+#include "hwrpb.h"
+#include "osf.h"
+
+#define PAGE_SHIFT 13
+#define PAGE_SIZE (1ul << PAGE_SHIFT)
+#define PAGE_OFFSET 0xfffffc0000000000UL
+
+#define HZ 1024
+
+struct pcb_struct pal_pcb __attribute__((section(".sbss")));
+
+unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE)));
+unsigned long page_L1[1024] __attribute__((aligned(PAGE_SIZE)));
+unsigned long page_L2[1024][1024] __attribute__((aligned(PAGE_SIZE)));
+
+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 = "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,
+
+ .hwrpb.vptb = 0x200000000UL,
+ .hwrpb.nr_processors = 1,
+ .hwrpb.processor_size = sizeof(struct percpu_struct),
+ .hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor),
+
+ .hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md),
+ .md.numclusters = 2,
+ .mc[0].usage = 2
+};
+
+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 end, pal_pages;
+
+ hwrpb.hwrpb.phys_addr = (unsigned int)(unsigned long)&hwrpb;
+
+ /* ??? For some reason GCC wants to use a LITERAL relocation for
+ _end instead of gp-relative relocations. */
+ __asm ("ldah %0,_end($gp) !gprelhigh\n\tlda %0,_end(%0) !gprellow"
+ : "=r"(end));
+
+ pal_pages = ((unsigned int)end + 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)
+{
+ pal_pcb.ptbr = (unsigned int)(unsigned long)page_dir;
+ pal_pcb.flags = 1;
+}
+
+static inline unsigned long
+build_pte (void *page)
+{
+ unsigned long bits;
+
+ bits = ((unsigned long)page - PAGE_OFFSET) << (32 - PAGE_SHIFT);
+ bits |= _PAGE_VALID;
+
+ return bits;
+}
+
+static inline void *
+pte_page (unsigned long pte)
+{
+ return (void *)((pte >> 32 << PAGE_SHIFT) + PAGE_OFFSET);
+}
+
+static void
+set_pte (unsigned long addr, void *page)
+{
+ unsigned long *pt = page_dir;
+ unsigned long index;
+
+ index = (addr >> (PAGE_SHIFT+20)) % 1024;
+ if (pt[index] != 0)
+ pt = pte_page (pt[index]);
+ else
+ __builtin_trap();
+
+ index = (addr >> (PAGE_SHIFT+10)) % 1024;
+ if (pt[index] != 0)
+ pt = pte_page (pt[index]);
+ else
+ __builtin_trap();
+
+ index = (addr >> PAGE_SHIFT) % 1024;
+ pt[index] = build_pte (page);
+}
+
+static void
+init_page_table (unsigned long memsize, unsigned long pal_pages)
+{
+ unsigned long i, addr, max_addr, page;
+
+ page_dir[0] = build_pte (page_L1);
+
+ for (i = 0; i < 1024; ++i)
+ page_L1[i] = build_pte (page_L2[i]);
+
+ set_pte ((unsigned long)INIT_HWRPB, &hwrpb);
+
+ addr = 0x20000000ul;
+ max_addr = 1ul << (PAGE_SHIFT + 20);
+ page = pal_pages << PAGE_SHIFT;
+
+ while (addr < max_addr && page < memsize)
+ {
+ set_pte (addr, (void *)(PAGE_OFFSET + page));
+ addr += PAGE_SIZE;
+ page += PAGE_SIZE;
+ }
+
+ /* SRM places the self-map for the VPTBR in the second entry. */
+ page_dir[1] = build_pte (page_dir);
+
+ /* Write the SRM vptptr. */
+ {
+ register unsigned long a0 __asm__("$16") = max_addr;
+ __asm ("call_pal 0x2d" : : "r"(a0));
+ }
+}
+
+void
+do_start(unsigned long memsize)
+{
+ init_hwrpb (memsize);
+ init_pcb ();
+ init_page_table (memsize, hwrpb.mc[0].numpages);
+
+ while (1) ;
+}