Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions core/src/main/java/com/ledmington/emu/ELFLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.ledmington.elf.section.sym.SymbolTableEntry;
import com.ledmington.elf.section.sym.SymbolTableEntryType;
import com.ledmington.elf.section.sym.SymbolTableSection;
import com.ledmington.mem.MemoryAddress;
import com.ledmington.mem.MemoryController;
import com.ledmington.utils.BitUtils;
import com.ledmington.utils.MiniLogger;
Expand Down Expand Up @@ -135,8 +136,8 @@ public void load(
*/
final Instruction halt = new GeneralInstruction(Opcode.HLT);
final byte[] haltEncoded = InstructionEncoder.toHex(halt, true);
mem.setPermissions(baseStackValue, haltEncoded.length, false, false, true);
mem.initialize(baseStackValue, haltEncoded);
mem.setPermissions(new MemoryAddress(baseStackValue), haltEncoded.length, false, false, true);
mem.initialize(new MemoryAddress(baseStackValue), haltEncoded);
push(baseStackValue);
}

Expand Down Expand Up @@ -349,8 +350,8 @@ private void setupStack(final long stackTop, final long stackBottom) {
logger.debug(
"Setting stack size to %,d bytes (%.3f MiB) at 0x%016x-0x%016x",
stackSize, stackSize / 1_048_576.0, stackBottom, stackTop - 1L);
mem.setPermissions(stackBottom, stackSize, true, true, false);
mem.initialize(stackBottom, stackSize, (byte) 0x00);
mem.setPermissions(new MemoryAddress(stackBottom), stackSize, true, true, false);
mem.initialize(new MemoryAddress(stackBottom), stackSize, (byte) 0x00);
}

private void loadCommandLineArgumentsAndEnvironmentVariables(
Expand Down Expand Up @@ -469,10 +470,10 @@ private void loadCommandLineArgumentsAndEnvironmentVariables(
throw new AssertionError("Content on the stack is not word-aligned.");
}

mem.initialize(stackBase, content);
mem.initialize(new MemoryAddress(stackBase), content);

// FIXME: setting the stack's permissions, again?
mem.setPermissions(stackBase, content.length, true, true, false);
mem.setPermissions(new MemoryAddress(stackBase), content.length, true, true, false);
}

private List<AuxiliaryEntry> getAuxiliaryVector(final ELF elf) {
Expand All @@ -489,6 +490,7 @@ private List<AuxiliaryEntry> getAuxiliaryVector(final ELF elf) {
new AuxiliaryEntry(AuxiliaryEntryType.AT_EGID, os.getEffectiveGroupID()));
}

@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private void loadSegments(final ProgramHeaderTable pht, final long baseAddress) {
logger.debug("Loading ELF segments into memory");

Expand All @@ -512,7 +514,8 @@ private void loadSegments(final ProgramHeaderTable pht, final long baseAddress)
(phte.isReadable() ? "R" : "")
+ (phte.isWriteable() ? "W" : "")
+ (phte.isExecutable() ? "X" : ""));
mem.setPermissions(start, end, phte.isReadable(), phte.isWriteable(), phte.isExecutable());
mem.setPermissions(
new MemoryAddress(start), end, phte.isReadable(), phte.isWriteable(), phte.isExecutable());

