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

Generated on Fri Jun 9 2017 13:03:34 for gem5 by doxygen 1.8.6