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

feat!: add keyboard handling

parent f1905442
No related branches found
No related tags found
No related merge requests found
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "irq.h"
#include "idt.h" #include "idt.h"
#include "x86.h" #include "x86.h"
#include "guest/stdio.h" #include "pmio.h"
#include "shared/ide_regs.h" #include "shared/ide_regs.h"
#include "shared/hypercall_params.h"
#include "gfx/gfx.h" #include "gfx/gfx.h"
#include "ide/ide.h" #include "ide/ide.h"
...@@ -13,6 +16,8 @@ ...@@ -13,6 +16,8 @@
#include "guest/resources/resources.h" #include "guest/resources/resources.h"
// --- DEFINE ---
// If PV == 1 => uses paravirtualized drivers (when available) // If PV == 1 => uses paravirtualized drivers (when available)
// If PV == 0 => uses physical (hardware) drivers (when available) // If PV == 0 => uses physical (hardware) drivers (when available)
#if PV == 1 #if PV == 1
...@@ -33,9 +38,62 @@ ...@@ -33,9 +38,62 @@
#define sprite_position sprite_phys_position #define sprite_position sprite_phys_position
#endif #endif
uint32_t x = 50;
uint32_t y = 50;
// --- FUNCTION ---
void keyboard_handler(void) {
#if PV == 1
hyper_keyboard_params_t *p_keyboard = (hyper_keyboard_params_t *)HYPERCALL_SHARED_ADDR;
char key = (char)p_keyboard->key;
#else
char key = (char)ind(REG_KEYBOARD_DATA);
#endif
// char str[125]; snprintf(str, 125, "key received : %c\n", key);
// console_send(str);
switch (key) {
case 'w':
y -= 25;
break;
case 's':
y += 25;
break;
case 'a':
x -= 25;
break;
case 'd':
x += 25;
break;
default:
// nothing
break;
}
sprite_position(0, x, y);
}
void guest_main() { void guest_main() {
idt_init(); // Initialize interrupt subsystem idt_init(); // Initialize interrupt subsystem
handler_t hd = {keyboard_handler, "IRQ_KEYBOARD"};
irq_install_handler(IRQ_KEYBOARD, hd);
sti(); // Enable hardware interrupts sti(); // Enable hardware interrupts
// - console - // - console -
...@@ -54,9 +112,14 @@ void guest_main() { ...@@ -54,9 +112,14 @@ void guest_main() {
// - sprite - // - sprite -
sprite_init(0, sprite_tuxjedi, SPRITE_TUXJEDI_WIDTH, SPRITE_TUXJEDI_HEIGHT); sprite_init(0, sprite_tuxjedi, SPRITE_TUXJEDI_WIDTH, SPRITE_TUXJEDI_HEIGHT);
sprite_position(0, 50, 50); sprite_position(0, x, y);
sprite_visibility(0, 1); sprite_visibility(0, 1);
// - main loop -
char *s = "-- guest enter while 1 --";
console_send(s);
while (1);
halt(); halt();
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "utils.h" #include "utils.h"
#include "descriptors.h" #include "descriptors.h"
#include "x86.h" #include "x86.h"
#include "irq.h"
#define GDT_KERNEL_CODE_SELECTOR 0x08 #define GDT_KERNEL_CODE_SELECTOR 0x08
...@@ -53,12 +54,18 @@ static idt_entry_t idt_build_entry(uint16_t selector, uint32_t offset, uint8_t t ...@@ -53,12 +54,18 @@ static idt_entry_t idt_build_entry(uint16_t selector, uint32_t offset, uint8_t t
// Low level handler defined in idt_asm.s // Low level handler defined in idt_asm.s
void _irq0(); void _irq0();
void _irq1();
// IRQ handler // IRQ handler
void irq_handler(uint32_t irq_number) { void irq_handler(uint32_t irq_number) {
handler_t *hd = irq_get_handler(irq_number);
if (hd != 0) hd->func();
} }
void idt_init() { void idt_init() {
irq_init();
idt_ptr.limit = sizeof(idt)-1; idt_ptr.limit = sizeof(idt)-1;
idt_ptr.base = (uint32_t)&idt; idt_ptr.base = (uint32_t)&idt;
...@@ -66,6 +73,7 @@ void idt_init() { ...@@ -66,6 +73,7 @@ void idt_init() {
memset(idt, 0, sizeof(idt)); memset(idt, 0, sizeof(idt));
idt[0] = idt_build_entry(GDT_KERNEL_CODE_SELECTOR, (uint32_t)_irq0, TYPE_INTERRUPT_GATE, DPL_KERNEL); idt[0] = idt_build_entry(GDT_KERNEL_CODE_SELECTOR, (uint32_t)_irq0, TYPE_INTERRUPT_GATE, DPL_KERNEL);
idt[1] = idt_build_entry(GDT_KERNEL_CODE_SELECTOR, (uint32_t)_irq1, TYPE_INTERRUPT_GATE, DPL_KERNEL);
idt_load(&idt_ptr); idt_load(&idt_ptr);
} }
...@@ -15,6 +15,11 @@ _irq0: ...@@ -15,6 +15,11 @@ _irq0:
push 0 ; put irq number on the stack push 0 ; put irq number on the stack
jmp irq_handler_wrapper jmp irq_handler_wrapper
global _irq1
_irq1:
push 1 ; put irq number on the stack
jmp irq_handler_wrapper
extern irq_handler extern irq_handler
irq_handler_wrapper: irq_handler_wrapper:
......
#include "irq.h"
#include "utils.h"
#include <stdint.h>
// --- DEFINE ---
#define IRQ_COUNT (IRQ_LAST-IRQ_FIRST + 1)
static handler_t irq_handlers[IRQ_COUNT];
// --- FUNCTION ---
void irq_init() {
memset(irq_handlers, 0, sizeof(irq_handlers));
}
void irq_install_handler(uint32_t irq, handler_t handler) {
irq_handlers[irq] = handler;
}
handler_t *irq_get_handler(uint32_t irq) {
return &irq_handlers[irq];
}
#ifndef _IRQ_H_
#define _IRQ_H_
#include <stdint.h>
// --- DEFINE ---
#define IRQ_FIRST 0
#define IRQ_LAST 15
#define IRQ_TIMER 0
#define IRQ_KEYBOARD 1
typedef struct {
void (*func)(void); // pointer to handler function
char name[64]; // associate a name to the function (for debugging purposes)
} handler_t;
// --- FUNCTION ---
// Initializes the array of IRQ handlers.
void irq_init();
// Installs a handler for the given IRQ.
// The irq parameter must be in the range [0,15] inclusive.
void irq_install_handler(uint32_t irq, handler_t handler);
// Retrieves the handler for a given IRQ.
// The irq parameter must be in the range [0,15] inclusive.
// Returns NULL if there is no handler for the given IRQ.
handler_t *irq_get_handler(uint32_t irq);
#endif // _IRQ_H_
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
void sprite_phys_init(uint8_t id, uint8_t *data, uint32_t width, uint32_t height) { void sprite_phys_init(uint8_t id, uint8_t *data, uint32_t width, uint32_t height) {
while(*(uint32_t *)REG_SPRITE_ST != 64);
*(uint32_t *)REG_SPRITE_CMD = 9; *(uint32_t *)REG_SPRITE_CMD = 9;
*(uint32_t *)REG_SPRITE_CMD = 27; *(uint32_t *)REG_SPRITE_CMD = 27;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define HYPERCALL_CODE_SPRITE_INIT 5 #define HYPERCALL_CODE_SPRITE_INIT 5
#define HYPERCALL_CODE_SPRITE_VISI 6 #define HYPERCALL_CODE_SPRITE_VISI 6
#define HYPERCALL_CODE_SPRITE_POS 7 #define HYPERCALL_CODE_SPRITE_POS 7
#define HYPERCALL_CODE_KEYBOARD 8
#define REG_TIMER_CMD 0x43 #define REG_TIMER_CMD 0x43
#define REG_TIMER_DATA 0x40 #define REG_TIMER_DATA 0x40
...@@ -29,6 +30,8 @@ ...@@ -29,6 +30,8 @@
#define REG_SPRITE_CMD 0x3E800010 #define REG_SPRITE_CMD 0x3E800010
#define REG_SPRITE_DATA 0x3E800020 #define REG_SPRITE_DATA 0x3E800020
#define REG_KEYBOARD_DATA 0x60
// --- SHARED STRUCT --- // --- SHARED STRUCT ---
typedef struct { typedef struct {
...@@ -74,6 +77,11 @@ typedef struct { ...@@ -74,6 +77,11 @@ typedef struct {
uint32_t y; // y position uint32_t y; // y position
} __attribute__((packed)) hyper_sprite_position_params_t; } __attribute__((packed)) hyper_sprite_position_params_t;
typedef struct {
uint32_t key; // code of the pressed key
} __attribute__((packed)) hyper_keyboard_params_t;
// --- FUNCTION --- // --- FUNCTION ---
// ... // ...
......
...@@ -132,6 +132,7 @@ static state_t *state_check(uint64_t addr, uint8_t size, uint32_t value) { ...@@ -132,6 +132,7 @@ static state_t *state_check(uint64_t addr, uint8_t size, uint32_t value) {
break; break;
case OP_READ_INJECT: case OP_READ_INJECT:
case OP_READ_INJECT_KEY:
if (state->addr == addr && state->size == size) if (state->addr == addr && state->size == size)
return state; return state;
...@@ -176,6 +177,13 @@ static void state_compute(state_t *state, uint32_t value, uint8_t *addr) { ...@@ -176,6 +177,13 @@ static void state_compute(state_t *state, uint32_t value, uint8_t *addr) {
state->size * 8, state->addr, state->value); state->size * 8, state->addr, state->value);
break; break;
case OP_READ_INJECT_KEY:
// WARNING: operation should not be here, but f*** it
printf("OPERATION : send last key pressed %c...\n", (char)last_key_pressed);
injecte_data(addr, state->size, last_key_pressed);
break;
case OP_WRITE_STORE_LOOP: case OP_WRITE_STORE_LOOP:
// - prevent advancing to the next state if loop is ongoing - // - prevent advancing to the next state if loop is ongoing -
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
typedef void (*state_handler_t)(struct kvm_run *run, ...); typedef void (*state_handler_t)(struct kvm_run *run, ...);
extern state_handler_t const STATE_HANDLERS[]; extern state_handler_t const STATE_HANDLERS[];
extern uint32_t last_key_pressed;
// --- FUNCITON --- // --- FUNCITON ---
......
...@@ -28,7 +28,7 @@ state_t STATE_TIMER[] = { ...@@ -28,7 +28,7 @@ state_t STATE_TIMER[] = {
state_t STATE_GFX_INIT[] = { state_t STATE_GFX_INIT[] = {
{ OP_READ_INJECT, REG_GFX_INIT_ST, 0, 1, NULL }, { OP_READ_INJECT, REG_GFX_INIT_ST, 0, 4, NULL },
{ OP_WRITE_EQUAL, REG_GFX_INIT_CMD, 5, 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_w },
{ OP_WRITE_STORE, REG_GFX_INIT_DATA, 0, 4, op_callback_gfx_init_store_h }, { OP_WRITE_STORE, REG_GFX_INIT_DATA, 0, 4, op_callback_gfx_init_store_h },
...@@ -51,7 +51,8 @@ state_t STATE_IDE[] = { ...@@ -51,7 +51,8 @@ state_t STATE_IDE[] = {
state_t STATE_SPRITE_INIT[] = { state_t STATE_SPRITE_INIT[] = {
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x9, 4, op_callback_sprite_init_prepare }, { OP_READ_INJECT, REG_SPRITE_ST, 64, 4, op_callback_sprite_init_prepare },
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x9, 4, NULL },
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x1B, 4, NULL }, { OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x1B, 4, NULL },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_init_store_id }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_init_store_id },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_init_store_width }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_init_store_width },
...@@ -65,17 +66,23 @@ state_t STATE_SPRITE_VIS[] = { ...@@ -65,17 +66,23 @@ state_t STATE_SPRITE_VIS[] = {
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0xE, 4, NULL }, { OP_WRITE_EQUAL, REG_SPRITE_CMD, 0xE, 4, NULL },
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x1B, 4, NULL }, { OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x1B, 4, NULL },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_visibility_store_id }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_visibility_store_id },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_visibility_store_toggle }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 1, op_callback_sprite_visibility_store_toggle },
{ OP_EMUL_END, 0, 0, 0, NULL }, { OP_EMUL_END, 0, 0, 0, op_callback_sprite_visibility_conclude },
}; };
state_t STATE_SPRITE_POS[] = { state_t STATE_SPRITE_POS[] = {
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x23, 4, NULL }, { OP_WRITE_EQUAL, REG_SPRITE_CMD, 35, 4, NULL },
{ OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x1B, 4, NULL }, { OP_WRITE_EQUAL, REG_SPRITE_CMD, 0x1B, 4, NULL },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_position_store_id }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_position_store_id },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_position_store_x }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_position_store_x },
{ OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_position_store_y }, { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 4, op_callback_sprite_position_store_y },
{ OP_EMUL_END, 0, 0, 0, op_callback_sprite_position_conclude },
};
state_t STATE_KEYBOARD[] = {
{ OP_READ_INJECT_KEY, REG_KEYBOARD_DATA, 0, 4, NULL },
{ OP_EMUL_END, 0, 0, 0, NULL }, { OP_EMUL_END, 0, 0, 0, NULL },
}; };
...@@ -87,6 +94,7 @@ state_t *STATE_ALL_STARTERS[] = { ...@@ -87,6 +94,7 @@ state_t *STATE_ALL_STARTERS[] = {
&STATE_SPRITE_INIT[0], &STATE_SPRITE_INIT[0],
&STATE_SPRITE_VIS[0], &STATE_SPRITE_VIS[0],
&STATE_SPRITE_POS[0], &STATE_SPRITE_POS[0],
&STATE_KEYBOARD[0],
}; };
bool flag_stop_loop = false; bool flag_stop_loop = false;
...@@ -110,7 +118,7 @@ static hyper_sprite_position_params_t param_sprite_pos; ...@@ -110,7 +118,7 @@ static hyper_sprite_position_params_t param_sprite_pos;
static uint64_t loop_idx = BUF_SIZE; static uint64_t loop_idx = BUF_SIZE;
static uint8_t loop_buf_8[BUF_SIZE]; static uint8_t loop_buf_8[BUF_SIZE];
static uint16_t *loop_buf_16 = (uint16_t *)loop_buf_8; static uint16_t *loop_buf_16 = (uint16_t *)loop_buf_8;
static uint32_t *loop_buf_32 = (uint32_t *)loop_buf_8; // static uint32_t *loop_buf_32 = (uint32_t *)loop_buf_8;
// --- FUNCTION --- // --- FUNCTION ---
...@@ -339,3 +347,12 @@ void op_callback_sprite_position_conclude(void *addr) { ...@@ -339,3 +347,12 @@ void op_callback_sprite_position_conclude(void *addr) {
sprites[p_sp_pos->id].y = p_sp_pos->y; sprites[p_sp_pos->id].y = p_sp_pos->y;
} }
// === KEYBOARD ===
void op_keyboard_pv_send_code(void *shared_buf, uint32_t key) {
hyper_keyboard_params_t param_key;
param_key.key = key;
memcpy(shared_buf, (void *)&param_key, sizeof(param_key));
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
// --- DEFINE --- // --- DEFINE ---
#define STATE_MACHINE_NUM 3 #define STATE_MACHINE_NUM 7
typedef enum { typedef enum {
...@@ -15,6 +15,7 @@ typedef enum { ...@@ -15,6 +15,7 @@ typedef enum {
OP_WRITE_STORE, // Store the written value into a specific location (used in callbacks) OP_WRITE_STORE, // Store the written value into a specific location (used in callbacks)
OP_WRITE_STORE_LOOP, // Store the written value into a specific location multiple time OP_WRITE_STORE_LOOP, // Store the written value into a specific location multiple time
OP_READ_INJECT, // Inject a value into the guest from a specific address OP_READ_INJECT, // Inject a value into the guest from a specific address
OP_READ_INJECT_KEY, // Inject last key pressed into the guest from a specific address
OP_EMUL_END, // End of the state machine, with an callback for completion OP_EMUL_END, // End of the state machine, with an callback for completion
} operation_t; } operation_t;
...@@ -267,4 +268,6 @@ void op_callback_sprite_position_store_y(void *addr); ...@@ -267,4 +268,6 @@ void op_callback_sprite_position_store_y(void *addr);
*/ */
void op_callback_sprite_position_conclude(void *addr); void op_callback_sprite_position_conclude(void *addr);
void op_keyboard_pv_send_code(void *shared_buf, uint32_t key);
#endif // _OPERATION_H_ #endif // _OPERATION_H_
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <err.h> #include <err.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -32,6 +33,7 @@ uint32_t width_gfx; ...@@ -32,6 +33,7 @@ uint32_t width_gfx;
uint32_t height_gfx; uint32_t height_gfx;
gfx_context_t *ctxt; gfx_context_t *ctxt;
sprite_t sprites[MAX_SPRITES]; sprite_t sprites[MAX_SPRITES];
uint32_t last_key_pressed;
char *disk_path; char *disk_path;
...@@ -143,6 +145,25 @@ int main(int argc, char* argv[]) ...@@ -143,6 +145,25 @@ int main(int argc, char* argv[])
// Close the file descriptor // Close the file descriptor
close(binfd); close(binfd);
// -- 5.5. Create virtual PIC (Programmable Interrupt Controller) --
if (ioctl(vmfd, KVM_CREATE_IRQCHIP, NULL) < 0)
err(1, "Error: creating the vPIC\n");
struct kvm_irqchip irqchip = {
.chip_id = 0, // 0 = PIC1, 1 = PIC2, 2 = IOAPIC
};
// retrieve the PIC registers
if (ioctl(vmfd, KVM_GET_IRQCHIP, &irqchip) < 0)
err(1, "Error: retrieving the PIC registers\n");
// configure the PIC to have auto-acknoledge from the guest
irqchip.chip.pic.auto_eoi = 1;
// set the PIC registers
if (ioctl(vmfd, KVM_SET_IRQCHIP, &irqchip) < 0)
err(1, "Error: setting the PIC registers\n");
// -- 6.1. Create a vCPU -- // -- 6.1. Create a vCPU --
vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0); vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0);
if (vcpufd == -1) err(1, "KVM_CREATE_VCPU"); if (vcpufd == -1) err(1, "KVM_CREATE_VCPU");
...@@ -195,10 +216,44 @@ int main(int argc, char* argv[]) ...@@ -195,10 +216,44 @@ int main(int argc, char* argv[])
ctxt = gfx_create("Basic Example", width_gfx, height_gfx); ctxt = gfx_create("Basic Example", width_gfx, height_gfx);
if (!ctxt) err(1, "KVM_SET_REGS"); if (!ctxt) err(1, "KVM_SET_REGS");
while (1) { bool done = false;
while (!done) {
gfx_background_update(ctxt);
// - handle key -
SDL_Keycode key = gfx_keypressed();
if (key != 0) {
// gfx_background_update(ctxt); if (key == SDLK_ESCAPE) {
done = true;
}
else {
// - write key code to guest -
last_key_pressed = (uint32_t)key;
// WARNING: no need to do it in emulation, but whatever...
op_keyboard_pv_send_code(shared_buf, last_key_pressed);
// - trigger interrupt -
struct kvm_irq_level irq_level;
irq_level.irq = 1; // 1 -> key interrupt
// drive signal -> up (1)
irq_level.level = 1;
if (ioctl(vmfd, KVM_IRQ_LINE, &irq_level) < 0)
err(1, "Error: driving irq signal up\n");
// drive signal -> down (0)
irq_level.level = 0;
if (ioctl(vmfd, KVM_IRQ_LINE, &irq_level) < 0)
err(1, "Error: driving irq signal down\n");
}
}
// - handle sprites -
for (uint8_t i = 0; i < MAX_SPRITES; i++) { for (uint8_t i = 0; i < MAX_SPRITES; i++) {
if (sprites[i].toggle == 1) { if (sprites[i].toggle == 1) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment