The Pedigree Project  0.1
x86_common/Multiprocessor.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #ifdef MULTIPROCESSOR
21 
22 #include "Multiprocessor.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/Spinlock.h"
25 #include "pedigree/kernel/processor/Processor.h"
26 #include "pedigree/kernel/processor/ProcessorInformation.h"
27 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
28 #include "pedigree/kernel/processor/types.h"
29 #include "pedigree/kernel/utilities/Vector.h"
30 #include "pedigree/kernel/utilities/utility.h"
31 
32 #if defined(X86)
33 #include "../x86/VirtualAddressSpace.h"
34 #elif defined(X64)
35 #include "../x64/VirtualAddressSpace.h"
36 #endif
37 
38 #include <machine/mach_pc/Acpi.h>
39 #include <machine/mach_pc/LocalApic.h>
40 #include <machine/mach_pc/Pc.h>
41 #include <machine/mach_pc/Smp.h>
42 
43 #if !defined(APIC)
44 #error APIC not defined
45 #endif
46 #if !defined(ACPI) && !defined(SMP)
47 #error Neither ACPI nor SMP defined
48 #endif
49 
50 // Don't track these locks - they are never going to be "correct" (they are for
51 // synchronisation, not for protecting a specific resource).
52 Spinlock Multiprocessor::m_ProcessorLock1(false, true);
53 Spinlock Multiprocessor::m_ProcessorLock2(true, true);
54 
55 extern "C" void mp_trampoline16(void);
56 extern "C" void mp_trampoline32(void);
57 extern "C" void *trampolinegdt;
58 extern "C" void *trampolinegdtr;
59 extern "C" void *trampolinegdt64;
60 extern "C" void *trampolinegdtr64;
61 
63 {
64  // Did we find a processor list?
65  bool bMPInfoFound = false;
66  // List of information about each usable processor
67  const Vector<ProcessorInformation *> *Processors = 0;
68 
69 #if defined(ACPI)
70  // Search through the ACPI tables
71  Acpi &acpi = Acpi::instance();
72  if ((bMPInfoFound = acpi.validProcessorInfo()) == true)
73  Processors = &acpi.getProcessorList();
74 #endif
75 
76 #if defined(SMP)
77  // Search through the SMP tables
78  Smp &smp = Smp::instance();
79  if (bMPInfoFound == false && (bMPInfoFound = smp.valid()) == true)
80  Processors = &smp.getProcessorList();
81 #endif
82 
83  // No processor list found
84  if (bMPInfoFound == false || !Processors)
85  {
86  NOTICE("Multiprocessor: couldn't find any information about multiple "
87  "processors");
88  return 1;
89  }
90 
91  NOTICE(
92  "Multiprocessor: Found " << Dec << Processors->count() << Hex
93  << " processors");
94 
95  // Copy the trampoline code to 0x7000
100  MemoryCopy(
101  reinterpret_cast<void *>(0x7000),
102  reinterpret_cast<void *>(&mp_trampoline16), 0x100);
103  MemoryCopy(
104  reinterpret_cast<void *>(0x7100),
105  reinterpret_cast<void *>(&mp_trampoline32), 0x100);
106  MemoryCopy(reinterpret_cast<void *>(0x7200), &trampolinegdtr64, 0x10);
107  MemoryCopy(reinterpret_cast<void *>(0x7210), &trampolinegdt64, 0xF0);
108 
109 // Parameters for the trampoline code
110 #if defined(X86)
111  volatile uint32_t *trampolineStack =
112  reinterpret_cast<volatile uint32_t *>(0x7FF8);
113  volatile uint32_t *trampolineKernelEntry =
114  reinterpret_cast<volatile uint32_t *>(0x7FF4);
115 
116  // Set the virtual address space
117  *reinterpret_cast<volatile uint32_t *>(0x7FFC) =
118  static_cast<X86VirtualAddressSpace &>(
120  .m_PhysicalPageDirectory;
121 #elif defined(X64)
122  volatile uint64_t *trampolineStack =
123  reinterpret_cast<volatile uint64_t *>(0x7FF0);
124  volatile uint64_t *trampolineKernelEntry =
125  reinterpret_cast<volatile uint64_t *>(0x7FE8);
126 
127  // Set the virtual address space
128  *reinterpret_cast<volatile uint64_t *>(0x7FF8) =
129  static_cast<X64VirtualAddressSpace &>(
131  .m_PhysicalPML4;
132 #endif
133 
134  // Set the entry point
135  *trampolineKernelEntry =
136  reinterpret_cast<uintptr_t>(&applicationProcessorStartup);
137 
138  LocalApic &localApic = Pc::instance().getLocalApic();
139  VirtualAddressSpace &kernelSpace =
141  // Startup the application processors through startup interprocessor
142  // interrupt
143  for (size_t i = 0; i < Processors->count(); i++)
144  {
145  // Add a ProcessorInformation object
146  ::ProcessorInformation *pProcessorInfo = 0;
147 
148  // Startup the processor
149  if (localApic.getId() != (*Processors)[i]->apicId)
150  {
151  // AP: set up a proper information structure
152  pProcessorInfo = new ::ProcessorInformation(
153  (*Processors)[i]->processorId, (*Processors)[i]->apicId);
154  Processor::m_ProcessorInformation.pushBack(pProcessorInfo);
155 
156  // Allocate kernel stack
157  VirtualAddressSpace::Stack *pStack = kernelSpace.allocateStack();
158 
159  // Set trampoline stack
160  *trampolineStack = reinterpret_cast<uintptr_t>(pStack->getTop());
161 
162  NOTICE(
163  " Booting processor #"
164  << Dec << (*Processors)[i]->processorId << ", stack at 0x"
165  << Hex << reinterpret_cast<uintptr_t>(pStack->getTop()));
166 
170 
171  // Acquire the lock
172  m_ProcessorLock1.acquire(false);
173 
174  localApic.interProcessorInterrupt(
175  (*Processors)[i]->apicId, 0x07, LocalApic::deliveryModeInit,
176  true, true);
177  for (int z = 0; z < 0x10000; z++)
178  ;
179 
180  // Send the Startup IPI to the processor
181  localApic.interProcessorInterrupt(
182  (*Processors)[i]->apicId, 0x07, LocalApic::deliveryModeStartup,
183  true, false);
184 
185  // Wait until the processor is started and has unlocked the lock
186  m_ProcessorLock1.acquire(false, false);
187  m_ProcessorLock1.release();
188  }
189  else
190  {
191  NOTICE(
192  "Currently running on CPU #"
193  << Dec << localApic.getId() << Hex
194  << ", skipping boot (not necessary)");
195 
197  &Processor::m_SafeBspProcessorInformation);
198  Processor::m_SafeBspProcessorInformation.setIds(
199  (*Processors)[i]->processorId, (*Processors)[i]->apicId);
200  }
201  }
202 
203  return Processors->count();
204 }
205 
207 {
208  m_ProcessorLock2.release();
209 }
210 
211 #endif
size_t count() const
Definition: Vector.h:264
A vector / dynamic array.
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual Stack * allocateStack()=0
static size_t initialise1() INITIALISATION_ONLY
static void initialise2() INITIALISATION_ONLY
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
Definition: Log.h:138
static ProcessorInformation m_ProcessorInformation
Definition: Processor.h:386