diff --git a/hal/ia32/Makefile b/hal/ia32/Makefile index 4ca7a85a5..25d211e94 100644 --- a/hal/ia32/Makefile +++ b/hal/ia32/Makefile @@ -7,7 +7,7 @@ include hal/tlb/Makefile -OBJS += $(addprefix $(PREFIX_O)hal/ia32/, _init.o _exceptions.o _interrupts.o spinlock.o exceptions.o interrupts.o cpu.o pmap.o timer.o hal.o string.o pci.o init.o) +OBJS += $(addprefix $(PREFIX_O)hal/ia32/, _init.o _exceptions.o _interrupts.o spinlock.o exceptions.o interrupts.o cpu.o pmap.o timer.o hal.o string.o pci.o init.o acpi.o) CFLAGS += -Ihal/ia32 ifeq ($(CONSOLE), vga) diff --git a/hal/ia32/_interrupts.S b/hal/ia32/_interrupts.S index e0d63de3f..505c9c6bc 100644 --- a/hal/ia32/_interrupts.S +++ b/hal/ia32/_interrupts.S @@ -179,6 +179,14 @@ INTERRUPT(_interrupts_irq12, 12, interrupts_dispatchIRQ) INTERRUPT(_interrupts_irq13, 13, interrupts_dispatchIRQ) INTERRUPT(_interrupts_irq14, 14, interrupts_dispatchIRQ) INTERRUPT(_interrupts_irq15, 15, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq16, 16, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq17, 17, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq18, 18, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq19, 19, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq20, 20, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq21, 21, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq22, 22, interrupts_dispatchIRQ) +INTERRUPT(_interrupts_irq23, 23, interrupts_dispatchIRQ) INTERRUPT(_interrupts_unexpected, 255, _interrupts_unexpected) diff --git a/hal/ia32/acpi.c b/hal/ia32/acpi.c new file mode 100644 index 000000000..772ac3a98 --- /dev/null +++ b/hal/ia32/acpi.c @@ -0,0 +1,31 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * ACPI kernel-userspace interface + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + +#include "include/errno.h" +#include "include/arch/ia32/ia32.h" +#include "halsyspage.h" + + +int hal_acpiGet(acpi_var_t var, int *value) +{ + switch (var) { + case acpi_rsdpAddr: + if (syspage->hs.acpi_version != ACPI_RSDP) { + return -EINVAL; + } + *value = syspage->hs.rsdp; + return EOK; + } + + return -EINVAL; +} diff --git a/hal/ia32/acpi.h b/hal/ia32/acpi.h new file mode 100644 index 000000000..99fbf56c0 --- /dev/null +++ b/hal/ia32/acpi.h @@ -0,0 +1,23 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * ACPI kernel-userspace interface + * + * Copyright 2025 Phoenix Systems + * Author: Adam Greloch + * + * %LICENSE% + */ + +#ifndef _HAL_ACPI_H_ +#define _HAL_ACPI_H_ + +#include "include/arch/ia32/ia32.h" + + +extern int hal_acpiGet(acpi_var_t var, int *value); + + +#endif diff --git a/hal/ia32/cpu.c b/hal/ia32/cpu.c index f88c1328b..7a835421d 100644 --- a/hal/ia32/cpu.c +++ b/hal/ia32/cpu.c @@ -22,6 +22,7 @@ #include "hal/pmap.h" #include "hal/hal.h" #include "hal/tlb/tlb.h" +#include "acpi.h" #include "pci.h" #include "ia32.h" #include "halsyspage.h" @@ -548,15 +549,27 @@ int hal_platformctl(void *ptr) platformctl_t *data = (platformctl_t *)ptr; switch (data->type) { + case pctl_acpi: + if (data->action == pctl_get) { + return hal_acpiGet(data->acpi.var, &data->acpi.value); + } + break; + case pctl_pci: if (data->action == pctl_get) { return hal_pciGetDevice(&data->pci.id, &data->pci.dev, data->pci.caps); } break; - case pctl_busmaster: + case pctl_pcicfg: + if (data->action == pctl_set) { + return hal_pciSetConfigOption(&data->pcicfg.dev, data->pcicfg.cfg, data->pcicfg.enable); + } + break; + + case pctl_usbownership: if (data->action == pctl_set) { - return hal_pciSetBusmaster(&data->busmaster.dev, data->busmaster.enable); + return hal_pciSetUsbOwnership(&data->usbownership.dev, data->usbownership.eecp, data->usbownership.osOwned); } break; diff --git a/hal/ia32/interrupts.c b/hal/ia32/interrupts.c index d52d3be44..d79177fa3 100644 --- a/hal/ia32/interrupts.c +++ b/hal/ia32/interrupts.c @@ -46,6 +46,14 @@ extern void _interrupts_irq12(void); extern void _interrupts_irq13(void); extern void _interrupts_irq14(void); extern void _interrupts_irq15(void); +extern void _interrupts_irq16(void); +extern void _interrupts_irq17(void); +extern void _interrupts_irq18(void); +extern void _interrupts_irq19(void); +extern void _interrupts_irq20(void); +extern void _interrupts_irq21(void); +extern void _interrupts_irq22(void); +extern void _interrupts_irq23(void); extern void _interrupts_unexpected(void); @@ -55,7 +63,8 @@ extern void _interrupts_syscall(void); extern void _interrupts_TLBShootdown(void); -#define SIZE_INTERRUPTS 16 +#define ISA_INTERRUPTS 16 +#define SIZE_INTERRUPTS 24 struct { @@ -209,6 +218,20 @@ int interrupts_dispatchIRQ(unsigned int n, cpu_context_t *ctx) } +static inline void _hal_ioapicUnmaskPCI(unsigned int n) +{ + u32 high, low; + + _hal_ioapicReadIRQ(interrupts_common.irqs[n].ioapic, n, &high, &low); + + if ((low & IOAPIC_IRQ_MASK) != 0) { + /* PCI interrupts are active low level triggered */ + low |= (IOAPIC_INTPOL | IOAPIC_TRIGGER); + _hal_ioapicWriteIRQ(interrupts_common.irqs[n].ioapic, n, high, low & ~IOAPIC_IRQ_MASK); + } +} + + int hal_interruptsSetHandler(intr_handler_t *h) { spinlock_ctx_t sc; @@ -219,6 +242,10 @@ int hal_interruptsSetHandler(intr_handler_t *h) hal_spinlockSet(&interrupts_common.interrupts[h->n].spinlock, &sc); HAL_LIST_ADD(&interrupts_common.interrupts[h->n].handler, h); + if (h->n >= ISA_INTERRUPTS) { + /* Assume IRQs above ISA_INTERRUPTS are PCI interrupts */ + _hal_ioapicUnmaskPCI(h->n); + } hal_spinlockClear(&interrupts_common.interrupts[h->n].spinlock, &sc); return EOK; @@ -429,8 +456,8 @@ static int _hal_ioapicInit(void) } } - /* Enable all IRQS */ - for (i = 0; i < SIZE_INTERRUPTS; ++i) { + /* Enable all ISA IRQs */ + for (i = 0; i < ISA_INTERRUPTS; ++i) { _hal_ioapicReadIRQ(interrupts_common.irqs[i].ioapic, i, &high, &low); _hal_ioapicWriteIRQ(interrupts_common.irqs[i].ioapic, i, high, low & ~IOAPIC_IRQ_MASK); } @@ -480,6 +507,14 @@ void _hal_interruptsInit(void) _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 13, _interrupts_irq13, flags); _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 14, _interrupts_irq14, flags); _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 15, _interrupts_irq15, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 16, _interrupts_irq16, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 17, _interrupts_irq17, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 18, _interrupts_irq18, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 19, _interrupts_irq19, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 20, _interrupts_irq20, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 21, _interrupts_irq21, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 22, _interrupts_irq22, flags); + _interrupts_setIDTEntry(INTERRUPTS_VECTOR_OFFSET + 23, _interrupts_irq23, flags); for (k = 0; k < SIZE_INTERRUPTS; k++) { hal_spinlockCreate(&interrupts_common.interrupts[k].spinlock, "interrupts_common.interrupts[].spinlock"); diff --git a/hal/ia32/pci.c b/hal/ia32/pci.c index 9de96ca7e..3c80b8f07 100644 --- a/hal/ia32/pci.c +++ b/hal/ia32/pci.c @@ -5,8 +5,8 @@ * * PCI driver * - * Copyright 2018, 2019, 2020 Phoenix Systems - * Author: Aleksander Kaminski, Kamil Amanowicz, Lukasz Kosinski + * Copyright 2018, 2019, 2020, 2024 Phoenix Systems + * Author: Aleksander Kaminski, Kamil Amanowicz, Lukasz Kosinski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -84,19 +84,24 @@ static int _hal_pciGetCaps(pci_dev_t *dev, void *caps) } -int hal_pciSetBusmaster(pci_dev_t *dev, u8 enable) +/* Sets a bit in PCI configuration command register */ +int _hal_pciSetCmdRegBit(pci_dev_t *dev, u8 bit, u8 enable) { spinlock_ctx_t sc; u32 dv; - if (dev == NULL) + if (dev == NULL) { return -EINVAL; + } hal_spinlockSet(&pci_common.spinlock, &sc); dv = _hal_pciGet(dev->bus, dev->dev, dev->func, 1); - dv &= ~(1 << 2); - if (enable) - dv |= (1 << 2); + if (enable != 0) { + dv |= (1 << bit); + } + else { + dv &= ~(1 << bit); + } _hal_pciSet(dev->bus, dev->dev, dev->func, 1, dv); hal_spinlockClear(&pci_common.spinlock, &sc); @@ -106,11 +111,64 @@ int hal_pciSetBusmaster(pci_dev_t *dev, u8 enable) } +int hal_pciSetUsbOwnership(pci_dev_t *dev, u8 eecp, u8 osOwned) +{ + spinlock_ctx_t sc; + u32 dv; + u8 reg = eecp >> 2U; /* eecp is a pci config offset */ + + if (dev == NULL) { + return -EINVAL; + } + + hal_spinlockSet(&pci_common.spinlock, &sc); + dv = _hal_pciGet(dev->bus, dev->dev, dev->func, reg); + if (osOwned != 0) { + dv |= (1 << 24); + } + else { + dv &= ~(1 << 24); + } + _hal_pciSet(dev->bus, dev->dev, dev->func, reg, dv); + + for (;;) { + dv = _hal_pciGet(dev->bus, dev->dev, dev->func, reg); + if ((osOwned != 0) && ((dv & (1 << 24)) != 0) && ((dv & (1 << 16)) == 0)) { + break; + } + + if ((osOwned == 0) && ((dv & (1 << 24)) == 0) && ((dv & (1 << 16)) != 0)) { + break; + } + } + hal_spinlockClear(&pci_common.spinlock, &sc); + + dev->command = dv & 0xffff; + + return EOK; +} + + +int hal_pciSetConfigOption(pci_dev_t *dev, pci_cfg_t cfg, u8 enable) +{ + switch (cfg) { + case pci_cfg_interruptdisable: + return _hal_pciSetCmdRegBit(dev, 10, enable); + case pci_cfg_memoryspace: + return _hal_pciSetCmdRegBit(dev, 1, enable); + case pci_cfg_busmaster: + return _hal_pciSetCmdRegBit(dev, 2, enable); + default: + return -EINVAL; + } +} + + int hal_pciGetDevice(pci_id_t *id, pci_dev_t *dev, void *caps) { spinlock_ctx_t sc; unsigned char b, d, f, i; - u32 dv, cl, mask, val; + u32 val0, cl, progif, mask, valB, val2; int res = EOK; if ((id == NULL) || (dev == NULL)) @@ -122,57 +180,62 @@ int hal_pciGetDevice(pci_id_t *id, pci_dev_t *dev, void *caps) hal_spinlockSet(&pci_common.spinlock, &sc); do { - if ((dv = _hal_pciGet(b, d, f, 0)) == 0xffffffff) + if ((val0 = _hal_pciGet(b, d, f, 0)) == 0xffffffff) break; - if ((id->vendor != PCI_ANY) && (id->vendor != (dv & 0xffff))) + if ((id->vendor != PCI_ANY) && (id->vendor != (val0 & 0xffff))) break; - if ((id->device != PCI_ANY) && (id->device != (dv >> 16))) + if ((id->device != PCI_ANY) && (id->device != (val0 >> 16))) break; - cl = _hal_pciGet(b, d, f, 2) >> 16; + val2 = _hal_pciGet(b, d, f, 0x2); + + cl = val2 >> 16; + progif = (val2 >> 8) & 0xff; if ((id->cl != PCI_ANY) && (id->cl != cl)) break; - val = _hal_pciGet(b, d, f, 0xb); + if ((id->progif != PCI_ANY) && (id->progif != progif)) + break; + + valB = _hal_pciGet(b, d, f, 0xb); - if ((id->subdevice != PCI_ANY) && (id->subdevice != (val >> 16))) + if ((id->subdevice != PCI_ANY) && (id->subdevice != (valB >> 16))) break; - if ((id->subvendor != PCI_ANY) && (id->subvendor != (val & 0xffff))) + if ((id->subvendor != PCI_ANY) && (id->subvendor != (valB & 0xffff))) break; dev->bus = b; dev->dev = d; dev->func = f; - dev->vendor = dv & 0xffff; - dev->device = dv >> 16; + dev->vendor = val0 & 0xffff; + dev->device = val0 >> 16; dev->cl = cl; - dev->subvendor = val & 0xffff; - dev->subdevice = val >> 16; + dev->subvendor = valB & 0xffff; + dev->subdevice = valB >> 16; - dv = _hal_pciGet(b, d, f, 1); - dev->status = dv >> 16; - dev->command = dv & 0xffff; + val0 = _hal_pciGet(b, d, f, 0x1); + dev->status = val0 >> 16; + dev->command = val0 & 0xffff; - val = _hal_pciGet(b, d, f, 2); - dev->progif = (val >> 8) & 0xff; - dev->revision = val & 0xff; - dev->type = (_hal_pciGet(b, d, f, 3) >> 16) & 0xff; - dev->irq = _hal_pciGet(b, d, f, 15) & 0xff; + dev->progif = progif; + dev->revision = val2 & 0xff; + dev->type = (_hal_pciGet(b, d, f, 0x3) >> 16) & 0xff; + dev->irq = _hal_pciGet(b, d, f, 0xf) & 0xff; /* Get resources */ for (i = 0; i < 6; i++) { - dev->resources[i].base = _hal_pciGet(b, d, f, 4 + i); + dev->resources[i].base = _hal_pciGet(b, d, f, 0x4 + i); /* Get resource flags and size */ - _hal_pciSet(b, d, f, 4 + i, 0xffffffff); - dev->resources[i].limit = _hal_pciGet(b, d, f, 4 + i); + _hal_pciSet(b, d, f, 0x4 + i, 0xffffffff); + dev->resources[i].limit = _hal_pciGet(b, d, f, 0x4 + i); mask = (dev->resources[i].base & 0x1) ? ~0x3 : ~0xf; dev->resources[i].limit = (~(dev->resources[i].limit & mask)) + 1; - _hal_pciSet(b, d, f, 4 + i, dev->resources[i].base); + _hal_pciSet(b, d, f, 0x4 + i, dev->resources[i].base); dev->resources[i].flags = dev->resources[i].base & ~mask; dev->resources[i].base &= mask; } diff --git a/hal/ia32/pci.h b/hal/ia32/pci.h index cb6f2b8db..67a63a5b6 100644 --- a/hal/ia32/pci.h +++ b/hal/ia32/pci.h @@ -5,8 +5,8 @@ * * PCI driver * - * Copyright 2019, 2020 Phoenix Systems - * Author: Kamil Amanowicz, Lukasz Kosinski + * Copyright 2019, 2020, 2024 Phoenix Systems + * Author: Kamil Amanowicz, Lukasz Kosinski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -19,12 +19,15 @@ #include "include/arch/ia32/ia32.h" -extern int hal_pciSetBusmaster(pci_dev_t *dev, u8 enable); +extern int hal_pciSetUsbOwnership(pci_dev_t *dev, u8 eecp, u8 enable); extern int hal_pciGetDevice(pci_id_t *id, pci_dev_t *dev, void *caps); +extern int hal_pciSetConfigOption(pci_dev_t *dev, pci_cfg_t option, u8 enable); + + extern void _hal_pciInit(void); diff --git a/include/arch/ia32/ia32.h b/include/arch/ia32/ia32.h index 2f34833df..7e574983b 100644 --- a/include/arch/ia32/ia32.h +++ b/include/arch/ia32/ia32.h @@ -5,8 +5,8 @@ * * IA32 basic peripherals control functions * - * Copyright 2018, 2019, 2020 Phoenix Systems - * Author: Aleksander Kaminski, Kamil Amanowicz, Lukasz Kosinski + * Copyright 2018, 2019, 2020, 2024 Phoenix Systems + * Author: Aleksander Kaminski, Kamil Amanowicz, Lukasz Kosinski, Adam Greloch * * This file is part of Phoenix-RTOS. * @@ -27,6 +27,7 @@ typedef struct { unsigned short subvendor; unsigned short subdevice; unsigned short cl; + unsigned short progif; } __attribute__((packed)) pci_id_t; @@ -71,23 +72,42 @@ typedef struct { } __attribute__((packed)) pci_dev_t; +typedef enum { acpi_rsdpAddr = 0 } acpi_var_t; + /* clang-format off */ +typedef enum { pci_cfg_interruptdisable, pci_cfg_memoryspace, pci_cfg_busmaster} pci_cfg_t; +/* clang-format on */ + typedef struct { + /* clang-format off */ enum { pctl_set = 0, pctl_get } action; - enum { pctl_pci = 0, pctl_busmaster, pctl_reboot, pctl_graphmode } type; + enum { pctl_pci = 0, pctl_acpi, pctl_pcicfg, pctl_usbownership, pctl_reboot, pctl_graphmode } type; + /* clang-format on */ union { + struct { + acpi_var_t var; + int value; + } acpi; + struct { pci_id_t id; pci_dev_t dev; - void* caps; + void *caps; } pci; struct { pci_dev_t dev; - int enable; - } busmaster; + pci_cfg_t cfg; + short enable; + } pcicfg; + + struct { + pci_dev_t dev; + short osOwned; + short eecp; + } usbownership; struct { unsigned int magic; @@ -104,7 +124,5 @@ typedef struct { }; } platformctl_t; -/* clang-format on */ - #endif diff --git a/include/arch/ia32/syspage.h b/include/arch/ia32/syspage.h index e5b902d92..c06914c7a 100644 --- a/include/arch/ia32/syspage.h +++ b/include/arch/ia32/syspage.h @@ -38,6 +38,7 @@ typedef struct { unsigned int ebda; unsigned int acpi_version; + unsigned long rsdp; /* addr_t */ unsigned int localApicAddr; unsigned long madt; /* addr_t */ unsigned int madtLength;