Browse Source

UserspaceEmulator: Load the target executable ELF semi-properly :^)

This patch adds a basic ELF program loader to the UserspaceEmulator and
creates MMU regions for each PT_LOAD header. (Note that we don't yet
respect the R/W/X flags etc.)

We also turn the SoftCPU into an X86::InstructionStream and give it an
EIP register so we can actually execute code by fetching memory through
our MMU abstraction.
Andreas Kling 5 years ago
parent
commit
ae1d14bc7a

+ 21 - 6
DevTools/UserspaceEmulator/Emulator.cpp

@@ -29,6 +29,7 @@
 #include <AK/LogStream.h>
 #include <Kernel/API/Syscall.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
 
 namespace UserspaceEmulator {
@@ -85,6 +86,8 @@ public:
         *reinterpret_cast<u32*>(m_data + offset) = value;
     }
 
+    u8* data() { return m_data; }
+
 private:
     u8* m_data { nullptr };
 };
@@ -107,12 +110,26 @@ void Emulator::setup_stack()
     m_cpu.push32(0);
 }
 
-int Emulator::exec(X86::SimpleInstructionStream& stream, u32 base)
+bool Emulator::load_elf(const ELF::Loader& elf)
+{
+    elf.image().for_each_program_header([&](const ELF::Image::ProgramHeader& program_header) {
+        if (program_header.type() != PT_LOAD)
+            return;
+        auto region = make<SimpleRegion>(program_header.vaddr().get(), program_header.size_in_memory());
+        memcpy(region->data(), program_header.raw_data(), program_header.size_in_image());
+        mmu().add_region(move(region));
+    });
+
+    m_cpu.set_eip(elf.image().entry().get());
+    return true;
+}
+
+int Emulator::exec()
 {
-    size_t offset = 0;
     while (!m_shutdown) {
-        auto insn = X86::Instruction::from_stream(stream, true, true);
-        out() << "\033[33;1m" << insn.to_string(base + offset) << "\033[0m";
+        auto base_eip = m_cpu.eip();
+        auto insn = X86::Instruction::from_stream(m_cpu, true, true);
+        out() << "\033[33;1m" << insn.to_string(base_eip) << "\033[0m";
 
         // FIXME: Remove this hack once it's no longer needed :^)
         if (insn.mnemonic() == "RET")
@@ -120,8 +137,6 @@ int Emulator::exec(X86::SimpleInstructionStream& stream, u32 base)
 
         (m_cpu.*insn.handler())(insn);
         m_cpu.dump();
-
-        offset += insn.length();
     }
     return m_exit_status;
 }

+ 4 - 1
DevTools/UserspaceEmulator/Emulator.h

@@ -29,6 +29,7 @@
 #include "SoftCPU.h"
 #include "SoftMMU.h"
 #include <AK/Types.h>
+#include <LibELF/Loader.h>
 #include <LibX86/Instruction.h>
 #include <sys/types.h>
 
@@ -38,7 +39,9 @@ class Emulator {
 public:
     Emulator();
 
-    int exec(X86::SimpleInstructionStream&, u32 base);
+    bool load_elf(const ELF::Loader&);
+
+    int exec();
     u32 virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3);
 
     SoftMMU& mmu() { return m_mmu; }

+ 24 - 3
DevTools/UserspaceEmulator/SoftCPU.cpp

@@ -78,9 +78,30 @@ void SoftCPU::dump() const
     printf("o=%u s=%u z=%u a=%u p=%u c=%u\n", of(), sf(), zf(), af(), pf(), cf());
 }
 
