bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 12/12] i386: Refactor int stacks to be per cpu for SMP


From: Almudena Garcia
Subject: Re: [PATCH 12/12] i386: Refactor int stacks to be per cpu for SMP
Date: Tue, 25 Oct 2022 19:31:52 +0200

void
 start_other_cpus(void)
 {
-       int cpu;
-       for (cpu = 0; cpu < NCPUS; cpu++)
-               if (cpu != cpu_number())
-                       cpu_start(cpu);
-}
+       unsigned long flags;
+
+       cpu_intr_save(&flags);
+
+       int ncpus = smp_get_numcpus();
+
+       //Copy cpu initialization assembly routine
+       memcpy((void*)phystokv(AP_BOOT_ADDR), (void*) &apboot,
+              (uint32_t)&apbootend - (uint32_t)&apboot);

+#ifndef APIC
+       lapic_enable(); /* Enable lapic only once */
+#endif
+       unsigned cpu;
+       bspdone = 0;
+       for (cpu = 1; cpu < ncpus; cpu++) {
+               machine_slot[cpu].running = FALSE;
+
+               //Start cpu
+               printf("Starting AP %d\n", cpu);
+               cpu_start(cpu);
+       }
+       printf("BSP: Completed SMP init\n");
+       bspdone = 1;
+
+       for (cpu = 1; cpu < ncpus; cpu++) {
+               do {
+                       asm volatile ("pause" : : : "memory");
+               } while (machine_slot[cpu].running == FALSE);
+       }
+
+        cpu_intr_restore(flags);
+}

I think that it's better start the AP one by one: only start other AP when the previous is already ready (enabled and configured).
As this way you can avoid concurrency problems


El mar, 25 oct 2022 a las 12:58, Damien Zammit (<damien@zamaudio.com>) escribió:
---
 i386/Makefrag.am                 |   6 +
 i386/i386/cpu_number.h           |  31 ++-
 i386/i386/cswitch.S              |   4 +-
 i386/i386/locore.S               |  48 ++--
 i386/i386/mp_desc.c              | 366 +++++++++++++++++++++----------
 i386/i386/mp_desc.h              |   9 +-
 i386/i386at/boothdr.S            |  18 +-
 i386/i386at/model_dep.c          |  28 +--
 linux/dev/arch/i386/kernel/irq.c |  13 +-
 linux/dev/init/main.c            |   2 +
 10 files changed, 349 insertions(+), 176 deletions(-)

diff --git a/i386/Makefrag.am b/i386/Makefrag.am
index 8d6ef8cd..b74aad35 100644
--- a/i386/Makefrag.am
+++ b/i386/Makefrag.am
@@ -30,6 +30,8 @@ if HOST_ix86
 #

 libkernel_a_SOURCES += \
+       i386/i386at/acpi_parse_apic.h \
+       i386/i386at/acpi_parse_apic.c \
        i386/i386at/autoconf.c \
        i386/i386at/autoconf.h \
        i386/i386at/biosmem.c \
@@ -94,7 +96,9 @@ libkernel_a_SOURCES += \
        i386/i386/ast_types.h \
        i386/i386/cpu.h \
        i386/i386/cpu_number.h \
+       i386/i386/cpu_number.c \
        i386/i386/cswitch.S \
+       i386/i386/cpuboot.S \
        i386/i386/db_disasm.c \
        i386/i386/db_interface.c \
        i386/i386/db_interface.h \
@@ -158,6 +162,8 @@ libkernel_a_SOURCES += \
        i386/i386/user_ldt.h \
        i386/i386/vm_param.h \
        i386/i386/xpr.h \
+       i386/i386/smp.h \
+       i386/i386/smp.c \
        i386/intel/pmap.c \
        i386/intel/pmap.h \
        i386/intel/read_fault.c \
diff --git a/i386/i386/cpu_number.h b/i386/i386/cpu_number.h
index 9aef6370..d56cb602 100644
--- a/i386/i386/cpu_number.h
+++ b/i386/i386/cpu_number.h
@@ -35,14 +35,35 @@
 /* More-specific code must define cpu_number() and CPU_NUMBER.  */
 #ifdef __i386__
 #define        CX(addr, reg)   addr(,reg,4)
