aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2023-06-21 17:14:46 +0200
committerHelge Deller <deller@gmx.de>2023-06-21 17:14:46 +0200
commit19de2b419cdf63683d5ccedc6872b35ce7763de9 (patch)
treefc1bc4ec9dc5a11035ec9cda9cae6d4d40514926
parente957f3e22f3d75bfbcf6576af4116b5ebe7fa726 (diff)
downloadseabios-hppa-19de2b419cdf63683d5ccedc6872b35ce7763de9.zip
seabios-hppa-19de2b419cdf63683d5ccedc6872b35ce7763de9.tar.gz
seabios-hppa-19de2b419cdf63683d5ccedc6872b35ce7763de9.tar.bz2
parisc: Fix SMP reboot
Most important is the flushing of the TLB entries Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--src/parisc/head.S93
-rw-r--r--src/parisc/parisc.c66
2 files changed, 93 insertions, 66 deletions
diff --git a/src/parisc/head.S b/src/parisc/head.S
index 891ec9a..900ec48 100644
--- a/src/parisc/head.S
+++ b/src/parisc/head.S
@@ -67,6 +67,15 @@ name:
#define INT_LEN 4
#endif
+/* various control register and irq bits */
+#define PSW_I 1
+#define PSW_Q 8
+#define CR_EIRR 23
+#define CR_IVA 14
+#define CR_EIEM 15
+#define PSW_W_SM 0x200
+#define PSW_W_BIT 36
+
.import $global$
.section ".head.text","ax"
.level 1.1
@@ -91,6 +100,8 @@ marker:
.align 0x80
ENTRY(startup)
+ rsm PSW_I, %r0 /* disable local irqs */
+
/* Make sure space registers are set to zero */
mtsp %r0,%sr0
mtsp %r0,%sr1
@@ -101,14 +112,34 @@ ENTRY(startup)
mtsp %r0,%sr6
mtsp %r0,%sr7
-#define PSW_W_SM 0x200
-#define PSW_W_BIT 36
-
;! nuke the W bit
.level 2.0
rsm PSW_W_SM, %r0
.level 1.1
+ /* If CPU HPA is already set in CPU_HPA_CR_REG then the
+ * CPU is already initialized and the machine was only reset */
+ mfctl CPU_HPA_CR_REG, %r1
+ comib,= 0,%r1,$startup_fresh_booted
+ nop
+
+$startup_just_rebooted:
+ /* Get current CPU HPA. It was stored there at initial bootup. */
+ mfctl CPU_HPA_CR_REG, %r5
+
+ /* branch if this is the monarch cpu */
+ load32 CPU_HPA, %r1
+ comb,= %r5,%r1,$is_monarch_cpu_reboot
+ nop
+
+ /* we assume the monarch CPU is in idle loop. wake it up. */
+ ldi -1, %r3 /* trigger IRQ0 (Timer) */
+ stw %r3, 0(%r1)
+ b,n enter_smp_idle_loop
+
+$startup_fresh_booted:
+ /* Here the machine was booted from scratch: */
+
/* Save CPU HPA in cr7, hopefully HP-UX will not use that register. */
mtctl %r5, CPU_HPA_CR_REG /* store CPU HPA */
@@ -121,38 +152,32 @@ ENTRY(enter_smp_idle_loop)
/* IDLE LOOP for SMP CPUs - wait for rendenzvous. */
mfctl CPU_HPA_CR_REG, %r25 /* get CPU HPA from cr7 */
-#define PSW_I 1
- rsm PSW_I, %r0 /* disable local irqs */
+ rsm PSW_I | PSW_Q, %r0 /* disable local irqs */
+ mtctl %r0, CR_EIEM /* disable all external irqs */
/* EIRR : clear all pending external intr */
-#define CR_EIRR 23
load32 -1,%r1
mtctl %r1, CR_EIRR
mfctl CR_EIRR, %r0
mtctl %r0, CR_EIRR
/* Load IVT for SMT tiny loop exit */
-#define CR_IVA 14
load32 BOOTADDR(smp_ivt),%r1
mtctl %r1, CR_IVA
/* enable CPU local interrupts */
-#define CR_EIEM 15
load32 1<<31, %r1 /* allow IRQ0 (Timer) */
mtctl %r1, CR_EIEM
ssm PSW_I, %r0 /* enable local irqs */
- /* endless idle loop, exits to $smp_exit_loop by IRQ only */
+ /* endless idle loop for secondary CPUs. Exits to $smp_exit_loop by IRQ only */
$smp_idle_loop:
b $smp_idle_loop
- or %r10,%r10,%r10
+ or %r10,%r10,%r10 /* qemu sleep instruction */
$smp_exit_loop:
- mtctl %r0, CR_EIEM
rsm PSW_I, %r0 /* disable local irqs */
-
- /* tell QEMU to drop all local TLB entries. */
- pdtlbe %r0(%sr1,%r0)
+ mtctl %r0, CR_EIEM
/* on 64bit: Address of PDCE_PROC for each non-monarch processor in GR26. */
load32 BOOTADDR(pdc_entry), %r26
@@ -160,11 +185,23 @@ $smp_exit_loop:
/* jump to rendevouz */
ldw 0x10(%r0),%r3 /* MEM_RENDEZ */
/* ldw 0x28(%r0),%r0 MEM_RENDEZ_HI - assume addr < 4GB */
- load32 enter_smp_idle_loop, %rp
+ cmpb,=,n %r0,%r3,startup /* branch to startup if not yet initialized */
+ load32 startup, %rp
bv,n 0(%r3)
-
$is_monarch_cpu:
+ /* Save boot_args. Only monarch CPU does this once. */
+ load32 BOOTADDR(0x040 + 10*4),%r1
+ stw,ma %r26,4(%r1)
+ stw,ma %r25,4(%r1)
+ stw,ma %r24,4(%r1)
+ stw,ma %r23,4(%r1)
+ stw,ma %r22,4(%r1)
+ stw,ma %r21,4(%r1)
+ stw,ma %r20,4(%r1)
+ stw,ma %r19,4(%r1)
+
+$is_monarch_cpu_reboot:
/* Initialize stack pointer */
load32 BOOTADDR(parisc_stack),%r1
ldo FRAME_SIZE(%r1),%sp
@@ -182,23 +219,11 @@ $bss_loop:
cmpb,<<,n %r3,%r4,$bss_loop
stw,ma %r0,4(%r3)
- /* Save boot args */
- load32 BOOTADDR(boot_args),%r1
- stw,ma %r26,4(%r1)
- stw,ma %r25,4(%r1)
- stw,ma %r24,4(%r1)
- stw,ma %r23,4(%r1)
- stw,ma %r22,4(%r1)
- stw,ma %r21,4(%r1)
- stw,ma %r20,4(%r1)
- stw,ma %r19,4(%r1)
-
load32 BOOTADDR(start_parisc_firmware),%r3
bv 0(%r3)
copy %r0,%r2
END(startup)
-
/*******************************************************
TOC handler
Write all GRs, CRs, SRs and the iaoq_back and iasq_back registers (in
@@ -381,18 +406,6 @@ ENTRY(iodc_entry)
ldw -32(%sp),%dp
END(iodc_entry)
- .data
-ENTRY(boot_args)
- .word 0 /* r26: ramsize */
- .word 0 /* r25: kernel entry point */
- .word 0 /* r24: cmdline */
- .word 0 /* r23: initrd_start */
- .word 0 /* r22: initrd_end */
- .word 0 /* r21: num CPUs */
- .word 0 /* r20: pdc_debug */
- .word 0 /* r19: fw_cfg port */
-END(boot_args)
-
/****************************************************************
* Rom Header for VGA / STI
****************************************************************/
diff --git a/src/parisc/parisc.c b/src/parisc/parisc.c
index 65ed177..5cae7b5 100644
--- a/src/parisc/parisc.c
+++ b/src/parisc/parisc.c
@@ -92,24 +92,21 @@ void wrmsr_smp(u32 index, u64 val) { }
* PA-RISC specific constants and functions.
********************************************************/
-/* Pointer to zero-page of PA-RISC */
-#define PAGE0 ((volatile struct zeropage *) 0UL)
-
-/* variables provided by qemu */
-extern unsigned long boot_args[];
-#define ram_size (boot_args[0])
-#define linux_kernel_entry (boot_args[1])
-#define cmdline (boot_args[2])
-#define initrd_start (boot_args[3])
-#define initrd_end (boot_args[4])
-#define smp_cpus (boot_args[5])
-#define pdc_debug (boot_args[6])
-#define fw_cfg_port (boot_args[7])
+/* variables provided by qemu - boot_args starting at pad0[10] */
+#define ram_size PAGE0->pad0[10]
+#define linux_kernel_entry PAGE0->pad0[11]
+#define cmdline PAGE0->pad0[12]
+#define initrd_start PAGE0->pad0[13]
+#define initrd_end PAGE0->pad0[14]
+#define smp_cpus PAGE0->pad0[15]
+#define pdc_debug PAGE0->pad0[16]
+#define fw_cfg_port PAGE0->pad0[17]
/* flags for pdc_debug */
-#define DEBUG_PDC 0x0001
-#define DEBUG_IODC 0x0002
-#define DEBUG_BOOT_IO 0x0004
+#define DEBUG_PDC 0x01
+#define DEBUG_IODC 0x02
+#define DEBUG_BOOT_IO 0x04
+#define DEBUG_CHASSIS 0x08
int pdc_console;
/* flags for pdc_console */
@@ -1720,13 +1717,14 @@ unsigned long __VISIBLE toc_handler(struct pdc_toc_pim_11 *pim)
p = (unsigned long *)&pim11->sr[0];
printf("SR0: %lx %lx %lx %lx %lx %lx %lx %lx\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
if (is_64bit()) {
- printf("IAQ: %lx.%lx %lx.%lx\n",
+ printf("IAQ: %lx.%lx %lx.%lx PSW: %lx\n",
(unsigned long)pim20->cr[17], (unsigned long)pim20->cr[18],
- (unsigned long)pim20->iasq_back, (unsigned long)pim20->iaoq_back);
+ (unsigned long)pim20->iasq_back, (unsigned long)pim20->iaoq_back,
+ (unsigned long)pim20->cr[22]);
printf("RP(r2): %lx\n", (unsigned long)pim20->gr[2]);
} else {
- printf("IAQ: %x.%x %x.%x\n", pim11->cr[17], pim11->cr[18],
- pim11->iasq_back, pim11->iaoq_back);
+ printf("IAQ: %x.%x %x.%x PSW: %x\n", pim11->cr[17], pim11->cr[18],
+ pim11->iasq_back, pim11->iaoq_back, pim11->cr[22]);
printf("RP(r2): %x\n", pim11->gr[2]);
}
@@ -2178,8 +2176,8 @@ void __VISIBLE start_parisc_firmware(void)
model.sw_id = romfile_loadstring_to_int("opt/hostid", model.sw_id);
dprintf(0, "fw_cfg: machine hostid %lu\n", model.sw_id);
- /* Initialize PAGE0 */
- memset((void*)PAGE0, 0, sizeof(*PAGE0));
+ /* Do not initialize PAGE0. We have the boot args stored there. */
+ /* memset((void*)PAGE0, 0, sizeof(*PAGE0)); */
/* copy pdc_entry entry into low memory. */
memcpy((void*)MEM_PDC_ENTRY, &pdc_entry_table, 3*4);
@@ -2254,13 +2252,13 @@ void __VISIBLE start_parisc_firmware(void)
// PlatformRunningOn = PF_QEMU; // emulate runningOnQEMU()
cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
- dprintf(1, "\nPARISC SeaBIOS Firmware, %ld x PA7300LC (PCX-L2) at %d.%06d MHz, %lu MB RAM.\n",
+ dprintf(1, "\nPARISC SeaBIOS Firmware, %d x PA7300LC (PCX-L2) at %d.%06d MHz, %d MB RAM.\n",
smp_cpus, cpu_hz / 1000000, cpu_hz % 1000000,
ram_size/1024/1024);
if (ram_size < MIN_RAM_SIZE) {
printf("\nSeaBIOS: Machine configured with too little "
- "memory (%ld MB), minimum is %d MB.\n\n",
+ "memory (%d MB), minimum is %d MB.\n\n",
ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
hlt();
}
@@ -2278,6 +2276,16 @@ void __VISIBLE start_parisc_firmware(void)
serial_setup();
block_setup();
+ PAGE0->vec_rendz = 0; /* No rendezvous yet. Add MEM_RENDEZ_HI later */
+ /* if this is a reboot, force secondary CPUs to enter smp_idle loop */
+ if (PAGE0->imm_soft_boot) {
+ for (i = 1; i < smp_cpus; i++) {
+ unsigned long hpa;
+ hpa = CPU_HPA_IDX(i);
+ *(int*)hpa = -1; /* send Wakeup IRQ to trigger QEMU to load boot address */
+ }
+ }
+
printf("\n");
printf("SeaBIOS PA-RISC Firmware Version %d\n"
"\n"
@@ -2293,9 +2301,9 @@ void __VISIBLE start_parisc_firmware(void)
" MHz %s Functional 0 KB\n",
i < 10 ? " ":"", i, i?"Idle ":"Active");
printf("\n\n");
- printf(" Available memory: %llu MB\n"
+ printf(" Available memory: %u MB\n"
" Good memory required: %d MB\n\n",
- (unsigned long long)ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
+ ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
// search boot devices
find_initial_parisc_boot_drives(&parisc_boot_harddisc, &parisc_boot_cdrom);
@@ -2338,6 +2346,10 @@ void __VISIBLE start_parisc_firmware(void)
PAGE0->mem_boot.dp.layers[1] = boot_drive->lun;
}
+ /* Qemu-specific: Drop *all* TLB entries for all CPUs before start. */
+ /* Necessary if machine was rebooted. */
+ asm("pdtlbe %%r0(%%sr1,%%r0)" : : : "memory");
+
/* directly start Linux kernel if it was given on qemu command line. */
if (linux_kernel_entry > 1) {
void (*start_kernel)(unsigned long mem_free, unsigned long cline,
@@ -2345,6 +2357,8 @@ void __VISIBLE start_parisc_firmware(void)
printf("Autobooting Linux kernel which was loaded by qemu...\n\n");
start_kernel = (void *) linux_kernel_entry;
+ /* zero out kernel entry point in case we reset the machine: */
+ linux_kernel_entry = 0;
start_kernel(PAGE0->mem_free, cmdline, initrd_start, initrd_end);
hlt(); /* this ends the emulator */
}