diff options
author | Andreas Kling <kling@serenityos.org> | 2020-07-21 02:29:59 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-21 02:37:29 +0200 |
commit | be5f42adea1a75db6e6fdf49e9e4c6c9992d7c6d (patch) | |
tree | b32e2828df3366be2a6923fcafc39cdc21b1e9c6 /Libraries/LibX86 | |
parent | f2d3cc7325c6c75b7ceff55c030c22ac89e3ce4d (diff) | |
download | serenity-be5f42adea1a75db6e6fdf49e9e4c6c9992d7c6d.zip |
UserspaceEmulator+LibX86: Start tracking uninitialized memory :^)
This patch introduces the concept of shadow bits. For every byte of
memory there is a corresponding shadow byte that contains metadata
about that memory.
Initially, the only metadata is whether the byte has been initialized
or not. That's represented by the least significant shadow bit.
Shadow bits travel together with regular values throughout the entire
CPU and MMU emulation. There are two main helper classes to facilitate
this: ValueWithShadow and ValueAndShadowReference.
ValueWithShadow<T> is basically a struct { T value; T shadow; } whereas
ValueAndShadowReference<T> is struct { T& value; T& shadow; }.
The latter is used as a wrapper around general-purpose registers, since
they can't use the plain ValueWithShadow memory as we need to be able
to address individual 8-bit and 16-bit subregisters (EAX, AX, AL, AH.)
Whenever a computation is made using uninitialized inputs, the result
is tainted and becomes uninitialized as well. This allows us to track
this state as it propagates throughout memory and registers.
This patch doesn't yet keep track of tainted flags, that will be an
important upcoming improvement to this.
I'm sure I've messed up some things here and there, but it seems to
basically work, so we have a place to start! :^)
Diffstat (limited to 'Libraries/LibX86')
-rw-r--r-- | Libraries/LibX86/Instruction.h | 116 |
1 files changed, 58 insertions, 58 deletions
diff --git a/Libraries/LibX86/Instruction.h b/Libraries/LibX86/Instruction.h index 50f88822b8..6d3fd98093 100644 --- a/Libraries/LibX86/Instruction.h +++ b/Libraries/LibX86/Instruction.h @@ -348,19 +348,19 @@ public: RegisterIndex16 reg16() const { return static_cast<RegisterIndex16>(register_index()); } RegisterIndex8 reg8() const { return static_cast<RegisterIndex8>(register_index()); } - template<typename CPU> - void write8(CPU&, const Instruction&, u8); - template<typename CPU> - void write16(CPU&, const Instruction&, u16); - template<typename CPU> - void write32(CPU&, const Instruction&, u32); - - template<typename CPU> - u8 read8(CPU&, const Instruction&); - template<typename CPU> - u16 read16(CPU&, const Instruction&); - template<typename CPU> - u32 read32(CPU&, const Instruction&); + template<typename CPU, typename T> + void write8(CPU&, const Instruction&, T); + template<typename CPU, typename T> + void write16(CPU&, const Instruction&, T); + template<typename CPU, typename T> + void write32(CPU&, const Instruction&, T); + + template<typename T, typename CPU> + T read8(CPU&, const Instruction&); + template<typename T, typename CPU> + T read16(CPU&, const Instruction&); + template<typename T, typename CPU> + T read32(CPU&, const Instruction&); template<typename CPU> LogicalAddress resolve(const CPU&, const Instruction&); @@ -519,35 +519,35 @@ ALWAYS_INLINE LogicalAddress MemoryOrRegisterReference::resolve16(const CPU& cpu switch (m_rm & 7) { case 0: - offset = cpu.bx() + cpu.si() + m_displacement16; + offset = cpu.bx().value() + cpu.si().value() + m_displacement16; break; case 1: - offset = cpu.bx() + cpu.di() + m_displacement16; + offset = cpu.bx().value() + cpu.di().value() + m_displacement16; break; case 2: default_segment = SegmentRegister::SS; - offset = cpu.bp() + cpu.si() + m_displacement16; + offset = cpu.bp().value() + cpu.si().value() + m_displacement16; break; case 3: default_segment = SegmentRegister::SS; - offset = cpu.bp() + cpu.di() + m_displacement16; + offset = cpu.bp().value() + cpu.di().value() + m_displacement16; break; case 4: - offset = cpu.si() + m_displacement16; + offset = cpu.si().value() + m_displacement16; break; case 5: - offset = cpu.di() + m_displacement16; + offset = cpu.di().value() + m_displacement16; break; case 6: if ((m_rm & 0xc0) == 0) offset = m_displacement16; else { default_segment = SegmentRegister::SS; - offset = cpu.bp() + m_displacement16; + offset = cpu.bp().value() + m_displacement16; } break; default: - offset = cpu.bx() + m_displacement16; + offset = cpu.bx().value() + m_displacement16; break; } @@ -563,25 +563,25 @@ ALWAYS_INLINE LogicalAddress MemoryOrRegisterReference::resolve32(const CPU& cpu switch (m_rm & 0x07) { case 0: - offset = cpu.eax() + m_displacement32; + offset = cpu.eax().value() + m_displacement32; break; case 1: - offset = cpu.ecx() + m_displacement32; + offset = cpu.ecx().value() + m_displacement32; break; case 2: - offset = cpu.edx() + m_displacement32; + offset = cpu.edx().value() + m_displacement32; break; case 3: - offset = cpu.ebx() + m_displacement32; + offset = cpu.ebx().value() + m_displacement32; break; case 4: offset = evaluate_sib(cpu, default_segment); break; case 6: - offset = cpu.esi() + m_displacement32; + offset = cpu.esi().value() + m_displacement32; break; case 7: - offset = cpu.edi() + m_displacement32; + offset = cpu.edi().value() + m_displacement32; break; default: // 5 if ((m_rm & 0xc0) == 0x00) { @@ -589,7 +589,7 @@ ALWAYS_INLINE LogicalAddress MemoryOrRegisterReference::resolve32(const CPU& cpu break; } else { default_segment = SegmentRegister::SS; - offset = cpu.ebp() + m_displacement32; + offset = cpu.ebp().value() + m_displacement32; break; } break; @@ -619,54 +619,54 @@ ALWAYS_INLINE u32 MemoryOrRegisterReference::evaluate_sib(const CPU& cpu, Segmen u32 index = 0; switch ((m_sib >> 3) & 0x07) { case 0: - index = cpu.eax(); + index = cpu.eax().value(); break; case 1: - index = cpu.ecx(); + index = cpu.ecx().value(); break; case 2: - index = cpu.edx(); + index = cpu.edx().value(); break; case 3: - index = cpu.ebx(); + index = cpu.ebx().value(); break; case 4: index = 0; break; case 5: - index = cpu.ebp(); + index = cpu.ebp().value(); break; case 6: - index = cpu.esi(); + index = cpu.esi().value(); break; case 7: - index = cpu.edi(); + index = cpu.edi().value(); break; } u32 base = m_displacement32; switch (m_sib & 0x07) { case 0: - base += cpu.eax(); + base += cpu.eax().value(); break; case 1: - base += cpu.ecx(); + base += cpu.ecx().value(); break; case 2: - base += cpu.edx(); + base += cpu.edx().value(); break; case 3: - base += cpu.ebx(); + base += cpu.ebx().value(); break; case 4: default_segment = SegmentRegister::SS; - base += cpu.esp(); + base += cpu.esp().value(); break; case 6: - base += cpu.esi(); + base += cpu.esi().value(); break; case 7: - base += cpu.edi(); + base += cpu.edi().value(); break; default: // 5 switch ((m_rm >> 6) & 3) { @@ -675,7 +675,7 @@ ALWAYS_INLINE u32 MemoryOrRegisterReference::evaluate_sib(const CPU& cpu, Segmen case 1: case 2: default_segment = SegmentRegister::SS; - base += cpu.ebp(); + base += cpu.ebp().value(); break; default: ASSERT_NOT_REACHED(); @@ -687,8 +687,8 @@ ALWAYS_INLINE u32 MemoryOrRegisterReference::evaluate_sib(const CPU& cpu, Segmen return (scale * index) + base; } -template<typename CPU> -ALWAYS_INLINE void MemoryOrRegisterReference::write8(CPU& cpu, const Instruction& insn, u8 value) +template<typename CPU, typename T> +ALWAYS_INLINE void MemoryOrRegisterReference::write8(CPU& cpu, const Instruction& insn, T value) { if (is_register()) { cpu.gpr8(reg8()) = value; @@ -699,8 +699,8 @@ ALWAYS_INLINE void MemoryOrRegisterReference::write8(CPU& cpu, const Instruction cpu.write_memory8(address, value); } -template<typename CPU> -ALWAYS_INLINE void MemoryOrRegisterReference::write16(CPU& cpu, const Instruction& insn, u16 value) +template<typename CPU, typename T> +ALWAYS_INLINE void MemoryOrRegisterReference::write16(CPU& cpu, const Instruction& insn, T value) { if (is_register()) { cpu.gpr16(reg16()) = value; @@ -711,8 +711,8 @@ ALWAYS_INLINE void MemoryOrRegisterReference::write16(CPU& cpu, const Instructio cpu.write_memory16(address, value); } -template<typename CPU> -ALWAYS_INLINE void MemoryOrRegisterReference::write32(CPU& cpu, const Instruction& insn, u32 value) +template<typename CPU, typename T> +ALWAYS_INLINE void MemoryOrRegisterReference::write32(CPU& cpu, const Instruction& insn, T value) { if (is_register()) { cpu.gpr32(reg32()) = value; @@ -723,31 +723,31 @@ ALWAYS_INLINE void MemoryOrRegisterReference::write32(CPU& cpu, const Instructio cpu.write_memory32(address, value); } -template<typename CPU> -ALWAYS_INLINE u8 MemoryOrRegisterReference::read8(CPU& cpu, const Instruction& insn) +template<typename T, typename CPU> +ALWAYS_INLINE T MemoryOrRegisterReference::read8(CPU& cpu, const Instruction& insn) { if (is_register()) - return cpu.gpr8(reg8()); + return cpu.const_gpr8(reg8()); auto address = resolve(cpu, insn); return cpu.read_memory8(address); } -template<typename CPU> -ALWAYS_INLINE u16 MemoryOrRegisterReference::read16(CPU& cpu, const Instruction& insn) +template<typename T, typename CPU> +ALWAYS_INLINE T MemoryOrRegisterReference::read16(CPU& cpu, const Instruction& insn) { if (is_register()) - return cpu.gpr16(reg16()); + return cpu.const_gpr16(reg16()); auto address = resolve(cpu, insn); return cpu.read_memory16(address); } -template<typename CPU> -ALWAYS_INLINE u32 MemoryOrRegisterReference::read32(CPU& cpu, const Instruction& insn) +template<typename T, typename CPU> +ALWAYS_INLINE T MemoryOrRegisterReference::read32(CPU& cpu, const Instruction& insn) { if (is_register()) - return cpu.gpr32(reg32()); + return cpu.const_gpr32(reg32()); auto address = resolve(cpu, insn); return cpu.read_memory32(address); |