Procházet zdrojové kódy

UserspaceEmulator: Add basic TLS (thread-local storage) support

The SoftMMU now receives full X86::LogicalAddress values from SoftCPU.
This allows the MMU to reroute TLS accesses to a special memory region.

The ELF executable's PT_TLS header tells us how to allocate the TLS.

Basically, the GS register points to a magical 4-byte area which has
a pointer to the TCB (thread control block). The TCB lives in normal
flat memory space and is accessed through the DS register.
Andreas Kling před 5 roky
rodič
revize
734f63d522

+ 16 - 4
DevTools/UserspaceEmulator/Emulator.cpp

@@ -124,11 +124,23 @@ void Emulator::setup_stack()
 bool Emulator::load_elf()
 bool Emulator::load_elf()
 {
 {
     m_elf->image().for_each_program_header([&](const ELF::Image::ProgramHeader& program_header) {
     m_elf->image().for_each_program_header([&](const ELF::Image::ProgramHeader& program_header) {
-        if (program_header.type() != PT_LOAD)
+        if (program_header.type() == PT_LOAD) {
+            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));
             return;
             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));
+        }
+        if (program_header.type() == PT_TLS) {
+            auto tcb_region = make<SimpleRegion>(0x20000000, program_header.size_in_memory());
+            memcpy(tcb_region->data(), program_header.raw_data(), program_header.size_in_image());
+
+            auto tls_region = make<SimpleRegion>(0, 4);
+            tls_region->write32(0, tcb_region->base() + 8);
+
+            mmu().add_region(move(tcb_region));
+            mmu().set_tls_region(move(tls_region));
+            return;
+        }
     });
     });
 
 
     m_cpu.set_eip(m_elf->image().entry().get());
     m_cpu.set_eip(m_elf->image().entry().get());

+ 19 - 18
DevTools/UserspaceEmulator/SoftCPU.cpp

@@ -51,6 +51,7 @@ SoftCPU::SoftCPU(Emulator& emulator)
     m_segment[(int)X86::SegmentRegister::DS] = 0x20;
     m_segment[(int)X86::SegmentRegister::DS] = 0x20;
     m_segment[(int)X86::SegmentRegister::ES] = 0x20;
     m_segment[(int)X86::SegmentRegister::ES] = 0x20;
     m_segment[(int)X86::SegmentRegister::SS] = 0x20;
     m_segment[(int)X86::SegmentRegister::SS] = 0x20;
+    m_segment[(int)X86::SegmentRegister::GS] = 0x28;
 }
 }
 
 
 void SoftCPU::dump() const
 void SoftCPU::dump() const
