Commit graph

568 commits

Author SHA1 Message Date
Andreas Kling ef84865c8c LibX86+UserspaceEmulator: Devirtualize and inline more instruction code
Use some template hacks to force GCC to inline more of the instruction
decoding stuff into the UserspaceEmulator main execution loop.

This is my last optimization for today, and we've gone from ~60 seconds
when running "UserspaceEmulator UserspaceEmulator id" to ~8 seconds :^)
2020-07-13 21:00:51 +02:00
Andreas Kling f608b9d89a UserspaceEmulator: Mark some generic instructions ALWAYS_INLINE :^) 2020-07-13 20:47:45 +02:00
Andreas Kling 2f81c20002 UserspaceEmulator: Move the SoftCPU stream virtuals to the header
They don't actually get inlined yet, but at least this devirtualizes
them which is nice.
2020-07-13 20:41:48 +02:00
Andreas Kling a27473cbc2 UserspaceEmulator+LibX86: Turn on -O3 optimization for emulation code
Since this code is performance-sensitive, let's have the compiler do
whatever it can to help us with the most important files.

This yields a ~8% speedup.
2020-07-13 20:23:00 +02:00
Andreas Kling 8656835935 UserspaceEmulator: Add a very simple instruction fetch cache
To avoid MMU region lookup on every single instruction fetch, we now
cache a raw pointer to the current instruction. This gets automatically
invalidated when we jump somewhere, but as long as we're executing
sequentially, instruction fetches will hit the cache and bypass all
the region lookup stuff.

This is about a ~2x speedup. :^)
2020-07-13 20:14:14 +02:00
Andreas Kling a83fe7f82d UserspaceEmulator: Add the POPFD instruction
I'm not sure the mask I'm using here is completely correct, but it's
not terribly important since we're a userspace-only emulator anyway.
2020-07-13 13:50:22 +02:00
Andreas Kling dba6f9b24b UserspaceEmulator: Add the NOT instruction (with bonus: NOP!) 2020-07-13 13:50:22 +02:00
Andreas Kling 5ecbfd8451 UserspaceEmulator: Add the STC/CLC and STD/CLD instructions 2020-07-13 13:50:22 +02:00
Andreas Kling 9f293054e8 UserspaceEmulator: Implement the ADC instruction 2020-07-13 13:50:22 +02:00
Andreas Kling 6230c60296 UserspaceEmulator: Make SBB actually respect the SoftCPU carry flag
We were forgetting to set the host CPU's carry flag before executing
the SBB instruction. This made the result a bit unpredictable. :^)
2020-07-13 13:50:22 +02:00
Andreas Kling a9f92e5d75 UserspaceEmulator: Remove an unnecessary step in some instructions
We don't need to move the result of shifts around like this, we can
just use inline assembly outputs to make it end up in the right place.
2020-07-13 13:50:22 +02:00
Andreas Kling 80d3306840 UserspaceEmulator: Fix wrong ESI/EDI step sizes in MOVSW and MOVSD 2020-07-13 13:50:22 +02:00
Andreas Kling e0580e2975 UserspaceEmulator: Add some more syscalls
We can now unmap mapped memory, among other things. This is all very
ad-hoc as I'm trying to run UserspaceEmulator inside itself. :^)
2020-07-13 13:50:22 +02:00
Andreas Kling 9b6464010f UserspaceEmulator: Add basic support for memory-mapped files
MmapRegion now supports using an mmap'ed file descriptor as backing.
2020-07-13 13:50:22 +02:00
Andreas Kling 63d3f5d19b UserspaceEmulator: Implement the PUSHFD instruction 2020-07-13 13:50:22 +02:00
Andreas Kling f6ad5edab0 UserspaceEmulator: Make mmap'ed memory track read/write protection
Here's the first time we get a taste of better information than the
real hardware can give us: unlike x86 CPUs, we can actually support
write-only memory, so now we do!

