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

Reply via email to