Maximilian Stein has uploaded this change for review. (
https://gem5-review.googlesource.com/7501
Change subject: arch-x86: Add Multiboot support
......................................................................
arch-x86: Add Multiboot support
* Imported from https://bitbucket.org/chrism333/gem5-patches/src/
* Boot Multiboot 1 compliant images
* Refactor initialization: separate basic x86 and Linux-specific
initialization
Change-Id: I2cee0132de09b306e497059fd2e4ef42737f76a6
---
M configs/common/FSConfig.py
M configs/example/fs.py
M src/arch/x86/SConscript
M src/arch/x86/X86System.py
M src/arch/x86/linux/system.cc
A src/arch/x86/multiboot/multiboot.hh
A src/arch/x86/multiboot/system.cc
A src/arch/x86/multiboot/system.hh
M src/arch/x86/system.cc
M src/arch/x86/system.hh
10 files changed, 461 insertions(+), 126 deletions(-)
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py
index c08353a..ed89d89 100644
--- a/configs/common/FSConfig.py
+++ b/configs/common/FSConfig.py
@@ -625,9 +625,9 @@
self.intel_mp_table.base_entries = base_entries
self.intel_mp_table.ext_entries = ext_entries
-def makeLinuxX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False,
- cmdline=None):
- self = LinuxX86System()
+def makeClsX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False,
+ cmdline=None, cls=LinuxX86System):
+ self = cls()
# Build up the x86 system and then specialize it for Linux
makeX86System(mem_mode, numCPUs, mdesc, self, Ruby)
@@ -671,12 +671,23 @@
self.e820_table.entries = entries
# Command line
- if not cmdline:
- cmdline = 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923
root=/dev/hda1'
- self.boot_osflags = fillInCmdline(mdesc, cmdline)
+ if cmdline is not None:
+ self.boot_osflags = cmdline
self.kernel = binary('x86_64-vmlinux-2.6.22.9')
return self
+def makeLinuxX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False,
+ cmdline=None):
+ if not cmdline:
+ cmdline = 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923
root=/dev/hda1'
+ cmdline = fillInCmdline(mdesc, cmdline)
+ return makeClsX86System(mem_mode, numCPUs, mdesc, Ruby, cmdline,
+ cls=LinuxX86System)
+
+def makeMultibootX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False,
+ cmdline=None):
+ return makeClsX86System(mem_mode, numCPUs, mdesc, Ruby, cmdline,
+ cls=MultibootX86System)
def makeDualRoot(full_system, testSystem, driveSystem, dumpfile):
self = Root(full_system = full_system)
diff --git a/configs/example/fs.py b/configs/example/fs.py
index 351d1c0..0a0ce1c 100644
--- a/configs/example/fs.py
+++ b/configs/example/fs.py
@@ -92,8 +92,12 @@
elif buildEnv['TARGET_ISA'] == "sparc":
test_sys = makeSparcSystem(test_mem_mode, bm[0], cmdline=cmdline)
elif buildEnv['TARGET_ISA'] == "x86":
- test_sys = makeLinuxX86System(test_mem_mode, options.num_cpus,
bm[0],
- options.ruby, cmdline=cmdline)
+ if options.multiboot:
+ test_sys = makeMultibootX86System(test_mem_mode,
options.num_cpus,
+ bm[0], options.ruby, cmdline=cmdline)
+ else:
+ test_sys = makeLinuxX86System(test_mem_mode, options.num_cpus,
+ bm[0], options.ruby, cmdline=cmdline)
elif buildEnv['TARGET_ISA'] == "arm":
test_sys = makeArmSystem(test_mem_mode, options.machine_type,
options.num_cpus, bm[0],
options.dtb_filename,
@@ -244,7 +248,11 @@
elif buildEnv['TARGET_ISA'] == 'sparc':
drive_sys = makeSparcSystem(drive_mem_mode, bm[1], cmdline=cmdline)
elif buildEnv['TARGET_ISA'] == 'x86':
- drive_sys = makeLinuxX86System(drive_mem_mode, np, bm[1],
+ if options.multiboot:
+ drive_sys = makeMultibootX86System(drive_mem_mode, np, bm[1],
+ cmdline=cmdline)
+ else:
+ drive_sys = makeLinuxX86System(drive_mem_mode, np, bm[1],
cmdline=cmdline)
elif buildEnv['TARGET_ISA'] == 'arm':
drive_sys = makeArmSystem(drive_mem_mode, options.machine_type, np,
@@ -298,6 +306,8 @@
parser = optparse.OptionParser()
Options.addCommonOptions(parser)
Options.addFSOptions(parser)
+parser.add_option("--multiboot", action="store_true",
+ help="Boot with Multiboot (version 1, x86 only)")
# Add the ruby specific and protocol specific options
if '--ruby' in sys.argv:
diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript
index 6f20f54..d7d77f6 100644
--- a/src/arch/x86/SConscript
+++ b/src/arch/x86/SConscript
@@ -60,6 +60,7 @@
Source('linux/linux.cc')
Source('linux/process.cc')
Source('linux/system.cc')
+ Source('multiboot/system.cc')
Source('nativetrace.cc')
Source('pagetable.cc')
Source('pagetable_walker.cc')
diff --git a/src/arch/x86/X86System.py b/src/arch/x86/X86System.py
index 02185b6..9490a81 100644
--- a/src/arch/x86/X86System.py
+++ b/src/arch/x86/X86System.py
@@ -63,3 +63,10 @@
e820_table = Param.X86E820Table(
X86E820Table(), 'E820 map of physical memory')
+
+class MultibootX86System(X86System):
+ type = 'MultibootX86System'
+ cxx_header = 'arch/x86/multiboot/system.hh'
+
+ e820_table = Param.X86E820Table(
+ X86E820Table(), 'E820 map of physical memory')
diff --git a/src/arch/x86/linux/system.cc b/src/arch/x86/linux/system.cc
index fc5bc2d..54a792e 100644
--- a/src/arch/x86/linux/system.cc
+++ b/src/arch/x86/linux/system.cc
@@ -42,6 +42,7 @@
#include "arch/vtophys.hh"
#include "arch/x86/isa_traits.hh"
#include "arch/x86/regs/int.hh"
+#include "base/loader/object_file.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "mem/port_proxy.hh"
@@ -65,6 +66,41 @@
{
X86System::initState();
+ if (!kernel)
+ fatal("No kernel to load.\n");
+
+ if (kernel->getArch() == ObjectFile::I386)
+ fatal("Loading a 32 bit x86 kernel is not supported.\n");
+
+ // This is the boot strap processor (BSP). Initialize it to look like
+ // the boot loader has just turned control over to the 64 bit OS. We
+ // won't actually set up real mode or legacy protected mode descriptor
+ // tables because we aren't executing any code that would require
+ // them. We do, however toggle the control bits in the correct order
+ // while allowing consistency checks and the underlying mechansims
+ // just to be safe.
+
+ const Addr PageMapLevel4 = 0x70000;
+ const Addr GDTBase = 0x76000;
+
+ setupFlatGdt(GDTBase, true);
+
+ setupPageTables(PageMapLevel4);
+
+ switchToLongMode(PageMapLevel4);
+
+ Addr ebdaPos = 0xF0000;
+ Addr fixed, table;
+
+ //Write out the SMBios/DMI table
+ writeOutSMBiosTable(ebdaPos, fixed, table);
+ ebdaPos += (fixed + table);
+ ebdaPos = roundUp(ebdaPos, 16);
+
+ //Write out the Intel MP Specification configuration table
+ writeOutMPTable(ebdaPos, fixed, table);
+ ebdaPos += (fixed + table);
+
// The location of the real mode data structure.
const Addr realModeData = 0x90200;
diff --git a/src/arch/x86/multiboot/multiboot.hh
b/src/arch/x86/multiboot/multiboot.hh
new file mode 100644
index 0000000..5dc377c
--- /dev/null
+++ b/src/arch/x86/multiboot/multiboot.hh
@@ -0,0 +1,78 @@
+
+#ifndef _ARCH_X86_MULTIBOOT_HH_
+#define _ARCH_X86_MULTIBOOT_HH_
+
+#include <inttypes.h>
+
+struct __attribute__((packed)) MultibootInfo
+{
+ uint32_t flags; /**< MultiBoot info version number */
+ uint32_t mem_lower; /**< available memory below 1MB */
+ uint32_t mem_upper; /**< available memory starting from 1MB [kB] */
+ uint32_t boot_device; /**< "root" partition */
+ uint32_t cmdline; /**< Kernel command line */
+ uint32_t mods_count; /**< number of modules */
+ uint32_t mods_addr; /**< module list */
+
+ union
+ {
+ struct __attribute__((packed))
+ {
+ /** (a.out) Kernel symbol table info */
+ uint32_t tabsize;
+ uint32_t strsize;
+ uint32_t addr;
+ uint32_t pad;
+ } a;
+
+ struct __attribute__((packed))
+ {
+ /** (ELF) Kernel section header table */
+ uint32_t num;
+ uint32_t size;
+ uint32_t addr;
+ uint32_t shndx;
+ } e;
+ } syms;
+
+ uint32_t mmap_length; /**< size of memory mapping buffer */
+ uint32_t mmap_addr; /**< address of memory mapping buffer */
+ uint32_t drives_length; /**< size of drive info buffer */
+ uint32_t drives_addr; /**< address of driver info buffer */
+ uint32_t config_table; /**< ROM configuration table */
+ uint32_t boot_loader_name; /**< Boot Loader Name */
+ uint32_t apm_table; /**< APM table */
+ uint32_t vbe_ctrl_info; /**< VESA video contoller info */
+ uint32_t vbe_mode_info; /**< VESA video mode info */
+ uint16_t vbe_mode; /**< VESA video mode number */
+ uint16_t vbe_interface_seg; /**< VESA segment of prot BIOS interface */
+ uint16_t vbe_interface_off; /**< VESA offset of prot BIOS interface */
+ uint16_t vbe_interface_len; /**< VESA lenght of prot BIOS interface */
+};
+
+struct __attribute__((packed)) MultibootHeader
+{
+ uint32_t magic;
+ uint32_t flags;
+ uint32_t checksum;
+ uint32_t header_addr;
+ uint32_t load_addr;
+ uint32_t load_end_addr;
+ uint32_t bss_end_addr;
+ uint32_t entry_addr;
+ uint32_t mode_type;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
+};
+
+struct __attribute__((packed)) MmapEntry
+{
+ uint32_t struct_size; /** Size of structure */
+ uint64_t addr; /** Start address */
+ uint64_t size; /** Size of memory range */
+ uint32_t type; /** type of memory range */
+ /* unspecified optional padding... */
+};
+
+#endif
diff --git a/src/arch/x86/multiboot/system.cc
b/src/arch/x86/multiboot/system.cc
new file mode 100644
index 0000000..3a07444
--- /dev/null
+++ b/src/arch/x86/multiboot/system.cc
@@ -0,0 +1,163 @@
+#include "arch/vtophys.hh"
+#include "arch/x86/isa_traits.hh"
+#include "arch/x86/multiboot/system.hh"
+#include "arch/x86/regs/int.hh"
+#include "base/trace.hh"
+#include "cpu/thread_context.hh"
+#include "mem/port_proxy.hh"
+#include "multiboot.hh"
+#include "params/MultibootX86System.hh"
+#include "sim/byteswap.hh"
+
+using namespace LittleEndianGuest;
+using namespace X86ISA;
+
+MultibootX86System::MultibootX86System(Params *p)
+ : X86System(p), commandLine(p->boot_osflags), e820Table(p->e820_table)
+{
+}
+
+MultibootX86System::~MultibootX86System()
+{
+}
+
+void
+MultibootX86System::initState()
+{
+ System::initState();
+
+ if (!kernel)
+ fatal("No kernel to load.\n");
+
+ // Start Kernel in 32-Bit legacy mode.
+
+ ThreadContext *tc = threadContexts[0];
+ // This is the boot strap processor (BSP). Initialize it to look like
+ // the boot loader has just turned control over to the multiboot OS.
+
+
+ /*
+ * Search for the Multiboot header
+ */
+
+ // Search for the magic Value within the first 8192 Bytes of the binary
+ const Addr kernelStart = tc->getSystemPtr()->kernelStart;
+ Addr mbHeaderAddr = -1;
+
+ for (int i = 0; i < 8192; i+=4)
+ {
+ uint32_t tmp;
+ physProxy.readBlob(kernelStart + i, (uint8_t*) &tmp, 4);
+
+ if ( tmp == 0x1BADB002)
+ {
+ mbHeaderAddr = kernelStart + i;
+ break;
+ }
+ }
+
+ if ( mbHeaderAddr == -1)
+ panic("The image does not contain a multiboot header.\n");
+
+ // Read the Multiboot Header
+ MultibootHeader mbHeader;
+ physProxy.readBlob(mbHeaderAddr, (uint8_t*) &mbHeader,
+ sizeof(MultibootHeader));
+
+ // Check the checksum
+ if ( (uint32_t) (mbHeader.magic + mbHeader.flags +
mbHeader.checksum) != 0)
+ panic("The Multiboot header checksum is invalid.\n");
+
+ if ( (mbHeader.flags & 0xffff) != 0)
+ panic("Multiboot feature requests are not supported.\n");
+
+ if ( (mbHeader.flags & (1<<16)) != 0)
+ panic("Loading the address fields from the multiboot header is
not "
+ "implemented. Use an .elf file which provides all necessary "
+ "information instead.\n");
+
+ /*
+ * Set up the gdt.
+ */
+
+ const Addr GDTBase = 0x76000;
+ setupFlatGdt(GDTBase, false);
+
+ /*
+ * Set up Multiboot info
+ */
+
+ // The location of th Multiboot Information.
+ const Addr mbInfoAddr = 0x90200;
+
+ // A pointer to the buffer for E820 entries.
+ const Addr e820MapPointer = mbInfoAddr + 0x60;
+
+
+ // write the e830 Map to Memory
+ // we cant use e820Table->writeTo because the layout used varies a bit
+ int e820TableEntryNr = e820Table->entries.size();
+
+ // for each entry in the E820 Table change its layout and write it to
+ // memory
+ for ( int i = 0; i < e820TableEntryNr; i++)
+ {
+ E820Entry* e820EntryPtr = e820Table->entries[i];
+ MmapEntry mmapEntry;
+
+ mmapEntry.struct_size = 20;
+ mmapEntry.addr = e820EntryPtr->addr;
+ mmapEntry.size = e820EntryPtr->size;
+ mmapEntry.type = e820EntryPtr->type;
+
+ physProxy.writeBlob(e820MapPointer + sizeof(MmapEntry) * i,
+ (uint8_t *) &mmapEntry, sizeof(MmapEntry));
+ }
+
+ // Write the commandline to memory
+
+ // A buffer to store the command line.
+ const Addr commandLineBuff = 0x90000;
+
+ if (commandLine.length() + 1 > mbInfoAddr - commandLineBuff)
+ panic("Command line \"%s\" is longer than %d characters.\n",
+ commandLine, mbInfoAddr - commandLineBuff - 1);
+ physProxy.writeBlob(commandLineBuff, (uint8_t *)commandLine.c_str(),
+ commandLine.length() + 1);
+
+
+ // Multiboot Info
+ MultibootInfo mbInfo;
+
+ // provide a memory map and the command line
+ mbInfo.flags = (1 << 6) | (1 << 2);
+
+ mbInfo.mmap_length = sizeof(MmapEntry) * e820TableEntryNr;
+ mbInfo.mmap_addr = e820MapPointer;
+
+ mbInfo.cmdline = X86ISA::htog((uint32_t)commandLineBuff);;
+
+ // Write multiboot info to memory
+ physProxy.writeBlob(mbInfoAddr, (uint8_t *) (&mbInfo),
+ sizeof(MultibootInfo));
+
+ /*
+ * Set up the CPU state
+ */
+
+ // write magic to eax
+ tc->setIntReg(INTREG_EAX, 0x2BADB002);
+
+ // Write address of multiboot info to ebx
+ tc->setIntReg(INTREG_EBX, mbInfoAddr);
+
+ switchToProtectedMode();
+
+ tc->pcState(tc->getSystemPtr()->kernelEntry);
+}
+
+MultibootX86System *
+MultibootX86SystemParams::create()
+{
+ return new MultibootX86System(this);
+}
diff --git a/src/arch/x86/multiboot/system.hh
b/src/arch/x86/multiboot/system.hh
new file mode 100644
index 0000000..a43c8e5
--- /dev/null
+++ b/src/arch/x86/multiboot/system.hh
@@ -0,0 +1,26 @@
+#ifndef __ARCH_X86_MULTIBOOT_SYSTEM_HH__
+#define __ARCH_X86_MULTIBOOT_SYSTEM_HH__
+
+#include <string>
+#include <vector>
+
+#include "arch/x86/bios/e820.hh"
+#include "arch/x86/system.hh"
+#include "params/MultibootX86System.hh"
+
+class MultibootX86System : public X86System
+{
+ protected:
+ std::string commandLine;
+ X86ISA::E820Table * e820Table;
+
+ public:
+ typedef MultibootX86SystemParams Params;
+ MultibootX86System(Params *p);
+ ~MultibootX86System();
+
+ void initState();
+};
+
+#endif
+
diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc
index ecde836..c2bdca90 100644
--- a/src/arch/x86/system.cc
+++ b/src/arch/x86/system.cc
@@ -42,6 +42,7 @@
#include "arch/x86/bios/intelmp.hh"
#include "arch/x86/bios/smbios.hh"
#include "arch/x86/isa_traits.hh"
+#include "arch/x86/utility.hh"
#include "base/loader/object_file.hh"
#include "cpu/thread_context.hh"
#include "params/X86System.hh"
@@ -103,117 +104,39 @@
tc->setMiscReg(MISCREG_SEG_ATTR(seg), (MiscReg)attr);
}
+
void
-X86System::initState()
+X86System::addGdtEntry(Addr GDTBase, uint8_t entry, uint64_t descriptor)
{
- System::initState();
+ physProxy.writeBlob(GDTBase + entry * 8, (uint8_t *)&descriptor, 8);
+}
- if (!kernel)
- fatal("No kernel to load.\n");
+void
+X86System::selectGdtEntry(SegmentRegIndex seg, uint8_t entry,
+ SegDescriptor desc, bool longMode)
+{
+ SegSelector selector = 0;
+ selector.si = entry;
+ auto tc = threadContexts[0];
+ tc->setMiscReg(MISCREG_SEG_SEL(seg), (MiscReg)selector);
+ installSegDesc(tc, seg, desc, longMode);
+}
- if (kernel->getArch() == ObjectFile::I386)
- fatal("Loading a 32 bit x86 kernel is not supported.\n");
-
- ThreadContext *tc = threadContexts[0];
- // This is the boot strap processor (BSP). Initialize it to look like
- // the boot loader has just turned control over to the 64 bit OS. We
- // won't actually set up real mode or legacy protected mode descriptor
- // tables because we aren't executing any code that would require
- // them. We do, however toggle the control bits in the correct order
- // while allowing consistency checks and the underlying mechansims
- // just to be safe.
-
+void
+X86System::setupPageTables(Addr PageMapLevel4)
+{
const int NumPDTs = 4;
- const Addr PageMapLevel4 = 0x70000;
- const Addr PageDirPtrTable = 0x71000;
+ const Addr PageDirPtrTable = PageMapLevel4 + 0x1000;
const Addr PageDirTable[NumPDTs] =
- {0x72000, 0x73000, 0x74000, 0x75000};
- const Addr GDTBase = 0x76000;
+ { PageMapLevel4 + 0x2000, PageMapLevel4 + 0x3000,
+ PageMapLevel4 + 0x4000, PageMapLevel4 + 0x5000};
const int PML4Bits = 9;
const int PDPTBits = 9;
const int PDTBits = 9;
/*
- * Set up the gdt.
- */
- uint8_t numGDTEntries = 0;
- // Place holder at selector 0
- uint64_t nullDescriptor = 0;
- physProxy.writeBlob(GDTBase + numGDTEntries * 8,
- (uint8_t *)(&nullDescriptor), 8);
- numGDTEntries++;
-
- SegDescriptor initDesc = 0;
- initDesc.type.codeOrData = 0; // code or data type
- initDesc.type.c = 0; // conforming
- initDesc.type.r = 1; // readable
- initDesc.dpl = 0; // privilege
- initDesc.p = 1; // present
- initDesc.l = 1; // longmode - 64 bit
- initDesc.d = 0; // operand size
- initDesc.g = 1; // granularity
- initDesc.s = 1; // system segment
- initDesc.limitHigh = 0xFFFF;
- initDesc.limitLow = 0xF;
- initDesc.baseHigh = 0x0;
- initDesc.baseLow = 0x0;
-
- //64 bit code segment
- SegDescriptor csDesc = initDesc;
- csDesc.type.codeOrData = 1;
- csDesc.dpl = 0;
- //Because we're dealing with a pointer and I don't think it's
- //guaranteed that there isn't anything in a nonvirtual class between
- //it's beginning in memory and it's actual data, we'll use an
- //intermediary.
- uint64_t csDescVal = csDesc;
- physProxy.writeBlob(GDTBase + numGDTEntries * 8,
- (uint8_t *)(&csDescVal), 8);
-
- numGDTEntries++;
-
- SegSelector cs = 0;
- cs.si = numGDTEntries - 1;
-
- tc->setMiscReg(MISCREG_CS, (MiscReg)cs);
-
- //32 bit data segment
- SegDescriptor dsDesc = initDesc;
- uint64_t dsDescVal = dsDesc;
- physProxy.writeBlob(GDTBase + numGDTEntries * 8,
- (uint8_t *)(&dsDescVal), 8);
-
- numGDTEntries++;
-
- SegSelector ds = 0;
- ds.si = numGDTEntries - 1;
-
- tc->setMiscReg(MISCREG_DS, (MiscReg)ds);
- tc->setMiscReg(MISCREG_ES, (MiscReg)ds);
- tc->setMiscReg(MISCREG_FS, (MiscReg)ds);
- tc->setMiscReg(MISCREG_GS, (MiscReg)ds);
- tc->setMiscReg(MISCREG_SS, (MiscReg)ds);
-
- tc->setMiscReg(MISCREG_TSL, 0);
- tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
- tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
-
- SegDescriptor tssDesc = initDesc;
- uint64_t tssDescVal = tssDesc;
- physProxy.writeBlob(GDTBase + numGDTEntries * 8,
- (uint8_t *)(&tssDescVal), 8);
-
- numGDTEntries++;
-
- SegSelector tss = 0;
- tss.si = numGDTEntries - 1;
-
- tc->setMiscReg(MISCREG_TR, (MiscReg)tss);
- installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true);
-
- /*
* Identity map the first 4GB of memory. In order to map this region
* of memory in long mode, there needs to be one actual page map level
* 4 entry which points to one page directory pointer table which
@@ -266,6 +189,66 @@
base += pageSize;
}
}
+}
+
+void
+X86System::setupFlatGdt(Addr GDTBase, bool longMode)
+{
+ ThreadContext *tc = threadContexts[0];
+
+ uint8_t numGDTEntries = 0;
+ // Place holder at selector 0
+ addGdtEntry(GDTBase, numGDTEntries++, 0);
+
+ SegDescriptor initDesc = 0;
+ initDesc.type.codeOrData = 0; // code or data type
+ initDesc.type.c = 0; // conforming
+ initDesc.type.r = 1; // readable
+ initDesc.dpl = 0; // privilege
+ initDesc.p = 1; // present
+ initDesc.l = 1; // longmode - 64 bit
+ initDesc.d = 0; // operand size
+ initDesc.g = 1; // granularity
+ initDesc.s = 1; // system segment
+ initDesc.limitHigh = 0xFFFF;
+ initDesc.limitLow = 0xF;
+ initDesc.baseHigh = 0x0;
+ initDesc.baseLow = 0x0;
+
+ //64 bit code segment
+ SegDescriptor csDesc = initDesc;
+ csDesc.type.codeOrData = 1;
+ csDesc.dpl = 0;
+ const uint8_t csIdx(numGDTEntries++);
+ addGdtEntry(GDTBase, csIdx, csDesc);
+ selectGdtEntry(SEGMENT_REG_CS, csIdx, csDesc, longMode);
+
+ //32 bit data segment
+ SegDescriptor dsDesc = initDesc;
+ const uint8_t dsIdx(numGDTEntries++);
+ addGdtEntry(GDTBase, dsIdx, dsDesc);
+
+ selectGdtEntry(SEGMENT_REG_DS, dsIdx, dsDesc, longMode);
+ selectGdtEntry(SEGMENT_REG_ES, dsIdx, dsDesc, longMode);
+ selectGdtEntry(SEGMENT_REG_FS, dsIdx, dsDesc, longMode);
+ selectGdtEntry(SEGMENT_REG_GS, dsIdx, dsDesc, longMode);
+ selectGdtEntry(SEGMENT_REG_SS, dsIdx, dsDesc, longMode);
+
+ tc->setMiscReg(MISCREG_TSL, 0);
+ tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
+ tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
+
+ SegDescriptor tssDesc = initDesc;
+ const uint8_t tssIdx(numGDTEntries++);
+ addGdtEntry(GDTBase, tssIdx, tssDesc);
+
+ selectGdtEntry(SYS_SEGMENT_REG_TR, tssIdx, tssDesc, longMode);
+}
+
+void
+X86System::switchToLongMode(Addr PageMapLevel4)
+{
+ ThreadContext *tc = threadContexts[0];
/*
* Transition from real mode all the way up to Long mode
@@ -291,33 +274,31 @@
efer.lme = 1;
tc->setMiscReg(MISCREG_EFER, efer);
- //Start using longmode segments.
- installSegDesc(tc, SEGMENT_REG_CS, csDesc, true);
- installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true);
- installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true);
- installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true);
- installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true);
- installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true);
-
//Activate long mode.
cr0.pg = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
tc->pcState(tc->getSystemPtr()->kernelEntry);
+}
- // We should now be in long mode. Yay!
+void
+X86System::switchToProtectedMode()
+{
+ ThreadContext *tc = threadContexts[0];
- Addr ebdaPos = 0xF0000;
- Addr fixed, table;
+ CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
+ //Turn off paging.
+ cr0.pg = 0;
+ tc->setMiscReg(MISCREG_CR0, cr0);
+ //Turn on protected mode.
+ cr0.pe = 1;
+ tc->setMiscReg(MISCREG_CR0, cr0);
+}
- //Write out the SMBios/DMI table
- writeOutSMBiosTable(ebdaPos, fixed, table);
- ebdaPos += (fixed + table);
- ebdaPos = roundUp(ebdaPos, 16);
-
- //Write out the Intel MP Specification configuration table
- writeOutMPTable(ebdaPos, fixed, table);
- ebdaPos += (fixed + table);
+void
+X86System::initState()
+{
+ System::initState();
}
void
diff --git a/src/arch/x86/system.hh b/src/arch/x86/system.hh
index 829a18d..fbbfa39 100644
--- a/src/arch/x86/system.hh
+++ b/src/arch/x86/system.hh
@@ -108,6 +108,28 @@
//XXX This may eventually have to do something useful.
return addr;
}
+
+ /**
+ * Helper function to install a GDT entry.
+ *
+ * @param entry GDT entry to install
+ * @param descriptor Descriptor to write into the GDT entry
+ */
+ void addGdtEntry(Addr GDTBase, uint8_t entry, uint64_t descriptor);
+
+ /**
+ * Helper function to select a GDT entry.
+ *
+ * @param reg Segement selector register
+ * @param entry GDT entry to select
+ */
+ void selectGdtEntry(X86ISA::SegmentRegIndex seg, uint8_t entry,
+ X86ISA::SegDescriptor desc, bool longMode);
+
+ void setupPageTables(Addr PageMapLevel4);
+ void setupFlatGdt(Addr GDTBase, bool longMode);
+ void switchToLongMode(Addr PageMapLevel4);
+ void switchToProtectedMode();
};
#endif
--
To view, visit https://gem5-review.googlesource.com/7501
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2cee0132de09b306e497059fd2e4ef42737f76a6
Gerrit-Change-Number: 7501
Gerrit-PatchSet: 1
Gerrit-Owner: Maximilian Stein <[email protected]>
Gerrit-Reviewer: Christian Menard <[email protected]>
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev