The Pedigree Project  0.1
Smp.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 #if defined(SMP)
21 
22 #include "Smp.h"
23 #include "pedigree/kernel/utilities/utility.h"
24 
25 #if !defined(SMP_NOTICE)
26 #undef NOTICE
27 #define NOTICE(x)
28 #endif
29 #if !defined(SMP_ERROR)
30 #undef ERROR
31 #define ERROR(x)
32 #endif
33 
34 Smp Smp::m_Instance;
35 
36 void Smp::initialise()
37 {
38  // Search for the multiprocessor floating pointer structure
39  if (find() == false)
40  {
41  ERROR("smp: not compliant to the Intel Multiprocessor Specification");
42  return;
43  }
44 
45  NOTICE(
46  "Intel Multiprocessor Specification 1."
47  << Dec << m_pFloatingPointer->revision);
48  NOTICE(
49  " floating pointer at "
50  << Hex << reinterpret_cast<uintptr_t>(m_pFloatingPointer));
51 
52  // One of the default configurations?
53  if (m_pFloatingPointer->features[0] != 0)
54  {
55  ERROR(
56  "smp: default configurations (#"
57  << Dec << m_pFloatingPointer->features[0] << ") not supported");
58  return;
59  }
60 
61  // Check the configuration table
62  m_pConfigTable = reinterpret_cast<ConfigTableHeader *>(
63  m_pFloatingPointer->physicalAddress);
64  if (m_pConfigTable == 0)
65  {
66  ERROR("smp: configuration table not present");
67  return;
68  }
69  if (reinterpret_cast<uintptr_t>(m_pConfigTable) >= 0x100000)
70  {
71  ERROR("smp: configuration table above 1MB");
72  return;
73  }
74 
75  NOTICE(
76  " configuration table at "
77  << Hex << reinterpret_cast<uintptr_t>(m_pConfigTable));
78 
79  if (m_pConfigTable->signature != 0x504D4350 ||
80  checksum(m_pConfigTable) != true ||
81  m_pConfigTable->revision != m_pFloatingPointer->revision)
82  {
83  ERROR("smp: configuration table invalid");
84  return;
85  }
86 
87 #if defined(APIC)
88 
89  // PIC-Mode implemented?
90  m_bPICMode = ((m_pFloatingPointer->features[1] & 0x80) == 0x80);
91 
92  // Local APIC address
93  m_LocalApicAddress = m_pConfigTable->localApicAddress;
94 
95 #endif
96 
97  // Loop through the configuration table base entries
98  uint8_t *pType = reinterpret_cast<uint8_t *>(
99  adjust_pointer(m_pConfigTable, sizeof(ConfigTableHeader)));
100  for (size_t i = 0; i < m_pConfigTable->entryCount; i++)
101  {
102  // Size of this table entry
103  size_t sEntry = 8;
104 
105  // Processor entry?
106  if (*pType == 0)
107  {
108  Processor *pProcessor = reinterpret_cast<Processor *>(pType);
109 
110  bool bUsable = ((pProcessor->flags & 0x01) == 0x01);
111 
112  NOTICE(
113  " Processor #" << Dec << pProcessor->localApicId
114  << (bUsable ? " usable" : " unusable"));
115 
116 #if defined(MULTIPROCESSOR)
117  // Is the processor usable?
118  if (bUsable)
119  {
120  // Add the processor to the list
121  Multiprocessor::ProcessorInformation *pProcessorInfo =
123  pProcessor->localApicId, pProcessor->localApicId);
124  m_Processors.pushBack(pProcessorInfo);
125  }
126 #endif
127 
128  sEntry = sizeof(Processor);
129  }
130  // Bus entry?
131  else if (*pType == 1)
132  {
133  Bus *pBus = reinterpret_cast<Bus *>(pType);
134 
135  char name[7];
136  StringCopyN(name, pBus->name, 6);
137  name[6] = '\0';
138 
139  NOTICE(" Bus #" << Dec << pBus->busId << " \"" << name << "\"");
140 
141  // TODO: Figure out how to pass these entries to the calling
142  // function
143  }
144  // I/O APIC entry?
145  else if (*pType == 2)
146  {
147  IoApic *pIoApic = reinterpret_cast<IoApic *>(pType);
148 
149  bool bUsable = ((pIoApic->flags & 0x01) == 0x01);
150 
151  NOTICE(
152  " I/O APIC #" << Dec << pIoApic->id
153  << (bUsable ? " usable" : "") << " at " << Hex
154  << pIoApic->address);
155 
156 #if defined(APIC)
157  // Is the I/O APIC usable?
158  if (bUsable)
159  {
160  // Add the I/O APIC to the list
161  Multiprocessor::IoApicInformation *pIoApicInfo =
163  pIoApic->id, pIoApic->address);
164  m_IoApics.pushBack(pIoApicInfo);
165  }
166 #endif
167  }
168  // I/O interrupt assignment?
169  else if (*pType == 3)
170  {
171  // IoInterruptAssignment *pIoInterruptAssignment =
172  // reinterpret_cast<IoInterruptAssignment*>(pType);
173 
174  // TODO: Figure out how to pass these entries to the calling
175  // function
176  }
177  // Local interrupt assignment?
178  else if (*pType == 4)
179  {
180  // LocalInterruptAssignment *pLocalInterruptAssignment =
181  // reinterpret_cast<LocalInterruptAssignment*>(pType);
182 
183  // TODO: Figure out how to pass these entries to the calling
184  // function
185  }
186 
187  pType = adjust_pointer(pType, sEntry);
188  }
189 
190  // TODO: Parse the extended table entries
191 
192  m_bValid = true;
193 }
194 
195 Smp::Smp()
196  : m_bValid(false), m_pFloatingPointer(0), m_pConfigTable(0)
197 #if defined(APIC)
198  ,
199  m_bPICMode(false), m_LocalApicAddress(0), m_IoApics()
200 #if defined(MULTIPROCESSOR)
201  ,
202  m_Processors()
203 #endif
204 #endif
205 {
206 }
207 
208 bool Smp::find()
209 {
210  // Search in the first kilobyte of the EBDA
211  uint16_t *ebdaSegment = reinterpret_cast<uint16_t *>(0x40E);
212  m_pFloatingPointer =
213  find(reinterpret_cast<void *>((*ebdaSegment) * 16), 0x400);
214 
215  if (m_pFloatingPointer == 0)
216  {
217  // Search in the last kilobyte of the base memory
218  uint16_t *baseSize = reinterpret_cast<uint16_t *>(0x413);
219  m_pFloatingPointer =
220  find(reinterpret_cast<void *>((*baseSize - 1) * 1024), 0x400);
221 
222  if (m_pFloatingPointer == 0)
223  {
224  // Search in the BIOS ROM address space
225  m_pFloatingPointer =
226  find(reinterpret_cast<void *>(0xF0000), 0x10000);
227  }
228  }
229 
230  return (m_pFloatingPointer != 0);
231 }
232 
233 Smp::FloatingPointer *Smp::find(void *pMemory, size_t sMemory)
234 {
235  FloatingPointer *pFloatingPointer =
236  reinterpret_cast<FloatingPointer *>(pMemory);
237  while (reinterpret_cast<uintptr_t>(pFloatingPointer) <
238  (reinterpret_cast<uintptr_t>(pMemory) + sMemory))
239  {
240  if (pFloatingPointer->signature == 0x5F504D5F &&
241  checksum(pFloatingPointer) == true)
242  return pFloatingPointer;
243  pFloatingPointer = adjust_pointer(pFloatingPointer, 16);
244  }
245  return 0;
246 }
247 
248 bool Smp::checksum(const FloatingPointer *pFloatingPointer)
249 {
250  return ::checksum(
251  reinterpret_cast<const uint8_t *>(pFloatingPointer),
252  pFloatingPointer->length * 16);
253 }
254 
255 bool Smp::checksum(const ConfigTableHeader *pConfigTable)
256 {
257  // Base table checksum
258  if (::checksum(
259  reinterpret_cast<const uint8_t *>(pConfigTable),
260  pConfigTable->baseTableLength) == false)
261  return false;
262 
263  // Extended table checksum
264  uint8_t sum = pConfigTable->extendedChecksum;
265  for (size_t i = 0; i < pConfigTable->extendedTableLength; i++)
266  sum += reinterpret_cast<const uint8_t *>(
267  pConfigTable)[pConfigTable->baseTableLength + i];
268  if (sum != 0)
269  return false;
270 
271  return true;
272 }
273 
274 #endif
Definition: Bus.h:31
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
The exception was caused by a hardware task switch.
Definition: Processor.h:80
#define ERROR(text)
Definition: Log.h:82
Definition: Log.h:138