blob: 497375623f8087f0d9bf8d059afe5c040a0684a3 [file] [log] [blame]
#include <string.h>
#include <stddef.h>
#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");
}