gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
system.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 The Hewlett-Packard Development Company
3  * Copyright (c) 2018 TU Dresden
4  * All rights reserved.
5  *
6  * The license below extends only to copyright in the software and shall
7  * not be construed as granting a license to any other intellectual
8  * property including but not limited to intellectual property relating
9  * to a hardware implementation of the functionality of the software
10  * licensed hereunder. You may use the software subject to the license
11  * terms below provided that you ensure that this notice is replicated
12  * unmodified and in its entirety in all distributions of the software,
13  * modified or unmodified, in source code or in binary form.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions are
17  * met: redistributions of source code must retain the above copyright
18  * notice, this list of conditions and the following disclaimer;
19  * redistributions in binary form must reproduce the above copyright
20  * notice, this list of conditions and the following disclaimer in the
21  * documentation and/or other materials provided with the distribution;
22  * neither the name of the copyright holders nor the names of its
23  * contributors may be used to endorse or promote products derived from
24  * this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Authors: Gabe Black
39  * Maximilian Stein
40  */
41 
42 #include "arch/x86/system.hh"
43 
44 #include "arch/x86/bios/intelmp.hh"
45 #include "arch/x86/bios/smbios.hh"
46 #include "arch/x86/faults.hh"
47 #include "arch/x86/isa_traits.hh"
49 #include "cpu/thread_context.hh"
50 #include "params/X86System.hh"
51 
52 using namespace X86ISA;
53 
55  System(p), smbiosTable(p->smbios_table),
56  mpFloatingPointer(p->intel_mp_pointer),
57  mpConfigTable(p->intel_mp_table),
58  rsdp(p->acpi_description_table_pointer)
59 {
60 }
61 
62 void
64  SegDescriptor desc, bool longmode)
65 {
66  bool honorBase = !longmode || seg == SEGMENT_REG_FS ||
67  seg == SEGMENT_REG_GS ||
68  seg == SEGMENT_REG_TSL ||
69  seg == SYS_SEGMENT_REG_TR;
70 
71  SegAttr attr = 0;
72 
73  attr.dpl = desc.dpl;
74  attr.unusable = 0;
75  attr.defaultSize = desc.d;
76  attr.longMode = desc.l;
77  attr.avl = desc.avl;
78  attr.granularity = desc.g;
79  attr.present = desc.p;
80  attr.system = desc.s;
81  attr.type = desc.type;
82  if (desc.s) {
83  if (desc.type.codeOrData) {
84  // Code segment
85  attr.expandDown = 0;
86  attr.readable = desc.type.r;
87  attr.writable = 0;
88  } else {
89  // Data segment
90  attr.expandDown = desc.type.e;
91  attr.readable = 1;
92  attr.writable = desc.type.w;
93  }
94  } else {
95  attr.readable = 1;
96  attr.writable = 1;
97  attr.expandDown = 0;
98  }
99 
100  tc->setMiscReg(MISCREG_SEG_BASE(seg), desc.base);
101  tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? desc.base : 0);
102  tc->setMiscReg(MISCREG_SEG_LIMIT(seg), desc.limit);
103  tc->setMiscReg(MISCREG_SEG_ATTR(seg), (RegVal)attr);
104 }
105 
106 void
108 {
110 
111  for (auto *tc: threadContexts) {
113 
114  if (tc->contextId() == 0) {
115  tc->activate();
116  } else {
117  // This is an application processor (AP). It should be initialized
118  // to look like only the BIOS POST has run on it and put then put
119  // it into a halted state.
120  tc->suspend();
121  }
122  }
123 
124  if (!kernel)
125  fatal("No kernel to load.\n");
126 
127  if (kernel->getArch() == ObjectFile::I386)
128  fatal("Loading a 32 bit x86 kernel is not supported.\n");
129 
130  ThreadContext *tc = threadContexts[0];
131  // This is the boot strap processor (BSP). Initialize it to look like
132  // the boot loader has just turned control over to the 64 bit OS. We
133  // won't actually set up real mode or legacy protected mode descriptor
134  // tables because we aren't executing any code that would require
135  // them. We do, however toggle the control bits in the correct order
136  // while allowing consistency checks and the underlying mechansims
137  // just to be safe.
138 
139  const int NumPDTs = 4;
140 
141  const Addr PageMapLevel4 = 0x70000;
142  const Addr PageDirPtrTable = 0x71000;
143  const Addr PageDirTable[NumPDTs] =
144  {0x72000, 0x73000, 0x74000, 0x75000};
145  const Addr GDTBase = 0x76000;
146 
147  const int PML4Bits = 9;
148  const int PDPTBits = 9;
149  const int PDTBits = 9;
150 
151  /*
152  * Set up the gdt.
153  */
154  uint8_t numGDTEntries = 0;
155  // Place holder at selector 0
156  uint64_t nullDescriptor = 0;
157  physProxy.writeBlob(GDTBase + numGDTEntries * 8, &nullDescriptor, 8);
158  numGDTEntries++;
159 
160  SegDescriptor initDesc = 0;
161  initDesc.type.codeOrData = 0; // code or data type
162  initDesc.type.c = 0; // conforming
163  initDesc.type.r = 1; // readable
164  initDesc.dpl = 0; // privilege
165  initDesc.p = 1; // present
166  initDesc.l = 1; // longmode - 64 bit
167  initDesc.d = 0; // operand size
168  initDesc.g = 1; // granularity
169  initDesc.s = 1; // system segment
170  initDesc.limit = 0xFFFFFFFF;
171  initDesc.base = 0;
172 
173  // 64 bit code segment
174  SegDescriptor csDesc = initDesc;
175  csDesc.type.codeOrData = 1;
176  csDesc.dpl = 0;
177  // Because we're dealing with a pointer and I don't think it's
178  // guaranteed that there isn't anything in a nonvirtual class between
179  // it's beginning in memory and it's actual data, we'll use an
180  // intermediary.
181  uint64_t csDescVal = csDesc;
182  physProxy.writeBlob(GDTBase + numGDTEntries * 8, (&csDescVal), 8);
183 
184  numGDTEntries++;
185 
186  SegSelector cs = 0;
187  cs.si = numGDTEntries - 1;
188 
189  tc->setMiscReg(MISCREG_CS, (RegVal)cs);
190 
191  // 32 bit data segment
192  SegDescriptor dsDesc = initDesc;
193  uint64_t dsDescVal = dsDesc;
194  physProxy.writeBlob(GDTBase + numGDTEntries * 8, (&dsDescVal), 8);
195 
196  numGDTEntries++;
197 
198  SegSelector ds = 0;
199  ds.si = numGDTEntries - 1;
200 
201  tc->setMiscReg(MISCREG_DS, (RegVal)ds);
202  tc->setMiscReg(MISCREG_ES, (RegVal)ds);
203  tc->setMiscReg(MISCREG_FS, (RegVal)ds);
204  tc->setMiscReg(MISCREG_GS, (RegVal)ds);
205  tc->setMiscReg(MISCREG_SS, (RegVal)ds);
206 
207  tc->setMiscReg(MISCREG_TSL, 0);
208  tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
209  tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
210 
211  SegDescriptor tssDesc = initDesc;
212  uint64_t tssDescVal = tssDesc;
213  physProxy.writeBlob(GDTBase + numGDTEntries * 8, (&tssDescVal), 8);
214 
215  numGDTEntries++;
216 
217  SegSelector tss = 0;
218  tss.si = numGDTEntries - 1;
219 
220  tc->setMiscReg(MISCREG_TR, (RegVal)tss);
221  installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true);
222 
223  /*
224  * Identity map the first 4GB of memory. In order to map this region
225  * of memory in long mode, there needs to be one actual page map level
226  * 4 entry which points to one page directory pointer table which
227  * points to 4 different page directory tables which are full of two
228  * megabyte pages. All of the other entries in valid tables are set
229  * to indicate that they don't pertain to anything valid and will
230  * cause a fault if used.
231  */
232 
233  // Put valid values in all of the various table entries which indicate
234  // that those entries don't point to further tables or pages. Then
235  // set the values of those entries which are needed.
236 
237  // Page Map Level 4
238 
239  // read/write, user, not present
240  uint64_t pml4e = htole<uint64_t>(0x6);
241  for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) {
242  physProxy.writeBlob(PageMapLevel4 + offset, (&pml4e), 8);
243  }
244  // Point to the only PDPT
245  pml4e = htole<uint64_t>(0x7 | PageDirPtrTable);
246  physProxy.writeBlob(PageMapLevel4, (&pml4e), 8);
247 
248  // Page Directory Pointer Table
249 
250  // read/write, user, not present
251  uint64_t pdpe = htole<uint64_t>(0x6);
252  for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8)
253  physProxy.writeBlob(PageDirPtrTable + offset, &pdpe, 8);
254  // Point to the PDTs
255  for (int table = 0; table < NumPDTs; table++) {
256  pdpe = htole<uint64_t>(0x7 | PageDirTable[table]);
257  physProxy.writeBlob(PageDirPtrTable + table * 8, &pdpe, 8);
258  }
259 
260  // Page Directory Tables
261 
262  Addr base = 0;
263  const Addr pageSize = 2 << 20;
264  for (int table = 0; table < NumPDTs; table++) {
265  for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) {
266  // read/write, user, present, 4MB
267  uint64_t pdte = htole(0x87 | base);
268  physProxy.writeBlob(PageDirTable[table] + offset, &pdte, 8);
269  base += pageSize;
270  }
271  }
272 
273  /*
274  * Transition from real mode all the way up to Long mode
275  */
276  CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
277  // Turn off paging.
278  cr0.pg = 0;
279  tc->setMiscReg(MISCREG_CR0, cr0);
280  // Turn on protected mode.
281  cr0.pe = 1;
282  tc->setMiscReg(MISCREG_CR0, cr0);
283 
284  CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
285  // Turn on pae.
286  cr4.pae = 1;
287  tc->setMiscReg(MISCREG_CR4, cr4);
288 
289  // Point to the page tables.
290  tc->setMiscReg(MISCREG_CR3, PageMapLevel4);
291 
292  Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
293  // Enable long mode.
294  efer.lme = 1;
295  tc->setMiscReg(MISCREG_EFER, efer);
296 
297  // Start using longmode segments.
298  installSegDesc(tc, SEGMENT_REG_CS, csDesc, true);
299  installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true);
300  installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true);
301  installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true);
302  installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true);
303  installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true);
304 
305  // Activate long mode.
306  cr0.pg = 1;
307  tc->setMiscReg(MISCREG_CR0, cr0);
308 
309  tc->pcState(tc->getSystemPtr()->kernelEntry);
310 
311  // We should now be in long mode. Yay!
312 
313  Addr ebdaPos = 0xF0000;
314  Addr fixed, table;
315 
316  // Write out the SMBios/DMI table.
317  writeOutSMBiosTable(ebdaPos, fixed, table);
318  ebdaPos += (fixed + table);
319  ebdaPos = roundUp(ebdaPos, 16);
320 
321  // Write out the Intel MP Specification configuration table.
322  writeOutMPTable(ebdaPos, fixed, table);
323  ebdaPos += (fixed + table);
324 }
325 
326 void
328  Addr &headerSize, Addr &structSize, Addr table)
329 {
330  // If the table location isn't specified, just put it after the header.
331  // The header size as of the 2.5 SMBios specification is 0x1F bytes.
332  if (!table)
333  table = header + 0x1F;
334  smbiosTable->setTableAddr(table);
335 
336  smbiosTable->writeOut(physProxy, header, headerSize, structSize);
337 
338  // Do some bounds checking to make sure we at least didn't step on
339  // ourselves.
340  assert(header > table || header + headerSize <= table);
341  assert(table > header || table + structSize <= header);
342 }
343 
344 void
346  Addr &fpSize, Addr &tableSize, Addr table)
347 {
348  // If the table location isn't specified and it exists, just put
349  // it after the floating pointer. The fp size as of the 1.4 Intel MP
350  // specification is 0x10 bytes.
351  if (mpConfigTable) {
352  if (!table)
353  table = fp + 0x10;
355  }
356 
357  fpSize = mpFloatingPointer->writeOut(physProxy, fp);
358  if (mpConfigTable)
359  tableSize = mpConfigTable->writeOut(physProxy, table);
360  else
361  tableSize = 0;
362 
363  // Do some bounds checking to make sure we at least didn't step on
364  // ourselves and the fp structure was the size we thought it was.
365  assert(fp > table || fp + fpSize <= table);
366  assert(table > fp || table + tableSize <= fp);
367  assert(fpSize == 0x10);
368 }
369 
370 
372 {
373  delete smbiosTable;
374 }
375 
376 X86System *
377 X86SystemParams::create()
378 {
379  return new X86System(this);
380 }
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
output header
Definition: nop.cc:39
virtual System * getSystemPtr()=0
void installSegDesc(ThreadContext *tc, SegmentRegIndex seg, SegDescriptor desc, bool longmode)
Definition: system.cc:63
Arch getArch() const
Definition: object_file.hh:124
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
X86SystemParams Params
Definition: system.hh:80
~X86System()
Definition: system.cc:371
void writeOut(PortProxy &proxy, Addr addr, Addr &headerSize, Addr &structSize)
Definition: smbios.cc:217
void invoke(ThreadContext *tc, const StaticInstPtr &inst=StaticInst::nullStaticInstPtr)
Definition: faults.cc:186
virtual TheISA::PCState pcState() const =0
Addr writeOut(PortProxy &proxy, Addr addr)
Definition: intelmp.cc:193
X86ISA::IntelMP::ConfigTable * mpConfigTable
Definition: system.hh:95
uint64_t RegVal
Definition: types.hh:168
X86System(Params *p)
Definition: system.cc:54
SegmentRegIndex
Definition: segment.hh:45
Definition: system.hh:77
Bitfield< 23, 0 > offset
Definition: types.hh:154
T roundUp(const T &val, const U &align)
This function is used to align addresses in memory.
Definition: intmath.hh:168
ThreadContext is the external interface to all thread state for anything outside of the CPU...
PortProxy physProxy
Port to physical memory used for writing object files into ram at boot.
Definition: system.hh:218
void initState() override
initState() is called on each SimObject when not restoring from a checkpoint.
Definition: system.cc:349
T htole(T value)
Definition: byteswap.hh:144
void writeOutSMBiosTable(Addr header, Addr &headerSize, Addr &tableSize, Addr table=0)
Definition: system.cc:327
void setTableAddr(Addr addr)
Definition: intelmp.hh:109
static MiscRegIndex MISCREG_SEG_ATTR(int index)
Definition: misc.hh:535
void initState()
Serialization stuff.
Definition: system.cc:107
static MiscRegIndex MISCREG_SEG_LIMIT(int index)
Definition: misc.hh:528
void writeBlob(Addr addr, const void *p, int size) const
Same as tryWriteBlob, but insists on success.
Definition: port_proxy.hh:189
Addr writeOut(PortProxy &proxy, Addr addr)
Definition: intelmp.cc:111
Bitfield< 51, 12 > base
Definition: pagetable.hh:142
std::vector< ThreadContext * > threadContexts
Definition: system.hh:190
Addr kernelEntry
Entry point in the kernel to start at.
Definition: system.hh:237
Bitfield< 2, 0 > seg
Definition: types.hh:84
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
X86ISA::SMBios::SMBiosTable * smbiosTable
Definition: system.hh:93
ObjectFile * kernel
Object pointer for the kernel code.
Definition: system.hh:224
void setTableAddr(Addr addr)
Definition: smbios.hh:221
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
static MiscRegIndex MISCREG_SEG_BASE(int index)
Definition: misc.hh:514
This is exposed globally, independent of the ISA.
Definition: acpi.hh:57
static MiscRegIndex MISCREG_SEG_EFF_BASE(int index)
Definition: misc.hh:521
Bitfield< 0 > p
Definition: pagetable.hh:152
Bitfield< 19, 16 > fp
Bitfield< 15, 13 > ds
X86ISA::IntelMP::FloatingPointer * mpFloatingPointer
Definition: system.hh:94
void writeOutMPTable(Addr fp, Addr &fpSize, Addr &tableSize, Addr table=0)
Definition: system.cc:345

Generated on Fri Feb 28 2020 16:26:56 for gem5 by doxygen 1.8.13