While this isn't immediately useful, it's still pretty cool. :^)
2020-07-13 13:50:22 +02:00
Andreas Kling 27c1690504 UserspaceEmulator: Pass arguments through to emulated process
Ultimately we'll want to support passing some options to the emulator
as well, but for now just pass all arguments (except argv[0] of course)
through to the emulated process.

This is still not perfect, but slightly better than what we had before.
2020-07-13 13:50:22 +02:00
Andreas Kling 3d42b85969 UserspaceEmulator: Move SimpleRegion to its own files 2020-07-13 13:50:22 +02:00
Andreas Kling 4d3787ae33 UserspaceEmulator: Support the fstat() and get_process_name() syscalls
For now, we just pretend that the process name is "EMULATED". We can
probably do better though. :^)
2020-07-13 13:50:22 +02:00
Andreas Kling 617655db0d UserspaceEmulator: Move exit() syscall logging to debug output
We want the emulated program to appear without noise in the terminal.
2020-07-12 21:37:54 +02:00
Andreas Kling 1d32c66dde UserspaceEmulator: Put some syscall logging behind DEBUG_SPAM 2020-07-12 21:37:54 +02:00
Andreas Kling 95a42efc62 UserspaceEmulator: Implement enough syscalls to get /bin/id running :^) 2020-07-12 21:37:54 +02:00
Andreas Kling 1b196df4c4 UserspaceEmulator: Implement/stub out various syscalls
Moving forward on getting /bin/id to run inside the emulator. :^)
2020-07-12 21:37:54 +02:00
Andreas Kling 56d3a949e6 UserspaceEmulator: Disable per-instruction trace dumps for now
With tracing turned on, it's just too slow when doing big operations
like initializing malloc freelists.
2020-07-12 21:37:54 +02:00
Andreas Kling 079021a607 UserspaceEmulator: Put the executable name in argv[0] :^)
The emulated program can now find its own name in argv[0]. Very cool!
2020-07-12 21:37:54 +02:00
Andreas Kling ddf7b817df UserspaceEmulator: Add Emulator::dump_backtrace()
This gives you a nice, symbolicated backtrace at the current EIP. :^)
2020-07-12 21:37:54 +02:00
Andreas Kling 584923445c UserspaceEmulator: "Add" a couple of syscalls
This patch adds gettid() and stubs out pledge() and unveil() for now.
2020-07-12 21:37:54 +02:00
Andreas Kling e461e3c8b0 UserspaceEmulator: Fix missing sign extension in PUSH_imm8 2020-07-12 17:44:14 +02:00
Andreas Kling 94f07660e9 UserspaceEmulator: Add some convenient SoftMMU APIs for copying data
We'll soon want to copy data in and out of the SoftMMU memory space.
2020-07-12 17:42:57 +02:00
Andreas Kling 274ac3c628 UserspaceEmulator: Implement the XADD instruction 2020-07-12 15:35:01 +02:00
Andreas Kling 04695957e2 UserspaceEmulator: Implement the MOVSX instruction 2020-07-12 15:33:29 +02:00
Andreas Kling 8940916232 UserspaceEmulator: Implement JMP_RM32 2020-07-12 14:54:30 +02:00
Andreas Kling a424208399 UserspaceEmulator: Implement DIV_RM32
Not using inline assembly for this one since flags are undefined after
a DIV instruction anyway.
2020-07-12 14:53:19 +02:00
Andreas Kling 062e2f8614 UserspaceEmulator: Implement the XCHG instruction 2020-07-12 14:45:46 +02:00
Andreas Kling 536ca0f8c9 UserspaceEmulator: Implement some more MOV variants 2020-07-12 14:45:35 +02:00
Andreas Kling 2d44f4526a UserspaceEmulator: Implement MOVSB/MOVSW/MOVSD 2020-07-12 14:45:02 +02:00
Andreas Kling ed57efff4f UserspaceEmulator: Implement the CMPXCHG instruction 2020-07-12 14:43:30 +02:00
Andreas Kling 6ec0a63af1 UserspaceEmulator: Fix broken MOV_RM8_reg8 2020-07-12 14:42:15 +02:00
Andreas Kling bdf72a7c7a UserspaceEmulator: Implement JMP_NEAR_imm
This is a full-width relative jump, when the 8-bit immediate variant
isn't large enough.
2020-07-12 01:36:45 +02:00
Andreas Kling 938a00ecf9 UserspaceEmulator: Implement the CMOVcc instruction 2020-07-12 01:36:45 +02:00
Andreas Kling adf3775955 UserspaceEmulator: Implement the SBB family of instructions 2020-07-12 01:36:45 +02:00
Andreas Kling 734f63d522 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.
2020-07-12 01:36:45 +02:00
Andreas Kling df95e25eaa UserspaceEmulator: Implement the NEG instruction
Per the Intel manuals, NEG is equivalent to subtracting a value from 0.
2020-07-12 01:36:45 +02:00
Andreas Kling aa13183615 UserspaceEmulator: Implement SETcc_RM8 2020-07-12 01:36:45 +02:00
Andreas Kling b524bc123d UserspaceEmulator: Implement the DEC family of instructions 2020-07-12 01:36:45 +02:00
Andreas Kling ce51cf90c6 UserspaceEmulator: Make sure ELF data segments are zero-initialized
(And all other memory, too.) This will mutate later when we add shadow
memory etc, but for now just zero-initialize it since that's expected
by the emulated program.
2020-07-12 01:36:45 +02:00
Andreas Kling 8a94622e54 UserspaceEmulator: Put memory read/write logging behind MEMORY_DEBUG 2020-07-11 23:57:14 +02:00
Andreas Kling 775bc158ba UserspaceEmulator: Implement the SHL family of instructions 2020-07-11 23:57:14 +02:00
Andreas Kling bfacb9583a UserspaceEmulator: Implement RET_imm16
This is just like RET, but it also pops N bytes off the stack.
2020-07-11 23:57:14 +02:00
Andreas Kling eb86264d3b UserspaceEmulator: Simplify op_foo templates
Instead of templatizing both the destination and source types, simply
templatize the operand type and sign-extend narrower source values at
the call sites instead.
2020-07-11 23:57:14 +02:00
Andreas Kling 6febad1ef3 UserspaceEmulator: The generic_RM*_imm8 functions need to sign extend
We are supposed to sign-extend the 8-bit immediate here,
"cmp eax, 0xff" is actually "cmp eax, 0xffffffff"
2020-07-11 23:57:14 +02:00
Andreas Kling 21837544bb UserspaceEmulator: Implement MOV_EAX_moff32 2020-07-11 23:57:14 +02:00
Andreas Kling 1579cbdc9d UserspaceEmulator: Implement CALL_RM32 2020-07-11 23:57:14 +02:00
Andreas Kling a6719ede0b UserspaceEmulator: Implement the SHR family of instructions 2020-07-11 23:57:14 +02:00
Andreas Kling 2ee451afed UserspaceEmulator: Implement SHR_RM32_imm8 2020-07-11 23:57:14 +02:00
Andreas Kling d79f15e219 UserspaceEmulator: Implement the OR family of instructions 2020-07-11 23:57:14 +02:00
Andreas Kling cb2e36dde7 UserspaceEmulator: Implement PUSH_imm8
Curiously, the 8-bit immediate is sign-extended.
2020-07-11 23:57:14 +02:00
Andreas Kling ab9c7ef63b UserspaceEmulator: Fix broken MOV_RM32_imm32
Oops, this was incorrectly moving into a GPR rather than the R/M.
2020-07-11 23:57:14 +02:00
Andreas Kling 6c7ae794ce UserspaceEmulator: Implement the 32-bit LEAVE instruction
The 16-bit variant is a bit weird. Let's wait until someone needs it.
2020-07-11 23:57:14 +02:00
Andreas Kling 321ee72fe7 UserspaceEmulator: Implement JMP_imm16 and JMP_imm32 2020-07-11 23:57:14 +02:00
Andreas Kling 12566b9df0 UserspaceEmulator: Implement the MOVZX instruction 2020-07-11 23:57:14 +02:00
Andreas Kling 0af485dfff UserspaceEmulator: Implement STOSB/STOSW/STOSD
...and add a template to handle REP* instruction prefixes. This can be
further generalized, but let's go one step at a time.
2020-07-11 23:57:14 +02:00
Andreas Kling 6688ce41b2 UserspaceEmulator: Implement some of the IMUL instruction family
The single-operand forms of IMUL are a little weird. We can deal with
them when they actually show up.
2020-07-11 23:57:14 +02:00
Andreas Kling 97f4cebc8d UserspaceEmulator+LibX86: Implement the LEA instruction
This piggybacks nicely on Instruction's ModR/M resolution code. :^)
2020-07-11 23:57:14 +02:00
Andreas Kling 463afa69a7 UserspaceEmulator: Improve the initial program stack a tiny bit
Instead of starting with argv=nullptr, envp=nullptr, programs now
start with both pointing to a null terminated array (that immediately
terminates.) :^)
2020-07-11 23:57:14 +02:00
Andreas Kling b094e5279c UserspaceEmulator: Both ADD and SUB modify the carry flag 2020-07-11 20:10:30 +02:00
Andreas Kling f23c258290 UserspaceEmulator: Implement the AND and TEST instructions 2020-07-11 20:10:30 +02:00
Andreas Kling 7596ae4596 UserspaceEmulator: Implement the RET instruction
We can now return from a CALL! :^)
2020-07-11 17:22:38 +02:00
Andreas Kling 0f63d8c9b4 UserspaceEmulator: Symbolicate disassembly output :^)
Since we have the ELF executable handy, we can actually symbolicate the
disassembly trace output really easily. Very cool! :^)
2020-07-11 17:18:07 +02:00
Andreas Kling dc66d70369 UserspaceEmulator: Don't exit the emulation loop on "RET" :^) 2020-07-11 17:13:15 +02:00
Andreas Kling 4d366b8b24 UserspaceEmulator: Implement PUSH_imm32 and PUSH_RM32 2020-07-11 17:12:44 +02:00
Andreas Kling 55d2bd9eec UserspaceEmulator: Implement short-range jump instructions 2020-07-11 17:12:21 +02:00
Andreas Kling 42787ae309 UserspaceEmulator: Implement the CALL_imm32 instruction 2020-07-11 17:05:04 +02:00
Andreas Kling 0a448ee960 UserspaceEmulator: Fix broken inline assembly for asymmetric op_foos
When the Destination and Source of an op_foo were types of different
sizes, the generated assembly was not filling up the "source" register
fully in some cases. This led to incorrect results.
2020-07-11 17:03:42 +02:00
Andreas Kling c4ec38ddb5 UserspaceEmulator: Print out the current EIP as we execute instructions 2020-07-11 16:48:27 +02:00
Andreas Kling ae1d14bc7a 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.
2020-07-11 16:45:48 +02:00
Andreas Kling 0eab5659f8 UserspaceEmulator: Set up a very basic program entry stack 2020-07-11 16:30:17 +02:00
Andreas Kling 76b9fb258d UserspaceEmulator: Convert the XOR instruction to inline assembly 2020-07-11 16:02:25 +02:00
Andreas Kling 9db588daf1 UserspaceEmulator: Convert the SUB instruction to inline assembly 2020-07-11 15:52:53 +02:00
Andreas Kling 7d41b95071 UserspaceEmulator: Tweak INC and SAR helpers to not be SoftCPU members
It's quite nice having these as compartmentalized free functions.
2020-07-11 15:47:53 +02:00
Andreas Kling e852768ba6 UserspaceEmulator: Add the INC and ADD instructions
More inline assembly. I'm still figuring out how to combine templates
and inline assembly, but it's turning out pretty cool. :^)
2020-07-11 14:20:08 +02:00
Andreas Kling 12ab46def9 UserspaceEmulator: Give SoftCPU an API for evaluating jump conditions
There are 16 conditions and they're all based on a combination of the
CPU flags.
2020-07-11 13:45:39 +02:00
Andreas Kling 133803b8a7 UserspaceEmulator: Split SAR inline assembly into 8/16/32 bit variants 2020-07-11 13:43:27 +02:00
Andreas Kling 743d4ccb8f UserspaceEmulator: Support MOV_RM32_reg32 with memory destination 2020-07-11 13:29:05 +02:00
Andreas Kling e5afe6a579 UserspaceEmulator: Implement the CMP family of instructions
These are identical to SUB, except they don't store the result (they
only upate the arithmetic flags.)
2020-07-11 13:27:40 +02:00
Andreas Kling f4ddca0a73 UserspaceEmulator: Warn in SoftMMU if accessing unknown memory 2020-07-10 20:29:44 +02:00
Andreas Kling 58fd010caf UserspaceEmulator: Implement a bunch of the MOV instructions 2020-07-10 20:29:14 +02:00
Andreas Kling 04d58f54b3 UserspaceEmulator: Implement the SAR instruction
Let's try doing this with some inline assembly. We know we're running
on an x86 target anyway. :^)
2020-07-10 20:20:27 +02:00
Andreas Kling 3899effb19 UserspaceEmulator: Implement the SUB family of instructions 2020-07-10 20:20:27 +02:00
Andreas Kling 0cf7fd5268 UserspaceEmulator+LibX86: Implement all the forms of XOR
And they're all generic, which will make it easy to support more ops.
2020-07-10 20:20:27 +02:00
Andreas Kling 9955819d92 UserspaceEmulator: Better 8/16 bit GPR accessors 2020-07-10 20:20:27 +02:00
Andreas Kling 6f27770cea UserspaceEmulator: Add 8/16 bit memory read/write operations 2020-07-10 20:20:27 +02:00
Andreas Kling f8b38eabeb UserspaceEmulator: First cut of generic instruction implementations
Let's use C++ templates to implement the generic parts of instructions.
There are tons of them with the same set of inputs, just different
behavior. Templates are perfect for this.
2020-07-10 20:20:27 +02:00
Andreas Kling 30ef30ca09 UserspaceEmulator: Add proper segment registers
Some things will flow better if we're able to index into a table of our
segment registers.
2020-07-10 20:20:27 +02:00
Andreas Kling 4f41fada39 UserspaceEmulator: Add accessors for the 16-bit GPRs 2020-07-10 20:20:27 +02:00
Andreas Kling f1801cfb28 UserspaceEmulator: Fix a Clang warning
Clang didn't like default construction of PartAddressableRegister,
so let's just use memset() then.
2020-07-10 20:20:27 +02:00
Andreas Kling 4d8683b632 UserspaceEmulator: Tidy up SoftCPU's general purpose registers
This patch adds a PartAddressableRegister type, which divides a 32-bit
value into separate parts needed for the EAX/AX/AL/AH register splits.

Clean up the code around register access to make it a little less
cumbersome to use.
2020-07-09 23:27:50 +02:00
Andreas Kling d10765bec3 UserspaceEmulator: Add an initial stack and implement PUSH/POP reg32
Programs now start out with a 64 KB stack at 0x10000000. :^)
2020-07-09 16:20:08 +02:00
Andreas Kling d5c46cf528 UserspaceEmulator: Start sketching out a SoftMMU class :^)
This Emulator sub-object will keep track of all active memory regions
and handle memory read/write operations from the CPU.

A memory region is currently represented by a virtual Region object
that can implement arbitrary behavior by overriding read/write ops.
2020-07-09 16:18:47 +02:00
Andreas Kling 3a73fdd244 UserspaceEmulator: Start executing in _start() instead of main()
This is one step closer to the real thing. :^)
2020-07-09 15:47:10 +02:00