+
+/* CPU_NUMBER(%ebx) will _not_ work! */
+#define        CPU_NUMBER(reg) \
+       pushfl                          ;\
+       cli                             ;\
+       pushl   %esi                    ;\
+       pushl   %edi                    ;\
+       pushl   %ebx                    ;\
+       pushl   %eax                    ;\
+       call    EXT(cpu_number)         ;\
+       movl    %eax, %ebx              ;\
+       popl    %eax                    ;\
+       movl    %ebx, reg               ;\
+       popl    %ebx                    ;\
+       popl    %edi                    ;\
+       popl    %esi                    ;\
+       popfl
+
 #endif
 #ifdef __x86_64__
 #define        CX(addr, reg)   addr(,reg,8)
+#warning Missing CPU_NUMBER() for 64 bit
+#define CPU_NUMBER(reg)
 #endif

-/* XXX For now */
-#define        CPU_NUMBER(reg) movl $0,reg
-#define cpu_number() 0
+#ifndef __ASSEMBLER__
+#include "kern/cpu_number.h"
+int cpu_number();
+#endif

 #else  /* NCPUS == 1 */

@@ -51,8 +72,4 @@

 #endif /* NCPUS == 1 */

-#ifndef __ASSEMBLER__
-#include "kern/cpu_number.h"
-#endif
-
 #endif /* _I386_CPU_NUMBER_H_ */
diff --git a/i386/i386/cswitch.S b/i386/i386/cswitch.S
index 718c8aac..46da2300 100644
--- a/i386/i386/cswitch.S
+++ b/i386/i386/cswitch.S
@@ -110,7 +110,7 @@ ENTRY(Thread_continue)
  */
 ENTRY(switch_to_shutdown_context)
        CPU_NUMBER(%edx)
-       movl    EXT(active_stacks)(,%edx,4),%ecx        /* get old kernel stack */
+       movl    CX(EXT(active_stacks),%edx),%ecx        /* get old kernel stack */
        movl    %ebx,KSS_EBX(%ecx)              /* save registers */
        movl    %ebp,KSS_EBP(%ecx)
        movl    %edi,KSS_EDI(%ecx)
@@ -124,7 +124,7 @@ ENTRY(switch_to_shutdown_context)
        movl    4(%esp),%ebx                    /* get routine to run next */
        movl    8(%esp),%esi                    /* get its argument */

-       movl    EXT(interrupt_stack)(,%edx,4),%ecx      /* point to its interrupt stack */
+       movl    CX(EXT(int_stack_base),%edx),%ecx       /* point to its interrupt stack */
        lea     INTSTACK_SIZE(%ecx),%esp        /* switch to it (top) */

        pushl   %eax                            /* push thread */
diff --git a/i386/i386/locore.S b/i386/i386/locore.S
index 8c2f57ea..64152b5b 100644
--- a/i386/i386/locore.S
+++ b/i386/i386/locore.S
@@ -540,21 +540,22 @@ _kret_iret:
  */
 trap_from_kernel:
 #if    MACH_KDB || MACH_TTD
-       movl    %esp,%ebx               /* save current stack */
+       CPU_NUMBER(%ecx)                /* get CPU number */

+       movl    %esp,%ebx               /* save current stack */
        movl    %esp,%edx               /* on an interrupt stack? */
+
        and     $(~(KERNEL_STACK_SIZE-1)),%edx
-       cmpl    EXT(int_stack_base),%edx
+       cmpl    CX(EXT(int_stack_base),%ecx),%edx
        je      1f                      /* OK if so */

-       CPU_NUMBER(%edx)                /* get CPU number */
-       cmpl    CX(EXT(kernel_stack),%edx),%esp
+       cmpl    CX(EXT(kernel_stack),%ecx),%esp
                                        /* already on kernel stack? */
        ja      0f
-       cmpl    CX(EXT(active_stacks),%edx),%esp
+       cmpl    CX(EXT(active_stacks),%ecx),%esp
        ja      1f                      /* switch if not */
 0:
-       movl    CX(EXT(kernel_stack),%edx),%esp
+       movl    CX(EXT(kernel_stack),%ecx),%esp
 1:
        pushl   %ebx                    /* save old stack */
        pushl   %ebx                    /* pass as parameter */
@@ -668,24 +669,25 @@ ENTRY(all_intrs)
        pushl   %edx
        cld                             /* clear direction flag */

