root/arch/i386/i386/cpu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cpu_init_first
  2. cpu_match
  3. cpu_attach
  4. cpu_init
  5. cpu_boot_secondary_processors
  6. cpu_init_idle_pcbs
  7. cpu_boot_secondary
  8. cpu_hatch
  9. cpu_copy_trampoline
  10. cpu_init_tss
  11. cpu_set_tss_gates
  12. mp_cpu_start
  13. mp_cpu_start_cleanup

    1 /*      $OpenBSD: cpu.c,v 1.25 2007/05/29 18:18:20 tom Exp $    */
    2 /* $NetBSD: cpu.c,v 1.1.2.7 2000/06/26 02:04:05 sommerfeld Exp $ */
    3 
    4 /*-
    5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by RedBack Networks Inc.
   10  *
   11  * Author: Bill Sommerfeld
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. All advertising materials mentioning features or use of this software
   22  *    must display the following acknowledgement:
   23  *        This product includes software developed by the NetBSD
   24  *        Foundation, Inc. and its contributors.
   25  * 4. Neither the name of The NetBSD Foundation nor the names of its
   26  *    contributors may be used to endorse or promote products derived
   27  *    from this software without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   33  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   39  * POSSIBILITY OF SUCH DAMAGE.
   40  */
   41 
   42 /*
   43  * Copyright (c) 1999 Stefan Grefen
   44  *
   45  * Redistribution and use in source and binary forms, with or without
   46  * modification, are permitted provided that the following conditions
   47  * are met:
   48  * 1. Redistributions of source code must retain the above copyright
   49  *    notice, this list of conditions and the following disclaimer.
   50  * 2. Redistributions in binary form must reproduce the above copyright
   51  *    notice, this list of conditions and the following disclaimer in the
   52  *    documentation and/or other materials provided with the distribution.
   53  * 3. All advertising materials mentioning features or use of this software
   54  *    must display the following acknowledgement:
   55  *      This product includes software developed by the NetBSD
   56  *      Foundation, Inc. and its contributors.
   57  * 4. Neither the name of The NetBSD Foundation nor the names of its
   58  *    contributors may be used to endorse or promote products derived
   59  *    from this software without specific prior written permission.
   60  *
   61  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
   62  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   63  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   64  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
   65  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   66  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   67  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   68  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   69  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   70  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   71  * SUCH DAMAGE.
   72  */
   73 
   74 #include "lapic.h"
   75 #include "ioapic.h"
   76 
   77 #include <sys/param.h>
   78 #include <sys/proc.h>
   79 #include <sys/user.h>
   80 #include <sys/systm.h>
   81 #include <sys/device.h>
   82 
   83 #include <uvm/uvm_extern.h>
   84 
   85 #include <machine/cpu.h>
   86 #include <machine/cpufunc.h>
   87 #include <machine/cpuvar.h>
   88 #include <machine/pmap.h>
   89 #include <machine/vmparam.h>
   90 #include <machine/mpbiosvar.h>
   91 #include <machine/npx.h>
   92 #include <machine/pcb.h>
   93 #include <machine/specialreg.h>
   94 #include <machine/segments.h>
   95 #include <machine/gdt.h>
   96 #include <machine/pio.h>
   97 
   98 #if NLAPIC > 0
   99 #include <machine/apicvar.h>
  100 #include <machine/i82489reg.h>
  101 #include <machine/i82489var.h>
  102 #endif
  103 
  104 #if NIOAPIC > 0
  105 #include <machine/i82093reg.h>
  106 #include <machine/i82093var.h>
  107 #endif
  108 
  109 #include <dev/ic/mc146818reg.h>
  110 #include <i386/isa/nvram.h>
  111 #include <dev/isa/isareg.h>
  112 
  113 int     cpu_match(struct device *, void *, void *);
  114 void    cpu_attach(struct device *, struct device *, void *);
  115 
  116 #ifdef MULTIPROCESSOR
  117 int mp_cpu_start(struct cpu_info *);
  118 void mp_cpu_start_cleanup(struct cpu_info *);
  119 struct cpu_functions mp_cpu_funcs =
  120     { mp_cpu_start, NULL, mp_cpu_start_cleanup };
  121 #endif
  122 
  123 /*
  124  * Statically-allocated CPU info for the primary CPU (or the only
  125  * CPU, on uniprocessors).  The CPU info list is initialized to
  126  * point at it.
  127  */
  128 struct cpu_info cpu_info_primary;
  129 struct cpu_info *cpu_info_list = &cpu_info_primary;
  130 
  131 void    cpu_init_tss(struct i386tss *, void *, void *);
  132 void    cpu_set_tss_gates(struct cpu_info *);
  133 
  134 #ifdef MULTIPROCESSOR
  135 /*
  136  * Array of CPU info structures.  Must be statically-allocated because
  137  * curproc, etc. are used early.
  138  */
  139 
  140 struct cpu_info *cpu_info[I386_MAXPROCS] = { &cpu_info_primary };
  141 
  142 void    cpu_hatch(void *);
  143 void    cpu_boot_secondary(struct cpu_info *);
  144 void    cpu_copy_trampoline(void);
  145 
  146 /*
  147  * Runs once per boot once multiprocessor goo has been detected and
  148  * the local APIC has been mapped.
  149  * Called from mpbios_scan();
  150  */
  151 void
  152 cpu_init_first()
  153 {
  154         int cpunum = lapic_cpu_number();
  155 
  156         if (cpunum != 0) {
  157                 cpu_info[0] = NULL;
  158                 cpu_info[cpunum] = &cpu_info_primary;
  159         }
  160 
  161         cpu_copy_trampoline();
  162 }
  163 #endif
  164 
  165 struct cfattach cpu_ca = {
  166         sizeof(struct cpu_info), cpu_match, cpu_attach
  167 };
  168 
  169 struct cfdriver cpu_cd = {
  170         NULL, "cpu", DV_DULL /* XXX DV_CPU */
  171 };
  172 
  173 int
  174 cpu_match(struct device *parent, void *matchv, void *aux)
  175 {
  176         struct cfdata *match = (struct cfdata *)matchv;
  177         struct cpu_attach_args *caa = (struct cpu_attach_args *)aux;
  178 
  179         if (strcmp(caa->caa_name, match->cf_driver->cd_name) == 0)
  180                 return (1);
  181         return (0);
  182 }
  183 
  184 void
  185 cpu_attach(struct device *parent, struct device *self, void *aux)
  186 {
  187         struct cpu_info *ci = (struct cpu_info *)self;
  188         struct cpu_attach_args *caa = (struct cpu_attach_args *)aux;
  189 
  190 #ifdef MULTIPROCESSOR
  191         int cpunum = caa->cpu_number;
  192         vaddr_t kstack;
  193         struct pcb *pcb;
  194 
  195         if (caa->cpu_role != CPU_ROLE_AP) {
  196                 if (cpunum != lapic_cpu_number()) {
  197                         panic("%s: running cpu is at apic %d"
  198                             " instead of at expected %d",
  199                             self->dv_xname, lapic_cpu_number(), cpunum);
  200                 }
  201 
  202                 ci = &cpu_info_primary;
  203                 bcopy(self, &ci->ci_dev, sizeof *self);
  204 
  205                 /* special-case boot CPU */                         /* XXX */
  206                 if (cpu_info[cpunum] == &cpu_info_primary) {        /* XXX */
  207                         cpu_info[cpunum] = NULL;                    /* XXX */
  208                 }                                                   /* XXX */
  209         }
  210         if (cpu_info[cpunum] != NULL)
  211                 panic("cpu at apic id %d already attached?", cpunum);
  212 
  213         cpu_info[cpunum] = ci;
  214 #endif
  215 
  216         ci->ci_self = ci;
  217         ci->ci_apicid = caa->cpu_number;
  218 #ifdef MULTIPROCESSOR
  219         ci->ci_cpuid = ci->ci_apicid;
  220 #else
  221         ci->ci_cpuid = 0;       /* False for APs, so what, they're not used */
  222 #endif
  223         ci->ci_signature = caa->cpu_signature;
  224         ci->ci_feature_flags = caa->feature_flags;
  225         ci->ci_func = caa->cpu_func;
  226 
  227 #ifdef MULTIPROCESSOR
  228         /*
  229          * Allocate UPAGES contiguous pages for the idle PCB and stack.
  230          */
  231 
  232         kstack = uvm_km_alloc(kernel_map, USPACE);
  233         if (kstack == 0) {
  234                 if (cpunum == 0) { /* XXX */
  235                         panic("cpu_attach: unable to allocate idle stack for"
  236                             " primary");
  237                 }
  238                 printf("%s: unable to allocate idle stack\n",
  239                     ci->ci_dev.dv_xname);
  240                 return;
  241         }
  242         pcb = ci->ci_idle_pcb = (struct pcb *)kstack;
  243         memset(pcb, 0, USPACE);
  244 
  245         pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
  246         pcb->pcb_tss.tss_esp0 = kstack + USPACE - 16 -
  247             sizeof (struct trapframe);
  248         pcb->pcb_tss.tss_esp = kstack + USPACE - 16 -
  249             sizeof (struct trapframe);
  250         pcb->pcb_pmap = pmap_kernel();
  251         pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdirpa;
  252         /* pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdir - KERNBASE; XXX ??? */
  253 
  254         cpu_default_ldt(ci);    /* Use the `global' ldt until one alloc'd */
  255 #endif
  256 
  257         /* further PCB init done later. */
  258 
  259 /* XXXSMP: must be shared with UP */
  260 #ifdef MULTIPROCESSOR
  261         printf(": ");
  262 
  263         switch (caa->cpu_role) {
  264         case CPU_ROLE_SP:
  265                 printf("(uniprocessor)\n");
  266                 ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY;
  267                 identifycpu(ci);
  268                 cpu_init(ci);
  269                 break;
  270 
  271         case CPU_ROLE_BP:
  272                 printf("apid %d (boot processor)\n", caa->cpu_number);
  273                 ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY;
  274                 identifycpu(ci);
  275                 cpu_init(ci);
  276 
  277 #if NLAPIC > 0
  278                 /*
  279                  * Enable local apic
  280                  */
  281                 lapic_enable();
  282                 lapic_calibrate_timer(ci);
  283 #endif
  284 #if NIOAPIC > 0
  285                 ioapic_bsp_id = caa->cpu_number;
  286 #endif
  287                 break;
  288 
  289         case CPU_ROLE_AP:
  290                 /*
  291                  * report on an AP
  292                  */
  293                 printf("apid %d (application processor)\n", caa->cpu_number);
  294                 gdt_alloc_cpu(ci);
  295                 cpu_alloc_ldt(ci);
  296                 ci->ci_flags |= CPUF_PRESENT | CPUF_AP;
  297                 identifycpu(ci);
  298                 ci->ci_next = cpu_info_list->ci_next;
  299                 cpu_info_list->ci_next = ci;
  300                 ncpus++;
  301                 break;
  302 
  303         default:
  304                 panic("unknown processor type??");
  305         }
  306 
  307         /* Mark this ID as taken if it's in the I/O APIC ID area */
  308         if (ci->ci_apicid < IOAPIC_ID_MAX)
  309                 ioapic_id_map &= ~(1 << ci->ci_apicid);
  310 
  311         if (mp_verbose) {
  312                 printf("%s: kstack at 0x%lx for %d bytes\n",
  313                     ci->ci_dev.dv_xname, kstack, USPACE);
  314                 printf("%s: idle pcb at %p, idle sp at 0x%x\n",
  315                     ci->ci_dev.dv_xname, pcb, pcb->pcb_esp);
  316         }
  317 #else   /* MULTIPROCESSOR */
  318         printf("\n");
  319 #endif  /* !MULTIPROCESSOR */
  320 }
  321 
  322 /*
  323  * Initialize the processor appropriately.
  324  */
  325 
  326 #ifdef MULTIPROCESSOR
  327 void
  328 cpu_init(struct cpu_info *ci)
  329 {
  330         /* configure the CPU if needed */
  331         if (ci->cpu_setup != NULL)
  332                 (*ci->cpu_setup)(ci);
  333 
  334         /*
  335          * Enable ring 0 write protection (486 or above, but 386
  336          * no longer supported).
  337          */
  338         lcr0(rcr0() | CR0_WP);
  339 
  340         if (cpu_feature & CPUID_PGE)
  341                 lcr4(rcr4() | CR4_PGE); /* enable global TLB caching */
  342 
  343         ci->ci_flags |= CPUF_RUNNING;
  344 #if defined(I686_CPU)
  345         /*
  346          * If we have FXSAVE/FXRESTOR, use them.
  347          */
  348         if (cpu_feature & CPUID_FXSR) {
  349                 lcr4(rcr4() | CR4_OSFXSR);
  350 
  351                 /*
  352                  * If we have SSE/SSE2, enable XMM exceptions.
  353                  */
  354                 if (cpu_feature & (CPUID_SSE|CPUID_SSE2))
  355                         lcr4(rcr4() | CR4_OSXMMEXCPT);
  356         }
  357 #endif /* I686_CPU */
  358 }
  359 
  360 void
  361 cpu_boot_secondary_processors()
  362 {
  363         struct cpu_info *ci;
  364         u_long i;
  365 
  366         for (i = 0; i < I386_MAXPROCS; i++) {
  367                 ci = cpu_info[i];
  368                 if (ci == NULL)
  369                         continue;
  370                 if (ci->ci_idle_pcb == NULL)
  371                         continue;
  372                 if ((ci->ci_flags & CPUF_PRESENT) == 0)
  373                         continue;
  374                 if (ci->ci_flags & (CPUF_BSP|CPUF_SP|CPUF_PRIMARY))
  375                         continue;
  376                 cpu_boot_secondary(ci);
  377         }
  378 }
  379 
  380 void
  381 cpu_init_idle_pcbs()
  382 {
  383         struct cpu_info *ci;
  384         u_long i;
  385 
  386         for (i=0; i < I386_MAXPROCS; i++) {
  387                 ci = cpu_info[i];
  388                 if (ci == NULL)
  389                         continue;
  390                 if (ci->ci_idle_pcb == NULL)
  391                         continue;
  392                 if ((ci->ci_flags & CPUF_PRESENT) == 0)
  393                         continue;
  394                 i386_init_pcb_tss_ldt(ci);
  395         }
  396 }
  397 
  398 void
  399 cpu_boot_secondary(struct cpu_info *ci)
  400 {
  401         struct pcb *pcb;
  402         int i;
  403         struct pmap *kpm = pmap_kernel();
  404         extern u_int32_t mp_pdirpa;
  405 
  406         if (mp_verbose)
  407                 printf("%s: starting", ci->ci_dev.dv_xname);
  408 
  409         /* XXX move elsewhere, not per CPU. */
  410         mp_pdirpa = kpm->pm_pdirpa;
  411 
  412         pcb = ci->ci_idle_pcb;
  413 
  414         if (mp_verbose)
  415                 printf(", init idle stack ptr is 0x%x\n", pcb->pcb_esp);
  416 
  417         CPU_STARTUP(ci);
  418 
  419         /*
  420          * wait for it to become ready
  421          */
  422         for (i = 100000; (!(ci->ci_flags & CPUF_RUNNING)) && i > 0; i--) {
  423                 delay(10);
  424         }
  425         if (!(ci->ci_flags & CPUF_RUNNING)) {
  426                 printf("%s failed to become ready\n", ci->ci_dev.dv_xname);
  427 #ifdef DDB
  428                 Debugger();
  429 #endif
  430         }
  431 
  432         CPU_START_CLEANUP(ci);
  433 }
  434 
  435 /*
  436  * The CPU ends up here when its ready to run
  437  * XXX should share some of this with init386 in machdep.c
  438  * for now it jumps into an infinite loop.
  439  */
  440 void
  441 cpu_hatch(void *v)
  442 {
  443         struct cpu_info *ci = (struct cpu_info *)v;
  444         int s;
  445 
  446         cpu_init_idt();
  447         lapic_enable();
  448         lapic_initclocks();
  449         lapic_set_lvt();
  450         gdt_init_cpu(ci);
  451         cpu_init_ldt(ci);
  452         npxinit(ci);
  453 
  454         lldt(GSEL(GLDT_SEL, SEL_KPL));
  455 
  456         cpu_init(ci);
  457 
  458         s = splhigh();          /* XXX prevent softints from running here.. */
  459         lapic_tpr = 0;
  460         enable_intr();
  461         if (mp_verbose)
  462                 printf("%s: CPU at apid %ld running\n",
  463                     ci->ci_dev.dv_xname, ci->ci_cpuid);
  464         microuptime(&ci->ci_schedstate.spc_runtime);
  465         splx(s);
  466 }
  467 
  468 void
  469 cpu_copy_trampoline()
  470 {
  471         /*
  472          * Copy boot code.
  473          */
  474         extern u_char cpu_spinup_trampoline[];
  475         extern u_char cpu_spinup_trampoline_end[];
  476 
  477         pmap_kenter_pa((vaddr_t)MP_TRAMPOLINE,  /* virtual */
  478             (paddr_t)MP_TRAMPOLINE,             /* physical */
  479             VM_PROT_ALL);                       /* protection */
  480         bcopy(cpu_spinup_trampoline, (caddr_t)MP_TRAMPOLINE,
  481             cpu_spinup_trampoline_end - cpu_spinup_trampoline);
  482 }
  483 
  484 #endif
  485 
  486 #ifdef notyet
  487 void
  488 cpu_init_tss(struct i386tss *tss, void *stack, void *func)
  489 {
  490         memset(tss, 0, sizeof *tss);
  491         tss->tss_esp0 = tss->tss_esp = (int)((char *)stack + USPACE - 16);
  492         tss->tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
  493         tss->__tss_cs = GSEL(GCODE_SEL, SEL_KPL);
  494         tss->tss_fs = GSEL(GCPU_SEL, SEL_KPL);
  495         tss->tss_gs = tss->__tss_es = tss->__tss_ds =
  496             tss->__tss_ss = GSEL(GDATA_SEL, SEL_KPL);
  497         tss->tss_cr3 = pmap_kernel()->pm_pdirpa;
  498         tss->tss_esp = (int)((char *)stack + USPACE - 16);
  499         tss->tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
  500         tss->__tss_eflags = PSL_MBO | PSL_NT;   /* XXX not needed? */
  501         tss->__tss_eip = (int)func;
  502 }
  503 
  504 /* XXX */
  505 #define IDTVEC(name)    __CONCAT(X, name)
  506 typedef void (vector)(void);
  507 extern vector IDTVEC(tss_trap08);
  508 #ifdef DDB
  509 extern vector Xintrddbipi;
  510 extern int ddb_vec;
  511 #endif
  512 
  513 void
  514 cpu_set_tss_gates(struct cpu_info *ci)
  515 {
  516         struct segment_descriptor sd;
  517 
  518         ci->ci_doubleflt_stack = (char *)uvm_km_alloc(kernel_map, USPACE);
  519         cpu_init_tss(&ci->ci_doubleflt_tss, ci->ci_doubleflt_stack,
  520             IDTVEC(tss_trap08));
  521         setsegment(&sd, &ci->ci_doubleflt_tss, sizeof(struct i386tss) - 1,
  522             SDT_SYS386TSS, SEL_KPL, 0, 0);
  523         ci->ci_gdt[GTRAPTSS_SEL].sd = sd;
  524         setgate(&idt[8], NULL, 0, SDT_SYSTASKGT, SEL_KPL,
  525             GSEL(GTRAPTSS_SEL, SEL_KPL));
  526 
  527 #if defined(DDB) && defined(MULTIPROCESSOR)
  528         /*
  529          * Set up seperate handler for the DDB IPI, so that it doesn't
  530          * stomp on a possibly corrupted stack.
  531          *
  532          * XXX overwriting the gate set in db_machine_init.
  533          * Should rearrange the code so that it's set only once.
  534          */
  535         ci->ci_ddbipi_stack = (char *)uvm_km_alloc(kernel_map, USPACE);
  536         cpu_init_tss(&ci->ci_ddbipi_tss, ci->ci_ddbipi_stack,
  537             Xintrddbipi);
  538 
  539         setsegment(&sd, &ci->ci_ddbipi_tss, sizeof(struct i386tss) - 1,
  540             SDT_SYS386TSS, SEL_KPL, 0, 0);
  541         ci->ci_gdt[GIPITSS_SEL].sd = sd;
  542 
  543         setgate(&idt[ddb_vec], NULL, 0, SDT_SYSTASKGT, SEL_KPL,
  544             GSEL(GIPITSS_SEL, SEL_KPL));
  545 #endif
  546 }
  547 #endif
  548 
  549 #ifdef MULTIPROCESSOR
  550 int
  551 mp_cpu_start(struct cpu_info *ci)
  552 {
  553 #if NLAPIC > 0
  554         int error;
  555 #endif
  556         unsigned short dwordptr[2];
  557 
  558         /*
  559          * "The BSP must initialize CMOS shutdown code to 0Ah ..."
  560          */
  561 
  562         outb(IO_RTC, NVRAM_RESET);
  563         outb(IO_RTC+1, NVRAM_RESET_JUMP);
  564 
  565         /*
  566          * "and the warm reset vector (DWORD based at 40:67) to point
  567          * to the AP startup code ..."
  568          */
  569 
  570         dwordptr[0] = 0;
  571         dwordptr[1] = MP_TRAMPOLINE >> 4;
  572 
  573         pmap_kenter_pa(0, 0, VM_PROT_READ|VM_PROT_WRITE);
  574         memcpy((u_int8_t *)0x467, dwordptr, 4);
  575         pmap_kremove(0, PAGE_SIZE);
  576 
  577 #if NLAPIC > 0
  578         /*
  579          * ... prior to executing the following sequence:"
  580          */
  581 
  582         if (ci->ci_flags & CPUF_AP) {
  583                 if ((error = i386_ipi_init(ci->ci_apicid)) != 0)
  584                         return (error);
  585 
  586                 delay(10000);
  587 
  588                 if (cpu_feature & CPUID_APIC) {
  589                         if ((error = i386_ipi(MP_TRAMPOLINE / PAGE_SIZE,
  590                             ci->ci_apicid, LAPIC_DLMODE_STARTUP)) != 0)
  591                                 return (error);
  592                         delay(200);
  593 
  594                         if ((error = i386_ipi(MP_TRAMPOLINE / PAGE_SIZE,
  595                             ci->ci_apicid, LAPIC_DLMODE_STARTUP)) != 0)
  596                                 return (error);
  597                         delay(200);
  598                 }
  599         }
  600 #endif
  601         return (0);
  602 }
  603 
  604 void
  605 mp_cpu_start_cleanup(struct cpu_info *ci)
  606 {
  607         /*
  608          * Ensure the NVRAM reset byte contains something vaguely sane.
  609          */
  610 
  611         outb(IO_RTC, NVRAM_RESET);
  612         outb(IO_RTC+1, NVRAM_RESET_RST);
  613 }
  614 #endif

/* [<][>][^][v][top][bottom][index][help] */