system.cc revision 13613:a19963be12ca
13116SN/A/* 23116SN/A * Copyright (c) 2007 The Hewlett-Packard Development Company 33116SN/A * Copyright (c) 2018 TU Dresden 43116SN/A * All rights reserved. 53116SN/A * 63116SN/A * The license below extends only to copyright in the software and shall 73116SN/A * not be construed as granting a license to any other intellectual 83116SN/A * property including but not limited to intellectual property relating 93116SN/A * to a hardware implementation of the functionality of the software 103116SN/A * licensed hereunder. You may use the software subject to the license 113116SN/A * terms below provided that you ensure that this notice is replicated 123116SN/A * unmodified and in its entirety in all distributions of the software, 133116SN/A * modified or unmodified, in source code or in binary form. 143116SN/A * 153116SN/A * Redistribution and use in source and binary forms, with or without 163116SN/A * modification, are permitted provided that the following conditions are 173116SN/A * met: redistributions of source code must retain the above copyright 183116SN/A * notice, this list of conditions and the following disclaimer; 193116SN/A * redistributions in binary form must reproduce the above copyright 203116SN/A * notice, this list of conditions and the following disclaimer in the 213116SN/A * documentation and/or other materials provided with the distribution; 223116SN/A * neither the name of the copyright holders nor the names of its 233116SN/A * contributors may be used to endorse or promote products derived from 243116SN/A * this software without specific prior written permission. 253116SN/A * 263116SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 273116SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 283116SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 293116SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 303116SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 313116SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 323116SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 333318SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 343318SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 353318SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 363116SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 373116SN/A * 3811263Sandreas.sandberg@arm.com * Authors: Gabe Black 394263SN/A * Maximilian Stein 404263SN/A */ 414263SN/A 424263SN/A#include "arch/x86/system.hh" 434263SN/A 444762SN/A#include "arch/x86/bios/intelmp.hh" 4510469SN/A#include "arch/x86/bios/smbios.hh" 464762SN/A#include "arch/x86/isa_traits.hh" 473116SN/A#include "base/loader/object_file.hh" 484263SN/A#include "cpu/thread_context.hh" 499152SN/A#include "params/X86System.hh" 508232SN/A 513116SN/Ausing namespace LittleEndianGuest; 523405SN/Ausing namespace X86ISA; 534762SN/A 543116SN/AX86System::X86System(Params *p) : 553116SN/A System(p), smbiosTable(p->smbios_table), 563116SN/A mpFloatingPointer(p->intel_mp_pointer), 573318SN/A mpConfigTable(p->intel_mp_table), 584263SN/A rsdp(p->acpi_description_table_pointer) 593318SN/A{ 604981SN/A} 6110913SN/A 6212064Sgabeblack@google.comvoid 6312064Sgabeblack@google.comX86ISA::installSegDesc(ThreadContext *tc, SegmentRegIndex seg, 6412064Sgabeblack@google.com SegDescriptor desc, bool longmode) 6511320Ssteve.reinhardt@amd.com{ 6611320Ssteve.reinhardt@amd.com bool honorBase = !longmode || seg == SEGMENT_REG_FS || 675535SN/A seg == SEGMENT_REG_GS || 684291SN/A seg == SEGMENT_REG_TSL || 694283SN/A seg == SYS_SEGMENT_REG_TR; 705500SN/A 719157SN/A SegAttr attr = 0; 723116SN/A 734981SN/A attr.dpl = desc.dpl; 744981SN/A attr.unusable = 0; 753318SN/A attr.defaultSize = desc.d; 764263SN/A attr.longMode = desc.l; 774218SN/A attr.avl = desc.avl; 784218SN/A attr.granularity = desc.g; 794218SN/A attr.present = desc.p; 804218SN/A attr.system = desc.s; 814218SN/A attr.type = desc.type; 824218SN/A if (desc.s) { 834283SN/A if (desc.type.codeOrData) { 844218SN/A // Code segment 854218SN/A attr.expandDown = 0; 864263SN/A attr.readable = desc.type.r; 874263SN/A attr.writable = 0; 884263SN/A } else { 894263SN/A // Data segment 904218SN/A attr.expandDown = desc.type.e; 915763SN/A attr.readable = 1; 925763SN/A attr.writable = desc.type.w; 935763SN/A } 943116SN/A } else { 954218SN/A attr.readable = 1; 964218SN/A attr.writable = 1; 973405SN/A attr.expandDown = 0; 983318SN/A } 993318SN/A 1003318SN/A tc->setMiscReg(MISCREG_SEG_BASE(seg), desc.base); 1013318SN/A tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? desc.base : 0); 1023318SN/A tc->setMiscReg(MISCREG_SEG_LIMIT(seg), desc.limit); 1033405SN/A tc->setMiscReg(MISCREG_SEG_ATTR(seg), (RegVal)attr); 1043405SN/A} 1053405SN/A 1064283SN/Avoid 1074283SN/AX86System::initState() 1084283SN/A{ 1094283SN/A System::initState(); 1104218SN/A 1114218SN/A if (!kernel) 1124218SN/A fatal("No kernel to load.\n"); 1134283SN/A 1144283SN/A if (kernel->getArch() == ObjectFile::I386) 1154218SN/A fatal("Loading a 32 bit x86 kernel is not supported.\n"); 1163318SN/A 1174218SN/A ThreadContext *tc = threadContexts[0]; 1184263SN/A // This is the boot strap processor (BSP). Initialize it to look like 1195954SN/A // the boot loader has just turned control over to the 64 bit OS. We 1205954SN/A // won't actually set up real mode or legacy protected mode descriptor 1215954SN/A // tables because we aren't executing any code that would require 1224263SN/A // them. We do, however toggle the control bits in the correct order 1234263SN/A // while allowing consistency checks and the underlying mechansims 1243116SN/A // just to be safe. 1253116SN/A 1269086SN/A const int NumPDTs = 4; 1279086SN/A 1289086SN/A const Addr PageMapLevel4 = 0x70000; 1299086SN/A const Addr PageDirPtrTable = 0x71000; 1309086SN/A const Addr PageDirTable[NumPDTs] = 1315954SN/A {0x72000, 0x73000, 0x74000, 0x75000}; 1325954SN/A const Addr GDTBase = 0x76000; 1335954SN/A 1345954SN/A const int PML4Bits = 9; 1359807SN/A const int PDPTBits = 9; 1365954SN/A const int PDTBits = 9; 1375954SN/A 1384981SN/A /* 1394981SN/A * Set up the gdt. 1404981SN/A */ 1414981SN/A uint8_t numGDTEntries = 0; 1424987SN/A // Place holder at selector 0 1434981SN/A uint64_t nullDescriptor = 0; 1444981SN/A physProxy.writeBlob(GDTBase + numGDTEntries * 8, 1454981SN/A (uint8_t *)(&nullDescriptor), 8); 1464981SN/A numGDTEntries++; 1474981SN/A 1484981SN/A SegDescriptor initDesc = 0; 1493116SN/A initDesc.type.codeOrData = 0; // code or data type 1503116SN/A initDesc.type.c = 0; // conforming 1513349SN/A initDesc.type.r = 1; // readable 1523116SN/A initDesc.dpl = 0; // privilege 1533116SN/A initDesc.p = 1; // present 1543116SN/A initDesc.l = 1; // longmode - 64 bit 1559807SN/A initDesc.d = 0; // operand size 1563116SN/A initDesc.g = 1; // granularity 1573116SN/A initDesc.s = 1; // system segment 1583116SN/A initDesc.limit = 0xFFFFFFFF; 1596124SN/A initDesc.base = 0; 1606124SN/A 1616124SN/A // 64 bit code segment 1623116SN/A SegDescriptor csDesc = initDesc; 1639198SN/A csDesc.type.codeOrData = 1; 1643116SN/A csDesc.dpl = 0; 1653116SN/A // Because we're dealing with a pointer and I don't think it's 1666124SN/A // guaranteed that there isn't anything in a nonvirtual class between 1676124SN/A // it's beginning in memory and it's actual data, we'll use an 1686124SN/A // intermediary. 1693116SN/A uint64_t csDescVal = csDesc; 1703349SN/A physProxy.writeBlob(GDTBase + numGDTEntries * 8, 1713116SN/A (uint8_t *)(&csDescVal), 8); 1723116SN/A 1733116SN/A numGDTEntries++; 1743116SN/A 1753116SN/A SegSelector cs = 0; 1763116SN/A cs.si = numGDTEntries - 1; 1773116SN/A 1783116SN/A tc->setMiscReg(MISCREG_CS, (RegVal)cs); 1793116SN/A 1803116SN/A // 32 bit data segment 1813318SN/A SegDescriptor dsDesc = initDesc; 1823318SN/A uint64_t dsDescVal = dsDesc; 1833318SN/A physProxy.writeBlob(GDTBase + numGDTEntries * 8, 1844283SN/A (uint8_t *)(&dsDescVal), 8); 1853116SN/A 1866124SN/A numGDTEntries++; 1876124SN/A 1886124SN/A SegSelector ds = 0; 1893116SN/A ds.si = numGDTEntries - 1; 1903405SN/A 1913318SN/A tc->setMiscReg(MISCREG_DS, (RegVal)ds); 1924218SN/A tc->setMiscReg(MISCREG_ES, (RegVal)ds); 1934218SN/A tc->setMiscReg(MISCREG_FS, (RegVal)ds); 1944218SN/A tc->setMiscReg(MISCREG_GS, (RegVal)ds); 1954218SN/A tc->setMiscReg(MISCREG_SS, (RegVal)ds); 1964218SN/A 1974218SN/A tc->setMiscReg(MISCREG_TSL, 0); 1984218SN/A tc->setMiscReg(MISCREG_TSG_BASE, GDTBase); 1994218SN/A tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1); 2004218SN/A 2014218SN/A SegDescriptor tssDesc = initDesc; 2024218SN/A uint64_t tssDescVal = tssDesc; 2034218SN/A physProxy.writeBlob(GDTBase + numGDTEntries * 8, 2044218SN/A (uint8_t *)(&tssDescVal), 8); 2054218SN/A 2064218SN/A numGDTEntries++; 2074218SN/A 2084218SN/A SegSelector tss = 0; 2094218SN/A tss.si = numGDTEntries - 1; 2104218SN/A 2116124SN/A tc->setMiscReg(MISCREG_TR, (RegVal)tss); 2126124SN/A installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true); 2134218SN/A 2144283SN/A /* 2154283SN/A * Identity map the first 4GB of memory. In order to map this region 2164283SN/A * of memory in long mode, there needs to be one actual page map level 2174263SN/A * 4 entry which points to one page directory pointer table which 2184283SN/A * points to 4 different page directory tables which are full of two 2194283SN/A * megabyte pages. All of the other entries in valid tables are set 2204283SN/A * to indicate that they don't pertain to anything valid and will 2214218SN/A * cause a fault if used. 2225763SN/A */ 2235763SN/A 2245763SN/A // Put valid values in all of the various table entries which indicate 2255763SN/A // that those entries don't point to further tables or pages. Then 2265763SN/A // set the values of those entries which are needed. 2274218SN/A 2284218SN/A // Page Map Level 4 2294218SN/A 2304218SN/A // read/write, user, not present 2314218SN/A uint64_t pml4e = X86ISA::htog(0x6); 2324218SN/A for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { 2334218SN/A physProxy.writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); 2344218SN/A } 2354218SN/A // Point to the only PDPT 2364218SN/A pml4e = X86ISA::htog(0x7 | PageDirPtrTable); 2374218SN/A physProxy.writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); 2384218SN/A 2394218SN/A // Page Directory Pointer Table 2404218SN/A 2414218SN/A // read/write, user, not present 2424218SN/A uint64_t pdpe = X86ISA::htog(0x6); 24311810Sbaz21@cam.ac.uk for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { 24411810Sbaz21@cam.ac.uk physProxy.writeBlob(PageDirPtrTable + offset, 2454218SN/A (uint8_t *)(&pdpe), 8); 2464218SN/A } 2474218SN/A // Point to the PDTs 2484218SN/A for (int table = 0; table < NumPDTs; table++) { 2494218SN/A pdpe = X86ISA::htog(0x7 | PageDirTable[table]); 2504218SN/A physProxy.writeBlob(PageDirPtrTable + table * 8, 2514218SN/A (uint8_t *)(&pdpe), 8); 2524218SN/A } 2534218SN/A 2544218SN/A // Page Directory Tables 2554218SN/A 2564218SN/A Addr base = 0; 2574218SN/A const Addr pageSize = 2 << 20; 2584218SN/A for (int table = 0; table < NumPDTs; table++) { 2594218SN/A for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { 2604218SN/A // read/write, user, present, 4MB 2614218SN/A uint64_t pdte = X86ISA::htog(0x87 | base); 2624218SN/A physProxy.writeBlob(PageDirTable[table] + offset, 2635763SN/A (uint8_t *)(&pdte), 8); 2645763SN/A base += pageSize; 2655763SN/A } 2664218SN/A } 2674218SN/A 2684218SN/A /* 2694218SN/A * Transition from real mode all the way up to Long mode 2704218SN/A */ 2714218SN/A CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); 2724218SN/A // Turn off paging. 2734218SN/A cr0.pg = 0; 2744263SN/A tc->setMiscReg(MISCREG_CR0, cr0); 2754263SN/A // Turn on protected mode. 2766124SN/A cr0.pe = 1; 2776124SN/A tc->setMiscReg(MISCREG_CR0, cr0); 2784263SN/A 2794263SN/A CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 2804263SN/A // Turn on pae. 2814218SN/A cr4.pae = 1; 2825763SN/A tc->setMiscReg(MISCREG_CR4, cr4); 2835763SN/A 2845763SN/A // Point to the page tables. 2854218SN/A tc->setMiscReg(MISCREG_CR3, PageMapLevel4); 2864218SN/A 2874218SN/A Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 2884218SN/A // Enable long mode. 2894218SN/A efer.lme = 1; 2904218SN/A tc->setMiscReg(MISCREG_EFER, efer); 2914218SN/A 2924218SN/A // Start using longmode segments. 2934218SN/A installSegDesc(tc, SEGMENT_REG_CS, csDesc, true); 2944218SN/A installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true); 2954218SN/A installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true); 2964218SN/A installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true); 2974218SN/A installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true); 2984218SN/A installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true); 2994218SN/A 3005763SN/A // Activate long mode. 3015763SN/A cr0.pg = 1; 3025763SN/A tc->setMiscReg(MISCREG_CR0, cr0); 3034218SN/A 3044218SN/A tc->pcState(tc->getSystemPtr()->kernelEntry); 3054218SN/A 3064218SN/A // We should now be in long mode. Yay! 3074218SN/A 3084218SN/A Addr ebdaPos = 0xF0000; 3094218SN/A Addr fixed, table; 3104218SN/A 3114218SN/A // Write out the SMBios/DMI table. 3124218SN/A writeOutSMBiosTable(ebdaPos, fixed, table); 3134218SN/A ebdaPos += (fixed + table); 3144218SN/A ebdaPos = roundUp(ebdaPos, 16); 3155763SN/A 3165763SN/A // Write out the Intel MP Specification configuration table. 3175763SN/A writeOutMPTable(ebdaPos, fixed, table); 3185763SN/A ebdaPos += (fixed + table); 3195763SN/A} 3205763SN/A 3214218SN/Avoid 3224218SN/AX86System::writeOutSMBiosTable(Addr header, 3234218SN/A Addr &headerSize, Addr &structSize, Addr table) 3245763SN/A{ 3255763SN/A // If the table location isn't specified, just put it after the header. 3265763SN/A // The header size as of the 2.5 SMBios specification is 0x1F bytes. 3275763SN/A if (!table) 3285763SN/A table = header + 0x1F; 3295763SN/A smbiosTable->setTableAddr(table); 3304218SN/A 3314218SN/A smbiosTable->writeOut(physProxy, header, headerSize, structSize); 3324218SN/A 3335763SN/A // Do some bounds checking to make sure we at least didn't step on 3345763SN/A // ourselves. 3355763SN/A assert(header > table || header + headerSize <= table); 3365763SN/A assert(table > header || table + structSize <= header); 3375763SN/A} 3385763SN/A 3395763SN/Avoid 3405763SN/AX86System::writeOutMPTable(Addr fp, 3415763SN/A Addr &fpSize, Addr &tableSize, Addr table) 3425763SN/A{ 3433318SN/A // If the table location isn't specified and it exists, just put 3446124SN/A // it after the floating pointer. The fp size as of the 1.4 Intel MP 3456124SN/A // specification is 0x10 bytes. 3466124SN/A if (mpConfigTable) { 3476124SN/A if (!table) 3484218SN/A table = fp + 0x10; 3494218SN/A mpFloatingPointer->setTableAddr(table); 3504218SN/A } 3513318SN/A 3523318SN/A fpSize = mpFloatingPointer->writeOut(physProxy, fp); 3534870SN/A if (mpConfigTable) 3543116SN/A tableSize = mpConfigTable->writeOut(physProxy, table); 3553116SN/A else 3563116SN/A tableSize = 0; 3573116SN/A 3583349SN/A // Do some bounds checking to make sure we at least didn't step on 3593116SN/A // ourselves and the fp structure was the size we thought it was. 3603116SN/A assert(fp > table || fp + fpSize <= table); 3613116SN/A assert(table > fp || table + tableSize <= fp); 3623116SN/A assert(fpSize == 0x10); 3633318SN/A} 3643116SN/A 3653116SN/A 3663116SN/AX86System::~X86System() 3673116SN/A{ 3683116SN/A delete smbiosTable; 3693116SN/A} 3703318SN/A 3713318SN/AX86System * 3723318SN/AX86SystemParams::create() 3736124SN/A{ 3746124SN/A return new X86System(this); 3753116SN/A} 3766124SN/A