-       movl    %esp,%edx               /* on an interrupt stack? */
-       and     $(~(KERNEL_STACK_SIZE-1)),%edx
-       cmpl    %ss:EXT(int_stack_base),%edx
+       CPU_NUMBER(%edx)
+
+       movl    %esp,%ecx               /* on an interrupt stack? */
+       and     $(~(KERNEL_STACK_SIZE-1)),%ecx
+       cmpl    %ss:CX(EXT(int_stack_base),%edx),%ecx
        je      int_from_intstack       /* if not: */

        pushl   %ds                     /* save segment registers */
        pushl   %es
        pushl   %fs
        pushl   %gs
-       mov     %ss,%dx                 /* switch to kernel segments */
-       mov     %dx,%ds
-       mov     %dx,%es
-       mov     %dx,%fs
-       mov     %dx,%gs
-
-       CPU_NUMBER(%edx)
+       mov     %ss,%cx                 /* switch to kernel segments */
+       mov     %cx,%ds
+       mov     %cx,%es
+       mov     %cx,%fs
+       mov     %cx,%gs

        movl    CX(EXT(int_stack_top),%edx),%ecx
+
        xchgl   %ecx,%esp               /* switch to interrupt stack */

 #if    STAT_TIME
@@ -724,19 +726,19 @@ LEXT(return_to_iret)                      /* ( label for kdb_kintr and hardclock) */
        pop     %fs
        pop     %es
        pop     %ds
-       pop     %edx
-       pop     %ecx
-       pop     %eax
+       popl    %edx
+       popl    %ecx
+       popl    %eax
        iret                            /* return to caller */

 int_from_intstack:
-       cmpl    EXT(int_stack_base),%esp        /* seemingly looping? */
+       cmpl    CX(EXT(int_stack_base),%edx),%esp /* seemingly looping? */
        jb      stack_overflowed        /* if not: */
        call    EXT(interrupt)          /* call interrupt routine */
 _return_to_iret_i:                     /* ( label for kdb_kintr) */
-       pop     %edx                    /* must have been on kernel segs */
-       pop     %ecx
-       pop     %eax                    /* no ASTs */
+       popl    %edx                    /* must have been on kernel segs */
+       popl    %ecx
+       popl    %eax                    /* no ASTs */
        iret

 stack_overflowed:
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
index 1e9ea0fc..0c68ec11 100644
--- a/i386/i386/mp_desc.c
+++ b/i386/i386/mp_desc.c
@@ -24,25 +24,36 @@
  * the rights to redistribute these changes.
  */

-#if    NCPUS > 1
-
-#include <string.h>
-
 #include <kern/cpu_number.h>
 #include <kern/debug.h>
 #include <kern/printf.h>
+#include <kern/smp.h>
+#include <kern/startup.h>
+#include <kern/kmutex.h>
 #include <mach/machine.h>
 #include <mach/xen.h>
 #include <vm/vm_kern.h>

 #include <i386/mp_desc.h>
 #include <i386/lock.h>
+#include <i386/apic.h>
+#include <i386/locore.h>
+#include <i386/gdt.h>
+#include <i386at/idt.h>
+#include <i386at/int_init.h>
+#include <i386/cpu.h>
+#include <i386/smp.h>
+
 #include <i386at/model_dep.h>
 #include <machine/ktss.h>
+#include <machine/smp.h>
 #include <machine/tss.h>
 #include <machine/io_perm.h>
 #include <machine/vm_param.h>

+#include <i386at/acpi_parse_apic.h>
+#include <string.h>
+
 /*
  * The i386 needs an interrupt stack to keep the PCB stack from being
  * overrun by interrupts.  All interrupt stacks MUST lie at lower addresses
@@ -52,20 +63,35 @@
 /*
  * Addresses of bottom and top of interrupt stacks.
  */
-vm_offset_t    interrupt_stack[NCPUS];
 vm_offset_t    int_stack_top[NCPUS];
 vm_offset_t    int_stack_base[NCPUS];

-/*
- * Barrier address.
- */
-vm_offset_t    int_stack_high;
+/* Interrupt stack allocation */
+uint8_t solid_intstack[NCPUS*INTSTACK_SIZE] __aligned(INTSTACK_SIZE);

+void
+interrupt_stack_alloc(void)
+{
+       int i;
+
+       /*
+        * Set up pointers to the top of the interrupt stack.
+        */
+
+       for (i = 0; i < NCPUS; i++) {
+               int_stack_base[i] = (vm_offset_t) &solid_intstack[i * INTSTACK_SIZE];
+               int_stack_top[i] = (vm_offset_t) &solid_intstack[(i + 1) * INTSTACK_SIZE];
+       }
+}
+
+#if    NCPUS > 1
 /*
- * First cpu`s interrupt stack.
+ * Flag to mark SMP init by BSP complete
  */
