Skip to content
Snippets Groups Projects
Commit 7b85ba6c authored by adrian.spycher's avatar adrian.spycher
Browse files

feat!: separate operation from handler, add state machine manager

parent d309cb2c
No related branches found
No related tags found
No related merge requests found
......@@ -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_
......@@ -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:
}
......@@ -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_
#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) ? &param_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) ? &param_gfx_init : (hyper_init_gfx_params_t *)addr;
printf("hypercall : initializing gfx %dx%d...\n", p_gfx_init->width, p_gfx_init->height);
// TODO:
}
#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_
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment