diff options
| author | Alexander Potapenko <glider@google.com> | 2025-09-15 16:23:10 +0200 |
|---|---|---|
| committer | Alexander Potapenko <glider@google.com> | 2025-09-19 08:38:14 +0000 |
| commit | adbde109f03932b9eee8106ce8bad4bc506d0713 (patch) | |
| tree | 1ba09463fde777a99591884afea2ad12255e2cc6 /executor | |
| parent | dd232cacbbd407c55bf26299264db0a2c3f0cfcf (diff) | |
sys/linux: executor: add IN_DX and OUT_DX to SYZOS x86 API
Add SYZOS calls that correspond to the IN and OUT x86 instructions
that perform port I/O.
These instructions have different variants, for now we just implement
the one that takes the port number from DX instead of encoding it in
the opcode.
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common_kvm_amd64_syzos.h | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h index 0e777872d..b9c3e8315 100644 --- a/executor/common_kvm_amd64_syzos.h +++ b/executor/common_kvm_amd64_syzos.h @@ -20,6 +20,8 @@ typedef enum { SYZOS_API_RDMSR = 50, SYZOS_API_WR_CRN = 70, SYZOS_API_WR_DRN = 110, + SYZOS_API_IN_DX = 130, + SYZOS_API_OUT_DX = 170, SYZOS_API_STOP, // Must be the last one } syzos_api_id; @@ -54,6 +56,11 @@ struct api_call_2 { uint64 args[2]; }; +struct api_call_3 { + struct api_call_header header; + uint64 args[3]; +}; + static void guest_uexit(uint64 exit_code); static void guest_execute_code(uint8* insns, uint64 size); static void guest_handle_cpuid(uint32 eax, uint32 ecx); @@ -61,6 +68,8 @@ static void guest_handle_wrmsr(uint64 reg, uint64 val); static void guest_handle_rdmsr(uint64 reg); static void guest_handle_wr_crn(struct api_call_2* cmd); static void guest_handle_wr_drn(struct api_call_2* cmd); +static void guest_handle_in_dx(struct api_call_2* cmd); +static void guest_handle_out_dx(struct api_call_3* cmd); typedef enum { UEXIT_END = (uint64)-1, @@ -116,6 +125,14 @@ guest_main(uint64 size, uint64 cpu) guest_handle_wr_drn((struct api_call_2*)cmd); break; } + case SYZOS_API_IN_DX: { + guest_handle_in_dx((struct api_call_2*)cmd); + break; + } + case SYZOS_API_OUT_DX: { + guest_handle_out_dx((struct api_call_3*)cmd); + break; + } } addr += cmd->size; size -= cmd->size; @@ -248,3 +265,53 @@ GUEST_CODE static noinline void guest_handle_wr_drn(struct api_call_2* cmd) return; } } + +// Read data from an I/O port, should result in KVM_EXIT_IO. +GUEST_CODE static noinline void guest_handle_in_dx(struct api_call_2* cmd) +{ + uint16 port = cmd->args[0]; + volatile int size = cmd->args[1]; + + if (size == 1) { + uint8 unused; + // Reads 1 byte from the port in DX into AL. + asm volatile("inb %1, %0" : "=a"(unused) : "d"(port)); + return; + } + if (size == 2) { + uint16 unused; + // Reads 2 bytes from the port in DX into AX. + asm volatile("inw %1, %0" : "=a"(unused) : "d"(port)); + return; + } + if (size == 4) { + uint32 unused; + // Reads 4 bytes from the port in DX into EAX. + asm volatile("inl %1, %0" : "=a"(unused) : "d"(port)); + } + return; +} + +// Write data to an I/O port, should result in KVM_EXIT_IO. +GUEST_CODE static noinline void guest_handle_out_dx(struct api_call_3* cmd) +{ + uint16 port = cmd->args[0]; + volatile int size = cmd->args[1]; + uint32 data = (uint32)cmd->args[2]; + + if (size == 1) { + // Writes 1 byte from AL to the port in DX. + asm volatile("outb %b0, %w1" ::"a"(data), "d"(port)); + return; + } + if (size == 2) { + // Writes 2 bytes from AX to the port in DX. + asm volatile("outw %w0, %w1" ::"a"(data), "d"(port)); + return; + } + if (size == 4) { + // Writes 4 bytes from EAX to the port in DX. + asm volatile("outl %k0, %w1" ::"a"(data), "d"(port)); + return; + } +} |
