diff options
Diffstat (limited to 'src/arch/x86')
-rw-r--r-- | src/arch/x86/linux/system.cc | 129 |
1 files changed, 128 insertions, 1 deletions
diff --git a/src/arch/x86/linux/system.cc b/src/arch/x86/linux/system.cc index 0633ccb7a..2569fb0ae 100644 --- a/src/arch/x86/linux/system.cc +++ b/src/arch/x86/linux/system.cc @@ -55,9 +55,11 @@ * Authors: Gabe Black */ +#include "arch/x86/intregs.hh" #include "arch/x86/linux/system.hh" #include "arch/vtophys.hh" #include "base/trace.hh" +#include "cpu/thread_context.hh" #include "mem/physical.hh" #include "params/LinuxX86System.hh" @@ -78,7 +80,132 @@ void LinuxX86System::startup() { X86System::startup(); - //Build the real mode data structure. + + // The location of the real mode data structure. + const Addr realModeData = 0x90200; + + // A port to write to memory. + FunctionalPort * physPort = threadContexts[0]->getPhysPort(); + + /* + * Deal with the command line stuff. + */ + + // A buffer to store the command line. + const Addr commandLineBuff = 0x90000; + // A pointer to the commandLineBuff stored in the real mode data. + const Addr commandLinePointer = realModeData + 0x228; + + if (commandLine.length() + 1 > realModeData - commandLineBuff) + panic("Command line \"%s\" is longer than %d characters.\n", + commandLine, realModeData - commandLineBuff - 1); + physPort->writeBlob(commandLineBuff, + (uint8_t *)commandLine.c_str(), commandLine.length() + 1); + + // Generate a pointer of the right size and endianness to put into + // commandLinePointer. + uint32_t guestCommandLineBuff = + X86ISA::htog((uint32_t)commandLineBuff); + physPort->writeBlob(commandLinePointer, + (uint8_t *)&guestCommandLineBuff, sizeof(guestCommandLineBuff)); + + /* + * Screen Info. + */ + + // We'll skip on this for now because it's only needed for framebuffers, + // something we don't support at the moment. + + /* + * EDID info + */ + + // Skipping for now. + + /* + * Saved video mode + */ + + // Skipping for now. + + /* + * Loader type. + */ + + // Skipping for now. + + /* + * E820 memory map + */ + + // A pointer to the number of E820 entries there are. + const Addr e820MapNrPointer = realModeData + 0x1e8; + + // A pointer to the buffer for E820 entries. + const Addr e820MapPointer = realModeData + 0x2d0; + + struct e820Entry + { + Addr addr; + Addr size; + uint32_t type; + }; + + // The size is computed this way to ensure no padding sneaks in. + int e820EntrySize = + sizeof(e820Entry().addr) + + sizeof(e820Entry().size) + + sizeof(e820Entry().type); + + // I'm not sure what these should actually be. On a real machine they + // would be generated by the BIOS, and they need to reflect the regions + // which are actually available/reserved. These values are copied from + // my development machine. + e820Entry e820Map[] = { + {ULL(0x0), ULL(0x9d400), 1}, + {ULL(0x9d400), ULL(0xa0000) - ULL(0x9d400), 2}, + {ULL(0xe8000), ULL(0x100000) - ULL(0xe8000), 2}, + {ULL(0x100000), ULL(0xcfff9300) - ULL(0x100000), 1}, + {ULL(0xcfff9300), ULL(0xd0000000) - ULL(0xcfff9300), 2}, + {ULL(0xfec00000), ULL(0x100000000) - ULL(0xfec00000), 2} + }; + + uint8_t e820Nr = sizeof(e820Map) / sizeof(e820Entry); + + // Make sure the number of entries isn't bigger than what the kernel + // would be capable of providing. + assert(e820Nr <= 128); + + uint8_t guestE820Nr = X86ISA::htog(e820Nr); + physPort->writeBlob(e820MapNrPointer, + (uint8_t *)&guestE820Nr, sizeof(guestE820Nr)); + + for (int i = 0; i < e820Nr; i++) { + e820Entry guestE820Entry; + guestE820Entry.addr = X86ISA::htog(e820Map[i].addr); + guestE820Entry.size = X86ISA::htog(e820Map[i].size); + guestE820Entry.type = X86ISA::htog(e820Map[i].type); + physPort->writeBlob(e820MapPointer + e820EntrySize * i, + (uint8_t *)&guestE820Entry.addr, + sizeof(guestE820Entry.addr)); + physPort->writeBlob( + e820MapPointer + e820EntrySize * i + + sizeof(guestE820Entry.addr), + (uint8_t *)&guestE820Entry.size, + sizeof(guestE820Entry.size)); + physPort->writeBlob( + e820MapPointer + e820EntrySize * i + + sizeof(guestE820Entry.addr) + + sizeof(guestE820Entry.size), + (uint8_t *)&guestE820Entry.type, + sizeof(guestE820Entry.type)); + } + + /* + * Pass the location of the real mode data structure to the kernel + * using register %esi. We'll use %rsi which should be equivalent. + */ + threadContexts[0]->setIntReg(INTREG_RSI, realModeData); } LinuxX86System * |