summaryrefslogtreecommitdiff
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
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.
-rw-r--r--Makefile5
-rw-r--r--init.c278
-rw-r--r--pal.S46
-rw-r--r--palcode.ld2
4 files changed, 192 insertions, 139 deletions
diff --git a/Makefile b/Makefile
index 5514e43..45dcfb7 100644
--- a/Makefile
+++ b/Makefile
@@ -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
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 ();
}
diff --git a/pal.S b/pal.S
index f62e623..913b8f8 100644
--- a/pal.S
+++ b/pal.S
@@ -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
diff --git a/palcode.ld b/palcode.ld
index a1304b5..59efb04 100644
--- a/palcode.ld
+++ b/palcode.ld
@@ -5,7 +5,7 @@ SECTIONS
{
. = 0xfffffc0000000000;
.text : { *(.text*) }
- .rodata : { *(.rodata) }
+ .rodata : { *(.rodata*) }
.data ALIGN(8192) : { *(.data.hwrpb) *(.data*) }
.got : { *(.got.plt) *(.got) }
.sdata : { *(.sdata*) }