segmentIndex++;
memorySegments.add(new Range(start, end));
Expand Down Expand Up @@ -544,7 +547,7 @@ private void initializeSection(final Section sec, final long baseAddress) {
logger.debug(
"Loading section %s in memory segment %,d at range 0x%x-0x%x (%,d bytes)",
sec.getName(), segmentIndex, startVirtualAddress, startVirtualAddress + size, size);
mem.initialize(startVirtualAddress, size, (byte) 0x00);
mem.initialize(new MemoryAddress(startVirtualAddress), size, (byte) 0x00);
}
case LoadableSection ls -> {
final long startVirtualAddress = baseAddress + sec.header().getVirtualAddress();
Expand All @@ -557,7 +560,7 @@ private void initializeSection(final Section sec, final long baseAddress) {
startVirtualAddress,
startVirtualAddress + content.length,
content.length);
mem.initialize(startVirtualAddress, content);
mem.initialize(new MemoryAddress(startVirtualAddress), content);
}
default ->
throw new IllegalArgumentException(String.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Objects;

import com.ledmington.cpu.x86.Register64;
import com.ledmington.mem.MemoryAddress;
import com.ledmington.mem.MemoryController;
import com.ledmington.utils.ReadOnlyByteBuffer;
import com.ledmington.utils.SuppressFBWarnings;
Expand Down Expand Up @@ -74,7 +75,7 @@ public long getPosition() {

@Override
public byte read() {
return mem.readCode(getPosition());
return mem.readCode(new MemoryAddress(getPosition()));
}

@Override
Expand Down
57 changes: 30 additions & 27 deletions core/src/main/java/com/ledmington/emu/X86Cpu.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.ledmington.cpu.x86.Register8;
import com.ledmington.emu.config.CPUConfig;
import com.ledmington.mem.Memory;
import com.ledmington.mem.MemoryAddress;
import com.ledmington.mem.MemoryController;
import com.ledmington.utils.BitUtils;
import com.ledmington.utils.MiniLogger;
Expand Down Expand Up @@ -143,7 +144,7 @@ public void executeOne() {
}

@Override
@SuppressWarnings({"PMD.NcssCount", "PMD.CognitiveComplexity"})
@SuppressWarnings({"PMD.NcssCount", "PMD.CognitiveComplexity", "PMD.AvoidInstantiatingObjectsInLoops"})
public void executeOne(final Instruction inst) {
assertIsRunning();

Expand Down Expand Up @@ -292,23 +293,23 @@ public void executeOne(final Instruction inst) {
() -> getAsLongSX(inst.firstOperand()),
() -> getAsLongSX(inst.secondOperand()),
(a, b) -> a - b,
result -> {},
_ -> {},
true,
MathUtils::willCarrySub,
MathUtils::willOverflowSub);
case TEST -> {
if (inst.firstOperand() instanceof final Register8 r1
&& inst.secondOperand() instanceof final Register8 r2) {
op(() -> rf.get(r1), () -> rf.get(r2), BitUtils::and, result -> {}, true);
op(() -> rf.get(r1), () -> rf.get(r2), BitUtils::and, _ -> {}, true);
} else if (inst.firstOperand() instanceof final Register16 r1
&& inst.secondOperand() instanceof final Register16 r2) {
op(() -> rf.get(r1), () -> rf.get(r2), BitUtils::and, result -> {}, true);
op(() -> rf.get(r1), () -> rf.get(r2), BitUtils::and, _ -> {}, true);
} else if (inst.firstOperand() instanceof final Register32 r1
&& inst.secondOperand() instanceof final Register32 r2) {
op(() -> rf.get(r1), () -> rf.get(r2), (a, b) -> a & b, result -> {}, true);
op(() -> rf.get(r1), () -> rf.get(r2), (a, b) -> a & b, _ -> {}, true);
} else if (inst.firstOperand() instanceof final Register64 r1
&& inst.secondOperand() instanceof final Register64 r2) {
op(() -> rf.get(r1), () -> rf.get(r2), (a, b) -> a & b, result -> {}, true);
op(() -> rf.get(r1), () -> rf.get(r2), (a, b) -> a & b, _ -> {}, true);
} else {
throw new IllegalArgumentException(String.format("Don't know what to do with '%s'.", inst));
}
Expand Down Expand Up @@ -380,27 +381,27 @@ public void executeOne(final Instruction inst) {
rf.set(op1, imm.asInt());
} else if (inst.firstOperand() instanceof final IndirectOperand io
&& inst.secondOperand() instanceof final Register8 op2) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
mem.write(address, rf.get(op2));
} else if (inst.firstOperand() instanceof final IndirectOperand io
&& inst.secondOperand() instanceof final Register16 op2) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
mem.write(address, rf.get(op2));
} else if (inst.firstOperand() instanceof final IndirectOperand io
&& inst.secondOperand() instanceof final Register32 op2) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
mem.write(address, rf.get(op2));
} else if (inst.firstOperand() instanceof final IndirectOperand io
&& inst.secondOperand() instanceof final Register64 op2) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
mem.write(address, rf.get(op2));
} else if (inst.firstOperand() instanceof final IndirectOperand io
&& inst.secondOperand() instanceof final Immediate imm) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
mem.write(address, imm.asInt());
} else if (inst.firstOperand() instanceof final Register32 op1
&& inst.secondOperand() instanceof final IndirectOperand io) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
rf.set(op1, mem.read4(address));
} else {
throw new IllegalArgumentException(
Expand All @@ -422,7 +423,7 @@ public void executeOne(final Instruction inst) {
long rdi = rf.get(Register64.RDI);

while (rcx != 0) {
mem.write(rdi, rax);
mem.write(new MemoryAddress(rdi), rax);
rdi += increment;
rcx--;
}
Expand All @@ -449,14 +450,16 @@ public void executeOne(final Instruction inst) {
case LEA -> {
final IndirectOperand src = (IndirectOperand) inst.secondOperand();
if (inst.firstOperand() instanceof final Register64 dest) {
final long address = computeIndirectOperand(src);
rf.set(dest, address);
final MemoryAddress address = computeIndirectOperand(src);
rf.set(dest, address.address());
} else if (inst.firstOperand() instanceof final Register32 dest) {
final int address = BitUtils.asInt(computeIndirectOperand(src));
final int address =
BitUtils.asInt(computeIndirectOperand(src).address());
rf.set(dest, address);
} else {
final Register16 dest = (Register16) inst.firstOperand();
final short address = BitUtils.asShort(computeIndirectOperand(src));
final short address =
BitUtils.asShort(computeIndirectOperand(src).address());
rf.set(dest, address);
}
}
Expand All @@ -471,7 +474,7 @@ public void executeOne(final Instruction inst) {
final long relativeAddress = getAsLongSX(imm);
jumpAddress = rip + relativeAddress;
} else if (inst.firstOperand() instanceof final IndirectOperand io) {
jumpAddress = computeIndirectOperand(io);
jumpAddress = computeIndirectOperand(io).address();
} else {
throw new IllegalStateException();
}
Expand Down Expand Up @@ -557,7 +560,7 @@ private void jumpTo(final long offset) {
}

private void op(final IndirectOperand iop, final Register8 op2, final BiFunction<Byte, Byte, Byte> task) {
final long address = computeIndirectOperand(iop);
final MemoryAddress address = computeIndirectOperand(iop);
op(() -> mem.read(address), () -> rf.get(op2), task, result -> mem.write(address, result), true);
}

Expand All @@ -568,8 +571,8 @@ private void op(final Register8 op1, final Register8 op2, final BiFunction<Byte,
task,
result -> rf.set(op1, result),
true,
(a, b) -> false,
(a, b) -> false);
(_, _) -> false,
(_, _) -> false);
}

private void op(
Expand Down Expand Up @@ -742,7 +745,7 @@ private void push(final long value) {
}

rf.set(Register64.RSP, newRSP);
mem.write(newRSP, value);
mem.write(new MemoryAddress(newRSP), value);
}

/**
Expand All @@ -758,7 +761,7 @@ private long pop() {
throw new StackUnderflow();
}

final long value = mem.read8(rsp);
final long value = mem.read8(new MemoryAddress(rsp));

// the stack "grows downward", so it "pops upward"
final long newRSP = rsp + 8L;
Expand All @@ -777,7 +780,7 @@ private int getAsIntZX(final Operand op) {
}

private int getAsIntZX(final IndirectOperand io) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
return switch (io.getPointerSize()) {
case BYTE_PTR -> BitUtils.asInt(mem.read(address));
case WORD_PTR -> BitUtils.asInt(mem.read2(address));
Expand Down Expand Up @@ -811,7 +814,7 @@ private long getAsLongSX(final Immediate imm) {

/** Returns a sign-extended long. */
private long getAsLongSX(final IndirectOperand io) {
final long address = computeIndirectOperand(io);
final MemoryAddress address = computeIndirectOperand(io);
if (io.getPointerSize() == PointerSize.QWORD_PTR) {
return mem.read8(address);
} else {
Expand All @@ -825,7 +828,7 @@ private long getAsLongSX(final IndirectOperand io) {
* @param io The indirect operand pointing at the memory.
* @return The pointed address.
*/
public long computeIndirectOperand(final IndirectOperand io) {
public MemoryAddress computeIndirectOperand(final IndirectOperand io) {
final long base = io.hasBase()
? (io.getBase() instanceof Register64
? rf.get((Register64) io.getBase())
Expand All @@ -838,7 +841,7 @@ public long computeIndirectOperand(final IndirectOperand io) {
: 0L;
final long scale = io.hasScale() ? io.getScale() : 1L;
final long displacement = io.hasDisplacement() ? io.getDisplacement() : 0L;
return base + index * scale + displacement;
return new MemoryAddress(base + index * scale + displacement);
}

@Override
Expand Down
19 changes: 10 additions & 9 deletions core/src/test/java/com/ledmington/emu/TestExecution.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.ledmington.cpu.x86.Register8;
import com.ledmington.cpu.x86.SegmentRegister;
import com.ledmington.mem.Memory;
import com.ledmington.mem.MemoryAddress;
import com.ledmington.mem.MemoryController;
import com.ledmington.utils.BitUtils;

Expand Down Expand Up @@ -131,20 +132,20 @@ void setup() {
cpu = X86Cpu.builder()
.memory(new MemoryController(new Memory() {
@Override
public byte read(final long address) {
throw new UnsupportedOperationException(String.format("Attempted read at 0x%016x", address));
public byte read(final MemoryAddress address) {
throw new UnsupportedOperationException(String.format("Attempted read at %s.", address));
}

@Override
public void write(final long address, final byte value) {
public void write(final MemoryAddress address, final byte value) {
throw new UnsupportedOperationException(
String.format("Attempted write of 0x%02x at 0x%016x", value, address));
String.format("Attempted write of 0x%02x at %s.", value, address));
}

@Override
public boolean isInitialized(final long address) {
public boolean isInitialized(final MemoryAddress address) {
throw new UnsupportedOperationException(
String.format("Attempted initialization check at 0x%016x", address));
String.format("Attempted initialization check at %s.", address));
}
}))
.checkInstructions()
Expand Down Expand Up @@ -570,7 +571,7 @@ void movsxd(final Register64 r1, final Register32 r2) {
@ParameterizedTest
@MethodSource("r16m16")
void lea16(final Register16 dest, final IndirectOperand src) {
final short address = BitUtils.asShort(cpu.computeIndirectOperand(src));
final short address = BitUtils.asShort(cpu.computeIndirectOperand(src).address());
final X86RegisterFile expected = new X86RegisterFile(cpu.getRegisters());
expected.set(dest, address);
cpu.executeOne(new GeneralInstruction(Opcode.LEA, dest, src));
Expand All @@ -583,7 +584,7 @@ void lea16(final Register16 dest, final IndirectOperand src) {
@ParameterizedTest
@MethodSource("r32m32")
void lea32(final Register32 dest, final IndirectOperand src) {
final int address = BitUtils.asInt(cpu.computeIndirectOperand(src));
final int address = BitUtils.asInt(cpu.computeIndirectOperand(src).address());
final X86RegisterFile expected = new X86RegisterFile(cpu.getRegisters());
expected.set(dest, address);
cpu.executeOne(new GeneralInstruction(Opcode.LEA, dest, src));
Expand All @@ -596,7 +597,7 @@ void lea32(final Register32 dest, final IndirectOperand src) {
@ParameterizedTest
@MethodSource("r64m64")
void lea64(final Register64 dest, final IndirectOperand src) {
final long address = cpu.computeIndirectOperand(src);
final long address = cpu.computeIndirectOperand(src).address();
final X86RegisterFile expected = new X86RegisterFile(cpu.getRegisters());
expected.set(dest, address);
cpu.executeOne(new GeneralInstruction(Opcode.LEA, dest, src));
Expand Down
Loading
Loading