mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 06:32:44 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									0eab5659f8
								
							
						
					
					
						commit
						ae1d14bc7a
					
				
					 5 changed files with 68 additions and 22 deletions
				
			
		|  | @ -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; | ||||
| } | ||||
|  |  | |||
|  | @ -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; } | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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 }; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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"; | ||||
|         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()); | ||||
|     if (!emulator.load_elf(*elf)) | ||||
|         return 1; | ||||
| 
 | ||||
|     return emulator.exec(); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling