From 64d9f0e98e8b81c8284a76440f4c898be634be9c Mon Sep 17 00:00:00 2001 From: Yan-Jie Wang Date: Wed, 17 May 2023 10:54:58 +0800 Subject: [PATCH 1/2] Move bus API and impls to dedicated files The bus interface can be used by other non-PCI MMIO and PIO devices. This pave the way for the serial device to use it. --- Makefile | 1 + src/bus.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bus.h | 38 ++++++++++++++++++++++++++++++++ src/pci.c | 64 ----------------------------------------------------- src/pci.h | 33 ++-------------------------- 5 files changed, 107 insertions(+), 95 deletions(-) create mode 100644 src/bus.c create mode 100644 src/bus.h diff --git a/Makefile b/Makefile index 6ff04e4..a200dc9 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ all: $(BIN) OBJS := \ vm.o \ serial.o \ + bus.o \ pci.o \ virtio-pci.o \ virtq.o \ diff --git a/src/bus.c b/src/bus.c new file mode 100644 index 0000000..464c034 --- /dev/null +++ b/src/bus.c @@ -0,0 +1,66 @@ +#include "bus.h" +#include + +static inline struct dev *bus_find_dev(struct bus *bus, uint64_t addr) +{ + struct dev **p = &bus->head; + + for (; *p; p = &(*p)->next) { + uint64_t start = (*p)->base; + uint64_t end = start + (*p)->len - 1; + if (addr >= start && addr <= end) + return *p; + } + return NULL; +} + +void bus_handle_io(struct bus *bus, + void *data, + uint8_t is_write, + uint64_t addr, + uint8_t size) +{ + struct dev *dev = bus_find_dev(bus, addr); + + if (dev && addr + size - 1 <= dev->base + dev->len - 1) { + dev->do_io(dev->owner, data, is_write, addr - dev->base, size); + } +} + +void bus_register_dev(struct bus *bus, struct dev *dev) +{ + dev->next = bus->head; + bus->head = dev; + bus->dev_num++; +} + +void bus_deregister_dev(struct bus *bus, struct dev *dev) +{ + struct dev **p = &bus->head; + + while (*p != dev && *p) { + p = &(*p)->next; + } + + if (*p) + *p = (*p)->next; +} + +void bus_init(struct bus *bus) +{ + bus->dev_num = 0; + bus->head = NULL; +} + +void dev_init(struct dev *dev, + uint64_t base, + uint64_t len, + void *owner, + dev_io_fn do_io) +{ + dev->base = base; + dev->len = len; + dev->owner = owner; + dev->do_io = do_io; + dev->next = NULL; +} diff --git a/src/bus.h b/src/bus.h new file mode 100644 index 0000000..548dda9 --- /dev/null +++ b/src/bus.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +struct dev; + +typedef void (*dev_io_fn)(void *owner, + void *data, + uint8_t is_write, + uint64_t offset, + uint8_t size); + +struct dev { + uint64_t base; + uint64_t len; + void *owner; + dev_io_fn do_io; + struct dev *next; +}; + +struct bus { + uint64_t dev_num; + struct dev *head; +}; + +void bus_register_dev(struct bus *bus, struct dev *dev); +void bus_deregister_dev(struct bus *bus, struct dev *dev); +void bus_handle_io(struct bus *bus, + void *data, + uint8_t is_write, + uint64_t addr, + uint8_t size); +void bus_init(struct bus *bus); +void dev_init(struct dev *dev, + uint64_t base, + uint64_t len, + void *owner, + dev_io_fn do_io); diff --git a/src/pci.c b/src/pci.c index 955cc24..6bc66bb 100644 --- a/src/pci.c +++ b/src/pci.c @@ -4,70 +4,6 @@ #include "pci.h" #include "utils.h" -static inline struct dev *bus_find_dev(struct bus *bus, uint64_t addr) -{ - struct dev **p = &bus->head; - - for (; *p; p = &(*p)->next) { - uint64_t start = (*p)->base; - uint64_t end = start + (*p)->len - 1; - if (addr >= start && addr <= end) - return *p; - } - return NULL; -} - -void bus_handle_io(struct bus *bus, - void *data, - uint8_t is_write, - uint64_t addr, - uint8_t size) -{ - struct dev *dev = bus_find_dev(bus, addr); - - if (dev && addr + size - 1 <= dev->base + dev->len - 1) { - dev->do_io(dev->owner, data, is_write, addr - dev->base, size); - } -} - -void bus_register_dev(struct bus *bus, struct dev *dev) -{ - dev->next = bus->head; - bus->head = dev; - bus->dev_num++; -} - -void bus_deregister_dev(struct bus *bus, struct dev *dev) -{ - struct dev **p = &bus->head; - - while (*p != dev && *p) { - p = &(*p)->next; - } - - if (*p) - *p = (*p)->next; -} - -void bus_init(struct bus *bus) -{ - bus->dev_num = 0; - bus->head = NULL; -} - -static inline void dev_init(struct dev *dev, - uint64_t base, - uint64_t len, - void *owner, - dev_io_fn do_io) -{ - dev->base = base; - dev->len = len; - dev->owner = owner; - dev->do_io = do_io; - dev->next = NULL; -} - static void pci_address_io(void *owner, void *data, uint8_t is_write, diff --git a/src/pci.h b/src/pci.h index e9354da..d26c565 100644 --- a/src/pci.h +++ b/src/pci.h @@ -1,40 +1,11 @@ #pragma once +#include "bus.h" #include #include #include #include -struct dev; - -typedef void (*dev_io_fn)(void *owner, - void *data, - uint8_t is_write, - uint64_t offset, - uint8_t size); - -struct dev { - uint64_t base; - uint64_t len; - void *owner; - dev_io_fn do_io; - struct dev *next; -}; - -struct bus { - uint64_t dev_num; - struct dev *head; -}; - -void bus_register_dev(struct bus *bus, struct dev *dev); -void bus_deregister_dev(struct bus *bus, struct dev *dev); -void bus_handle_io(struct bus *bus, - void *data, - uint8_t is_write, - uint64_t addr, - uint8_t size); -void bus_init(struct bus *bus); - union pci_config_address { struct { unsigned reg_offset : 2; @@ -84,4 +55,4 @@ void pci_dev_init(struct pci_dev *dev, struct pci *pci, struct bus *io_bus, struct bus *mmio_bus); -void pci_init(); \ No newline at end of file +void pci_init(); From d63b17b21073a447adb433b008f3265c08fb6338 Mon Sep 17 00:00:00 2001 From: Yan-Jie Wang Date: Wed, 17 May 2023 11:15:36 +0800 Subject: [PATCH 2/2] Use bus interface in the serial device Before this change, the VM exit handler used the hard-coded I/O port numbers to handle I/O for the serial device. This change makes the serial device registers its I/O port interface by using bus interface and removes the hard-coded I/O port numbers in the VM exit handling routine. --- src/pci.h | 2 +- src/serial.c | 30 ++++++++++++++++++------------ src/serial.h | 6 +++--- src/vm.c | 14 +++++--------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/pci.h b/src/pci.h index d26c565..0d696f6 100644 --- a/src/pci.h +++ b/src/pci.h @@ -1,10 +1,10 @@ #pragma once -#include "bus.h" #include #include #include #include +#include "bus.h" union pci_config_address { struct { diff --git a/src/serial.c b/src/serial.c index b951367..567c0bc 100644 --- a/src/serial.c +++ b/src/serial.c @@ -196,9 +196,23 @@ static void serial_out(serial_dev_t *s, uint16_t offset, void *data) } } + +static void serial_handle_io(void *owner, + void *data, + uint8_t is_write, + uint64_t offset, + uint8_t size) +{ + serial_dev_t *s = (serial_dev_t *) owner; + void (*serial_op)(serial_dev_t *, uint16_t, void *) = + is_write ? serial_out : serial_in; + + serial_op(s, offset, data); +} + static void handler(int sig, siginfo_t *si, void *uc) {} -int serial_init(serial_dev_t *s) +int serial_init(serial_dev_t *s, struct bus *bus) { sigset_t mask; @@ -226,18 +240,10 @@ int serial_init(serial_dev_t *s) if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) return throw_err("Failed to unblock timer signal"); - return 0; -} - -void serial_handle(serial_dev_t *s, struct kvm_run *r) -{ - void *data = (uint8_t *) r + r->io.data_offset; - void (*serial_op)(serial_dev_t *, uint16_t, void *) = - (r->io.direction == KVM_EXIT_IO_OUT) ? serial_out : serial_in; + dev_init(&s->dev, COM1_PORT_BASE, COM1_PORT_SIZE, s, serial_handle_io); + bus_register_dev(bus, &s->dev); - uint32_t c = r->io.count; - for (uint16_t off = r->io.port - COM1_PORT_BASE; c--; data += r->io.size) - serial_op(s, off, data); + return 0; } void serial_exit(serial_dev_t *s) diff --git a/src/serial.h b/src/serial.h index f3a5374..384d8da 100644 --- a/src/serial.h +++ b/src/serial.h @@ -2,10 +2,10 @@ #include #include +#include "bus.h" #define COM1_PORT_BASE 0x03f8 #define COM1_PORT_SIZE 8 -#define COM1_PORT_END (COM1_PORT_BASE + COM1_PORT_SIZE) typedef struct serial_dev serial_dev_t; @@ -13,9 +13,9 @@ struct serial_dev { void *priv; pthread_t main_tid, worker_tid; int infd; /* file descriptor for serial input */ + struct dev dev; }; void serial_console(serial_dev_t *s); -int serial_init(serial_dev_t *s); -void serial_handle(serial_dev_t *s, struct kvm_run *r); +int serial_init(serial_dev_t *s, struct bus *bus); void serial_exit(serial_dev_t *s); diff --git a/src/vm.c b/src/vm.c index e57a1d3..38d6490 100644 --- a/src/vm.c +++ b/src/vm.c @@ -115,11 +115,11 @@ int vm_init(vm_t *v) vm_init_regs(v); vm_init_cpu_id(v); - if (serial_init(&v->serial)) - return throw_err("Failed to init UART device"); bus_init(&v->io_bus); bus_init(&v->mmio_bus); pci_init(&v->pci, &v->io_bus); + if (serial_init(&v->serial, &v->io_bus)) + return throw_err("Failed to init UART device"); virtio_blk_init(&v->virtio_blk_dev); return 0; } @@ -223,13 +223,9 @@ void vm_handle_io(vm_t *v, struct kvm_run *run) void *data = (void *) run + run->io.data_offset; bool is_write = run->io.direction == KVM_EXIT_IO_OUT; - if (run->io.port >= COM1_PORT_BASE && run->io.port < COM1_PORT_END) { - serial_handle(&v->serial, run); - } else { - for (int i = 0; i < run->io.count; i++) { - bus_handle_io(&v->io_bus, data, is_write, addr, run->io.size); - addr += run->io.size; - } + for (int i = 0; i < run->io.count; i++) { + bus_handle_io(&v->io_bus, data, is_write, addr, run->io.size); + addr += run->io.size; } }