From d309cb2c0ff06d0b6cbe5da4e472e562fb508266 Mon Sep 17 00:00:00 2001
From: "adrian.spycher" <adrian.spycher@etu.hesge.ch>
Date: Sun, 20 Oct 2024 18:46:05 +0200
Subject: [PATCH] feat!: refactore code

---
 shared/hypercall_params.h |  16 +++-
 vmm/handler.c             | 151 ++++++++++++++++++++++++++++++++++++++
 vmm/handler.h             |  45 ++++++++++++
 vmm/vmm_main.c            |  57 +++-----------
 4 files changed, 219 insertions(+), 50 deletions(-)
 create mode 100644 vmm/handler.c
 create mode 100644 vmm/handler.h

diff --git a/shared/hypercall_params.h b/shared/hypercall_params.h
index c804f80..6916bc6 100644
--- a/shared/hypercall_params.h
+++ b/shared/hypercall_params.h
@@ -5,8 +5,14 @@
 
 // --- DEFINE ---
 
-#define HYPERCALL_SHARED_ADDR 0xC0000000
-#define HYPERCALL_BUFF_SIZE 4096
+#define HYPERCALL_PMIO_ADDR   0xABBA
+
+#define HYPERCALL_SHARED_ADDR   0xC0000000
+#define HYPERCALL_BUFF_SIZE     4096
+
+#define HYPERCALL_CODE_CONSOLE    1
+#define HYPERCALL_CODE_TIMER      2
+#define HYPERCALL_CODE_GFX_INIT   3
 
 // --- SHARED STRUCT ---
 
@@ -20,6 +26,12 @@ typedef struct {
     uint32_t us;    // delay in micro-seconds
 } __attribute__((packed)) hyper_timer_sleep_params_t;
 
+typedef struct {
+
+    uint32_t width;   // horizontal resolution in pixels
+    uint32_t height;  // vertical resolution in pixels 
+} __attribute__((packed)) hyper_init_gfx_params_t;
+
 // --- FUNCTION ---
 
 // ...
diff --git a/vmm/handler.c b/vmm/handler.c
new file mode 100644
index 0000000..00b058b
--- /dev/null
+++ b/vmm/handler.c
@@ -0,0 +1,151 @@
+#include "handler.h"
+
+#include <err.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "shared/hypercall_params.h"
+
+// --- DEFINE ---
+
+state_handler_t const STATE_HANDLERS[] = {
+
+    [KVM_EXIT_HLT] = handle_halt,
+    [KVM_EXIT_IO] = handle_pmio,
+    [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 FUNCTION ---
+
+static uint32_t retrieve_value(uint8_t *addr, uint8_t size) {
+
+    uint32_t value;
+
+    switch (size) {
+
+        case 1:
+            value = *(uint8_t *)addr;
+        break;
+
+        case 2:
+            value = *(uint16_t *)addr;
+        break;
+
+        case 4:
+            value = *(uint32_t *)addr;
+        break;
+
+        default:
+            errx(1, "Unsupported size trying to retrieve value.\n");
+        break;
+    }
+
+    return value;
+}
+
+// --- FUNCTION ---
+
+// - VMM EXIT REASON HANDLER -
+
+void handle_halt(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem) {
+
+    // printf("KVM_EXIT_HLT\n");
+}
+
+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);
+
+        switch (run->io.port) {
+
+            case HYPERCALL_PMIO_ADDR:
+                handle_hypercall(value, shared_buf, mem);
+            break;
+
+            case 0x43:
+            break;
+
+            case 0x40:
+            break;
+        }
+    }
+}
+
+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);
+        printf("MMIO guest write: \taddr=0x%llx \tlen=%d \tvalue=%d\n", run->mmio.phys_addr, run->mmio.len * 8, value);
+    }
+}
+
+// - HYPERCALL HANDLER -
+
+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);
+        break;
+
+        case HYPERCALL_CODE_TIMER:
+            handle_hypercall_timer(shared_buf);
+        break;
+
+        case HYPERCALL_CODE_GFX_INIT: 
+            handle_hypercall_gfx_init(shared_buf);
+        break;
+
+        default:
+            // TODO:
+        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
new file mode 100644
index 0000000..29ada07
--- /dev/null
+++ b/vmm/handler.h
@@ -0,0 +1,45 @@
+#define _STATES_H_
+#ifdef _STATES_H_
+
+#include <stdint.h>
+#include <linux/kvm.h>
+
+// --- 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 ---
+
+void handle_halt(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem);
+
+void handle_pmio(struct kvm_run *run, uint8_t *shared_buf, uint8_t *mem);
+
+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_
diff --git a/vmm/vmm_main.c b/vmm/vmm_main.c
index efcdbae..2660c38 100644
--- a/vmm/vmm_main.c
+++ b/vmm/vmm_main.c
@@ -12,7 +12,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include "states.h"
+#include "handler.h"
 #include "shared/hypercall_params.h"
 
 // -- DEFINE --
@@ -96,8 +96,7 @@ int main(int argc, char* argv[])
     if (bytes_read < 0) err(1, "Error reading guestOS binary file");
 
     // Check if all bytes were read
-    if (bytes_read != st.st_size) 
-        err(1, "Error: Only %ld of %ld bytes read from file\n", bytes_read, st.st_size);
+    if (bytes_read != st.st_size) err(1, "Error: Only %ld of %ld bytes read from file\n", bytes_read, st.st_size);
 
     // Close the file descriptor
     close(binfd);
@@ -142,56 +141,18 @@ int main(int argc, char* argv[])
 
     bool done = false;
     while (!done) {
-        if (ioctl(vcpufd, KVM_RUN, NULL) == -1) err(1, "KVM_RUN");
-
-        // handle VM exits (blocking call)
-        switch (run->exit_reason) {
-
-            case KVM_EXIT_HLT:    // "halt" CPU instruction
-
-                puts("KVM_EXIT_HLT");
-                break;
-
-            case KVM_EXIT_IO:     // Encountered a PMIO VMexit
-
-                if (run->io.direction == KVM_EXIT_IO_OUT) {
-
-                    uint8_t *addr = (uint8_t *)run + run->io.data_offset;
-                    uint8_t code = *(uint8_t *)addr;
 
-                    switch (code) {
-
-                        case 1: // console
-
-                            hyper_virtual_console_params_t *p_consol = (hyper_virtual_console_params_t *)shared_buf;
-                            printf("%s\n", p_consol->msg + mem);
-                            break;
-
-                        case 2: // timer
-
-                            hyper_timer_sleep_params_t *p_timer = (hyper_timer_sleep_params_t *)shared_buf;
-                            printf("waiting %dus\n", p_timer->us);
-                            sleep(p_timer->us / 1e6);
-                            done = true;
-                            break;
-                    }
-                }
+        if (ioctl(vcpufd, KVM_RUN, NULL) == -1) err(1, "KVM_RUN");
 
-                break;
+        state_handler_t handler = STATE_HANDLERS[run->exit_reason];
 
-            case KVM_EXIT_MMIO:   // Encountered a MMIO VMexit
+        if (handler) {
 
-                // !TODO!
-                break;
+            handler(run, shared_buf, mem);
+        }
+        else {
 
-            // handle errors
-            case KVM_EXIT_SHUTDOWN :
-            case KVM_EXIT_FAIL_ENTRY :
-            case KVM_EXIT_INTERNAL_ERROR :
-            default :
-                errx(1, "exit_reason = 0x%x", run->exit_reason);
-                done = true;
-                break;
+            errx(1, "exit_reason = 0x%x", run->exit_reason);
         }
     }
 }
-- 
GitLab