+u8 SoftCPU::read8()
+{
+    auto value = read_memory8({ cs(), eip() });
+    m_eip += 1;
+    return value;
+}
+
+u16 SoftCPU::read16()
+{
+    auto value = read_memory16({ cs(), eip() });
+    m_eip += 2;
+    return value;
+}
+
+u32 SoftCPU::read32()
+{
+    auto value = read_memory32({ cs(), eip() });
+    m_eip += 4;
+    return value;
+}
+
 u8 SoftCPU::read_memory8(X86::LogicalAddress address)
 {
-    ASSERT(address.selector() == 0x20);
+    ASSERT(address.selector() == 0x18 || address.selector() == 0x20);
     auto value = m_emulator.mmu().read8(address.offset());
     printf("\033[36;1mread_memory8: @%08x -> %02x\033[0m\n", address.offset(), value);
     return value;
@@ -88,7 +109,7 @@ u8 SoftCPU::read_memory8(X86::LogicalAddress address)
 
 u16 SoftCPU::read_memory16(X86::LogicalAddress address)
 {
-    ASSERT(address.selector() == 0x20);
+    ASSERT(address.selector() == 0x18 || address.selector() == 0x20);
     auto value = m_emulator.mmu().read16(address.offset());
     printf("\033[36;1mread_memory16: @%08x -> %04x\033[0m\n", address.offset(), value);
     return value;
@@ -96,7 +117,7 @@ u16 SoftCPU::read_memory16(X86::LogicalAddress address)
 
 u32 SoftCPU::read_memory32(X86::LogicalAddress address)
 {
-    ASSERT(address.selector() == 0x20);
+    ASSERT(address.selector() == 0x18 || address.selector() == 0x20);
     auto value = m_emulator.mmu().read32(address.offset());
     printf("\033[36;1mread_memory32: @%08x -> %08x\033[0m\n", address.offset(), value);
     return value;

+ 15 - 1
DevTools/UserspaceEmulator/SoftCPU.h

@@ -48,11 +48,16 @@ union PartAddressableRegister {
     };
 };
 
-class SoftCPU final : public X86::Interpreter {
+class SoftCPU final
+    : public X86::Interpreter
+    , public X86::InstructionStream {
 public:
     explicit SoftCPU(Emulator&);
     void dump() const;
 
+    u32 eip() const { return m_eip; }
+    void set_eip(u32 eip) { m_eip = eip; }
+
     struct Flags {
         enum Flag {
             CF = 0x0001,
@@ -274,6 +279,13 @@ public:
     }
 
 private:
+    // ^X86::InstructionStream
+    virtual bool can_read() override { return false; }
+    virtual u8 read8() override;
+    virtual u16 read16() override;
+    virtual u32 read32() override;
+
+    // ^X86::Interpreter
     virtual void AAA(const X86::Instruction&) override;
     virtual void AAD(const X86::Instruction&) override;
     virtual void AAM(const X86::Instruction&) override;
@@ -779,6 +791,8 @@ private:
     PartAddressableRegister m_gpr[8];
     u16 m_segment[8] { 0 };
     u32 m_eflags { 0 };
+
+    u32 m_eip { 0 };
 };
 
 }

+ 3 - 10
DevTools/UserspaceEmulator/main.cpp

@@ -30,7 +30,6 @@
 #include <AK/MappedFile.h>
 #include <LibCore/ArgsParser.h>
 #include <LibELF/Loader.h>
-#include <LibX86/Instruction.h>
 
 int main(int argc, char** argv)
 {
@@ -48,15 +47,9 @@ int main(int argc, char** argv)
 
     auto elf = ELF::Loader::create((const u8*)mapped_file.data(), mapped_file.size());
 
-    auto _start_symbol = elf->find_demangled_function("_start");
-    if (!_start_symbol.has_value()) {
-        warn() << "Could not find '_start' symbol in executable";
+    UserspaceEmulator::Emulator emulator;
+    if (!emulator.load_elf(*elf))
         return 1;
-    }
 
-    auto main_code = _start_symbol.value().raw_data();
-    X86::SimpleInstructionStream stream((const u8*)main_code.characters_without_null_termination(), main_code.length());
-
-    UserspaceEmulator::Emulator emulator;
-    return emulator.exec(stream, _start_symbol.value().value());
+    return emulator.exec();
 }