-extern char            _intstack[];    /* bottom */
-extern char            _eintstack[];   /* top */
+int bspdone;
+
+extern void *apboot, *apbootend;
+extern volatile ApicLocalUnit* lapic;

 /*
  * Multiprocessor i386/i486 systems use a separate copy of the
@@ -77,7 +103,7 @@ extern char          _eintstack[];   /* top */
  */

 /*
- * Allocated descriptor tables.
+ * Descriptor tables.
  */
 struct mp_desc_table   *mp_desc_table[NCPUS] = { 0 };

@@ -98,16 +124,121 @@ extern struct real_gate           idt[IDTSZ];
 extern struct real_descriptor  gdt[GDTSZ];
 extern struct real_descriptor  ldt[LDTSZ];

+static void
+set_control_regs_and_pmap(void)
+{
+       /* XXX move to intel/pmap.h */
+       extern pt_entry_t *kernel_page_dir;
+       int i;
+
+       /*
+        * We'll have to temporarily install a direct mapping
+        * between physical memory and low linear memory,
+        * until we start using our new kernel segment descriptors.
+        */
+#if INIT_VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
+       vm_offset_t delta = INIT_VM_MIN_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS;
+       if ((vm_offset_t)(-delta) < delta)
+               delta = (vm_offset_t)(-delta);
+       int nb_direct = delta >> PDESHIFT;
+       for (i = 0; i < nb_direct; i++)
+               kernel_page_dir[lin2pdenum_cont(INIT_VM_MIN_KERNEL_ADDRESS) + i] =
+                       kernel_page_dir[lin2pdenum_cont(LINEAR_MIN_KERNEL_ADDRESS) + i];
+#endif
+        /* We need BIOS memory mapped at 0xc0000 & co for BIOS accesses */
+#if VM_MIN_KERNEL_ADDRESS != 0
+       kernel_page_dir[lin2pdenum_cont(LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS)] =
+               kernel_page_dir[lin2pdenum_cont(LINEAR_MIN_KERNEL_ADDRESS)];
+#endif
+
+#ifdef  MACH_PV_PAGETABLES
+       for (i = 0; i < PDPNUM; i++)
+               pmap_set_page_readonly_init((void*) kernel_page_dir + i * INTEL_PGBYTES);
+#if PAE
+       pmap_set_page_readonly_init(kernel_pmap->pdpbase);
+#endif  /* PAE */
+#endif  /* MACH_PV_PAGETABLES */
+#if PAE
+#ifdef __x86_64__
+       set_cr3((unsigned long)_kvtophys(kernel_pmap->l4base));
+#else
+       set_cr3((unsigned long)_kvtophys(kernel_pmap->pdpbase));
+#endif
+#ifndef MACH_HYP
+       if (!CPU_HAS_FEATURE(CPU_FEATURE_PAE))
+               panic("CPU doesn't have support for PAE.");
+       set_cr4(get_cr4() | CR4_PAE);
+#endif  /* MACH_HYP */
+#else
+       set_cr3((unsigned long)_kvtophys(kernel_page_dir));
+#endif  /* PAE */
+#ifndef MACH_HYP
+       /* Turn paging on.
+        * TODO: Why does setting the WP bit here cause a crash?
+        */
+       set_cr0(get_cr0() | CR0_PG /* | CR0_WP */);
+       set_cr0(get_cr0() & ~(CR0_CD | CR0_NW));
+       if (CPU_HAS_FEATURE(CPU_FEATURE_PGE))
+               set_cr4(get_cr4() | CR4_PGE);
+#endif  /* MACH_HYP */
+       flush_instr_queue();
+}
+
+static void
+remove_initial_pmap(void)
+{
+       /* XXX move to intel/pmap.h */
+       extern pt_entry_t *kernel_page_dir;
+
+#if INIT_VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
+       int i;
+       vm_offset_t delta = INIT_VM_MIN_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS;
+       if ((vm_offset_t)(-delta) < delta)
+               delta = (vm_offset_t)(-delta);
+       int nb_direct = delta >> PDESHIFT;
+       /* Get rid of the temporary direct mapping and flush it out of the TLB.  */
+       for (i = 0 ; i < nb_direct; i++) {
+#ifdef  MACH_XEN
+#ifdef  MACH_PSEUDO_PHYS
+               if (!hyp_mmu_update_pte(kv_to_ma(&kernel_page_dir[lin2pdenum_cont(VM_MIN_KERNEL_ADDRESS) + i]), 0))
+#else   /* MACH_PSEUDO_PHYS */
+               if (hyp_do_update_va_mapping(VM_MIN_KERNEL_ADDRESS + i * INTEL_PGBYTES, 0, UVMF_INVLPG | UVMF_ALL))
+#endif  /* MACH_PSEUDO_PHYS */
+                       printf("couldn't unmap frame %d\n", i);
+#else   /* MACH_XEN */
+               kernel_page_dir[lin2pdenum_cont(INIT_VM_MIN_KERNEL_ADDRESS) + i] = 0;
+#endif  /* MACH_XEN */
+       }
+#endif
+       /* Keep BIOS memory mapped */
+#if VM_MIN_KERNEL_ADDRESS != 0
+       kernel_page_dir[lin2pdenum_cont(LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS)] =
+               kernel_page_dir[lin2pdenum_cont(LINEAR_MIN_KERNEL_ADDRESS)];
+#endif
+
+       /* Not used after boot, better give it back.  */
+#ifdef  MACH_XEN
+       hyp_free_page(0, (void*) VM_MIN_KERNEL_ADDRESS);
+#endif  /* MACH_XEN */
+
+       flush_tlb();
+
+#ifdef  MACH_XEN
+       hyp_p2m_init();
+#endif  /* MACH_XEN */
+}
+
 /*
  * Allocate and initialize the per-processor descriptor tables.
  */

