diff --git a/Makefile b/Makefile index d6d24d6..e4a3403 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ else VECHO = @printf endif -OBJS := vm.o serial.o main.o +OBJS := vm.o serial.o main.o pci.o OBJS := $(addprefix $(OUT)/,$(OBJS)) deps := $(OBJS:%.o=%.o.d) diff --git a/configs/linux.config b/configs/linux.config index dfb6be6..712abf5 100644 --- a/configs/linux.config +++ b/configs/linux.config @@ -1,6 +1,6 @@ -CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" +CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=90300 +CONFIG_GCC_VERSION=90400 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y CONFIG_AS_VERSION=23400 @@ -235,6 +235,7 @@ CONFIG_X86_MPPARSE=y # CONFIG_RETPOLINE is not set # CONFIG_X86_CPU_RESCTRL is not set # CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_IOSF_MBI is not set # CONFIG_SCHED_OMIT_FRAME_POINTER is not set # CONFIG_HYPERVISOR_GUEST is not set # CONFIG_MK8 is not set @@ -259,6 +260,7 @@ CONFIG_CPU_SUP_CENTAUR=y CONFIG_CPU_SUP_ZHAOXIN=y CONFIG_HPET_TIMER=y # CONFIG_DMI is not set +# CONFIG_GART_IOMMU is not set CONFIG_NR_CPUS_RANGE_BEGIN=1 CONFIG_NR_CPUS_RANGE_END=1 CONFIG_NR_CPUS_DEFAULT=1 @@ -272,6 +274,9 @@ CONFIG_X86_IO_APIC=y # # Performance monitoring # +# CONFIG_PERF_EVENTS_INTEL_UNCORE is not set +# CONFIG_PERF_EVENTS_INTEL_RAPL is not set +# CONFIG_PERF_EVENTS_INTEL_CSTATE is not set # CONFIG_PERF_EVENTS_AMD_POWER is not set # CONFIG_PERF_EVENTS_AMD_UNCORE is not set # end of Performance monitoring @@ -343,8 +348,11 @@ CONFIG_ARCH_SUPPORTS_ACPI=y # # Bus options (PCI etc.) # +CONFIG_PCI_DIRECT=y +# CONFIG_PCI_CNB20LE_QUIRK is not set # CONFIG_ISA_BUS is not set # CONFIG_ISA_DMA_API is not set +CONFIG_AMD_NB=y # end of Bus options (PCI etc.) # @@ -546,8 +554,61 @@ CONFIG_ARCH_HAS_PTE_SPECIAL=y CONFIG_HAVE_EISA=y # CONFIG_EISA is not set CONFIG_HAVE_PCI=y -# CONFIG_PCI is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# + +# +# DesignWare PCI Core Support +# +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_CXL_BUS is not set # CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set # # Generic Driver Options @@ -615,8 +676,14 @@ CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y # Misc devices # # CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set # CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set # CONFIG_SRAM is not set +# CONFIG_DW_XDATA_PCIE is not set +# CONFIG_PCI_ENDPOINT_TEST is not set # CONFIG_XILINX_SDFEC is not set # CONFIG_C2PORT is not set @@ -626,6 +693,8 @@ CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y # CONFIG_EEPROM_93CX6 is not set # end of EEPROM support +# CONFIG_CB710_CORE is not set + # # Texas Instruments shared transport line discipline # @@ -634,7 +703,15 @@ CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y # # Altera FPGA firmware download module (requires I2C) # +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set # CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_HABANA_AI is not set # CONFIG_PVPANIC is not set # end of Misc devices @@ -644,6 +721,15 @@ CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y CONFIG_SCSI_MOD=y # end of SCSI device support +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + # CONFIG_MACINTOSH_DRIVERS is not set # @@ -670,6 +756,7 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set @@ -701,6 +788,7 @@ CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y CONFIG_SERIO_I8042=y CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # CONFIG_SERIO_ALTERA_PS2 is not set @@ -734,11 +822,14 @@ CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y # CONFIG_SERIAL_8250_16550A_VARIANTS is not set # CONFIG_SERIAL_8250_FINTEK is not set CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set # CONFIG_SERIAL_8250_DW is not set # CONFIG_SERIAL_8250_RT288X is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MID is not set # # Non-8250 serial port support @@ -746,28 +837,36 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_UARTLITE is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set # CONFIG_SERIAL_LANTIQ is not set # CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_BCM63XX is not set # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set # CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set # CONFIG_SERIAL_FSL_LPUART is not set # CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_SPRD is not set # end of Serial drivers # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set # CONFIG_NULL_TTY is not set # CONFIG_SERIAL_DEV_BUS is not set # CONFIG_TTY_PRINTK is not set # CONFIG_VIRTIO_CONSOLE is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set # CONFIG_MWAVE is not set # CONFIG_DEVMEM is not set # CONFIG_NVRAM is not set +CONFIG_DEVPORT=y # CONFIG_HANGCHECK_TIMER is not set # CONFIG_TCG_TPM is not set # CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set # CONFIG_RANDOM_TRUST_BOOTLOADER is not set # end of Character devices @@ -811,12 +910,20 @@ CONFIG_BCMA_POSSIBLE=y # # CONFIG_MFD_MADERA is not set # CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMT is not set +# CONFIG_MFD_JANZ_CMODIO is not set # CONFIG_MFD_KEMPLD is not set # CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_RDC321X is not set # CONFIG_MFD_SM501 is not set # CONFIG_MFD_SYSCON is not set # CONFIG_MFD_TI_AM335X_TSCADC is not set # CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set # end of Multifunction device drivers # CONFIG_REGULATOR is not set @@ -833,6 +940,8 @@ CONFIG_BCMA_POSSIBLE=y # # Graphics support # +# CONFIG_AGP is not set +# CONFIG_VGA_ARB is not set # CONFIG_DRM is not set # CONFIG_DRM_DEBUG_MODESET_LOCK is not set @@ -941,6 +1050,18 @@ CONFIG_HID_GENERIC=y # CONFIG_HID_SENSOR_HUB is not set # CONFIG_HID_ALPS is not set # end of Special HID drivers + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support + +# +# AMD SFH HID Support +# +# CONFIG_AMD_SFH_HID is not set +# end of AMD SFH HID Support # end of HID support CONFIG_USB_OHCI_LITTLE_ENDIAN=y @@ -979,9 +1100,13 @@ CONFIG_RTC_MC146818_LIB=y # CONFIG_COMEDI is not set # CONFIG_STAGING is not set # CONFIG_X86_PLATFORM_DEVICES is not set +CONFIG_PMC_ATOM=y # CONFIG_CHROME_PLATFORMS is not set # CONFIG_MELLANOX_PLATFORM is not set -# CONFIG_COMMON_CLK is not set +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_XILINX_VCU is not set # CONFIG_HWSPINLOCK is not set # @@ -1052,6 +1177,8 @@ CONFIG_CLKBLD_I8253=y # CONFIG_EXTCON is not set # CONFIG_MEMORY is not set # CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set # CONFIG_PWM is not set # @@ -1088,6 +1215,7 @@ CONFIG_CLKBLD_I8253=y # end of Performance monitor support # CONFIG_RAS is not set +# CONFIG_USB4 is not set # # Android @@ -1195,6 +1323,7 @@ CONFIG_GENERIC_STRNLEN_USER=y CONFIG_GENERIC_FIND_FIRST_BIT=y # CONFIG_CORDIC is not set # CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y CONFIG_GENERIC_PCI_IOMAP=y CONFIG_GENERIC_IOMAP=y CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y @@ -1396,6 +1525,7 @@ CONFIG_HAVE_OBJTOOL_MCOUNT=y CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_TRACING_SUPPORT=y # CONFIG_FTRACE is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y @@ -1418,6 +1548,7 @@ CONFIG_IO_DELAY_0X80=y # CONFIG_DEBUG_ENTRY is not set # CONFIG_DEBUG_NMI_SELFTEST is not set # CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set # CONFIG_UNWINDER_ORC is not set # CONFIG_UNWINDER_FRAME_POINTER is not set CONFIG_UNWINDER_GUESS=y diff --git a/src/pci.c b/src/pci.c new file mode 100644 index 0000000..0022743 --- /dev/null +++ b/src/pci.c @@ -0,0 +1,244 @@ +#include +#include + +#include "pci.h" +#include "utils.h" + +static inline struct dev *bus_find_dev(struct bus *bus, uint64_t addr) +{ + struct dev **p = &bus->head; + + while (*p) { + uint64_t start = (*p)->base; + uint64_t end = start + (*p)->len - 1; + if (addr >= start && addr <= end) + return *p; + p = &(*p)->next; + } + 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, + uint64_t offset, + uint8_t size) +{ + struct pci *pci = (struct pci *) owner; + void *p = (void *) &pci->pci_addr + offset; + /* The data in port 0xCF8 is as an address when Guest Linux accesses the configuration space */ + if (is_write) + memcpy(p, data, size); + else + memcpy(data, p, size); + pci->pci_addr.reg_offset = 0; +} + +static inline void pci_activate_bar(struct pci_dev *dev, + uint8_t bar, + struct bus *bus) +{ + uint32_t mask = ~(dev->bar_size[bar] - 1); + if (!dev->bar_active[bar] && dev->space_dev[bar].base & mask) + bus_register_dev(bus, &dev->space_dev[bar]); + dev->bar_active[bar] = true; +} + +static inline void pci_deactivate_bar(struct pci_dev *dev, + uint8_t bar, + struct bus *bus) +{ + uint32_t mask = ~(dev->bar_size[bar] - 1); + if (dev->bar_active[bar] && dev->space_dev[bar].base & mask) + bus_deregister_dev(bus, &dev->space_dev[bar]); + dev->bar_active[bar] = false; +} + +static void pci_command_bar(struct pci_dev *dev) +{ + bool enable_io = PCI_HDR_READ(dev->hdr, PCI_COMMAND, 16) & PCI_COMMAND_IO; + bool enable_mem = + PCI_HDR_READ(dev->hdr, PCI_COMMAND, 16) & PCI_COMMAND_MEMORY; + for (int i = 0; i < PCI_STD_NUM_BARS; i++) { + struct bus *bus = dev->bar_is_io_space[i] ? dev->io_bus : dev->mmio_bus; + bool enable = dev->bar_is_io_space[i] ? enable_io : enable_mem; + + if (enable) + pci_activate_bar(dev, i, bus); + else + pci_deactivate_bar(dev, i, bus); + } +} + +static void pci_config_command(struct pci_dev *dev) +{ + pci_command_bar(dev); +} + +static void pci_config_bar(struct pci_dev *dev, uint8_t bar) +{ + uint32_t mask = ~(dev->bar_size[bar] - 1); + uint32_t old_bar = PCI_HDR_READ(dev->hdr, PCI_BAR_OFFSET(bar), 32); + uint32_t new_bar = (old_bar & mask) | dev->bar_is_io_space[bar]; + PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), new_bar, 32); + dev->space_dev[bar].base = new_bar; +} + +static void pci_config_write(struct pci_dev *dev, + void *data, + uint64_t offset, + uint8_t size) +{ + void *p = dev->hdr + offset; + + memcpy(p, data, size); + if (offset == PCI_COMMAND) { + pci_config_command(dev); + } else if (offset >= PCI_BASE_ADDRESS_0 && offset <= PCI_BASE_ADDRESS_5) { + uint8_t bar = (offset - PCI_BASE_ADDRESS_0) >> 2; + pci_config_bar(dev, bar); + } else if (offset == PCI_ROM_ADDRESS) { + PCI_HDR_WRITE(dev->hdr, PCI_ROM_ADDRESS, 0, 32); + } + /* TODO: write to capability */ +} + +static void pci_config_read(struct pci_dev *dev, + void *data, + uint64_t offset, + uint8_t size) +{ + void *p = dev->hdr + offset; + memcpy(data, p, size); +} + +static void pci_config_do_io(void *owner, + void *data, + uint8_t is_write, + uint64_t offset, + uint8_t size) +{ + struct pci_dev *dev = (struct pci_dev *) owner; + if (is_write) + pci_config_write(dev, data, offset, size); + else + pci_config_read(dev, data, offset, size); +} + +static void pci_data_io(void *owner, + void *data, + uint8_t is_write, + uint64_t offset, + uint8_t size) +{ + struct pci *pci = (struct pci *) owner; + uint64_t addr = pci->pci_addr.value | offset; + bus_handle_io(&pci->pci_bus, data, is_write, addr, size); +} + +void pci_set_bar(struct pci_dev *dev, + uint8_t bar, + uint32_t bar_size, + bool is_io_space, + dev_io_fn do_io) +{ + /* TODO: mem type, prefetch */ + /* FIXME: bar_size must be power of 2 */ + PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), is_io_space, 32); + dev->bar_size[bar] = bar_size; + dev->bar_is_io_space[bar] = is_io_space; + dev_init(&dev->space_dev[bar], 0, bar_size, dev, do_io); +} + +void pci_set_status(struct pci_dev *dev, uint16_t status) +{ + PCI_HDR_WRITE(dev->hdr, PCI_STATUS, status, 16); +} + +void pci_dev_init(struct pci_dev *dev, + struct pci *pci, + struct bus *io_bus, + struct bus *mmio_bus) +{ + memset(dev, 0x00, sizeof(struct pci_dev)); + dev->hdr = dev->cfg_space; + dev->pci_bus = &pci->pci_bus; + dev->io_bus = io_bus; + dev->mmio_bus = mmio_bus; +} + +void pci_register_dev(struct pci_dev *dev) +{ + /* FIXEME: it just simply register on pci bus 0 */ + /* FIXEME: dev_num might exceed 32 */ + union pci_config_address addr = {.enable_bit = 1, + .dev_num = dev->pci_bus->dev_num}; + dev_init(&dev->config_dev, addr.value, PCI_CFG_SPACE_SIZE, dev, + pci_config_do_io); + bus_register_dev(dev->pci_bus, &dev->config_dev); +} + +#define PCI_CONFIG_ADDR 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +void pci_init(struct pci *pci, struct bus *io_bus) +{ + dev_init(&pci->pci_addr_dev, PCI_CONFIG_ADDR, sizeof(uint32_t), pci, + pci_address_io); + dev_init(&pci->pci_bus_dev, PCI_CONFIG_DATA, sizeof(uint32_t), pci, + pci_data_io); + bus_init(&pci->pci_bus); + bus_register_dev(io_bus, &pci->pci_addr_dev); + bus_register_dev(io_bus, &pci->pci_bus_dev); +} \ No newline at end of file diff --git a/src/pci.h b/src/pci.h new file mode 100644 index 0000000..c0ce355 --- /dev/null +++ b/src/pci.h @@ -0,0 +1,87 @@ +#pragma once + +#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; + unsigned reg_num : 6; + unsigned func_num : 3; + unsigned dev_num : 5; + unsigned bus_num : 8; + unsigned reserved : 7; + unsigned enable_bit : 1; + }; + uint32_t value; +}; + +#define PCI_HDR_READ(hdr, offset, width) (*((uint##width##_t *) (hdr + offset))) +#define PCI_HDR_WRITE(hdr, offset, value, width) \ + ((uint##width##_t *) (hdr + offset))[0] = value +#define PCI_BAR_OFFSET(bar) (PCI_BASE_ADDRESS_0 + ((bar) << 2)) + +struct pci_dev { + uint8_t cfg_space[PCI_CFG_SPACE_SIZE]; + void *hdr; + uint32_t bar_size[6]; + bool bar_active[6]; + bool bar_is_io_space[6]; + struct dev space_dev[6]; + struct dev config_dev; + struct bus *io_bus; + struct bus *mmio_bus; + struct bus *pci_bus; +}; + +struct pci { + union pci_config_address pci_addr; + struct bus pci_bus; + struct dev pci_bus_dev; + struct dev pci_addr_dev; +}; + +void pci_set_bar(struct pci_dev *dev, + uint8_t bar, + uint32_t bar_size, + bool is_io_space, + dev_io_fn do_io); +void pci_set_status(struct pci_dev *dev, uint16_t status); +void pci_register_dev(struct pci_dev *dev); +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 diff --git a/src/vm.c b/src/vm.c index 8639040..d1ff12c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -17,7 +17,9 @@ #include #include "err.h" +#include "pci.h" #include "serial.h" +#include "virtio-pci.h" #include "vm.h" static int vm_init_regs(vm_t *v) @@ -115,7 +117,8 @@ int vm_init(vm_t *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); return 0; } @@ -203,6 +206,28 @@ int vm_load_initrd(vm_t *v, const char *initrd_path) return 0; } +void vm_handle_io(vm_t *v, struct kvm_run *run) +{ + uint64_t addr = run->io.port; + 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; + } + } +} + +void vm_handle_mmio(vm_t *v, struct kvm_run *run) +{ + bus_handle_io(&v->mmio_bus, run->mmio.data, run->mmio.is_write, + run->mmio.phys_addr, run->mmio.len); +} + int vm_run(vm_t *v) { int run_size = ioctl(v->kvm_fd, KVM_GET_VCPU_MMAP_SIZE, 0); @@ -217,8 +242,10 @@ int vm_run(vm_t *v) } switch (run->exit_reason) { case KVM_EXIT_IO: - if (run->io.port >= COM1_PORT_BASE && run->io.port < COM1_PORT_END) - serial_handle(&v->serial, run); + vm_handle_io(v, run); + break; + case KVM_EXIT_MMIO: + vm_handle_mmio(v, run); break; case KVM_EXIT_INTR: serial_console(&v->serial); diff --git a/src/vm.h b/src/vm.h index 3f5fd70..e6d2353 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1,14 +1,18 @@ #pragma once #define RAM_SIZE (1 << 30) -#define KERNEL_OPTS "console=ttyS0" +#define KERNEL_OPTS "console=ttyS0 pci=conf1" +#include "pci.h" #include "serial.h" typedef struct { int kvm_fd, vm_fd, vcpu_fd; void *mem; serial_dev_t serial; + struct bus mmio_bus; + struct bus io_bus; + struct pci pci; } vm_t; int vm_init(vm_t *v); @@ -16,4 +20,6 @@ int vm_load_image(vm_t *v, const char *image_path); int vm_load_initrd(vm_t *v, const char *initrd_path); int vm_run(vm_t *v); int vm_irq_line(vm_t *v, int irq, int level); +void vm_handle_io(vm_t *v, struct kvm_run *run); +void vm_handle_mmio(vm_t *v, struct kvm_run *run); void vm_exit(vm_t *v);