diff --git a/guest/guest_main.c b/guest/guest_main.c index f76e2fa85657fd1516ab418c9f12aa30cddd362f..1d0cfed8841b0af4a69df8d046ae7bed3a813542 100644 --- a/guest/guest_main.c +++ b/guest/guest_main.c @@ -1,9 +1,12 @@ #include <stdint.h> +#include <stdbool.h> +#include "irq.h" #include "idt.h" #include "x86.h" -#include "guest/stdio.h" +#include "pmio.h" #include "shared/ide_regs.h" +#include "shared/hypercall_params.h" #include "gfx/gfx.h" #include "ide/ide.h" @@ -13,6 +16,8 @@ #include "guest/resources/resources.h" +// --- DEFINE --- + // If PV == 1 => uses paravirtualized drivers (when available) // If PV == 0 => uses physical (hardware) drivers (when available) #if PV == 1 @@ -33,9 +38,62 @@ #define sprite_position sprite_phys_position #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() { idt_init(); // Initialize interrupt subsystem + + handler_t hd = {keyboard_handler, "IRQ_KEYBOARD"}; + irq_install_handler(IRQ_KEYBOARD, hd); + sti(); // Enable hardware interrupts // - console - @@ -54,9 +112,14 @@ void guest_main() { // - sprite - 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); + // - main loop - + char *s = "-- guest enter while 1 --"; + console_send(s); + + while (1); halt(); } diff --git a/guest/idt.c b/guest/idt.c index f49386dbe0193b45cff65f8ceca1d39a40f5bc0b..47d54cc77e7b826eee201cb1109d5262ea1ac926 100644 --- a/guest/idt.c +++ b/guest/idt.c @@ -2,6 +2,7 @@ #include "utils.h" #include "descriptors.h" #include "x86.h" +#include "irq.h" #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 // Low level handler defined in idt_asm.s void _irq0(); +void _irq1(); // IRQ handler void irq_handler(uint32_t irq_number) { + + handler_t *hd = irq_get_handler(irq_number); + if (hd != 0) hd->func(); } void idt_init() { + irq_init(); + idt_ptr.limit = sizeof(idt)-1; idt_ptr.base = (uint32_t)&idt; @@ -66,6 +73,7 @@ void idt_init() { memset(idt, 0, sizeof(idt)); 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); } diff --git a/guest/idt_asm.s b/guest/idt_asm.s index bfd31a8b6510d004419aafdac1ca81559c4adb7a..1f0519f1bd80c7b61d1ac7ddd34b329faf97f0e7 100644 --- a/guest/idt_asm.s +++ b/guest/idt_asm.s @@ -15,6 +15,11 @@ _irq0: push 0 ; put irq number on the stack jmp irq_handler_wrapper +global _irq1 +_irq1: + push 1 ; put irq number on the stack + jmp irq_handler_wrapper + extern irq_handler irq_handler_wrapper: diff --git a/guest/irq.c b/guest/irq.c new file mode 100644 index 0000000000000000000000000000000000000000..a421e74746dcde8f656a4c1e452cb2394b957874 --- /dev/null +++ b/guest/irq.c @@ -0,0 +1,28 @@ +#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]; +} + diff --git a/guest/irq.h b/guest/irq.h new file mode 100644 index 0000000000000000000000000000000000000000..219f9187f2750bb053f64ad5f51c375c66b5ec29 --- /dev/null +++ b/guest/irq.h @@ -0,0 +1,34 @@ +#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_ diff --git a/guest/sprite/sprite_phys.c b/guest/sprite/sprite_phys.c index dea1b2da23ea4ce2a163391715a68c8b132301d9..7f4220b2e467fe69d37992738176eb28520b2a13 100644 --- a/guest/sprite/sprite_phys.c +++ b/guest/sprite/sprite_phys.c @@ -11,6 +11,8 @@ 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 = 27; diff --git a/shared/hypercall_params.h b/shared/hypercall_params.h index ea5ad45721d7b2f6e74ad9f66c6e23d8b823db32..e4f4e15aec30e2206a68b5cf025837319160ea60 100644 --- a/shared/hypercall_params.h +++ b/shared/hypercall_params.h @@ -17,6 +17,7 @@ #define HYPERCALL_CODE_SPRITE_INIT 5 #define HYPERCALL_CODE_SPRITE_VISI 6 #define HYPERCALL_CODE_SPRITE_POS 7 +#define HYPERCALL_CODE_KEYBOARD 8 #define REG_TIMER_CMD 0x43 #define REG_TIMER_DATA 0x40 @@ -29,6 +30,8 @@ #define REG_SPRITE_CMD 0x3E800010 #define REG_SPRITE_DATA 0x3E800020 +#define REG_KEYBOARD_DATA 0x60 + // --- SHARED STRUCT --- typedef struct { @@ -74,6 +77,11 @@ typedef struct { uint32_t y; // y position } __attribute__((packed)) hyper_sprite_position_params_t; +typedef struct { + + uint32_t key; // code of the pressed key +} __attribute__((packed)) hyper_keyboard_params_t; + // --- FUNCTION --- // ... diff --git a/vmm/handler.c b/vmm/handler.c index 07c8cfbba2fbed530a79910ac194f1b72a9493e9..957b38bf825af34b13ac0f0fc392356a5e9ce746 100644 --- a/vmm/handler.c +++ b/vmm/handler.c @@ -132,6 +132,7 @@ static state_t *state_check(uint64_t addr, uint8_t size, uint32_t value) { break; case OP_READ_INJECT: + case OP_READ_INJECT_KEY: if (state->addr == addr && state->size == size) return state; @@ -176,6 +177,13 @@ static void state_compute(state_t *state, uint32_t value, uint8_t *addr) { state->size * 8, state->addr, state->value); 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: // - prevent advancing to the next state if loop is ongoing - diff --git a/vmm/handler.h b/vmm/handler.h index d604a76884170fbbe2f0fc7228cbc6031e53393d..d5ec52523df9d1233b5a5c572ec63abb88ea2e67 100644 --- a/vmm/handler.h +++ b/vmm/handler.h @@ -10,6 +10,7 @@ typedef void (*state_handler_t)(struct kvm_run *run, ...); extern state_handler_t const STATE_HANDLERS[]; +extern uint32_t last_key_pressed; // --- FUNCITON --- diff --git a/vmm/operation.c b/vmm/operation.c index ac3b74f3649f2b005926d0679507f051e4d835b6..e5d63364373d22fe0179b626f7e1d881a9ea650b 100644 --- a/vmm/operation.c +++ b/vmm/operation.c @@ -28,7 +28,7 @@ state_t STATE_TIMER[] = { 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_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 }, @@ -51,7 +51,8 @@ state_t STATE_IDE[] = { 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_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 }, @@ -65,18 +66,24 @@ state_t STATE_SPRITE_VIS[] = { { OP_WRITE_EQUAL, REG_SPRITE_CMD, 0xE, 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_toggle }, - { OP_EMUL_END, 0, 0, 0, NULL }, + { OP_WRITE_STORE, REG_SPRITE_DATA, 0, 1, op_callback_sprite_visibility_store_toggle }, + { OP_EMUL_END, 0, 0, 0, op_callback_sprite_visibility_conclude }, }; 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_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_y }, - { OP_EMUL_END, 0, 0, 0, NULL }, + { 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 }, }; state_t *STATE_ALL_STARTERS[] = { @@ -87,6 +94,7 @@ state_t *STATE_ALL_STARTERS[] = { &STATE_SPRITE_INIT[0], &STATE_SPRITE_VIS[0], &STATE_SPRITE_POS[0], + &STATE_KEYBOARD[0], }; bool flag_stop_loop = false; @@ -110,7 +118,7 @@ static hyper_sprite_position_params_t param_sprite_pos; static uint64_t loop_idx = BUF_SIZE; static uint8_t loop_buf_8[BUF_SIZE]; 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 --- @@ -339,3 +347,12 @@ void op_callback_sprite_position_conclude(void *addr) { 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 *)¶m_key, sizeof(param_key)); +} diff --git a/vmm/operation.h b/vmm/operation.h index bd53f5ab20317c249a7d79fd96cc5887e5509265..59c96bee2eefd2ec8391bba91510e1685975199c 100644 --- a/vmm/operation.h +++ b/vmm/operation.h @@ -7,7 +7,7 @@ // --- DEFINE --- -#define STATE_MACHINE_NUM 3 +#define STATE_MACHINE_NUM 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_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_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 } operation_t; @@ -267,4 +268,6 @@ void op_callback_sprite_position_store_y(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_ diff --git a/vmm/vmm_main.c b/vmm/vmm_main.c index c22b3809e612af1f61e67ea9395a5682e992d791..e4f08a86b89f9f32fb66a7c5978c63b8699d0195 100644 --- a/vmm/vmm_main.c +++ b/vmm/vmm_main.c @@ -1,3 +1,4 @@ +#include <SDL2/SDL_keycode.h> #include <SDL2/SDL_render.h> #include <err.h> #include <stdbool.h> @@ -32,6 +33,7 @@ uint32_t width_gfx; uint32_t height_gfx; gfx_context_t *ctxt; sprite_t sprites[MAX_SPRITES]; +uint32_t last_key_pressed; char *disk_path; @@ -143,6 +145,25 @@ int main(int argc, char* argv[]) // Close the file descriptor 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 -- vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0); if (vcpufd == -1) err(1, "KVM_CREATE_VCPU"); @@ -195,10 +216,44 @@ int main(int argc, char* argv[]) ctxt = gfx_create("Basic Example", width_gfx, height_gfx); 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++) { if (sprites[i].toggle == 1) {