-struct mp_desc_table *
+int
 mp_desc_init(int mycpu)
 {
        struct mp_desc_table *mpt;
+       vm_offset_t mem;

-       if (mycpu == master_cpu) {
+       if (mycpu == 0) {
                /*
                 * Master CPU uses the tables built at boot time.
                 * Just set the TSS and GDT pointers.
@@ -118,108 +249,26 @@ mp_desc_init(int mycpu)
        }
        else {
                /*
-                * Other CPUs allocate the table from the bottom of
-                * the interrupt stack.
+                * Allocate tables for other CPUs
                 */
-               mpt = (struct mp_desc_table *) interrupt_stack[mycpu];
+               if (!init_alloc_aligned(sizeof(struct mp_desc_table), &mem))
+                       panic("not enough memory for descriptor tables");
+               mpt = (struct mp_desc_table *)phystokv(mem);

                mp_desc_table[mycpu] = mpt;
                mp_ktss[mycpu] = &mpt->ktss;
                mp_gdt[mycpu] = mpt->gdt;

                /*
-                * Copy the tables
-                */
-               memcpy(mpt->idt,
-                 idt,
-                 sizeof(idt));
-               memcpy(mpt->gdt,
-                 gdt,
-                 sizeof(gdt));
-               memcpy(mpt->ldt,
-                 ldt,
-                 sizeof(ldt));
-               memset(&mpt->ktss, 0,
-                 sizeof(struct task_tss));
-
-               /*
-                * Fix up the entries in the GDT to point to
-                * this LDT and this TSS.
+                * Zero the tables
                 */
-#ifdef MACH_RING1
-               panic("TODO %s:%d\n",__FILE__,__LINE__);
-#else  /* MACH_RING1 */
-               _fill_gdt_sys_descriptor(mpt->gdt, KERNEL_LDT,
-                       (unsigned)&mpt->ldt,
-                       LDTSZ * sizeof(struct real_descriptor) - 1,
-                       ACC_P|ACC_PL_K|ACC_LDT, 0);
-               _fill_gdt_sys_descriptor(mpt->gdt, KERNEL_TSS,
-                       (unsigned)&mpt->ktss,
-                       sizeof(struct task_tss) - 1,
-                       ACC_P|ACC_PL_K|ACC_TSS, 0);
-
-               mpt->ktss.tss.ss0 = KERNEL_DS;
-               mpt->ktss.tss.io_bit_map_offset = IOPB_INVAL;
-               mpt->ktss.barrier = 0xFF;
-#endif /* MACH_RING1 */
-
-               return mpt;
-       }
-}
-
-kern_return_t intel_startCPU(int slot_num)
-{
-       printf("TODO: intel_startCPU\n");
-}
-
-/*
- * Called after all CPUs have been found, but before the VM system
- * is running.  The machine array must show which CPUs exist.
- */
-void
-interrupt_stack_alloc(void)
-{
-       int             i;
-       int             cpu_count;
-       vm_offset_t     stack_start;
-
-       /*
-        * Count the number of CPUs.
-        */
-       cpu_count = 0;
-       for (i = 0; i < NCPUS; i++)
-           if (machine_slot[i].is_cpu)
-               cpu_count++;
-
-       /*
-        * Allocate an interrupt stack for each CPU except for
-        * the master CPU (which uses the bootstrap stack)
-        */
-       if (!init_alloc_aligned(INTSTACK_SIZE*(cpu_count-1), &stack_start))
-               panic("not enough memory for interrupt stacks");
-       stack_start = phystokv(stack_start);
+               memset(mpt->idt, 0, sizeof(idt));
+               memset(mpt->gdt, 0, sizeof(gdt));
+               memset(mpt->ldt, 0, sizeof(ldt));
+               memset(&mpt->ktss, 0, sizeof(struct task_tss));

-       /*
-        * Set up pointers to the top of the interrupt stack.
-        */
-       for (i = 0; i < NCPUS; i++) {
-           if (i == master_cpu) {
-               interrupt_stack[i] = (vm_offset_t) _intstack;
-               int_stack_top[i]   = (vm_offset_t) _eintstack;
-           }
-           else if (machine_slot[i].is_cpu) {
-               interrupt_stack[i] = stack_start;
-               int_stack_top[i]   = stack_start + INTSTACK_SIZE;
-
-               stack_start += INTSTACK_SIZE;
-           }
+               return mycpu;
        }
-
-       /*
-        * Set up the barrier address.  All thread stacks MUST
-        * be above this address.
-        */
-       int_stack_high = stack_start;
 }

 /* XXX should be adjusted per CPU speed */
@@ -255,24 +304,111 @@ void
 interrupt_processor(int cpu)
 {
        printf("interrupt cpu %d\n",cpu);
+       smp_pmap_update(apic_get_cpu_apic_id(cpu));
+}
+
+void
+cpu_setup()
+{
+    unsigned apic_id = (((ApicLocalUnit*)phystokv(lapic_addr))->apic_id.r >> 24) & 0xff;
+    uint16_t cpu = apic_get_cpu_kernel_id(apic_id);
+
+    printf("AP=(%u) before\n", cpu);
+
+    set_control_regs_and_pmap();
+    printf("AP=(%u) cr* done\n", cpu);
+
+    cpu = mp_desc_init(cpu);
+    printf("AP=(%u) mpdesc done\n", cpu);
+
+    ap_gdt_init(cpu);
+    printf("AP=(%u) gdt done\n", cpu);
+
+    ap_idt_init(cpu);
+    printf("AP=(%u) idt done\n", cpu);
+
+    ap_int_init(cpu);
+    printf("AP=(%u) int done\n", cpu);
+
+    ap_ldt_init(cpu);
+    printf("AP=(%u) ldt done\n", cpu);
+
+    ap_ktss_init(cpu);
+    printf("AP=(%u) ktss done\n", cpu);
+
+    remove_initial_pmap();
+    printf("AP=(%u) pmap done\n", cpu);
+
+    /* Initialize machine_slot fields with the cpu data */
+    machine_slot[cpu].cpu_subtype = CPU_SUBTYPE_AT386;
+    machine_slot[cpu].cpu_type = machine_slot[0].cpu_type;
+
+    lapic_enable();
+    asm("sti");
+
+    slave_main();
+}
+
+void
+cpu_ap_main()
+{
+    do {
+        asm volatile ("pause" : : : "memory");
+    } while (!bspdone);
+
+    cpu_setup();
 }

 kern_return_t
 cpu_start(int cpu)
 {
-       if (machine_slot[cpu].running)
-               return KERN_FAILURE;
+    assert(machine_slot[cpu].running != TRUE);
+
+    uint16_t apic_id = apic_get_cpu_apic_id(cpu);
+
+    printf("Trying to enable: %d\n", apic_id);

-       return intel_startCPU(cpu);
+    smp_startup_cpu(apic_id, AP_BOOT_ADDR);
+
+    printf("Started cpu %d (lapic id %04x)\n", cpu, apic_id);
+
+    return KERN_SUCCESS;
 }

 void
 start_other_cpus(void)
 {
-       int cpu;
-       for (cpu = 0; cpu < NCPUS; cpu++)
-               if (cpu != cpu_number())
-                       cpu_start(cpu);
-}
+       unsigned long flags;
+
+       cpu_intr_save(&flags);
+
+       int ncpus = smp_get_numcpus();
+
+       //Copy cpu initialization assembly routine
+       memcpy((void*)phystokv(AP_BOOT_ADDR), (void*) &apboot,
+              (uint32_t)&apbootend - (uint32_t)&apboot);

+#ifndef APIC
+       lapic_enable(); /* Enable lapic only once */
+#endif
+       unsigned cpu;
+       bspdone = 0;
+       for (cpu = 1; cpu < ncpus; cpu++) {
+               machine_slot[cpu].running = FALSE;
+
+               //Start cpu
+               printf("Starting AP %d\n", cpu);
+               cpu_start(cpu);
+       }
+       printf("BSP: Completed SMP init\n");
+       bspdone = 1;
+
+       for (cpu = 1; cpu < ncpus; cpu++) {
+               do {
+                       asm volatile ("pause" : : : "memory");
+               } while (machine_slot[cpu].running == FALSE);
+       }
+
+        cpu_intr_restore(flags);
+}
 #endif /* NCPUS > 1 */
