system.cc revision 6712
15390SN/A/* 25390SN/A * Copyright (c) 2007 The Hewlett-Packard Development Company 35390SN/A * All rights reserved. 45390SN/A * 55390SN/A * Redistribution and use of this software in source and binary forms, 65390SN/A * with or without modification, are permitted provided that the 75390SN/A * following conditions are met: 85390SN/A * 95390SN/A * The software must be used only for Non-Commercial Use which means any 105390SN/A * use which is NOT directed to receiving any direct monetary 115390SN/A * compensation for, or commercial advantage from such use. Illustrative 125390SN/A * examples of non-commercial use are academic research, personal study, 135390SN/A * teaching, education and corporate research & development. 145390SN/A * Illustrative examples of commercial use are distributing products for 155390SN/A * commercial advantage and providing services using the software for 165390SN/A * commercial advantage. 175390SN/A * 185390SN/A * If you wish to use this software or functionality therein that may be 195390SN/A * covered by patents for commercial use, please contact: 205390SN/A * Director of Intellectual Property Licensing 215390SN/A * Office of Strategy and Technology 225390SN/A * Hewlett-Packard Company 235390SN/A * 1501 Page Mill Road 245390SN/A * Palo Alto, California 94304 255390SN/A * 265390SN/A * Redistributions of source code must retain the above copyright notice, 275390SN/A * this list of conditions and the following disclaimer. Redistributions 285390SN/A * in binary form must reproduce the above copyright notice, this list of 295390SN/A * conditions and the following disclaimer in the documentation and/or 305390SN/A * other materials provided with the distribution. Neither the name of 315630Sgblack@eecs.umich.edu * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its 325630Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 335390SN/A * this software without specific prior written permission. No right of 345630Sgblack@eecs.umich.edu * sublicense is granted herewith. Derivatives of the software and 355634Sgblack@eecs.umich.edu * output created using the software may be prepared, but only for 365630Sgblack@eecs.umich.edu * Non-Commercial Uses. Derivatives of the software may be shared with 375634Sgblack@eecs.umich.edu * others provided: (i) the others agree to abide by the list of 385390SN/A * conditions herein which includes the Non-Commercial Use restrictions; 395390SN/A * and (ii) such Derivatives of the software include the above copyright 405390SN/A * notice to acknowledge the contribution from this software where 415390SN/A * applicable, this list of conditions and the disclaimer below. 425634Sgblack@eecs.umich.edu * 435390SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 445630Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 455657Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 465827Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 475657Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 485630Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 495827Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 505634Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 515657Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 525630Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 535631Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 545631Sgblack@eecs.umich.edu * 555631Sgblack@eecs.umich.edu * Authors: Gabe Black 565631Sgblack@eecs.umich.edu */ 575631Sgblack@eecs.umich.edu 585631Sgblack@eecs.umich.edu#include "arch/x86/bios/smbios.hh" 595631Sgblack@eecs.umich.edu#include "arch/x86/bios/intelmp.hh" 605656Sgblack@eecs.umich.edu#include "arch/x86/miscregs.hh" 615656Sgblack@eecs.umich.edu#include "arch/x86/system.hh" 625656Sgblack@eecs.umich.edu#include "arch/vtophys.hh" 635632Sgblack@eecs.umich.edu#include "base/intmath.hh" 645632Sgblack@eecs.umich.edu#include "base/loader/object_file.hh" 655632Sgblack@eecs.umich.edu#include "base/loader/symtab.hh" 665632Sgblack@eecs.umich.edu#include "base/remote_gdb.hh" 675632Sgblack@eecs.umich.edu#include "base/trace.hh" 685631Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 695632Sgblack@eecs.umich.edu#include "mem/physical.hh" 705632Sgblack@eecs.umich.edu#include "params/X86System.hh" 715632Sgblack@eecs.umich.edu#include "sim/byteswap.hh" 725631Sgblack@eecs.umich.edu 735631Sgblack@eecs.umich.edu 745631Sgblack@eecs.umich.eduusing namespace LittleEndianGuest; 755688Sgblack@eecs.umich.eduusing namespace X86ISA; 765688Sgblack@eecs.umich.edu 775688Sgblack@eecs.umich.eduX86System::X86System(Params *p) : 785686Sgblack@eecs.umich.edu System(p), smbiosTable(p->smbios_table), 795686Sgblack@eecs.umich.edu mpFloatingPointer(p->intel_mp_pointer), 805686Sgblack@eecs.umich.edu mpConfigTable(p->intel_mp_table), 815390SN/A rsdp(p->acpi_description_table_pointer) 825630Sgblack@eecs.umich.edu{} 835390SN/A 845630Sgblack@eecs.umich.edustatic void 855630Sgblack@eecs.umich.eduinstallSegDesc(ThreadContext *tc, SegmentRegIndex seg, 865630Sgblack@eecs.umich.edu SegDescriptor desc, bool longmode) 875630Sgblack@eecs.umich.edu{ 885630Sgblack@eecs.umich.edu uint64_t base = desc.baseLow + (desc.baseHigh << 24); 895630Sgblack@eecs.umich.edu bool honorBase = !longmode || seg == SEGMENT_REG_FS || 905657Sgblack@eecs.umich.edu seg == SEGMENT_REG_GS || 915657Sgblack@eecs.umich.edu seg == SEGMENT_REG_TSL || 925390SN/A seg == SYS_SEGMENT_REG_TR; 935390SN/A uint64_t limit = desc.limitLow | (desc.limitHigh << 16); 945632Sgblack@eecs.umich.edu 956073Sgblack@eecs.umich.edu SegAttr attr = 0; 966073Sgblack@eecs.umich.edu 976073Sgblack@eecs.umich.edu attr.dpl = desc.dpl; 986073Sgblack@eecs.umich.edu attr.unusable = 0; 996073Sgblack@eecs.umich.edu attr.defaultSize = desc.d; 1006073Sgblack@eecs.umich.edu attr.longMode = desc.l; 1016073Sgblack@eecs.umich.edu attr.avl = desc.avl; 1026073Sgblack@eecs.umich.edu attr.granularity = desc.g; 1036073Sgblack@eecs.umich.edu attr.present = desc.p; 1046073Sgblack@eecs.umich.edu attr.system = desc.s; 1056073Sgblack@eecs.umich.edu attr.type = desc.type; 1066073Sgblack@eecs.umich.edu if (desc.s) { 1075632Sgblack@eecs.umich.edu if (desc.type.codeOrData) { 1085827Sgblack@eecs.umich.edu // Code segment 1095827Sgblack@eecs.umich.edu attr.expandDown = 0; 1105657Sgblack@eecs.umich.edu attr.readable = desc.type.r; 1115390SN/A attr.writable = 0; 1125390SN/A } else { 1137811Ssteve.reinhardt@amd.com // Data segment 1145390SN/A attr.expandDown = desc.type.e; 1155630Sgblack@eecs.umich.edu attr.readable = 1; 116 attr.writable = desc.type.w; 117 } 118 } else { 119 attr.readable = 1; 120 attr.writable = 1; 121 attr.expandDown = 0; 122 } 123 124 tc->setMiscReg(MISCREG_SEG_BASE(seg), base); 125 tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? base : 0); 126 tc->setMiscReg(MISCREG_SEG_LIMIT(seg), limit); 127 tc->setMiscReg(MISCREG_SEG_ATTR(seg), (MiscReg)attr); 128} 129 130void 131X86System::startup() 132{ 133 System::startup(); 134 ThreadContext *tc = threadContexts[0]; 135 // This is the boot strap processor (BSP). Initialize it to look like 136 // the boot loader has just turned control over to the 64 bit OS. We 137 // won't actually set up real mode or legacy protected mode descriptor 138 // tables because we aren't executing any code that would require 139 // them. We do, however toggle the control bits in the correct order 140 // while allowing consistency checks and the underlying mechansims 141 // just to be safe. 142 143 const int NumPDTs = 4; 144 145 const Addr PageMapLevel4 = 0x70000; 146 const Addr PageDirPtrTable = 0x71000; 147 const Addr PageDirTable[NumPDTs] = 148 {0x72000, 0x73000, 0x74000, 0x75000}; 149 const Addr GDTBase = 0x76000; 150 151 const int PML4Bits = 9; 152 const int PDPTBits = 9; 153 const int PDTBits = 9; 154 155 // Get a port to write the page tables and descriptor tables. 156 FunctionalPort * physPort = tc->getPhysPort(); 157 158 /* 159 * Set up the gdt. 160 */ 161 uint8_t numGDTEntries = 0; 162 // Place holder at selector 0 163 uint64_t nullDescriptor = 0; 164 physPort->writeBlob(GDTBase + numGDTEntries * 8, 165 (uint8_t *)(&nullDescriptor), 8); 166 numGDTEntries++; 167 168 //64 bit code segment 169 SegDescriptor csDesc = 0; 170 csDesc.type.codeOrData = 1; 171 csDesc.type.c = 0; // Not conforming 172 csDesc.type.r = 1; // Readable 173 csDesc.dpl = 0; // Privelege level 0 174 csDesc.p = 1; // Present 175 csDesc.l = 1; // 64 bit 176 csDesc.d = 0; // default operand size 177 csDesc.g = 1; // Page granularity 178 csDesc.s = 1; // Not a system segment 179 csDesc.limitHigh = 0xF; 180 csDesc.limitLow = 0xFF; 181 //Because we're dealing with a pointer and I don't think it's 182 //guaranteed that there isn't anything in a nonvirtual class between 183 //it's beginning in memory and it's actual data, we'll use an 184 //intermediary. 185 uint64_t csDescVal = csDesc; 186 physPort->writeBlob(GDTBase + numGDTEntries * 8, 187 (uint8_t *)(&csDescVal), 8); 188 189 numGDTEntries++; 190 191 SegSelector cs = 0; 192 cs.si = numGDTEntries - 1; 193 194 tc->setMiscReg(MISCREG_CS, (MiscReg)cs); 195 196 //32 bit data segment 197 SegDescriptor dsDesc = 0; 198 dsDesc.type.codeOrData = 0; 199 dsDesc.type.e = 0; // Not expand down 200 dsDesc.type.w = 1; // Writable 201 dsDesc.dpl = 0; // Privelege level 0 202 dsDesc.p = 1; // Present 203 dsDesc.d = 1; // default operand size 204 dsDesc.g = 1; // Page granularity 205 dsDesc.s = 1; // Not a system segment 206 dsDesc.limitHigh = 0xF; 207 dsDesc.limitLow = 0xFF; 208 uint64_t dsDescVal = dsDesc; 209 physPort->writeBlob(GDTBase + numGDTEntries * 8, 210 (uint8_t *)(&dsDescVal), 8); 211 212 numGDTEntries++; 213 214 SegSelector ds = 0; 215 ds.si = numGDTEntries - 1; 216 217 tc->setMiscReg(MISCREG_DS, (MiscReg)ds); 218 tc->setMiscReg(MISCREG_ES, (MiscReg)ds); 219 tc->setMiscReg(MISCREG_FS, (MiscReg)ds); 220 tc->setMiscReg(MISCREG_GS, (MiscReg)ds); 221 tc->setMiscReg(MISCREG_SS, (MiscReg)ds); 222 223 tc->setMiscReg(MISCREG_TSL, 0); 224 tc->setMiscReg(MISCREG_TSG_BASE, GDTBase); 225 tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1); 226 227 SegDescriptor tssDesc = 0; 228 tssDesc.type = 0xB; 229 tssDesc.dpl = 0; // Privelege level 0 230 tssDesc.p = 1; // Present 231 tssDesc.d = 1; // default operand size 232 tssDesc.g = 1; // Page granularity 233 tssDesc.s = 1; // Not a system segment 234 tssDesc.limitHigh = 0xF; 235 tssDesc.limitLow = 0xFF; 236 uint64_t tssDescVal = tssDesc; 237 physPort->writeBlob(GDTBase + numGDTEntries * 8, 238 (uint8_t *)(&tssDescVal), 8); 239 240 numGDTEntries++; 241 242 SegSelector tss = 0; 243 tss.si = numGDTEntries - 1; 244 245 tc->setMiscReg(MISCREG_TR, (MiscReg)tss); 246 installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true); 247 248 /* 249 * Identity map the first 4GB of memory. In order to map this region 250 * of memory in long mode, there needs to be one actual page map level 251 * 4 entry which points to one page directory pointer table which 252 * points to 4 different page directory tables which are full of two 253 * megabyte pages. All of the other entries in valid tables are set 254 * to indicate that they don't pertain to anything valid and will 255 * cause a fault if used. 256 */ 257 258 // Put valid values in all of the various table entries which indicate 259 // that those entries don't point to further tables or pages. Then 260 // set the values of those entries which are needed. 261 262 // Page Map Level 4 263 264 // read/write, user, not present 265 uint64_t pml4e = X86ISA::htog(0x6); 266 for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { 267 physPort->writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); 268 } 269 // Point to the only PDPT 270 pml4e = X86ISA::htog(0x7 | PageDirPtrTable); 271 physPort->writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); 272 273 // Page Directory Pointer Table 274 275 // read/write, user, not present 276 uint64_t pdpe = X86ISA::htog(0x6); 277 for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { 278 physPort->writeBlob(PageDirPtrTable + offset, 279 (uint8_t *)(&pdpe), 8); 280 } 281 // Point to the PDTs 282 for (int table = 0; table < NumPDTs; table++) { 283 pdpe = X86ISA::htog(0x7 | PageDirTable[table]); 284 physPort->writeBlob(PageDirPtrTable + table * 8, 285 (uint8_t *)(&pdpe), 8); 286 } 287 288 // Page Directory Tables 289 290 Addr base = 0; 291 const Addr pageSize = 2 << 20; 292 for (int table = 0; table < NumPDTs; table++) { 293 for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { 294 // read/write, user, present, 4MB 295 uint64_t pdte = X86ISA::htog(0x87 | base); 296 physPort->writeBlob(PageDirTable[table] + offset, 297 (uint8_t *)(&pdte), 8); 298 base += pageSize; 299 } 300 } 301 302 /* 303 * Transition from real mode all the way up to Long mode 304 */ 305 CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); 306 //Turn off paging. 307 cr0.pg = 0; 308 tc->setMiscReg(MISCREG_CR0, cr0); 309 //Turn on protected mode. 310 cr0.pe = 1; 311 tc->setMiscReg(MISCREG_CR0, cr0); 312 313 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 314 //Turn on pae. 315 cr4.pae = 1; 316 tc->setMiscReg(MISCREG_CR4, cr4); 317 318 //Point to the page tables. 319 tc->setMiscReg(MISCREG_CR3, PageMapLevel4); 320 321 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 322 //Enable long mode. 323 efer.lme = 1; 324 tc->setMiscReg(MISCREG_EFER, efer); 325 326 //Start using longmode segments. 327 installSegDesc(tc, SEGMENT_REG_CS, csDesc, true); 328 installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true); 329 installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true); 330 installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true); 331 installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true); 332 installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true); 333 334 //Activate long mode. 335 cr0.pg = 1; 336 tc->setMiscReg(MISCREG_CR0, cr0); 337 338 tc->setPC(tc->getSystemPtr()->kernelEntry); 339 tc->setNextPC(tc->readPC()); 340 341 // We should now be in long mode. Yay! 342 343 Addr ebdaPos = 0xF0000; 344 Addr fixed, table; 345 346 //Write out the SMBios/DMI table 347 writeOutSMBiosTable(ebdaPos, fixed, table); 348 ebdaPos += (fixed + table); 349 ebdaPos = roundUp(ebdaPos, 16); 350 351 //Write out the Intel MP Specification configuration table 352 writeOutMPTable(ebdaPos, fixed, table); 353 ebdaPos += (fixed + table); 354} 355 356void 357X86System::writeOutSMBiosTable(Addr header, 358 Addr &headerSize, Addr &structSize, Addr table) 359{ 360 // Get a port to write the table and header to memory. 361 FunctionalPort * physPort = threadContexts[0]->getPhysPort(); 362 363 // If the table location isn't specified, just put it after the header. 364 // The header size as of the 2.5 SMBios specification is 0x1F bytes 365 if (!table) 366 table = header + 0x1F; 367 smbiosTable->setTableAddr(table); 368 369 smbiosTable->writeOut(physPort, header, headerSize, structSize); 370 371 // Do some bounds checking to make sure we at least didn't step on 372 // ourselves. 373 assert(header > table || header + headerSize <= table); 374 assert(table > header || table + structSize <= header); 375} 376 377void 378X86System::writeOutMPTable(Addr fp, 379 Addr &fpSize, Addr &tableSize, Addr table) 380{ 381 // Get a port to write the table and header to memory. 382 FunctionalPort * physPort = threadContexts[0]->getPhysPort(); 383 384 // If the table location isn't specified and it exists, just put 385 // it after the floating pointer. The fp size as of the 1.4 Intel MP 386 // specification is 0x10 bytes. 387 if (mpConfigTable) { 388 if (!table) 389 table = fp + 0x10; 390 mpFloatingPointer->setTableAddr(table); 391 } 392 393 fpSize = mpFloatingPointer->writeOut(physPort, fp); 394 if (mpConfigTable) 395 tableSize = mpConfigTable->writeOut(physPort, table); 396 else 397 tableSize = 0; 398 399 // Do some bounds checking to make sure we at least didn't step on 400 // ourselves and the fp structure was the size we thought it was. 401 assert(fp > table || fp + fpSize <= table); 402 assert(table > fp || table + tableSize <= fp); 403 assert(fpSize == 0x10); 404} 405 406 407X86System::~X86System() 408{ 409 delete smbiosTable; 410} 411 412void 413X86System::serialize(std::ostream &os) 414{ 415 System::serialize(os); 416} 417 418 419void 420X86System::unserialize(Checkpoint *cp, const std::string §ion) 421{ 422 System::unserialize(cp,section); 423} 424 425X86System * 426X86SystemParams::create() 427{ 428 return new X86System(this); 429} 430