@@ -83,59 +84,59 @@ u32 SoftCPU::read32()
 
 
 u8 SoftCPU::read_memory8(X86::LogicalAddress address)
 u8 SoftCPU::read_memory8(X86::LogicalAddress address)
 {
 {
-    ASSERT(address.selector() == 0x18 || address.selector() == 0x20);
-    auto value = m_emulator.mmu().read8(address.offset());
+    ASSERT(address.selector() == 0x18 || address.selector() == 0x20 || address.selector() == 0x28);
+    auto value = m_emulator.mmu().read8(address);
 #ifdef MEMORY_DEBUG
 #ifdef MEMORY_DEBUG
-    printf("\033[36;1mread_memory8: @%08x -> %02x\033[0m\n", address.offset(), value);
+    printf("\033[36;1mread_memory8: @%08x:%08x -> %02x\033[0m\n", address.selector(), address.offset(), value);
 #endif
 #endif
     return value;
     return value;
 }
 }
 
 
 u16 SoftCPU::read_memory16(X86::LogicalAddress address)
 u16 SoftCPU::read_memory16(X86::LogicalAddress address)
 {
 {
-    ASSERT(address.selector() == 0x18 || address.selector() == 0x20);
-    auto value = m_emulator.mmu().read16(address.offset());
+    ASSERT(address.selector() == 0x18 || address.selector() == 0x20 || address.selector() == 0x28);
+    auto value = m_emulator.mmu().read16(address);
 #ifdef MEMORY_DEBUG
 #ifdef MEMORY_DEBUG
-    printf("\033[36;1mread_memory16: @%08x -> %04x\033[0m\n", address.offset(), value);
+    printf("\033[36;1mread_memory16: @%04x:%08x -> %04x\033[0m\n", address.selector(), address.offset(), value);
 #endif
 #endif
     return value;
     return value;
 }
 }
 
 
 u32 SoftCPU::read_memory32(X86::LogicalAddress address)
 u32 SoftCPU::read_memory32(X86::LogicalAddress address)
 {
 {
-    ASSERT(address.selector() == 0x18 || address.selector() == 0x20);
-    auto value = m_emulator.mmu().read32(address.offset());
+    ASSERT(address.selector() == 0x18 || address.selector() == 0x20 || address.selector() == 0x28);
+    auto value = m_emulator.mmu().read32(address);
 #ifdef MEMORY_DEBUG
 #ifdef MEMORY_DEBUG
-    printf("\033[36;1mread_memory32: @%08x -> %08x\033[0m\n", address.offset(), value);
+    printf("\033[36;1mread_memory32: @%04x:%08x -> %08x\033[0m\n", address.selector(), address.offset(), value);
 #endif
 #endif
     return value;
     return value;
 }
 }
 
 
 void SoftCPU::write_memory8(X86::LogicalAddress address, u8 value)
 void SoftCPU::write_memory8(X86::LogicalAddress address, u8 value)
 {
 {
-    ASSERT(address.selector() == 0x20);
+    ASSERT(address.selector() == 0x20 || address.selector() == 0x28);
 #ifdef MEMORY_DEBUG
 #ifdef MEMORY_DEBUG
-    printf("\033[35;1mwrite_memory8: @%08x <- %02x\033[0m\n", address.offset(), value);
+    printf("\033[35;1mwrite_memory8: @%04x:%08x <- %02x\033[0m\n", address.selector(), address.offset(), value);
 #endif
 #endif
-    m_emulator.mmu().write8(address.offset(), value);
+    m_emulator.mmu().write8(address, value);
 }
 }
 
 
 void SoftCPU::write_memory16(X86::LogicalAddress address, u16 value)
 void SoftCPU::write_memory16(X86::LogicalAddress address, u16 value)
 {
 {
-    ASSERT(address.selector() == 0x20);
+    ASSERT(address.selector() == 0x20 || address.selector() == 0x28);
 #ifdef MEMORY_DEBUG
 #ifdef MEMORY_DEBUG
-    printf("\033[35;1mwrite_memory16: @%08x <- %04x\033[0m\n", address.offset(), value);
+    printf("\033[35;1mwrite_memory16: @%04x:%08x <- %04x\033[0m\n", address.selector(), address.offset(), value);
 #endif
 #endif
-    m_emulator.mmu().write16(address.offset(), value);
+    m_emulator.mmu().write16(address, value);
 }
 }
 
 
 void SoftCPU::write_memory32(X86::LogicalAddress address, u32 value)
 void SoftCPU::write_memory32(X86::LogicalAddress address, u32 value)
 {
 {
-    ASSERT(address.selector() == 0x20);
+    ASSERT(address.selector() == 0x20 || address.selector() == 0x28);
 #ifdef MEMORY_DEBUG
 #ifdef MEMORY_DEBUG
-    printf("\033[35;1mwrite_memory32: @%08x <- %08x\033[0m\n", address.offset(), value);
+    printf("\033[35;1mwrite_memory32: @%04x:%08x <- %08x\033[0m\n", address.selector(), address.offset(), value);
 #endif
 #endif
-    m_emulator.mmu().write32(address.offset(), value);
+    m_emulator.mmu().write32(address, value);
 }
 }
 
 
 void SoftCPU::push32(u32 value)
 void SoftCPU::push32(u32 value)

+ 30 - 21
DevTools/UserspaceEmulator/SoftMMU.cpp