diff --git a/i386/i386/mp_desc.h b/i386/i386/mp_desc.h
index ebe1471d..59d50e77 100644
--- a/i386/i386/mp_desc.h
+++ b/i386/i386/mp_desc.h
@@ -27,6 +27,8 @@
 #ifndef        _I386_MP_DESC_H_
 #define        _I386_MP_DESC_H_

+#include <mach/kern_return.h>
+
 #if MULTIPROCESSOR

 /*
@@ -44,6 +46,8 @@
 #include "gdt.h"
 #include "ldt.h"

+#define AP_BOOT_ADDR   0x7000
+
 /*
  * The descriptor tables are together in a structure
  * allocated one per processor (except for the boot processor).
@@ -70,11 +74,12 @@ extern struct task_tss              *mp_ktss[NCPUS];
  */
 extern struct real_descriptor  *mp_gdt[NCPUS];

+extern uint8_t solid_intstack[];

 /*
  * Each CPU calls this routine to set up its descriptor tables.
  */
-extern struct mp_desc_table *  mp_desc_init(int);
+extern int mp_desc_init(int);


 extern void interrupt_processor(int cpu);
@@ -88,4 +93,6 @@ extern kern_return_t cpu_start(int cpu);

 extern kern_return_t cpu_control(int cpu, const int *info, unsigned int count);

