#include #include #include "hwrpb.h" #include "osf.h" #include "uart.h" #define PAGE_SHIFT 13 #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 HZ 1024 struct pcb_struct pal_pcb __attribute__((section(".sbss"))); 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, .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 }; unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE))); extern char _end[]; static unsigned long last_alloc = (unsigned long)_end; static void * alloc (unsigned long size, unsigned long align) { unsigned long p = (last_alloc + align - 1) & ~(align - 1); last_alloc = p + size; return (void *)p; } 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) { pal_pcb.ptbr = PA((unsigned long)page_dir); pal_pcb.flags = 1; } static inline unsigned long build_pte (void *page) { unsigned long bits; bits = PA((unsigned long)page) << (32 - PAGE_SHIFT); bits += _PAGE_VALID | _PAGE_KRE | _PAGE_KWE; return bits; } static inline void * pte_page (unsigned long pte) { return (void *)VA(pte >> 32 << PAGE_SHIFT); } 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 { unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE); pt[index] = build_pte (npt); pt = npt; } index = (addr >> (PAGE_SHIFT+10)) % 1024; if (pt[index] != 0) pt = pte_page (pt[index]); else { unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE); pt[index] = build_pte (npt); pt = npt; } index = (addr >> PAGE_SHIFT) % 1024; pt[index] = build_pte (page); } static void init_page_table (unsigned long memsize) { unsigned long i, addr, max_addr, page; 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); /* Write the SRM vptptr. */ { register unsigned long a0 __asm__("$16") = 0xfffffffe00000000UL; __asm ("call_pal 0x2d" : : "r"(a0)); } } void do_start(unsigned long memsize, void (*kernel_entry)(void)) { init_page_table (memsize); init_hwrpb (memsize); init_pcb (); uart_init (); uart_puts (COM1, "Hello, World!\n"); if (kernel_entry) kernel_entry(); asm ("halt"); }