@@ -28,10 +28,13 @@
 
 
 namespace UserspaceEmulator {
 namespace UserspaceEmulator {
 
 
-SoftMMU::Region* SoftMMU::find_region(u32 address)
+SoftMMU::Region* SoftMMU::find_region(X86::LogicalAddress address)
 {
 {
+    if (address.selector() == 0x28)
+        return m_tls_region.ptr();
+
     for (auto& region : m_regions) {
     for (auto& region : m_regions) {
-        if (region.contains(address))
+        if (region.contains(address.offset()))
             return &region;
             return &region;
     }
     }
     return nullptr;
     return nullptr;
@@ -39,75 +42,81 @@ SoftMMU::Region* SoftMMU::find_region(u32 address)
 
 
 void SoftMMU::add_region(NonnullOwnPtr<Region> region)
 void SoftMMU::add_region(NonnullOwnPtr<Region> region)
 {
 {
-    ASSERT(!find_region(region->base()));
+    ASSERT(!find_region({ 0x20, region->base() }));
     // FIXME: More sanity checks pls
     // FIXME: More sanity checks pls
     m_regions.append(move(region));
     m_regions.append(move(region));
 }
 }
 
 
-u8 SoftMMU::read8(u32 address)
+void SoftMMU::set_tls_region(NonnullOwnPtr<Region> region)
+{
+    ASSERT(!m_tls_region);
+    m_tls_region = move(region);
+}
+
+u8 SoftMMU::read8(X86::LogicalAddress address)
 {
 {
     auto* region = find_region(address);
     auto* region = find_region(address);
     if (!region) {
     if (!region) {
-        warn() << "SoftMMU::read8: No region for @" << (const void*)address;
+        warn() << "SoftMMU::read8: No region for @" << (const void*)address.offset();
         TODO();
         TODO();
     }
     }
 
 
-    return region->read8(address - region->base());
+    return region->read8(address.offset() - region->base());
 }
 }
 
 
-u16 SoftMMU::read16(u32 address)
+u16 SoftMMU::read16(X86::LogicalAddress address)
 {
 {
     auto* region = find_region(address);
     auto* region = find_region(address);
     if (!region) {
     if (!region) {
-        warn() << "SoftMMU::read16: No region for @" << (const void*)address;
+        warn() << "SoftMMU::read16: No region for @" << (const void*)address.offset();
         TODO();
         TODO();
     }
     }
 
 
-    return region->read16(address - region->base());
+    return region->read16(address.offset() - region->base());
 }
 }
 
 
-u32 SoftMMU::read32(u32 address)
+u32 SoftMMU::read32(X86::LogicalAddress address)
 {
 {
     auto* region = find_region(address);
     auto* region = find_region(address);
     if (!region) {
     if (!region) {
-        warn() << "SoftMMU::read32: No region for @" << (const void*)address;
+        warn() << "SoftMMU::read32: No region for @" << (const void*)address.offset();
         TODO();
         TODO();
     }
     }
 
 
-    return region->read32(address - region->base());
+    return region->read32(address.offset() - region->base());
 }
 }
 
 
-void SoftMMU::write8(u32 address, u8 value)
+void SoftMMU::write8(X86::LogicalAddress address, u8 value)
 {
 {
     auto* region = find_region(address);
     auto* region = find_region(address);
     if (!region) {
     if (!region) {
-        warn() << "SoftMMU::write8: No region for @" << (const void*)address;
+        warn() << "SoftMMU::write8: No region for @" << (const void*)address.offset();
         TODO();
         TODO();
     }
     }
 
 
-    region->write8(address - region->base(), value);
+    region->write8(address.offset() - region->base(), value);
 }
 }
 
 
-void SoftMMU::write16(u32 address, u16 value)
+void SoftMMU::write16(X86::LogicalAddress address, u16 value)
 {
 {
     auto* region = find_region(address);
     auto* region = find_region(address);
     if (!region) {
     if (!region) {
-        warn() << "SoftMMU::write16: No region for @" << (const void*)address;
+        warn() << "SoftMMU::write16: No region for @" << (const void*)address.offset();
         TODO();
         TODO();
     }
     }
 
 
-    region->write16(address - region->base(), value);
+    region->write16(address.offset() - region->base(), value);
 }
 }
 
 
-void SoftMMU::write32(u32 address, u32 value)
+void SoftMMU::write32(X86::LogicalAddress address, u32 value)
 {
 {
     auto* region = find_region(address);
     auto* region = find_region(address);
     if (!region) {
     if (!region) {
-        warn() << "SoftMMU::write32: No region for @" << (const void*)address;
+        warn() << "SoftMMU::write32: No region for @" << (const void*)address.offset();
         TODO();
         TODO();
     }
     }
 
 
-    region->write32(address - region->base(), value);
+    region->write32(address.offset() - region->base(), value);
 }
 }
 
 
 }
 }

+ 12 - 7
DevTools/UserspaceEmulator/SoftMMU.h

@@ -27,7 +27,9 @@
 #pragma once
 #pragma once
 
 
 #include <AK/NonnullOwnPtrVector.h>
 #include <AK/NonnullOwnPtrVector.h>
+#include <AK/OwnPtr.h>
 #include <AK/Types.h>
 #include <AK/Types.h>
+#include <LibX86/Instruction.h>
 
 
 namespace UserspaceEmulator {
 namespace UserspaceEmulator {
 
 
@@ -63,18 +65,21 @@ public:
         u32 m_size { 0 };
         u32 m_size { 0 };
     };
     };
 
 
-    u8 read8(u32 address);
-    u16 read16(u32 address);
-    u32 read32(u32 address);
+    u8 read8(X86::LogicalAddress);
+    u16 read16(X86::LogicalAddress);
+    u32 read32(X86::LogicalAddress);
 
 
-    void write8(u32 address, u8 value);
-    void write16(u32 address, u16 value);
-    void write32(u32 address, u32 value);
+    void write8(X86::LogicalAddress, u8);
+    void write16(X86::LogicalAddress, u16);
+    void write32(X86::LogicalAddress, u32);
+
+    Region* find_region(X86::LogicalAddress);
 
 
-    Region* find_region(u32 address);
     void add_region(NonnullOwnPtr<Region>);
     void add_region(NonnullOwnPtr<Region>);
+    void set_tls_region(NonnullOwnPtr<Region>);
 
 
 private:
 private:
+    OwnPtr<Region> m_tls_region;
     NonnullOwnPtrVector<Region> m_regions;
     NonnullOwnPtrVector<Region> m_regions;
 };
 };