+extern void interrupt_stack_alloc(void);
+
 #endif /* _I386_MP_DESC_H_ */
diff --git a/i386/i386at/boothdr.S b/i386/i386at/boothdr.S
index 82d4b34a..002ce5bf 100644
--- a/i386/i386at/boothdr.S
+++ b/i386/i386at/boothdr.S
@@ -1,6 +1,6 @@

 #include <mach/machine/asm.h>
-
+#include <i386/apic.h>
 #include <i386/i386asm.h>

        /*
@@ -54,7 +54,18 @@ boot_entry:
        movw    %ax,%ss

        /* Switch to our own interrupt stack.  */
-       movl    $_intstack+INTSTACK_SIZE,%esp
+       movl    $solid_intstack+INTSTACK_SIZE, %esp
+       andl    $0xfffffff0,%esp
+
+       /* Enable local apic */
+       xorl    %eax, %eax
+       xorl    %edx, %edx
+       movl    $APIC_MSR, %ecx
+       rdmsr
+       orl     $APIC_MSR_ENABLE, %eax
+       orl     $APIC_MSR_BSP, %eax
+       movl    $APIC_MSR, %ecx
+       wrmsr

        /* Reset EFLAGS to a known state.  */
        pushl   $0
@@ -91,9 +102,6 @@ iplt_done:
        /* Jump into C code.  */
        call    EXT(c_boot_entry)

-       .comm   _intstack,INTSTACK_SIZE
-       .comm   _eintstack,0
-
 .align 16
        .word 0
 boot_gdt_descr:
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index 1819526b..d12a4632 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -134,11 +134,9 @@ extern char        version[];
 /* If set, reboot the system on ctrl-alt-delete.  */
 boolean_t      rebootflag = FALSE;     /* exported to kdintr */

