[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 6/6 gnumach] smp: Fix INIT/STARTUP IPI sequence
From: |
Samuel Thibault |
Subject: |
Re: [PATCH 6/6 gnumach] smp: Fix INIT/STARTUP IPI sequence |
Date: |
Mon, 5 Feb 2024 23:36:41 +0100 |
User-agent: |
NeoMutt/20170609 (1.8.3) |
Hello,
Damien Zammit, le lun. 05 févr. 2024 11:34:09 +0000, a ecrit:
> Outstanding: Find a way to allocate memory below 1MiB.
We could make the biosmem's biosmem_bootstrap_common code reserve the
first physical page it finds from the multiboot mem map.
> diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
> index 071aa292..6a040ab8 100644
> --- a/i386/i386/mp_desc.c
> +++ b/i386/i386/mp_desc.c
> @@ -292,17 +292,24 @@ cpu_ap_main()
> kern_return_t
> cpu_start(int cpu)
> {
> + int err, i, vec;
> +
> assert(machine_slot[cpu].running != TRUE);
>
> uint16_t apic_id = apic_get_cpu_apic_id(cpu);
>
> - printf("Trying to enable: %d\n", apic_id);
> + vec = apboot_addr >> 12;
>
> - smp_startup_cpu(apic_id, apboot_addr);
> + printf("Trying to enable: %d at 0x%x\n", apic_id, vec);
>
> - printf("Started cpu %d (lapic id %04x)\n", cpu, apic_id);
> + err = smp_startup_cpu(apic_id, vec);
I'd say rather keep the >>12 part inside smp_startup_cpu, like it was.
> - return KERN_SUCCESS;
> + if (!err) {
> + printf("Started cpu %d (lapic id %04x)\n", cpu, apic_id);
> + return KERN_SUCCESS;
> + }
> + printf("FATAL: Cannot init AP %d\n", cpu);
> + for (;;);
> }
>
> void
> diff --git a/i386/i386/smp.c b/i386/i386/smp.c
> index 87f59913..397defa6 100644
> --- a/i386/i386/smp.c
> +++ b/i386/i386/smp.c
> @@ -18,10 +18,14 @@
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
>
> +#include <string.h>
> #include <i386/apic.h>
> #include <i386/smp.h>
> #include <i386/cpu.h>
> +#include <i386/pio.h>
> +#include <i386/vm_param.h>
> #include <i386at/idt.h>
> +#include <i386at/cram.h>
> #include <i386at/acpi_parse_apic.h>
> #include <kern/printf.h>
> #include <mach/machine.h>
> @@ -75,59 +79,105 @@ void smp_pmap_update(unsigned apic_id)
> smp_send_ipi(apic_id, CALL_PMAP_UPDATE);
> }
>
> -/* See Intel IA32/64 Software Developer's Manual 3A Section 8.4.4.1 */
> -void smp_startup_cpu(unsigned apic_id, unsigned vector)
> +static void
> +wait_for_ipi(void)
> {
> - /* Clear APIC errors */
> - lapic->error_status.r = 0;
> + int loops = 100000;
This is arbitrary and can arbitrarily break if processor conditions
change. Does the manual specify a reactivity bound time? Can we not use
the hpet counter as a clock source?
> + while (lapic->icr_low.delivery_status == SEND_PENDING) {
> + cpu_pause();
> + loops--;
> + if (loops == 0) {
> + printf("FATAL: wait_for_ipi: busy\n");
> + for (;;);
> + }
> + }
> +}
> +
> +static int
> +smp_send_ipi_init(int apic_id)
> +{
> + int err;
>
> - printf("Sending IPIs to APIC ID %u...", apic_id);
> + lapic->error_status.r = 0;
>
> /* Assert INIT IPI */
> - apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, ASSERT, LEVEL, 0, apic_id);
> + apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, ASSERT, EDGE, 0, apic_id);
This is an involved change, can we have a reference on why in the end it
should be edge?
> /* Wait for delivery */
> - do {
> - cpu_pause();
> - } while(lapic->icr_low.delivery_status == SEND_PENDING);
> + wait_for_ipi();
> + hpet_mdelay(10);
>
> /* Deassert INIT IPI */
> - apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, DE_ASSERT, LEVEL, 0,
> apic_id);
> + apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, DE_ASSERT, EDGE, 0, apic_id);
Ditto.
> /* Wait for delivery */
> - do {
> - cpu_pause();
> - } while(lapic->icr_low.delivery_status == SEND_PENDING);
> + wait_for_ipi();
>
> - /* Wait 10 msec */
> - hpet_mdelay(10);
> + err = lapic->error_status.r;
> + if (err) {
> + printf("ESR error upon INIT 0x%x\n", err);
> + }
> + return 0;
> +}
>
> - /* Clear APIC errors */
> - lapic->error_status.r = 0;
> +static int
> +smp_send_ipi_startup(int apic_id, int vector)
> +{
> + int err;
>
> - /* First StartUp IPI */
> - apic_send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, LEVEL, vector >>
> 12, apic_id);
> + lapic->error_status.r = 0;
>
> - /* Wait 200 usec */
> - hpet_udelay(200);
> + /* StartUp IPI */
> + apic_send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, EDGE, vector,
> apic_id);
Ditto.
> /* Wait for delivery */
> - do {
> - cpu_pause();
> - } while(lapic->icr_low.delivery_status == SEND_PENDING);
> + wait_for_ipi();
>
> - /* Second StartUp IPI */
> - apic_send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, LEVEL, vector >>
> 12, apic_id);
> + err = lapic->error_status.r;
> + if (err) {
> + printf("ESR error upon STARTUP 0x%x\n", err);
> + }
> + return 0;
> +}
>
> - /* Wait 200 usec */
> +/* See Intel IA32/64 Software Developer's Manual 3A Section 8.4.4.1 */
> +int smp_startup_cpu(unsigned apic_id, unsigned vector)
> +{
> + int err;
> +
> +#if 0
> + /* This is a legacy method of INIT that only works with
> + * old hardware that does not support SIPIs.
> + * Must use INIT DEASSERT LEVEL triggered IPI to use this block.
> + * (At least one AMD FCH does not support this IPI mode,
> + * See AMD BKDG FAM16h document # 48751 page 461).
> + */
> +
> + /* Tell CMOS to warm reset through through 40:67 */
> + outb(CMOS_ADDR, CMOS_SHUTDOWN);
> + outb(CMOS_DATA, CM_JMP_467);
> +
> + /* Set warm reset vector to point to AP startup code */
> + uint16_t dword[2];
> + dword[0] = 0;
> + dword[1] = vector << 8;
Rather use 12-4, otherwise 8 is surprising.
> + memcpy((uint8_t *)phystokv(0x467), dword, 4);
> +#endif
> +
> + /* Local cache flush */
> + asm("wbinvd":::"memory");
> +
> + printf("Sending IPIs to APIC ID %u...\n", apic_id);
> + err = smp_send_ipi_init(apic_id);
> + hpet_mdelay(10);
> + err = smp_send_ipi_startup(apic_id, vector);
> + hpet_udelay(200);
> + err = smp_send_ipi_startup(apic_id, vector);
> hpet_udelay(200);
> -
> - /* Wait for delivery */
> - do {
> - cpu_pause();
> - } while(lapic->icr_low.delivery_status == SEND_PENDING);
>
> printf("done\n");
> + return 0;
> }
>
> /*
- Re: [PATCH 1/6 gnumach] Fix apic_send_ipi function clobbering read only fields, (continued)
- [PATCH 2/6 gnumach] separate lapic_enable from lapic_setup, Damien Zammit, 2024/02/05
- [PATCH 3/6 gnumach] smp: Remove hardcoded AP_BOOT_ADDR, Damien Zammit, 2024/02/05
- [PATCH 4/6 gnumach] Add HPET timer for small accurate delays, Damien Zammit, 2024/02/05
- [PATCH 5/6 gnumach] smp: Use HPET instead of pit one-shot that is unreliable, Damien Zammit, 2024/02/05
- [PATCH 6/6 gnumach] smp: Fix INIT/STARTUP IPI sequence, Damien Zammit, 2024/02/05
- Re: [PATCH 6/6 gnumach] smp: Fix INIT/STARTUP IPI sequence,
Samuel Thibault <=