diff options
author | Helge Deller <deller@gmx.de> | 2023-06-21 17:14:46 +0200 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2023-06-21 17:14:46 +0200 |
commit | 19de2b419cdf63683d5ccedc6872b35ce7763de9 (patch) | |
tree | fc1bc4ec9dc5a11035ec9cda9cae6d4d40514926 | |
parent | e957f3e22f3d75bfbcf6576af4116b5ebe7fa726 (diff) | |
download | seabios-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.S | 93 | ||||
-rw-r--r-- | src/parisc/parisc.c | 66 |
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 */ } |