-/* Interrupt stack.  */
-static char int_stack[KERNEL_STACK_SIZE] __aligned(KERNEL_STACK_SIZE);
-#if NCPUS <= 1
-vm_offset_t int_stack_top[1], int_stack_base[1];
-#endif
+/* Interrupt stacks  */
+extern vm_offset_t int_stack_top[], int_stack_base[];
+extern uint8_t solid_intstack[];    /* bottom */

 #ifdef LINUX_DEV
 extern void linux_init(void);
@@ -171,15 +169,20 @@ void machine_init(void)
        hyp_init();
 #else  /* MACH_HYP */

+#if (NCPUS > 1)
+       acpi_apic_init();
+#endif
 #if defined(APIC)
-       if (acpi_apic_init() != ACPI_SUCCESS) {
-               panic("APIC not found, unable to boot");
-       }
        ioapic_configure();
        lapic_enable_timer();
+#else
+       startrtclock();
+#endif
 #if (NCPUS > 1)
        smp_init();
+#endif

+#if defined(APIC)
 #warning FIXME: Rather unmask them from their respective drivers
        /* kd */
        unmask_irq(1);
@@ -187,8 +190,7 @@ void machine_init(void)
        unmask_irq(4);
        /* com1 */
        unmask_irq(3);
-#endif /* NCPUS > 1 */
-#endif /* APIC */
+#endif

 #ifdef LINUX_DEV
        /*
@@ -557,8 +559,7 @@ i386at_init(void)
        hyp_p2m_init();
 #endif /* MACH_XEN */

-       int_stack_base[0] = (vm_offset_t)&int_stack;
-       int_stack_top[0] = int_stack_base[0] + KERNEL_STACK_SIZE - 4;
+       interrupt_stack_alloc();
 }

 /*
@@ -650,7 +651,6 @@ void c_boot_entry(vm_offset_t bi)
 #endif /* MACH_KDB */

        machine_slot[0].is_cpu = TRUE;
-       machine_slot[0].running = TRUE;
        machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386;

        switch (cpu_type)
@@ -698,6 +698,8 @@ startrtclock(void)
 {
 #ifndef APIC
        clkstart();
+       asm ("sti");
+       unmask_irq(0);
 #endif
 }

diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c
index 67feea84..6f99003e 100644
--- a/linux/dev/arch/i386/kernel/irq.c
+++ b/linux/dev/arch/i386/kernel/irq.c
@@ -31,6 +31,7 @@
 #include <i386/spl.h>
 #include <i386/irq.h>
 #include <i386/pit.h>
+#include <i386/model_dep.h>

 #define MACH_INCLUDE
 #include <linux/mm.h>
@@ -421,7 +422,7 @@ reserve_mach_irqs (void)
 {
   unsigned int i;

-  for (i = 0; i < NINTR; i++)
+  for (i = 1; i < NINTR; i++)
     {
       if (ivect[i] != intnull)
        /* This dummy action does not specify SA_SHIRQ, so
@@ -707,7 +708,6 @@ void
 init_IRQ (void)
 {
   char *p;
-  int latch = (CLKNUM + hz / 2) / hz;

   /*
    * Ensure interrupts are disabled.
@@ -715,19 +715,12 @@ init_IRQ (void)
   (void) splhigh ();

 #ifndef APIC
-  /*
-   * Program counter 0 of 8253 to interrupt hz times per second.
-   */
-  outb_p (PIT_C0 | PIT_SQUAREMODE | PIT_READMODE, PITCTL_PORT);
-  outb_p (latch & 0xff, PITCTR0_PORT);
-  outb (latch >> 8, PITCTR0_PORT);
-#endif
-
   /*
    * Install our clock interrupt handler.
    */
   old_clock_handler = ivect[0];
   ivect[0] = linux_timer_intr;
+#endif

   reserve_mach_irqs ();

diff --git a/linux/dev/init/main.c b/linux/dev/init/main.c
index 6d853957..207724f3 100644
--- a/linux/dev/init/main.c
+++ b/linux/dev/init/main.c
@@ -160,7 +160,9 @@ linux_init (void)
   pcmcia_init ();
 #endif

+#ifndef APIC
   restore_IRQ ();
+#endif

   linux_auto_config = 0;
 }
--
2.34.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]