diff --git a/shared/hypercall_params.h b/shared/hypercall_params.h index 6916bc63ce65406ae96b26bfe6fe112fbbdb40ba..c1338ad75713eb727bd9cd84166b8768e7454f84 100644 --- a/shared/hypercall_params.h +++ b/shared/hypercall_params.h @@ -14,6 +14,13 @@ #define HYPERCALL_CODE_TIMER 2 #define HYPERCALL_CODE_GFX_INIT 3 +#define REG_TIMER_CMD 0x43 +#define REG_TIMER_DATA 0x40 + +#define REG_GFX_INIT_ST 0x4E700000 +#define REG_GFX_INIT_CMD 0x4E700100 +#define REG_GFX_INIT_DATA 0x4E700200 + // --- SHARED STRUCT --- typedef struct { @@ -36,4 +43,4 @@ typedef struct { // ... -#endif +#endif // _HYPERCALL_PARAMS_H_ diff --git a/vmm/handler.c b/vmm/handler.c index 00b058be194a4d8ed7ed67a5a078421d53ece341..65c476afad22c1a9a0bf29a4f97be0022792276b 100644 --- a/vmm/handler.c +++ b/vmm/handler.c @@ -4,7 +4,9 @@ #include <stdio.h> #include <stdint.h> #include <unistd.h> +#include <stdbool.h> +#include "operation.h" #include "shared/hypercall_params.h" // --- DEFINE --- @@ -16,27 +18,13 @@ state_handler_t const STATE_HANDLERS[] = { [KVM_EXIT_MMIO] = handle_mmio, }; -static state_t const STATE_TIMER[] = { - - { OP_WRITE_EQUAL, 0x43, 20, 2, NULL }, - { OP_WRITE_EQUAL, 0x40, 0, 4, NULL }, - { OP_WRITE_EQUAL, 0, 0, 0, NULL }, -}; - -static state_t const STATE_VGA[] = { - - { OP_WRITE_EQUAL, 0x3C2, 0x67, 1, NULL }, - { OP_WRITE_EQUAL, 0x3C4, 0xF02, 2, NULL }, - { OP_WRITE_EQUAL, 0x3CE, 0x506, 2, NULL }, - { OP_WRITE_EQUAL, 0x3DA, 0x80, 1, NULL }, - { OP_WRITE_EQUAL, 0x3C0, 0x20, 1, NULL }, - { OP_WRITE_EQUAL, 0x3C5, 0x0F, 1, NULL }, - { OP_WRITE_EQUAL, 0, 0, 0, NULL }, -}; +static state_t *current_state = NULL; // --- STATIC FUNCTION --- -static uint32_t retrieve_value(uint8_t *addr, uint8_t size) { +// - UTILS - + +static uint32_t retrieve_data(uint8_t *addr, uint8_t size) { uint32_t value; @@ -55,13 +43,124 @@ static uint32_t retrieve_value(uint8_t *addr, uint8_t size) { break; default: - errx(1, "Unsupported size trying to retrieve value.\n"); + errx(1, "Unsupported size trying to retrieve data.\n"); break; } return value; } +static void injecte_data(uint8_t *addr, uint8_t size, uint32_t value) { + + switch (size) { + + case 1: + *((uint8_t *)addr) = (uint8_t)value; + break; + + case 2: + *((uint16_t *)addr) = (uint16_t)value; + break; + + case 4: + *((uint32_t *)addr) = (uint32_t)value; + break; + + default: + errx(1, "Unsupported size trying to inject data.\n"); + break; + } +} + +static state_t *state_check(uint64_t addr, uint8_t size, uint32_t value) { + + for (uint32_t i = 0; i < STATE_MACHINE_NUM + 1; i++) { + + // - get next state or first state of one of all state machine available - + if (i == 0 && current_state == NULL) continue; + + state_t *next_state = (i == 0) ? current_state : STATE_ALL_STARTERS[i - 1]; + + // - check the validity of the next state - + switch (next_state->op) { + + case OP_WRITE_EQUAL: + + if (next_state->addr == addr && next_state->size == size && next_state->value == value) + return next_state; + break; + + case OP_WRITE_STORE: + + if (next_state->addr == addr && next_state->size == size && next_state->callback != NULL) + return next_state; + break; + + case OP_EMUL_END: + case OP_READ_INJECT: + // nothing... + break; + } + } + + return NULL; +} + +static void state_compute(state_t *state, uint32_t value) { + + switch (state->op) { + + case OP_WRITE_STORE: + + state->callback(&value); + break; + + case OP_READ_INJECT: + + injecte_data((uint8_t *)&state->addr, state->size, state->value); + printf("PMIO guest read: size=%d port=0x%x [value injected by VMM=0x%x]\n", + state->size * 8, state->addr, state->value); + break; + + case OP_EMUL_END: + case OP_WRITE_EQUAL: + // nothing... + break; + } + + // - check and compute last operation - + current_state = state + 1; + if (current_state->op == OP_EMUL_END) { + + if (current_state->callback != NULL) + current_state->callback(NULL); + + current_state = NULL; + } +} + +// - OPERATION WRAPPER - + +static void wrapper_op_console(uint8_t *shared_buf, uint8_t *mem) { + + hyper_virtual_console_params_t *p_consol = (hyper_virtual_console_params_t *)shared_buf; + p_consol->msg = p_consol->msg + (uint64_t)mem; + + op_callback_console_conclude(p_consol); +} + +static void wrapper_op_timer(uint8_t *shared_buf) { + + hyper_timer_sleep_params_t *p_timer = (hyper_timer_sleep_params_t *)shared_buf; + op_callback_timer_conclude(p_timer); +} + +static void wrapper_op_gfx_init(uint8_t *shared_buf) { + + hyper_init_gfx_params_t *p_init_gfx = (hyper_init_gfx_params_t *)shared_buf; + op_callback_gfx_init_conclude(p_init_gfx); +} + // --- FUNCTION --- // - VMM EXIT REASON HANDLER - @@ -75,20 +174,19 @@ void handle_pmio(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem) { if (run->io.direction == KVM_EXIT_IO_OUT) { - uint32_t value = retrieve_value((uint8_t *)run + run->io.data_offset, run->io.size); - printf("PMIO guest write: \tsize=%d \tport=0x%x \tvalue=%d\n", run->io.size * 8, run->io.port, value); + uint32_t value = retrieve_data((uint8_t *)run + run->io.data_offset, run->io.size); + printf("PMIO guest write: \tport=0x%x \tsize=%d \tvalue=%d\n", run->io.port, run->io.size * 8, value); - switch (run->io.port) { + if (run->io.port == HYPERCALL_PMIO_ADDR) { - case HYPERCALL_PMIO_ADDR: - handle_hypercall(value, shared_buf, mem); - break; + handle_hypercall(value, shared_buf, mem); - case 0x43: - break; + } else { - case 0x40: - break; + current_state = state_check(run->io.port, run->io.size, value); + + if (current_state != NULL) + state_compute(current_state, value); } } } @@ -97,8 +195,13 @@ void handle_mmio(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem) { if (run->mmio.is_write) { - uint32_t value = retrieve_value((uint8_t *)run->mmio.data, run->mmio.len); + uint32_t value = retrieve_data((uint8_t *)run->mmio.data, run->mmio.len); printf("MMIO guest write: \taddr=0x%llx \tlen=%d \tvalue=%d\n", run->mmio.phys_addr, run->mmio.len * 8, value); + + current_state = state_check(run->mmio.phys_addr, run->mmio.len, value); + + if (current_state != NULL) + state_compute(current_state, value); } } @@ -109,43 +212,20 @@ void handle_hypercall(uint32_t code, uint8_t *shared_buf, uint8_t *mem) { switch (code) { case HYPERCALL_CODE_CONSOLE: - handle_hypercall_console(shared_buf, mem); + wrapper_op_console(shared_buf, mem); break; case HYPERCALL_CODE_TIMER: - handle_hypercall_timer(shared_buf); + wrapper_op_timer(shared_buf); break; case HYPERCALL_CODE_GFX_INIT: - handle_hypercall_gfx_init(shared_buf); + wrapper_op_gfx_init(shared_buf); break; default: - // TODO: + errx(1, "Unsupported hypercall code.\n"); break; } } -void handle_hypercall_console(uint8_t *shared_buf, uint8_t *mem) { - - hyper_virtual_console_params_t *p_consol = (hyper_virtual_console_params_t *)shared_buf; - - printf("hypercall : sending a message...\n"); - printf("%s\n", p_consol->msg + mem); -} - -void handle_hypercall_timer(uint8_t *shared_buf) { - - hyper_timer_sleep_params_t *p_timer = (hyper_timer_sleep_params_t *)shared_buf; - - printf("hypercall : setting up a %dus timer...\n", p_timer->us); - sleep(p_timer->us / 1e6); -} - -void handle_hypercall_gfx_init(uint8_t *shared_buf) { - - hyper_init_gfx_params_t *p_init_gfx = (hyper_init_gfx_params_t *)shared_buf; - - printf("hypercall : initializing gfx...\n"); - // TODO: -} diff --git a/vmm/handler.h b/vmm/handler.h index 29ada075aeb57bf58497be0650d500a1c4751358..205bc24545566fb0cd4db364935ef808a3374e12 100644 --- a/vmm/handler.h +++ b/vmm/handler.h @@ -6,24 +6,8 @@ // --- DEFINE --- -typedef enum { - - OP_WRITE_EQUAL, - OP_READ_INJECT, - OP_EMUL_END, -} operation_t; - typedef void (*state_handler_t)(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem); -typedef struct { - - operation_t op; // the operation to perform - uint32_t addr; // the address written to/read from - uint32_t value; // the expected written value or value to inject - uint8_t size; // the size of the operation (8, 16 or 32 bits) - void (*callback)(); // custom function that would be executed at the end of the state -} state_t; - extern state_handler_t const STATE_HANDLERS[]; // --- FUNCITON --- @@ -36,10 +20,4 @@ void handle_mmio(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem); void handle_hypercall(uint32_t code, uint8_t *shared_buf, uint8_t *mem); -void handle_hypercall_console(uint8_t *shared_buf, uint8_t *mem); - -void handle_hypercall_timer(uint8_t *shared_buf); - -void handle_hypercall_gfx_init(uint8_t *shared_buf); - -#endif // !_STATES_H_ +#endif // _STATES_H_ diff --git a/vmm/operation.c b/vmm/operation.c new file mode 100644 index 0000000000000000000000000000000000000000..471256fd52eca87574b9e7aa731aefccb81d20d3 --- /dev/null +++ b/vmm/operation.c @@ -0,0 +1,79 @@ +#include "operation.h" + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> + +#include "shared/hypercall_params.h" + +// --- DEFINE --- + +state_t STATE_TIMER[] = { + + { OP_WRITE_EQUAL, REG_TIMER_CMD, 20, 2, NULL }, + { OP_WRITE_STORE, REG_TIMER_DATA, 0, 4, op_callback_timer_store }, + { OP_EMUL_END, 0, 0, 0, op_callback_timer_conclude }, +}; + +state_t STATE_GFX_INIT[] = { + + { OP_READ_INJECT, REG_GFX_INIT_ST, 0, 4, NULL }, + { OP_WRITE_EQUAL, REG_GFX_INIT_CMD, 5, 4, NULL }, + { OP_WRITE_STORE, REG_GFX_INIT_DATA, 0, 4, op_callback_gfx_init_store_w}, + { OP_WRITE_STORE, REG_GFX_INIT_DATA, 0, 4, op_callback_gfx_init_store_h}, + { OP_EMUL_END, 0, 0, 0, op_callback_gfx_init_conclude}, +}; + +state_t *STATE_ALL_STARTERS[] = { + + &STATE_TIMER[0], + &STATE_GFX_INIT[0], +}; + +static hyper_timer_sleep_params_t param_timer; +static hyper_init_gfx_params_t param_gfx_init; + +// --- STATIC FUNCTION --- + +// ... + +// --- FUNCTION --- + +void op_callback_console_conclude(void *addr) { + + hyper_virtual_console_params_t *p_consol = (hyper_virtual_console_params_t *)addr; + + printf("hypercall : sending a message...\n"); + printf("%s\n", (char *)p_consol->msg); +} + +void op_callback_timer_store(void *addr) { + + param_timer.us = *(uint32_t *)addr; +} + +void op_callback_timer_conclude(void *addr) { + + hyper_timer_sleep_params_t *p_timer = (addr == NULL) ? ¶m_timer : (hyper_timer_sleep_params_t *)addr; + + printf("hypercall : setting up a %dus timer...\n", p_timer->us); + sleep(p_timer->us / 1e6); +} + +void op_callback_gfx_init_store_w(void *addr) { + + param_gfx_init.width = *(uint32_t *)addr; +} + +void op_callback_gfx_init_store_h(void *addr) { + + param_gfx_init.height = *(uint32_t *)addr; +} + +void op_callback_gfx_init_conclude(void *addr) { + + hyper_init_gfx_params_t *p_gfx_init = (addr == NULL) ? ¶m_gfx_init : (hyper_init_gfx_params_t *)addr; + + printf("hypercall : initializing gfx %dx%d...\n", p_gfx_init->width, p_gfx_init->height); + // TODO: +} diff --git a/vmm/operation.h b/vmm/operation.h new file mode 100644 index 0000000000000000000000000000000000000000..e77ef141188a6d798fdadde90ada7ddd46cd4735 --- /dev/null +++ b/vmm/operation.h @@ -0,0 +1,51 @@ +#define _OPERATION_H_ +#ifdef _OPERATION_H_ + +#include <stdint.h> +#include <unistd.h> + + +// --- DEFINE --- + +#define STATE_MACHINE_NUM 2 + +typedef enum { + + OP_WRITE_EQUAL, + OP_WRITE_STORE, + OP_READ_INJECT, + OP_EMUL_END, +} operation_t; + +typedef struct { + + operation_t op; // the operation to perform + uint32_t addr; // the address written to/read from + uint32_t value; // the expected written value or value to inject + uint8_t size; // the size of the operation (8, 16 or 32 bits) + void (*callback)(void *addr); // custom function that would be executed at the end of the state +} state_t; + +extern state_t *STATE_ALL_STARTERS[]; + +extern state_t STATE_TIMER[]; + +extern state_t STATE_GFX_INIT[]; + +extern state_t STATE_VGA[]; + +// --- FUNCITON --- + +void op_callback_console_conclude(void *addr); + +void op_callback_timer_store(void *addr); + +void op_callback_timer_conclude(void *addr); + +void op_callback_gfx_init_store_w(void *addr); + +void op_callback_gfx_init_store_h(void *addr); + +void op_callback_gfx_init_conclude(void *addr); + +#endif // _OPERATION_H_