From 67bdcf6245abb2e6f73ad24d1ec7e06a2754fdd7 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 23 Feb 2026 12:14:47 -0800 Subject: [PATCH 01/11] pcie ecam driver --- drivers/Makefile | 6 +- drivers/acpi/tables.c | 50 +++- drivers/acpica_osl/osl.c | 100 ++++++- drivers/include/acpi/tables.h | 10 + drivers/include/pcie/pcie.h | 26 ++ drivers/include/pcie/pcie_init.h | 24 ++ drivers/pci/pci_config.c | 254 ------------------ .../{include/pci/pci_config.h => pcie/pcie.c} | 21 +- drivers/pcie/pcie_init.c | 90 +++++++ kernel/core/kentry.c | 9 + scripts/simulate_qemu | 32 ++- 11 files changed, 335 insertions(+), 287 deletions(-) create mode 100644 drivers/include/pcie/pcie.h create mode 100644 drivers/include/pcie/pcie_init.h delete mode 100644 drivers/pci/pci_config.c rename drivers/{include/pci/pci_config.h => pcie/pcie.c} (54%) create mode 100644 drivers/pcie/pcie_init.c diff --git a/drivers/Makefile b/drivers/Makefile index 7ce23f3..6e8b6ad 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -24,14 +24,12 @@ $(call add_directory,apic,APIC) $(call add_directory,ioapic,IOAPIC) $(call add_directory,acpi,ACPI) $(call add_directory,acpica_osl,ACPICA_OSL) -$(call add_directory,pci,PCI) +$(call add_directory,pcie,PCIE) ifdef BUILD_DRIVERS_HPET $(call add_directory,hpet,HPET) endif - -#TODO: switch to PCIe - + ifdef BUILD_DRIVERS_SERIAL $(call add_directory,serial,SERIAL) endif diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index d1e9deb..d88c12f 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -41,6 +41,9 @@ #else /* HPET */ #define FOUND_HPET 0x00 #endif /* HPET */ +#define FOUND_MCFG 0x08 + +#define FOUND_ALL (FOUND_FADT | FOUND_MADT | FOUND_HPET | FOUND_MCFG) #define GAS_TYPE_SYS 0 #define GAS_TYPE_IO 1 @@ -166,6 +169,28 @@ struct acpi_madt_t { uint8_t InterruptControllerStructure[]; } __attribute__((packed)); +struct acpi_mcfg_conf_entry_t { + uint64_t base; + uint16_t group; + uint8_t bus_start; + uint8_t bus_end; + uint32_t resv; +} __attribute__((packed)); + +struct acpi_mcfg_t { + uint8_t Signature[4]; + uint32_t Length; + uint8_t Revision; + uint8_t Checksum; + uint8_t OEMID[6]; + uint8_t OEMTableID[8]; + uint32_t OEMRevision; + uint32_t CreatorID; + uint32_t CreatorRevision; + uint64_t Reserved; + struct acpi_mcfg_conf_entry_t conf[]; +} __attribute__((packed)); + #ifdef HPET struct acpi_hpet_t { uint8_t Signature[4]; @@ -191,6 +216,7 @@ struct acpi_hpet_t { static struct acpi_fadt_t* acpi_fadt; static struct acpi_madt_t* acpi_madt; +static struct acpi_mcfg_t* acpi_mcfg; #ifdef HPET static struct acpi_hpet_t* acpi_hpet[8]; static uint8_t hpet_count; @@ -300,10 +326,11 @@ void acpi_copy_tables(void) { #ifdef HPET CHECK_AND_COPY("HPET", "HPET", acpi_hpet[hpet_count], FOUND_HPET, hpet_count++); #endif /* HPET */ + CHECK_AND_COPY("MCFG", "MCFG", acpi_mcfg, FOUND_MCFG, (void)0); #undef CHECK_FAIL } - if (found != (FOUND_FADT | FOUND_MADT | FOUND_HPET )) { + if (found != FOUND_ALL) { logging_log_error("Could not find all ACPI tables"); panic(PANIC_ACPI); } @@ -352,10 +379,11 @@ void acpi_copy_tables(void) { #ifdef HPET CHECK_AND_COPY("HPET", "HPET", acpi_hpet[hpet_count], FOUND_HPET, hpet_count++); #endif /* HPET */ + CHECK_AND_COPY("MCFG", "MCFG", acpi_mcfg, FOUND_MCFG, (void)0); #undef CHECK_FAIL } - if (found != (FOUND_FADT | FOUND_MADT | FOUND_HPET)) { + if (found != FOUND_ALL) { logging_log_warning("Could not find all ACPI tables. Falling back to RSDPV1"); goto fallback; } @@ -387,6 +415,24 @@ uint16_t acpi_get_sci_int(void) { return acpi_fadt->SCI_INT; } +void acpi_parse_mcfg_conf_start(uint64_t* handle) { + *handle = (uint64_t)&acpi_mcfg->conf[0]; +} + +void acpi_parse_mcfg_conf(struct acpi_mcfg_conf_t* conf, uint64_t* handle) { + if (*handle > (uint64_t)acpi_mcfg + acpi_mcfg->Length) { + *handle = 0; + return; + } + + const struct acpi_mcfg_conf_entry_t* entry = (struct acpi_mcfg_conf_entry_t*)*handle; + conf->base = entry->base; + conf->segment = entry->group; + conf->bus_start = entry->bus_start; + conf->bus_end = entry->bus_end; + *handle = (uint64_t)(entry + 1); +} + #ifdef HPET void acpi_get_hpet_bases(uint64_t* bases) { bases[0] = bases[1] = bases[2] = bases[3] = diff --git a/drivers/acpica_osl/osl.c b/drivers/acpica_osl/osl.c index fdc5147..2a3a2a2 100644 --- a/drivers/acpica_osl/osl.c +++ b/drivers/acpica_osl/osl.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -282,23 +282,95 @@ ACPI_STATUS AcpiOsSignal(UINT32 func, void* info) { } ACPI_STATUS AcpiOsReadPciConfiguration(ACPI_PCI_ID* id, UINT32 reg, UINT64* val, UINT32 width) { - *val = pci_read_conf_noalign( - (uint8_t)reg, - (uint8_t)id->Function, - (uint8_t)id->Device, - (uint8_t)id->Bus, - (uint8_t)width); + uint32_t reg_cur; + uint32_t reg_end; + uint32_t read; + uint64_t constr = 0; + uint8_t shft = 0; + switch (width) { + case 8: + reg_end = reg + 1; + break; + case 16: + reg_end = reg + 2; + break; + case 32: + reg_end = reg + 4; + break; + case 64: + reg_end = reg + 8; + break; + default: + return AE_SUPPORT; + } + + for (reg_cur = reg - (reg % 4); reg_cur < reg_end; reg_cur += 4) { + read = pcie_read(id->Segment, (uint8_t)id->Bus, (uint8_t)id->Device, (uint8_t)id->Function, (uint16_t)reg_cur); + if (reg_cur < reg) { + shft = (uint8_t)(8 * (reg - reg_cur)); + constr |= read << shft; + shft = 32 - shft; + } + else { + constr |= (uint64_t)read >> shft; + shft += 32; + } + } + + switch (width) { + case 8: + *val = constr & 0xFF; + break; + case 16: + *val = constr & 0xFFFF; + break; + case 32: + *val = constr & 0xFFFFFFFF; + break; + case 64: + *val = constr; + break; + } + return AE_OK; } ACPI_STATUS AcpiOsWritePciConfiguration(ACPI_PCI_ID* id, UINT32 reg, UINT64 val, UINT32 width) { - pci_write_conf_noalign( - (uint8_t)reg, - (uint8_t)id->Function, - (uint8_t)id->Device, - (uint8_t)id->Bus, - (uint8_t)width, - val); + uint32_t reg_cur; + uint32_t reg_end; + uint32_t write; + uint8_t shft = 0; + switch (width) { + case 8: + reg_end = reg + 1; + break; + case 16: + reg_end = reg + 2; + break; + case 32: + reg_end = reg + 4; + break; + case 64: + reg_end = reg + 8; + break; + default: + return AE_SUPPORT; + } + + for (reg_cur = reg - (reg % 4); reg_cur < reg_end; reg_cur += 4) { + if (reg_cur < reg) { + shft = (uint8_t)(8 * (reg - reg_cur)); + write = (uint32_t)(val << shft); + shft = 32 - shft; + } + else { + write = (uint32_t)(val >> shft); + val += 32; + } + + pcie_write(id->Segment, (uint8_t)id->Bus, (uint8_t)id->Device, (uint8_t)id->Function, (uint16_t)reg_cur, write); + } + return AE_OK; } diff --git a/drivers/include/acpi/tables.h b/drivers/include/acpi/tables.h index bef75db..15f72e4 100644 --- a/drivers/include/acpi/tables.h +++ b/drivers/include/acpi/tables.h @@ -101,11 +101,21 @@ struct acpi_madt_ics_local_apic_nmi_t { uint8_t LocalAPICLINTNum; } __attribute__((packed)); +struct acpi_mcfg_conf_t { + uint64_t base; + uint16_t segment; + uint8_t bus_start; + uint8_t bus_end; +}; + extern void acpi_copy_tables(void); extern void acpi_parse_madt_ics_start(uint64_t* handle); extern void acpi_parse_madt_ics(struct acpi_madt_ics_gen_t** ics, uint64_t* handle, uint8_t type); +extern void acpi_parse_mcfg_conf_start(uint64_t* handle); +extern void acpi_parse_mcfg_conf(struct acpi_mcfg_conf_t* conf, uint64_t* handle); + extern uint16_t acpi_get_sci_int(void); #ifdef HPET diff --git a/drivers/include/pcie/pcie.h b/drivers/include/pcie/pcie.h new file mode 100644 index 0000000..22599cb --- /dev/null +++ b/drivers/include/pcie/pcie.h @@ -0,0 +1,26 @@ +/* pcie_init.h - Peripheral Controller Interface Express driver interface */ +/* Copyright (C) 2025-2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_INCLUDE_PCIE_H +#define DRIVERS_INCLUDE_PCIE_H + +#include + +extern uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off); +extern void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val); + +#endif /* DRIVERS_INCLUDE_PCIE_H */ diff --git a/drivers/include/pcie/pcie_init.h b/drivers/include/pcie/pcie_init.h new file mode 100644 index 0000000..141f47d --- /dev/null +++ b/drivers/include/pcie/pcie_init.h @@ -0,0 +1,24 @@ +/* pcie_init.h - Peripheral Controller Interface Express initialization interfce */ +/* Copyright (C) 2025-2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_INCLUDE_PCIE_INIT_H +#define DRIVERS_INCLUDE_PCIE_INIT_H + +extern void pcie_init(void); +extern void pcie_enumerate(void); + +#endif /* DRIVERS_INCLUDE_PCIE_INIT_H */ diff --git a/drivers/pci/pci_config.c b/drivers/pci/pci_config.c deleted file mode 100644 index e0354fe..0000000 --- a/drivers/pci/pci_config.c +++ /dev/null @@ -1,254 +0,0 @@ -/* pci_config.c - Peripheral Controller Interface configuration space access */ -/* Copyright (C) 2025-2026 Ebrahim Aleem -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see -*/ - -#include - -#include - -#include - -#define CONF_ADDR 0xCF8 -#define CONF_DATA 0xCFC - -#define REG_MASK 0xFC -#define REG_SIZE 4 - -union conf_addr_t { - uint32_t raw; - struct { - uint8_t reg; - uint8_t fun; - uint8_t dev; - uint8_t bus; - uint8_t flg; - } conf_addr __attribute__((packed)); -}; - -uint32_t pci_read_conf(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus) { - outd(CONF_ADDR, (union conf_addr_t){ - .conf_addr.reg = reg, - .conf_addr.fun = fun, - .conf_addr.dev = dev, - .conf_addr.bus = bus - }.raw - ); - - io_wait(); - - return ind(CONF_DATA); -} - -void pci_write_conf(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus, uint32_t data) { - outd(CONF_ADDR, (union conf_addr_t){ - .conf_addr.reg = reg, - .conf_addr.fun = fun, - .conf_addr.dev = dev, - .conf_addr.bus = bus - }.raw - ); - - io_wait(); - - outd(CONF_DATA, data); -} - -uint64_t pci_read_conf_noalign(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus, uint8_t width) { - const uint8_t reg_base = reg & REG_MASK; - uint32_t data0; - - switch (reg - reg_base) { - case 0: - data0 = pci_read_conf(reg_base, fun, dev, bus); - switch (width) { - case 8: - return data0 & 0xFF; - case 16: - return data0 & 0xFFFF; - case 32: - return data0; - case 64: - return (uint64_t)data0 - | ((uint64_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) << 32); - default: - return 0; - } - case 1: - data0 = pci_read_conf(reg_base, fun, dev, bus) >> 8; - switch (width) { - case 8: - return data0 & 0xFF; - case 16: - return data0 & 0xFFFF; - case 32: - return (uint32_t)data0 - | (((uint32_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFF) << 24); - case 64: - return (uint64_t)data0 - | (((uint64_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus)) << 24) - | (((uint64_t)pci_read_conf(reg_base + REG_SIZE * 2, fun, dev, bus) & 0xFF) << 56); - default: - return 0; - } - case 2: - data0 = pci_read_conf(reg_base, fun, dev, bus) >> 16; - switch (width) { - case 8: - return data0 & 0xFF; - case 16: - return data0; - case 32: - return (uint32_t)data0 - | (((uint32_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFFFF) << 16); - case 64: - return (uint64_t)data0 - | (((uint64_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus)) << 16) - | (((uint64_t)pci_read_conf(reg_base + REG_SIZE * 2, fun, dev, bus) & 0xFFFF) << 48); - default: - return 0; - } - case 3: - data0 = pci_read_conf(reg_base, fun, dev, bus) >> 24; - switch (width) { - case 8: - return data0; - case 16: - return (uint32_t)data0 - | (((uint32_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFF) << 8); - case 32: - return (uint32_t)data0 - | (((uint32_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFFFFFF) << 8); - case 64: - return (uint64_t)data0 - | (((uint64_t)pci_read_conf(reg_base + REG_SIZE, fun, dev, bus)) << 8) - | (((uint64_t)pci_read_conf(reg_base + REG_SIZE * 2, fun, dev, bus) & 0xFFFFFF) << 40); - default: - return 0; - } - default: - return 0; - } -} - -void pci_write_conf_noalign(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus, uint8_t width, uint64_t data) { - const uint8_t reg_base = reg & REG_MASK; - - switch (reg - reg_base) { - case 0: - switch (width) { - case 8: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFFFF00) | (data & 0xFF)); - return; - case 16: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFF0000) | (data & 0xFFFF)); - return; - case 32: - pci_write_conf(reg_base, fun, dev, bus, data & 0xFFFFFFFF); - return; - case 64: - pci_write_conf(reg_base, fun, dev, bus, data & 0xFFFFFFFF); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, (data >> 32) & 0xFFFFFFFF); - return; - default: - return; - } - case 1: - switch (width) { - case 8: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFF00FF) | ((data << 8) & 0xFF00)); - return; - case 16: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFF0000FF) | ((data << 8) & 0xFFFF00)); - return; - case 32: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFF) | ((data << 8) & 0xFFFFFF00)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFFFFFF00) | (data & 0xFF)); - return; - case 64: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFF) | ((data << 8) & 0xFFFFFF00)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, ((data >> 24) & 0xFFFFFFFF)); - pci_write_conf(reg_base + REG_SIZE * 2, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE * 2, fun, dev, bus) & 0xFFFFFF00) | ((data >> 56) & 0xFF)); - return; - default: - return; - } - case 2: - switch (width) { - case 8: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFF00FFFF) | ((data << 16) & 0xFF0000)); - return; - case 16: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFF) | ((data << 16) & 0xFFFF0000)); - return; - case 32: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFF) | ((data << 16) & 0xFFFF0000)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFFFF0000) | ((data >> 16) & 0xFFFF)); - return; - case 64: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFF) | ((data << 16) & 0xFFFF0000)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, - ((data >> 16) & 0xFFFFFFFF)); - pci_write_conf(reg_base + REG_SIZE * 2, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE * 2, fun, dev, bus) & 0xFFFF0000) | ((data >> 48) & 0xFFFF)); - return; - default: - return; - } - case 3: - switch (width) { - case 8: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFFFF) | ((data << 24) & 0xFF000000)); - return; - case 16: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFFFF) | ((data << 24) & 0xFF000000)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFFFFFF00) | ((data >> 8) & 0xFF)); - return; - case 32: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFFFF) | ((data << 24) & 0xFF000000)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE, fun, dev, bus) & 0xFF000000) | ((data >> 8) & 0xFFFFFF)); - return; - case 64: - pci_write_conf(reg_base, fun, dev, bus, - (pci_read_conf(reg_base, fun, dev, bus) & 0xFFFFFF) | ((data << 24) & 0xFF000000)); - pci_write_conf(reg_base + REG_SIZE, fun, dev, bus, (data >> 8) & 0xFFFFFFFF); - pci_write_conf(reg_base + REG_SIZE * 2, fun, dev, bus, - (pci_read_conf(reg_base + REG_SIZE * 2, fun, dev, bus) & 0xFF000000) | ((data >> 40) & 0xFFFFFF)); - return; - default: - return; - } - default: - return; - } -} diff --git a/drivers/include/pci/pci_config.h b/drivers/pcie/pcie.c similarity index 54% rename from drivers/include/pci/pci_config.h rename to drivers/pcie/pcie.c index 5c7496c..c68973e 100644 --- a/drivers/include/pci/pci_config.h +++ b/drivers/pcie/pcie.c @@ -1,4 +1,4 @@ -/* pci_config.h - Peripheral Controller Interface configuration space access interface */ +/* pcie_init.c - Peripheral Controller Interface Express driver */ /* Copyright (C) 2025-2026 Ebrahim Aleem * * This program is free software: you can redistribute it and/or modify @@ -15,15 +15,18 @@ * along with this program. If not, see */ -#ifndef DRIVERS_PIC_PIC_CONFIG -#define DRIVERS_PIC_PIC_CONFIG - #include -extern uint32_t pci_read_conf(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus); -extern void pci_write_conf(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus, uint32_t data); +#include + +#define FUN_OFF(dev, fun) (((uint64_t)dev << 15) | ((uint64_t)fun << 12)) + +uint64_t** ecam_bus_bases; -extern uint64_t pci_read_conf_noalign(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus, uint8_t width); -extern void pci_write_conf_noalign(uint8_t reg, uint8_t fun, uint8_t dev, uint8_t bus, uint8_t width, uint64_t data); +uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off) { + return *(volatile uint32_t*)(ecam_bus_bases[segment][bus] | FUN_OFF(dev, fun) + off); +} -#endif /* DRIVERS_PIC_PIC_CONFIG */ +void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val) { + *(volatile uint32_t*)(ecam_bus_bases[segment][bus] | FUN_OFF(dev, fun) + off) = val; +} diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c new file mode 100644 index 0000000..5a42c98 --- /dev/null +++ b/drivers/pcie/pcie_init.c @@ -0,0 +1,90 @@ +/* pcie_init.c - Peripheral Controller Interface Express initialization */ +/* Copyright (C) 2025-2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +#include +#include +#include + +#include + +#define BUS_BASE(ecam, bus) (ecam + ((uint64_t)bus << 20)) + +extern uint64_t** ecam_bus_bases; + +void pcie_init(void) { + uint64_t mcfg_handle; + struct acpi_mcfg_conf_t conf; + uint16_t max_seg = 0; + uint16_t j; + uint8_t max_bus; + uint16_t i; + uint64_t vaddr = 0; + + acpi_parse_mcfg_conf_start(&mcfg_handle); + while (mcfg_handle) { + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + + if (conf.segment > max_seg) { + max_seg = conf.segment; + } + } + + ecam_bus_bases = kmalloc(sizeof(uint64_t*) * max_seg); + + for (i = 0; i < max_seg; i++) { + max_bus = 0; + j = 0; + + acpi_parse_mcfg_conf_start(&mcfg_handle); + while (mcfg_handle) { + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + + if (conf.segment == i && conf.bus_end >= max_bus) { + max_bus = conf.bus_end; + j = 1; + } + } + + if (!j) { + ecam_bus_bases[i] = 0; + continue; + } + + ecam_bus_bases[i] = kmalloc(sizeof(uint64_t) * (max_bus + 1)); + kmemset(ecam_bus_bases[i], 0, sizeof(uint64_t) * (max_bus + 1)); + + acpi_parse_mcfg_conf_start(&mcfg_handle); + while (mcfg_handle) { + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + + if (conf.segment == i) { + for (j = conf.bus_start; j <= conf.bus_end; j++) { + vaddr = mm_alloc_v(PAGE_SIZE_4K); + paging_map(vaddr, BUS_BASE(conf.base, j), PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + ecam_bus_bases[i][j] = vaddr; + } + } + } + } +} + +void pcie_enumerate(void) { +} diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 94777f3..ebf1ccf 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -39,6 +39,7 @@ #include #include #include +#include struct boot_context_t boot_context; @@ -74,10 +75,18 @@ void kentry(void) { ioapic_init(); logging_log_debug("APIC and IOAPIC init done"); + logging_log_debug("Early PCIE init"); + pcie_init(); + logging_log_debug("Early PCIE init done"); + logging_log_debug("ACPICA init"); acpica_init(); logging_log_debug("ACPICA init done"); + logging_log_debug("PCIE enumeration"); + pcie_enumerate(); + logging_log_debug("PCIE enumeration done"); + logging_log_info("Boot Complete ModulOS"); logging_log_info("Begining AP bootstrap sequence"); diff --git a/scripts/simulate_qemu b/scripts/simulate_qemu index 5fd0b45..edb381a 100755 --- a/scripts/simulate_qemu +++ b/scripts/simulate_qemu @@ -1,9 +1,33 @@ #!/bin/bash mkdir -p build/test-runtime/ -qemu-system-x86_64 -s -smp 4 -serial vc -serial file:build/test-runtime/serial \ - -d cpu_reset,int -m 16G -monitor stdio \ - -drive format=raw,file=build/modulos.img,if=ide,media=disk \ - -smbios type=0,uefi=on -bios /usr/share/qemu/OVMF.fd \ +qemu-system-x86_64 \ + -machine q35 \ + -s -smp 4 \ + -serial vc \ + -serial file:build/test-runtime/serial \ + -d cpu_reset,int \ + -m 16G \ + -monitor stdio \ + -drive if=none,id=disk0,file=build/modulos.img,format=raw \ + -device ahci,id=ahci \ + -device ide-hd,drive=disk0,bus=ahci.0,bootindex=1 \ + -smbios type=0,uefi=on \ + -bios /usr/share/qemu/OVMF.fd \ -device VGA + + + + +#-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \ + + +#qemu-system-x86_64 -s -smp 4 -serial vc -serial file:build/test-runtime/serial \ +# -d cpu_reset,int -m 16G -monitor stdio \ +# -drive format=raw,file=build/modulos.img,if=ide,media=disk \ +# -smbios type=0,uefi=on -bios /usr/share/qemu/OVMF.fd \ +# -device VGA \ +# -machine q35 + +#-drive if=pflash,format=raw,file=scripts/OVMF_VARS.fd \ From a9760d32e857df9f092b24bb78030608b3d14dea Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 23 Feb 2026 14:44:03 -0800 Subject: [PATCH 02/11] pcie enumeration without init --- Makefile | 2 +- drivers/acpi/tables.c | 2 +- drivers/include/pcie/pcie_init.h | 1 + drivers/pcie/pcie.c | 8 +-- drivers/pcie/pcie_init.c | 89 ++++++++++++++++++++++++++------ kernel/core/paging.c | 2 +- kernel/include/core/paging.h | 3 +- scripts/simulate_qemu | 8 ++- 8 files changed, 89 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index cc357d4..bfadf15 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -#export DEBUG = 1 +export DEBUG = 1 export DEBUG_LOGGING = 1 # Global options diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index d88c12f..4bb0aeb 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -420,7 +420,7 @@ void acpi_parse_mcfg_conf_start(uint64_t* handle) { } void acpi_parse_mcfg_conf(struct acpi_mcfg_conf_t* conf, uint64_t* handle) { - if (*handle > (uint64_t)acpi_mcfg + acpi_mcfg->Length) { + if (*handle + sizeof(struct acpi_mcfg_conf_entry_t) > (uint64_t)acpi_mcfg + acpi_mcfg->Length) { *handle = 0; return; } diff --git a/drivers/include/pcie/pcie_init.h b/drivers/include/pcie/pcie_init.h index 141f47d..88422d5 100644 --- a/drivers/include/pcie/pcie_init.h +++ b/drivers/include/pcie/pcie_init.h @@ -19,6 +19,7 @@ #define DRIVERS_INCLUDE_PCIE_INIT_H extern void pcie_init(void); + extern void pcie_enumerate(void); #endif /* DRIVERS_INCLUDE_PCIE_INIT_H */ diff --git a/drivers/pcie/pcie.c b/drivers/pcie/pcie.c index c68973e..900b821 100644 --- a/drivers/pcie/pcie.c +++ b/drivers/pcie/pcie.c @@ -19,14 +19,14 @@ #include -#define FUN_OFF(dev, fun) (((uint64_t)dev << 15) | ((uint64_t)fun << 12)) +#define FUN_OFF(fun) ((uint64_t)fun << 12) -uint64_t** ecam_bus_bases; +uint64_t*** ecam_dev_bases; uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off) { - return *(volatile uint32_t*)(ecam_bus_bases[segment][bus] | FUN_OFF(dev, fun) + off); + return *(volatile uint32_t*)((ecam_dev_bases[segment][bus][dev] | FUN_OFF(fun)) + off); } void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val) { - *(volatile uint32_t*)(ecam_bus_bases[segment][bus] | FUN_OFF(dev, fun) + off) = val; + *(volatile uint32_t*)((ecam_dev_bases[segment][bus][dev] | FUN_OFF(fun)) + off) = val; } diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c index 5a42c98..1446443 100644 --- a/drivers/pcie/pcie_init.c +++ b/drivers/pcie/pcie_init.c @@ -16,75 +16,130 @@ */ #include +#include #include #include #include #include +#include #include -#define BUS_BASE(ecam, bus) (ecam + ((uint64_t)bus << 20)) +#define DEV_BASE(ecam, bus, dev) (ecam + (((uint64_t)bus << 20) | ((uint64_t)dev << 15))) -extern uint64_t** ecam_bus_bases; +#define DEVICE_EXISTS(seg, bus, dev) (VENDOR_ID(seg, bus, dev) != 0xFFFF) + +#define VENDOR_ID(seg, bus, dev) (0xFFFF & pcie_read(seg, bus, dev, 0, 0x0)) +#define DEVICE_ID(seg, bus, dev) (0xFFFF & (pcie_read(seg, bus, dev, 0, 0x0) >> 16)) +#define HEADER_TYPE(seg, bus, dev) (0x7F & (pcie_read(seg, bus, dev, 0, 0xC) >> 16)) + +#define PCI_BRIDGE_SEC_NUM(seg, bus, dev) (0xFF & (pcie_read(seg, bus, dev, 0, 0x18) >> 8)) + +extern uint64_t*** ecam_dev_bases; void pcie_init(void) { uint64_t mcfg_handle; struct acpi_mcfg_conf_t conf; uint16_t max_seg = 0; uint16_t j; - uint8_t max_bus; + uint16_t max_bus; uint16_t i; uint64_t vaddr = 0; + uint8_t k; acpi_parse_mcfg_conf_start(&mcfg_handle); - while (mcfg_handle) { - acpi_parse_mcfg_conf(&conf, &mcfg_handle); - + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + while (mcfg_handle) { if (conf.segment > max_seg) { max_seg = conf.segment; } + + acpi_parse_mcfg_conf(&conf, &mcfg_handle); } - ecam_bus_bases = kmalloc(sizeof(uint64_t*) * max_seg); + max_seg++; + + ecam_dev_bases = kmalloc(sizeof(uint64_t*) * max_seg ); for (i = 0; i < max_seg; i++) { max_bus = 0; j = 0; acpi_parse_mcfg_conf_start(&mcfg_handle); + acpi_parse_mcfg_conf(&conf, &mcfg_handle); while (mcfg_handle) { - acpi_parse_mcfg_conf(&conf, &mcfg_handle); - if (conf.segment == i && conf.bus_end >= max_bus) { max_bus = conf.bus_end; j = 1; } + + acpi_parse_mcfg_conf(&conf, &mcfg_handle); } if (!j) { - ecam_bus_bases[i] = 0; + ecam_dev_bases[i] = 0; continue; } - ecam_bus_bases[i] = kmalloc(sizeof(uint64_t) * (max_bus + 1)); - kmemset(ecam_bus_bases[i], 0, sizeof(uint64_t) * (max_bus + 1)); + ecam_dev_bases[i] = kmalloc(sizeof(uint64_t) * (max_bus + 1)); + kmemset(ecam_dev_bases[i], 0, sizeof(uint64_t) * (max_bus + 1)); acpi_parse_mcfg_conf_start(&mcfg_handle); + acpi_parse_mcfg_conf(&conf, &mcfg_handle); while (mcfg_handle) { - acpi_parse_mcfg_conf(&conf, &mcfg_handle); - if (conf.segment == i) { for (j = conf.bus_start; j <= conf.bus_end; j++) { - vaddr = mm_alloc_v(PAGE_SIZE_4K); - paging_map(vaddr, BUS_BASE(conf.base, j), PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); - ecam_bus_bases[i][j] = vaddr; + ecam_dev_bases[i][j] = kmalloc(32 * sizeof(uint64_t)); + for (k = 0; k < 32; k++) { + vaddr = mm_alloc_v(PAGE_SIZE_4K); + paging_map(vaddr, DEV_BASE(conf.base, j, k), PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + ecam_dev_bases[i][j][k] = vaddr; + } } } + + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + } + } +} + +static void enumerate_bus(uint16_t seg, uint8_t bus) { + uint8_t dev; + logging_log_debug("Enumerating pcie bus %u.%u", seg, bus); + for (dev = 0; dev < 32; dev++) { + if (!DEVICE_EXISTS(seg, bus, dev)) { + continue; + } + switch (HEADER_TYPE(seg, bus, dev)) { + case 0: + logging_log_debug("Found device 0x%x:0x%x on %u.%u.%u", + VENDOR_ID(seg, bus, dev), DEVICE_ID(seg, bus, dev), seg, bus, dev); + break; + case 1: + logging_log_debug("Found PCI bridge on %u.%u.%u", seg, bus, dev); + enumerate_bus(seg, PCI_BRIDGE_SEC_NUM(seg, bus, dev)); + break; + case 2: + logging_log_debug("Found CardBus bridge on %u.%u.%u", seg, bus, dev); + break; + default: + logging_log_error("Bad device on pcie %u.%u.%u", seg, bus, dev); + break; } } + logging_log_debug("Done enumerating pcie bus %u.%u", seg, bus); } void pcie_enumerate(void) { + uint64_t mcfg_handle; + struct acpi_mcfg_conf_t conf; + + acpi_parse_mcfg_conf_start(&mcfg_handle); + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + while (mcfg_handle) { + enumerate_bus(conf.segment, conf.bus_start); + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + } } diff --git a/kernel/core/paging.c b/kernel/core/paging.c index 47bf506..010c0f2 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -82,7 +82,7 @@ void paging_init(void) { lock_init(&paging_lock); } -uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint8_t flg, enum page_size_t page_size) { +uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum page_size_t page_size) { uint64_t* access; enum page_size_t lvl = page_walk(vaddr, &access); diff --git a/kernel/include/core/paging.h b/kernel/include/core/paging.h index 12c2d4c..82319a7 100644 --- a/kernel/include/core/paging.h +++ b/kernel/include/core/paging.h @@ -24,6 +24,7 @@ #define PAGE_PRESENT 0x1 #define PAGE_RW 0x2 #define PAT_MMIO_4K 0x98 +#define PAT_MMIO_2M 0x1018 #define PAGE_BASE_MASK 0xFFFFFFFFFFFFF000 @@ -42,7 +43,7 @@ enum page_size_t { extern void paging_init(void); -extern uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint8_t flg, enum page_size_t page_size); +extern uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum page_size_t page_size); extern void paging_unmap(uint64_t vaddr, enum page_size_t page_size); extern uint64_t paging_ident(uint64_t paddr); diff --git a/scripts/simulate_qemu b/scripts/simulate_qemu index edb381a..e86341d 100755 --- a/scripts/simulate_qemu +++ b/scripts/simulate_qemu @@ -10,8 +10,14 @@ qemu-system-x86_64 \ -m 16G \ -monitor stdio \ -drive if=none,id=disk0,file=build/modulos.img,format=raw \ - -device ahci,id=ahci \ + -device pcie-root-port,id=pcie.1,bus=pcie.0,chassis=1 \ + -device pcie-root-port,id=pcie.2,bus=pcie.0,chassis=2 \ + -device pcie-root-port,id=pcie.3,bus=pcie.2,chassis=3 \ + -device ahci,id=ahci,bus=pcie.1 \ -device ide-hd,drive=disk0,bus=ahci.0,bootindex=1 \ + -device usb-ehci,id=uhci.0,bus=pcie.3 \ + -device usb-ehci,id=uhci.1,bus=pcie.3 \ + -device qemu-xhci,id=xhci.0,bus=pcie.2 \ -smbios type=0,uefi=on \ -bios /usr/share/qemu/OVMF.fd \ -device VGA From bf5a1f49987ac67a5dc9732330ec286844f9abe7 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 23 Feb 2026 16:10:20 -0800 Subject: [PATCH 03/11] function enumeration --- Makefile | 2 +- drivers/include/pcie/pcie.h | 2 + drivers/pcie/pcie_init.c | 91 ++++++++++++++++++++++++------------- kernel/core/kentry.c | 5 +- 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index bfadf15..cc357d4 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -export DEBUG = 1 +#export DEBUG = 1 export DEBUG_LOGGING = 1 # Global options diff --git a/drivers/include/pcie/pcie.h b/drivers/include/pcie/pcie.h index 22599cb..aa58d90 100644 --- a/drivers/include/pcie/pcie.h +++ b/drivers/include/pcie/pcie.h @@ -20,6 +20,8 @@ #include +#define PCI_CMD_REG 0x4 + extern uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off); extern void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val); diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c index 1446443..315bbd9 100644 --- a/drivers/pcie/pcie_init.c +++ b/drivers/pcie/pcie_init.c @@ -29,16 +29,70 @@ #define DEV_BASE(ecam, bus, dev) (ecam + (((uint64_t)bus << 20) | ((uint64_t)dev << 15))) -#define DEVICE_EXISTS(seg, bus, dev) (VENDOR_ID(seg, bus, dev) != 0xFFFF) +#define FUNCTION_EXISTS(seg, bus, dev, func) (VENDOR_ID(seg, bus, dev, func) != 0xFFFF) -#define VENDOR_ID(seg, bus, dev) (0xFFFF & pcie_read(seg, bus, dev, 0, 0x0)) -#define DEVICE_ID(seg, bus, dev) (0xFFFF & (pcie_read(seg, bus, dev, 0, 0x0) >> 16)) -#define HEADER_TYPE(seg, bus, dev) (0x7F & (pcie_read(seg, bus, dev, 0, 0xC) >> 16)) +#define VENDOR_ID(seg, bus, dev, func) (0xFFFF & pcie_read(seg, bus, dev, func, 0x0)) +#define DEVICE_ID(seg, bus, dev, func) (0xFFFF & (pcie_read(seg, bus, dev, func, 0x0) >> 16)) +#define REV_ID(seg, bus, dev, func) (0xFF & pcie_read(seg, bus, dev, func, 0x8)) +#define PROG_IF(seg, bus, dev, func) (0xFF & (pcie_read(seg, bus, dev, func, 0x8) >> 8)) +#define SUBCLASS(seg, bus, dev, func) (0xFF & (pcie_read(seg, bus, dev, func, 0x8) >> 16)) +#define CLASS_CODE(seg, bus, dev, func) (0xFF & (pcie_read(seg, bus, dev, func, 0x8) >> 24)) +#define HEADER_TYPE(seg, bus, dev, func) (0x7F & (pcie_read(seg, bus, dev, func, 0xC) >> 16)) +#define IS_MULTIFUNC(seg, bus, dev) (0x80 & (pcie_read(seg, bus, dev, 0, 0xC) >> 16)) -#define PCI_BRIDGE_SEC_NUM(seg, bus, dev) (0xFF & (pcie_read(seg, bus, dev, 0, 0x18) >> 8)) + +#define PCI_BRIDGE_SEC_NUM(seg, bus, dev, func) (0xFF & (pcie_read(seg, bus, dev, func, 0x18) >> 8)) + +#define DISABLE_INT(seg, bus, dev, func) pcie_write(seg, bus, dev, func, 0x4, pcie_read(seg, bus, dev, 0, 0x4) | 0x400); extern uint64_t*** ecam_dev_bases; +static void enumerate_bus(uint16_t seg, uint8_t bus); + +static void configure_device(uint16_t seg, uint8_t bus, uint8_t dev, uint8_t func) { + DISABLE_INT(seg, bus, dev, func); + + switch (HEADER_TYPE(seg, bus, dev, func)) { + case 0: + logging_log_debug("Found device 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u", + VENDOR_ID(seg, bus, dev, 0), DEVICE_ID(seg, bus, dev, func), CLASS_CODE(seg, bus, dev, func), + SUBCLASS(seg, bus, dev, func), PROG_IF(seg, bus, dev, func), REV_ID(seg, bus, dev, func), seg, bus, dev, func); + break; + case 1: + logging_log_debug("Found PCI bridge on %u.%u.%u.%u", seg, bus, dev, func); + enumerate_bus(seg, PCI_BRIDGE_SEC_NUM(seg, bus, dev, func)); + break; + case 2: + logging_log_debug("Found CardBus bridge on %u.%u.%u.%u", seg, bus, dev, func); + break; + default: + logging_log_error("Bad device on pcie %u.%u.%u.%u", seg, bus, dev, func); + break; + } +} + +static void enumerate_bus(uint16_t seg, uint8_t bus) { + uint8_t dev; + uint8_t func; + logging_log_debug("Enumerating pcie bus %u.%u", seg, bus); + for (dev = 0; dev < 32; dev++) { + if (!FUNCTION_EXISTS(seg, bus, dev, 0)) { + continue; + } + + configure_device(seg, bus, dev, 0); + + if (IS_MULTIFUNC(seg, bus, dev)) { + for (func = 1; func < 8; func ++) { + if (FUNCTION_EXISTS(seg, bus, dev, func)) { + configure_device(seg, bus, dev, func); + } + } + } + } + logging_log_debug("Done enumerating pcie bus %u.%u", seg, bus); +} + void pcie_init(void) { uint64_t mcfg_handle; struct acpi_mcfg_conf_t conf; @@ -105,33 +159,6 @@ void pcie_init(void) { } } -static void enumerate_bus(uint16_t seg, uint8_t bus) { - uint8_t dev; - logging_log_debug("Enumerating pcie bus %u.%u", seg, bus); - for (dev = 0; dev < 32; dev++) { - if (!DEVICE_EXISTS(seg, bus, dev)) { - continue; - } - switch (HEADER_TYPE(seg, bus, dev)) { - case 0: - logging_log_debug("Found device 0x%x:0x%x on %u.%u.%u", - VENDOR_ID(seg, bus, dev), DEVICE_ID(seg, bus, dev), seg, bus, dev); - break; - case 1: - logging_log_debug("Found PCI bridge on %u.%u.%u", seg, bus, dev); - enumerate_bus(seg, PCI_BRIDGE_SEC_NUM(seg, bus, dev)); - break; - case 2: - logging_log_debug("Found CardBus bridge on %u.%u.%u", seg, bus, dev); - break; - default: - logging_log_error("Bad device on pcie %u.%u.%u", seg, bus, dev); - break; - } - } - logging_log_debug("Done enumerating pcie bus %u.%u", seg, bus); -} - void pcie_enumerate(void) { uint64_t mcfg_handle; struct acpi_mcfg_conf_t conf; diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index ebf1ccf..2f35b97 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -77,16 +77,13 @@ void kentry(void) { logging_log_debug("Early PCIE init"); pcie_init(); + pcie_enumerate(); logging_log_debug("Early PCIE init done"); logging_log_debug("ACPICA init"); acpica_init(); logging_log_debug("ACPICA init done"); - logging_log_debug("PCIE enumeration"); - pcie_enumerate(); - logging_log_debug("PCIE enumeration done"); - logging_log_info("Boot Complete ModulOS"); logging_log_info("Begining AP bootstrap sequence"); From 67bed802f05dffdd7e4713de0d8307247668d138 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 23 Feb 2026 17:46:03 -0800 Subject: [PATCH 04/11] register ahci initializations to scheduler queue --- Makefile | 2 + drivers/Makefile | 4 + drivers/ahci/ahci_init.c | 66 +++++++++++++ drivers/include/ahci/ahci_init.h | 34 +++++++ drivers/include/pcie/generic_database.h | 44 +++++++++ drivers/pcie/generic_database.c | 120 ++++++++++++++++++++++++ drivers/pcie/pcie_init.c | 31 ++++-- kernel/core/process.c | 14 +++ kernel/include/core/process.h | 4 + 9 files changed, 310 insertions(+), 9 deletions(-) create mode 100644 drivers/ahci/ahci_init.c create mode 100644 drivers/include/ahci/ahci_init.h create mode 100644 drivers/include/pcie/generic_database.h create mode 100644 drivers/pcie/generic_database.c diff --git a/Makefile b/Makefile index cc357d4..4de59b9 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,8 @@ export BUILD_DRIVERS_SERIAL = 1 export BUILD_DRIVERS_HPET = 1 +export BUILD_DRIVERS_AHCI = 1 + # End of options export SRC_TREE_ROOT = . diff --git a/drivers/Makefile b/drivers/Makefile index 6e8b6ad..99cccf6 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -34,6 +34,10 @@ ifdef BUILD_DRIVERS_SERIAL $(call add_directory,serial,SERIAL) endif +ifdef BUILD_DRIVERS_AHCI +$(call add_directory,ahci,AHCI) +endif + include $(SRC_TREE_ROOT)/scripts/Makefile.kcflags include $(SRC_TREE_ROOT)/scripts/Makefile.targets diff --git a/drivers/ahci/ahci_init.c b/drivers/ahci/ahci_init.c new file mode 100644 index 0000000..3fd1f51 --- /dev/null +++ b/drivers/ahci/ahci_init.c @@ -0,0 +1,66 @@ +/* ahci_init.c - Advanced Host Controller Interface initialization */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +#include +#include +#include +#include + +struct ahci_t { + uint16_t seg; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint8_t class_code; + uint8_t subclass; + uint8_t prog_if; + uint8_t rev_id; +}; + +static void ahci_init(void* cntx) { + struct ahci_t* ahci = cntx; + + logging_log_info("AHCI driver initialization for %u/%u/%u/%u at %u.%u.%u.%u.", + ahci->class_code, ahci->subclass, ahci->prog_if, ahci->rev_id, ahci->seg, ahci->bus, ahci->dev, ahci->func); +} + +void ahci_generic( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id) { + + struct ahci_t* ahci = kmalloc(sizeof(struct ahci_t)); + ahci->seg = seg; + ahci->bus = bus; + ahci->dev = dev; + ahci->func = func; + ahci->class_code = class_code; + ahci->subclass = subclass; + ahci->prog_if = prog_if; + ahci->rev_id = rev_id; + + scheduler_schedule(process_from_func(ahci_init, ahci)); +} diff --git a/drivers/include/ahci/ahci_init.h b/drivers/include/ahci/ahci_init.h new file mode 100644 index 0000000..3e58fc6 --- /dev/null +++ b/drivers/include/ahci/ahci_init.h @@ -0,0 +1,34 @@ +/* ahci_init.h - Advanced Host Controller Interface initialization interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_AHCI_AHCI_INIT_H +#define DRIVERS_AHCI_AHCI_INIT_H + +#include +#include + +extern void ahci_generic( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id); + +#endif /* DRIVERS_AHCI_AHCI_INIT_H */ diff --git a/drivers/include/pcie/generic_database.h b/drivers/include/pcie/generic_database.h new file mode 100644 index 0000000..c1b03d1 --- /dev/null +++ b/drivers/include/pcie/generic_database.h @@ -0,0 +1,44 @@ +/* generic_base.h - Peripheral Controller Interface Express generic drivers database interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_INCLUDE_GENERIC_DATABASE_H +#define DRIVERS_INCLUDE_GENERIC_DATABASE_H + +#include + +typedef void (*generic_driver_t)( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id); + +extern void pcie_generic_init( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id); + +#endif /* DRIVERS_INCLUDE_GENERIC_DATABASE_H */ + diff --git a/drivers/pcie/generic_database.c b/drivers/pcie/generic_database.c new file mode 100644 index 0000000..784771a --- /dev/null +++ b/drivers/pcie/generic_database.c @@ -0,0 +1,120 @@ +/* generic_database.c - Peripheral Controller Interface Express generic drivers database */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +#ifdef AHCI +#include +#endif /* AHCI */ + +#define CLASS_LIMIT 0x1 + +#ifdef AHCI + +#ifndef U_MASS_STORAGE_CONTROLLER +#define U_MASS_STORAGE_CONTROLLER +#endif /* U_MASS_STORAGE_CONTROLLER */ + +#ifndef U_SATA +#define U_SATA +#endif /* U_SATA */ + +#ifndef U_AHCI +#define U_AHCI +#endif /* U_AHCI */ + +#endif /* AHCI */ + +#ifdef U_SATA +#define SATA_LIMIT 0x02 +static generic_driver_t sata_table[SATA_LIMIT + 1] = { +#ifdef U_AHCI + [0x01] = ahci_generic +#endif /* U_AHCI */ +}; + +static void u_sata( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id) { + if (prog_if > SATA_LIMIT) { + return; + } + + if (sata_table[prog_if]) { + sata_table[prog_if](seg, bus, dev, func, class_code, subclass, prog_if, rev_id); + } +} +#endif /* U_SATA */ + +#ifdef U_MASS_STORAGE_CONTROLLER +#define MASS_STORAGE_CONTROLLER_LIMIT 0x06 +static generic_driver_t mass_storage_controller_table[MASS_STORAGE_CONTROLLER_LIMIT + 1] = { +#ifdef U_SATA + [0x06] = u_sata +#endif /* U_SATA */ +}; + +static void u_mass_storage_controller( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id) { + if (subclass > MASS_STORAGE_CONTROLLER_LIMIT) { + return; + } + + if (mass_storage_controller_table[subclass]) { + mass_storage_controller_table[subclass](seg, bus, dev, func, class_code, subclass, prog_if, rev_id); + } +} +#endif /* U_MASS_STORAGE_CONTROLLER */ + +static generic_driver_t class_table[CLASS_LIMIT + 1] = { +#ifdef U_MASS_STORAGE_CONTROLLER + [0x01] = u_mass_storage_controller +#endif /* U_MASS_STORAGE_CONTROLLER */ +}; + +void pcie_generic_init( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id) { + if (class_code > CLASS_LIMIT) { + return; + } + + if (class_table[class_code]) { + class_table[class_code](seg, bus, dev, func, class_code, subclass, prog_if, rev_id); + } +} diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c index 315bbd9..a68448b 100644 --- a/drivers/pcie/pcie_init.c +++ b/drivers/pcie/pcie_init.c @@ -17,6 +17,7 @@ #include #include +#include #include @@ -49,26 +50,38 @@ extern uint64_t*** ecam_dev_bases; static void enumerate_bus(uint16_t seg, uint8_t bus); -static void configure_device(uint16_t seg, uint8_t bus, uint8_t dev, uint8_t func) { +static void configure_function(uint16_t seg, uint8_t bus, uint8_t dev, uint8_t func) { DISABLE_INT(seg, bus, dev, func); + const uint16_t vendor_id = VENDOR_ID(seg, bus, dev, func); + const uint16_t device_id = DEVICE_ID(seg, bus, dev, func); + const uint8_t class_code = CLASS_CODE(seg, bus, dev, func); + const uint8_t subclass = SUBCLASS(seg, bus, dev, func); + const uint8_t prog_if = PROG_IF(seg, bus, dev, func); + const uint8_t rev_id = REV_ID(seg, bus, dev, func); + + switch (HEADER_TYPE(seg, bus, dev, func)) { case 0: - logging_log_debug("Found device 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u", - VENDOR_ID(seg, bus, dev, 0), DEVICE_ID(seg, bus, dev, func), CLASS_CODE(seg, bus, dev, func), - SUBCLASS(seg, bus, dev, func), PROG_IF(seg, bus, dev, func), REV_ID(seg, bus, dev, func), seg, bus, dev, func); + logging_log_debug("Found device function 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u.", + vendor_id, device_id, class_code, subclass, prog_if, rev_id, seg, bus, dev, func); break; case 1: - logging_log_debug("Found PCI bridge on %u.%u.%u.%u", seg, bus, dev, func); + logging_log_debug("Found PCI bridge function 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u", + vendor_id, device_id, class_code, subclass, prog_if, rev_id, seg, bus, dev, func); enumerate_bus(seg, PCI_BRIDGE_SEC_NUM(seg, bus, dev, func)); break; case 2: - logging_log_debug("Found CardBus bridge on %u.%u.%u.%u", seg, bus, dev, func); + logging_log_debug("Found CardBus bridge function 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u", + vendor_id, device_id, class_code, subclass, prog_if, rev_id, seg, bus, dev, func); break; default: - logging_log_error("Bad device on pcie %u.%u.%u.%u", seg, bus, dev, func); + logging_log_debug("Found unkown function 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u", + vendor_id, device_id, class_code, subclass, prog_if, rev_id, seg, bus, dev, func); break; } + + pcie_generic_init(seg, bus, dev, func, class_code, subclass, prog_if, rev_id); } static void enumerate_bus(uint16_t seg, uint8_t bus) { @@ -80,12 +93,12 @@ static void enumerate_bus(uint16_t seg, uint8_t bus) { continue; } - configure_device(seg, bus, dev, 0); + configure_function(seg, bus, dev, 0); if (IS_MULTIFUNC(seg, bus, dev)) { for (func = 1; func < 8; func ++) { if (FUNCTION_EXISTS(seg, bus, dev, func)) { - configure_device(seg, bus, dev, func); + configure_function(seg, bus, dev, func); } } } diff --git a/kernel/core/process.c b/kernel/core/process.c index df889eb..1445b92 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -35,6 +35,11 @@ static uint64_t next_pid; static uint8_t lock_proc; +__attribute__((noreturn)) static void function_setup(process_function_t func, void* cntx) { + func(cntx); + process_kill_current(); +} + void process_init(uint64_t init_rsp) { next_pid = 1; lock_init(&lock_proc); @@ -100,6 +105,15 @@ struct pcb_t* process_from_vaddr(uint64_t vaddr) { return pcb; } +struct pcb_t* process_from_func(process_function_t func, void* cntx) { + struct pcb_t* pcb = process_from_vaddr((uint64_t)function_setup); + + pcb->rdi = (uint64_t)func; + pcb->rsi = (uint64_t)cntx; + + return pcb; +} + void process_kill_current(void) { lock_acquire(&lock_proc); struct pcb_t* pcb = proc_data_get()->current_process; diff --git a/kernel/include/core/process.h b/kernel/include/core/process.h index 58e1156..da49c6b 100644 --- a/kernel/include/core/process.h +++ b/kernel/include/core/process.h @@ -86,6 +86,8 @@ struct preempt_frame_t { uint64_t ss; } __attribute__((packed)); +typedef void (*process_function_t)(void* cntx); + extern uint64_t process_get_pid(void); extern void process_init(uint64_t init_rsp); @@ -94,6 +96,8 @@ extern void process_init_ap(uint64_t init_rsp); extern struct pcb_t* process_from_vaddr(uint64_t vaddr); +extern struct pcb_t* process_from_func(process_function_t func, void* cntx); + extern void process_resume(struct pcb_t* pcb) __attribute__((noreturn)); extern void process_kill_current(void) __attribute__((noreturn)); From 8041cd433697e817523cccec650ed5721e22a700 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Fri, 27 Feb 2026 12:28:14 -0800 Subject: [PATCH 05/11] fixed function offset for ecam --- Makefile | 2 +- drivers/ahci/ahci_init.c | 6 +++++- drivers/include/pcie/pcie.h | 16 ++++++++++++++- drivers/pcie/pcie.c | 8 +++----- drivers/pcie/pcie_init.c | 39 +++++++++++++++++++++++++------------ scripts/simulate_qemu | 20 ++++--------------- 6 files changed, 55 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index 4de59b9..de0f7fa 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -#export DEBUG = 1 +export DEBUG = 1 export DEBUG_LOGGING = 1 # Global options diff --git a/drivers/ahci/ahci_init.c b/drivers/ahci/ahci_init.c index 3fd1f51..4264c68 100644 --- a/drivers/ahci/ahci_init.c +++ b/drivers/ahci/ahci_init.c @@ -19,6 +19,8 @@ #include +#include + #include #include #include @@ -38,8 +40,10 @@ struct ahci_t { static void ahci_init(void* cntx) { struct ahci_t* ahci = cntx; - logging_log_info("AHCI driver initialization for %u/%u/%u/%u at %u.%u.%u.%u.", + logging_log_info("AHCI driver initialization for %u/%u/%u/%u at %u.%u.%u.%u", ahci->class_code, ahci->subclass, ahci->prog_if, ahci->rev_id, ahci->seg, ahci->bus, ahci->dev, ahci->func); + + //uint32_t bar = pcie_read(ahci->seg, ahci->bus, ahci->dev, ahci->func, PCI_BAR5_REG); } void ahci_generic( diff --git a/drivers/include/pcie/pcie.h b/drivers/include/pcie/pcie.h index aa58d90..53edc9f 100644 --- a/drivers/include/pcie/pcie.h +++ b/drivers/include/pcie/pcie.h @@ -20,7 +20,21 @@ #include -#define PCI_CMD_REG 0x4 +#define PCI_ID_REG 0x00 +#define PCI_CMD_REG 0x04 +#define PCI_CLASS_REG 0x08 +#define PCI_ATTR_REG 0x0C +#define PCI_BAR0_REG 0x10 +#define PCI_BAR1_REG 0x14 +#define PCI_BAR2_REG 0x18 +#define PCI_BAR3_REG 0x1C +#define PCI_BAR4_REG 0x20 +#define PCI_BAR5_REG 0x24 + +#define PCI_CMD_IOSE 0x001 +#define PCI_CMD_MSE 0x002 +#define PCI_CMD_BME 0x004 +#define PCI_CMD_ID 0x400 extern uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off); extern void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val); diff --git a/drivers/pcie/pcie.c b/drivers/pcie/pcie.c index 900b821..1e1d869 100644 --- a/drivers/pcie/pcie.c +++ b/drivers/pcie/pcie.c @@ -19,14 +19,12 @@ #include -#define FUN_OFF(fun) ((uint64_t)fun << 12) - -uint64_t*** ecam_dev_bases; +uint64_t**** ecam; uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off) { - return *(volatile uint32_t*)((ecam_dev_bases[segment][bus][dev] | FUN_OFF(fun)) + off); + return *(volatile uint32_t*)(ecam[segment][bus][dev][fun] + off); } void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val) { - *(volatile uint32_t*)((ecam_dev_bases[segment][bus][dev] | FUN_OFF(fun)) + off) = val; + *(volatile uint32_t*)(ecam[segment][bus][dev][fun] + off) = val; } diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c index a68448b..0d34a7e 100644 --- a/drivers/pcie/pcie_init.c +++ b/drivers/pcie/pcie_init.c @@ -28,7 +28,7 @@ #include -#define DEV_BASE(ecam, bus, dev) (ecam + (((uint64_t)bus << 20) | ((uint64_t)dev << 15))) +#define FUN_BASE(ecam, bus, dev, fun) (ecam + (((uint64_t)bus << 20) | ((uint64_t)dev << 15) | ((uint64_t)fun << 12))) #define FUNCTION_EXISTS(seg, bus, dev, func) (VENDOR_ID(seg, bus, dev, func) != 0xFFFF) @@ -41,12 +41,13 @@ #define HEADER_TYPE(seg, bus, dev, func) (0x7F & (pcie_read(seg, bus, dev, func, 0xC) >> 16)) #define IS_MULTIFUNC(seg, bus, dev) (0x80 & (pcie_read(seg, bus, dev, 0, 0xC) >> 16)) +#define IS_MULTIFUNC_DIRECT(base) (0x80 & (*(volatile uint32_t*)(base + 0x0C) >> 16)) #define PCI_BRIDGE_SEC_NUM(seg, bus, dev, func) (0xFF & (pcie_read(seg, bus, dev, func, 0x18) >> 8)) #define DISABLE_INT(seg, bus, dev, func) pcie_write(seg, bus, dev, func, 0x4, pcie_read(seg, bus, dev, 0, 0x4) | 0x400); -extern uint64_t*** ecam_dev_bases; +extern uint64_t**** ecam; static void enumerate_bus(uint16_t seg, uint8_t bus); @@ -63,7 +64,7 @@ static void configure_function(uint16_t seg, uint8_t bus, uint8_t dev, uint8_t f switch (HEADER_TYPE(seg, bus, dev, func)) { case 0: - logging_log_debug("Found device function 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u.", + logging_log_debug("Found device function 0x%x:0x%x (%u/%u/%u/%u) on %u.%u.%u.%u", vendor_id, device_id, class_code, subclass, prog_if, rev_id, seg, bus, dev, func); break; case 1: @@ -113,8 +114,8 @@ void pcie_init(void) { uint16_t j; uint16_t max_bus; uint16_t i; - uint64_t vaddr = 0; - uint8_t k; + uint8_t k, l; + uint64_t vaddr; acpi_parse_mcfg_conf_start(&mcfg_handle); acpi_parse_mcfg_conf(&conf, &mcfg_handle); @@ -128,7 +129,7 @@ void pcie_init(void) { max_seg++; - ecam_dev_bases = kmalloc(sizeof(uint64_t*) * max_seg ); + ecam = kmalloc(sizeof(uint64_t***) * max_seg ); for (i = 0; i < max_seg; i++) { max_bus = 0; @@ -146,23 +147,37 @@ void pcie_init(void) { } if (!j) { - ecam_dev_bases[i] = 0; + ecam[i] = 0; continue; } - ecam_dev_bases[i] = kmalloc(sizeof(uint64_t) * (max_bus + 1)); - kmemset(ecam_dev_bases[i], 0, sizeof(uint64_t) * (max_bus + 1)); + ecam[i] = kmalloc(sizeof(uint64_t**) * (max_bus + 1)); + kmemset(ecam[i], 0, sizeof(uint64_t) * (max_bus + 1)); acpi_parse_mcfg_conf_start(&mcfg_handle); acpi_parse_mcfg_conf(&conf, &mcfg_handle); while (mcfg_handle) { if (conf.segment == i) { for (j = conf.bus_start; j <= conf.bus_end; j++) { - ecam_dev_bases[i][j] = kmalloc(32 * sizeof(uint64_t)); + ecam[i][j] = kmalloc(32 * sizeof(uint64_t*)); for (k = 0; k < 32; k++) { vaddr = mm_alloc_v(PAGE_SIZE_4K); - paging_map(vaddr, DEV_BASE(conf.base, j, k), PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); - ecam_dev_bases[i][j][k] = vaddr; + paging_map(vaddr, FUN_BASE(conf.base, j, k, 0), PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + + if (IS_MULTIFUNC_DIRECT(vaddr)) { + ecam[i][j][k] = kmalloc(8 * sizeof(uint64_t)); + ecam[i][j][k][0] = vaddr; + for (l = 1; l < 8; l++) { + vaddr = mm_alloc_v(PAGE_SIZE_4K); + paging_map(vaddr, FUN_BASE(conf.base, j, k, l), PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + ecam[i][j][k][l] = vaddr; + } + } + else { + ecam[i][j][k] = kmalloc(sizeof(uint64_t)); + ecam[i][j][k][0] = vaddr; + } + } } } diff --git a/scripts/simulate_qemu b/scripts/simulate_qemu index e86341d..bee931a 100755 --- a/scripts/simulate_qemu +++ b/scripts/simulate_qemu @@ -1,6 +1,8 @@ #!/bin/bash mkdir -p build/test-runtime/ +truncate -s 4G build/test-runtime/disk1.img + qemu-system-x86_64 \ -machine q35 \ -s -smp 4 \ @@ -10,30 +12,16 @@ qemu-system-x86_64 \ -m 16G \ -monitor stdio \ -drive if=none,id=disk0,file=build/modulos.img,format=raw \ + -drive if=none,id=disk1,file=build/test-runtime/disk1.img,format=raw \ -device pcie-root-port,id=pcie.1,bus=pcie.0,chassis=1 \ -device pcie-root-port,id=pcie.2,bus=pcie.0,chassis=2 \ -device pcie-root-port,id=pcie.3,bus=pcie.2,chassis=3 \ -device ahci,id=ahci,bus=pcie.1 \ -device ide-hd,drive=disk0,bus=ahci.0,bootindex=1 \ + -device ide-hd,drive=disk1,bus=ahci.1 \ -device usb-ehci,id=uhci.0,bus=pcie.3 \ -device usb-ehci,id=uhci.1,bus=pcie.3 \ -device qemu-xhci,id=xhci.0,bus=pcie.2 \ -smbios type=0,uefi=on \ -bios /usr/share/qemu/OVMF.fd \ -device VGA - - - - - -#-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \ - - -#qemu-system-x86_64 -s -smp 4 -serial vc -serial file:build/test-runtime/serial \ -# -d cpu_reset,int -m 16G -monitor stdio \ -# -drive format=raw,file=build/modulos.img,if=ide,media=disk \ -# -smbios type=0,uefi=on -bios /usr/share/qemu/OVMF.fd \ -# -device VGA \ -# -machine q35 - -#-drive if=pflash,format=raw,file=scripts/OVMF_VARS.fd \ From 11536b0f68663dc4c7e19747258f1503463ff93b Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sat, 7 Mar 2026 11:44:31 -0800 Subject: [PATCH 06/11] minimal ahci initialization --- Makefile | 2 +- drivers/ahci/ahci_init.c | 242 +++++++++++++++++++++++++++++++++++- drivers/include/pcie/pcie.h | 2 + kernel/core/scheduler.c | 1 + kernel/include/core/time.h | 1 + 5 files changed, 246 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 379628d..7cb2e53 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -export DEBUG = 1 +#export DEBUG = 1 export DEBUG_LOGGING = 1 # Global options diff --git a/drivers/ahci/ahci_init.c b/drivers/ahci/ahci_init.c index 4264c68..1970972 100644 --- a/drivers/ahci/ahci_init.c +++ b/drivers/ahci/ahci_init.c @@ -25,6 +25,46 @@ #include #include #include +#include +#include +#include +#include + +#include + +#define CAP_OFF 0x00 +#define GHC_OFF 0x04 +#define PI_OFF 0x0C +#define PXCLB_OFF(port) (0x100 + (0x80 * port) + 0x00) +#define PXCLBU_OFF(port) (0x100 + (0x80 * port) + 0x04) +#define PXFB_OFF(port) (0x100 + (0x80 * port) + 0x08) +#define PXFBU_OFF(port) (0x100 + (0x80 * port) + 0x0C) +#define PXCMD_OFF(port) (0x100 + (0x80 * port) + 0x18) +#define PXSSTS_OFF(port) (0x100 + (0x80 * port) + 0x28) +#define PXSCTL_OFF(port) (0x100 + (0x80 * port) + 0x2C) +#define PXSERR_OFF(port) (0x100 + (0x80 * port) + 0x30) + +#define CAP_NCS_MASK 0x1F00u +#define CAP_NCS_SHFT 8 +#define CAP_S64A 0x80000000u + +#define GHC_AE 0x80000000u +#define GHC_IE 0x1u + +#define CMD_ST 0x0001u +#define CMD_FRE 0x0010u +#define CMD_FR 0x4000u +#define CMD_CR 0x8000u + +#define SERR_CLEAR 0xFFF0F03 + +#define SCTL_DET_MSK 0x000Fu +#define SCTL_DET_RST 0x0001u + +#define SSTS_DET_EST 0x0003u + +#define CL_SIZE 256 +#define FIS_SIZE 1024 struct ahci_t { uint16_t seg; @@ -35,15 +75,215 @@ struct ahci_t { uint8_t subclass; uint8_t prog_if; uint8_t rev_id; + uint8_t num_com_slots; + uint64_t hba_reg; + struct { + uint64_t com_list_base; + uint64_t fis_base; + }* ports[32]; }; +static inline void hba_write(struct ahci_t* ahci, uint64_t off, uint32_t val) { + *(volatile uint32_t*)(ahci->hba_reg + off) = val; +} + +static inline uint32_t hba_read(struct ahci_t* ahci, uint64_t off) { + return *(volatile uint32_t*)(ahci->hba_reg + off); +} + +static inline void port_clear_errors(struct ahci_t* ahci, uint32_t i) { + hba_write(ahci, PXSERR_OFF(i), SERR_CLEAR); +} + +static void port_reset(struct ahci_t* ahci, uint32_t i) { + uint32_t read; + + read = hba_read(ahci, PXCMD_OFF(i)); + hba_write(ahci, PXCMD_OFF(i), read & ~CMD_ST); + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & CMD_CR) { + time_busy_wait(490 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & CMD_CR) { + logging_log_error("AHCI port %u hung", i); + } + } + + read = hba_read(ahci, PXSCTL_OFF(i)); + read &= ~SCTL_DET_MSK; + read |= SCTL_DET_RST; + hba_write(ahci, PXSCTL_OFF(i), read); + + time_busy_wait(1 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXSCTL_OFF(i)); + read &= ~SCTL_DET_MSK; + hba_write(ahci, PXSCTL_OFF(i), read); + + do { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXSSTS_OFF(i)); + } while ((read & SSTS_DET_EST) != SSTS_DET_EST); + + port_clear_errors(ahci, i); + logging_log_debug("HBA port %u reset complete", i); +} + static void ahci_init(void* cntx) { struct ahci_t* ahci = cntx; + uint32_t bar, i, read, ports, j; + uint8_t s64a; + uint32_t cl_pool_p = 0; + uint32_t fis_pool_p = 0; + uint64_t cl_pool_v = 0; + uint64_t fis_pool_v = 0; logging_log_info("AHCI driver initialization for %u/%u/%u/%u at %u.%u.%u.%u", ahci->class_code, ahci->subclass, ahci->prog_if, ahci->rev_id, ahci->seg, ahci->bus, ahci->dev, ahci->func); - //uint32_t bar = pcie_read(ahci->seg, ahci->bus, ahci->dev, ahci->func, PCI_BAR5_REG); + bar = pcie_read(ahci->seg, ahci->bus, ahci->dev, ahci->func, PCI_BAR5_REG) & PCI_BAR_BA_MAKS; + if (!bar) { + bar = (uint32_t)mm_alloc_pmax(0x2000, 0x2000, (uint64_t)~((uint32_t)0)); + if (!bar) { + logging_log_error("Failed to allocate memory for AHCI HBA space"); + panic(PANIC_NO_MEM); + } + } + pcie_write(ahci->seg, ahci->bus, ahci->dev, ahci->func, PCI_BAR5_REG, bar); + + ahci->hba_reg = mm_alloc_v(0x2000); + if (!ahci->hba_reg) { + logging_log_error("Failed to allocate for HBA register space"); + panic(PANIC_NO_MEM); + } + + paging_map(ahci->hba_reg, bar, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + paging_map(ahci->hba_reg + PAGE_SIZE_4K, bar + PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + + logging_log_debug("AHCI HBA mapped to 0x%lx", ahci->hba_reg); + + /* minimal initialization sequence */ + read = hba_read(ahci, GHC_OFF); + read &= ~GHC_IE; + read |= GHC_AE; + hba_write(ahci, GHC_OFF, read); + + ports = hba_read(ahci, PI_OFF); + + for (i = 0; i < 32; i++) { + if (ports & (1u << i)) { + logging_log_debug("AHCI supports port %u", i); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & (CMD_ST | CMD_FRE | CMD_FR | CMD_CR)) { + /* stop port execution */ + hba_write(ahci, PXCMD_OFF(i), read & ~CMD_ST); + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & CMD_CR) { + time_busy_wait(490 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & CMD_CR) { + logging_log_error("Failed to stop AHCI port %u. Port reset", i); + port_reset(ahci, i); + i--; + continue; + } + } + + if (read & CMD_FRE) { + hba_write(ahci, PXCMD_OFF(i), read & !CMD_FRE); + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & CMD_FR) { + time_busy_wait(490 * TIME_CONV_MS_TO_NS); + read = hba_read(ahci, PXCMD_OFF(i)); + if (read & CMD_FR) { + logging_log_error("Failed to stop AHCI port %u. Port reset", i); + port_reset(ahci, i); + i--; + continue; + } + } + } + } + } + } + + read = hba_read(ahci, CAP_OFF); + ahci->num_com_slots = (read & CAP_NCS_MASK) >> CAP_NCS_SHFT; + s64a = !!(read & CAP_S64A); + + j = 0; + for (i = 0; i < 32; i++) { + if (ports & (1u << i)) { + ahci->ports[i] = kmalloc(sizeof(*ahci->ports[i])); + + if (j % (PAGE_SIZE_4K / CL_SIZE) == 0) { + cl_pool_p = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); + if (!cl_pool_p) { + logging_log_error("Failed to allocate command list buffer"); + panic(PANIC_NO_MEM); + } + + cl_pool_v = mm_alloc_v(PAGE_SIZE_4K); + if (!cl_pool_v) { + logging_log_error("Failed to allocate command list buffer"); + panic(PANIC_NO_MEM); + } + + paging_map(cl_pool_v, cl_pool_p, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + } + + if (j % (PAGE_SIZE_4K / FIS_SIZE) == 0) { + fis_pool_p = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); + if (!fis_pool_p) { + logging_log_error("Failed to allocate FIS buffer"); + panic(PANIC_NO_MEM); + } + + fis_pool_v = mm_alloc_v(PAGE_SIZE_4K); + if (!fis_pool_v) { + logging_log_error("Failed to allocate FIS list buffer"); + panic(PANIC_NO_MEM); + } + + paging_map(fis_pool_v, fis_pool_p, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + } + + hba_write(ahci, PXCLB_OFF(i), cl_pool_p); + ahci->ports[i]->com_list_base = cl_pool_v; + + hba_write(ahci, PXFB_OFF(i), fis_pool_p); + ahci->ports[i]->fis_base = fis_pool_v; + + kmemset((void*)cl_pool_v, 0, CL_SIZE); + kmemset((void*)fis_pool_v, 0, FIS_SIZE); + + cl_pool_p += CL_SIZE; + cl_pool_v += CL_SIZE; + + fis_pool_p += FIS_SIZE; + fis_pool_v += FIS_SIZE; + j++; + + if (s64a) { + hba_write(ahci, PXCLBU_OFF(i), 0); + hba_write(ahci, PXFBU_OFF(i), 0); + } + + read = hba_read(ahci, PXCMD_OFF(i)); + read |= CMD_FRE; + hba_write(ahci, PXCMD_OFF(i), read); + port_clear_errors(ahci, i); + + logging_log_debug("AHCI port %u ready", i); + } + else { + ahci->ports[i] = 0; + } + } + + logging_log_info("AHCI init done"); } void ahci_generic( diff --git a/drivers/include/pcie/pcie.h b/drivers/include/pcie/pcie.h index 53edc9f..6ee320f 100644 --- a/drivers/include/pcie/pcie.h +++ b/drivers/include/pcie/pcie.h @@ -36,6 +36,8 @@ #define PCI_CMD_BME 0x004 #define PCI_CMD_ID 0x400 +#define PCI_BAR_BA_MAKS 0xFFFFE000 + extern uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off); extern void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val); diff --git a/kernel/core/scheduler.c b/kernel/core/scheduler.c index dcf7cf8..be58fd8 100644 --- a/kernel/core/scheduler.c +++ b/kernel/core/scheduler.c @@ -34,6 +34,7 @@ void scheduler_schedule(struct pcb_t* pcb) { lock_acquire(&lock_sched); if (active_queue_tail) { active_queue_tail->next = pcb; + active_queue_tail = active_queue_tail->next; } else { active_queue = pcb; diff --git a/kernel/include/core/time.h b/kernel/include/core/time.h index a226554..7976c0c 100644 --- a/kernel/include/core/time.h +++ b/kernel/include/core/time.h @@ -27,6 +27,7 @@ extern void time_init(void); +//TODO: implement task sleep extern uint64_t time_busy_wait(uint64_t min_ns); extern uint64_t time_since_init_ns(void); From 55930265b78d2651bfbf4b92f6325944fb6738e1 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sat, 7 Mar 2026 12:34:07 -0800 Subject: [PATCH 07/11] fixed acpi table mapping --- Makefile | 2 +- drivers/acpi/tables.c | 137 +++++++++++++++++++++++++++--------------- kernel/core/mm.c | 8 +-- 3 files changed, 92 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 7cb2e53..379628d 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -#export DEBUG = 1 +export DEBUG = 1 export DEBUG_LOGGING = 1 # Global options diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 090a346..376701f 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -233,11 +234,7 @@ static uint8_t hpet_count; #define CHECK_AND_COPY(sig, tbl, store, fnd, post) \ do { \ if (!kmemcmp((uint8_t*)gen->Signature, sig, 4)) { \ - map_table(gen); \ - if (verify_checksum(gen)) { \ - CHECK_FAIL(sig); \ - } \ - logging_log_info("Found ACPI " tbl " @ 0x%lX", (uint64_t)gen); \ + logging_log_info("Copying ACPI " tbl " @ 0x%lX", (uint64_t)gen); \ store = kmalloc(gen->Length); \ kmemcpy((void*)store, (void*)gen, gen->Length); \ found |= fnd; \ @@ -246,45 +243,68 @@ static uint8_t hpet_count; } \ while (0) -static void map_header(const volatile void* table) { - // ACPI memory will never collide, so identity map everything +static inline uint8_t verify_checksum(const volatile struct acpi_gen_header_t* table) { const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table; - uint64_t alloc_base = (uint64_t)gen & PAGE_BASE_MASK; + return hash_byte_sum((void*)gen, gen->Length); +} + +static volatile void* map_table(const volatile void* table) { + uint64_t base = (uint64_t)table & PAGE_BASE_MASK, vaddr, len, off; + volatile struct acpi_gen_header_t* v_table; - if (!paging_map(alloc_base, alloc_base, PAGE_PRESENT | PAT_MMIO_4K, PAGE_4K)) { - logging_log_error("Failed to map ACPI header"); - panic(PANIC_PAGING); + vaddr = mm_alloc_v(PAGE_SIZE_4K * 2); + if (!vaddr) { + logging_log_error("Failed to allocate memory for ACPI table"); + panic(PANIC_NO_MEM); } - if ((uint64_t)gen != alloc_base) { - alloc_base += PAGE_SIZE_4K; - if (!paging_map(alloc_base, alloc_base, PAGE_PRESENT | PAT_MMIO_4K, PAGE_4K)) { - logging_log_error("Failed to map ACPI header"); - panic(PANIC_PAGING); - } + paging_map(vaddr, base, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + paging_map(vaddr + PAGE_SIZE_4K, base + PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + + v_table = (volatile struct acpi_gen_header_t*)(vaddr + (uint64_t)table - base); + if (!vaddr) { + logging_log_error("Failed to allocate memory for ACPI table"); + panic(PANIC_NO_MEM); } -} -static void map_table(const volatile void* table) { - const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table; - uint64_t alloc_base = (uint64_t)gen & PAGE_BASE_MASK; + logging_log_debug("Found ACPI table %4.4s", &v_table->Signature[0]); + if (verify_checksum(v_table)) { + paging_unmap(vaddr + base, PAGE_4K); + paging_unmap(vaddr + PAGE_SIZE_4K, PAGE_4K); - if ((uint64_t)gen != alloc_base) { - alloc_base += PAGE_SIZE_4K; + mm_free_v(vaddr, PAGE_SIZE_4K * 2); + + logging_log_warning("Bad Checksum for %4.4s", &v_table->Signature[0]); + return 0; } - while (alloc_base < (uint64_t)gen + gen->Length) { - alloc_base += PAGE_SIZE_4K; - if (!paging_map(alloc_base, alloc_base, PAGE_PRESENT | PAT_MMIO_4K, PAGE_4K)) { - logging_log_error("Failed to map ACPI table"); - panic(PANIC_PAGING); - } + len = v_table->Length + (uint64_t)table - base; + + paging_unmap(vaddr, PAGE_4K); + paging_unmap(vaddr + PAGE_SIZE_4K, PAGE_4K); + + mm_free_v(vaddr, PAGE_SIZE_4K * 2); + + vaddr = mm_alloc_v(len); + for (off = 0; off < len; off += PAGE_SIZE_4K) { + paging_map(vaddr + off, base + off, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); } + + return (void*)(vaddr + (uint64_t)table - base); } -static inline uint8_t verify_checksum(const volatile void* table) { - const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table; - return hash_byte_sum((void*)gen, gen->Length); +static void unmap_table(const volatile void* table) { + volatile struct acpi_gen_header_t* v_table = (volatile struct acpi_gen_header_t*)table; + uint64_t base, len, off; + + base = (uint64_t)table & PAGE_BASE_MASK; + len = v_table->Length + (uint64_t)table - base; + + for (off = 0; off < len; off += PAGE_SIZE_4K) { + paging_unmap(base + off, PAGE_4K); + } + + mm_free_v(base, len); } void acpi_copy_tables(void) { @@ -309,16 +329,15 @@ void acpi_copy_tables(void) { case RSDPV1: fallback: found = 0; - const struct acpi_rsdt_t* rsdt = (const struct acpi_rsdt_t*)(uint64_t)boot_context.rsdp.RsdtAddress; - map_header(rsdt); - if (kmemcmp(rsdt->Signature, "RSDT", 4)) { - logging_log_error("Bad ACPI RSDT signature"); + volatile struct acpi_rsdt_t* rsdt = (volatile struct acpi_rsdt_t*)(uint64_t)boot_context.rsdp.RsdtAddress; + rsdt = map_table(rsdt); + if (!rsdt) { + logging_log_error("Bad RSDT checksum"); panic(PANIC_ACPI); } - map_table(rsdt); - if (verify_checksum(rsdt)) { - logging_log_error("Bad ACPI RSDT checksum"); + if (kmemcmp((void*)rsdt->Signature, "RSDT", 4)) { + logging_log_error("Bad ACPI RSDT signature"); panic(PANIC_ACPI); } @@ -327,7 +346,11 @@ void acpi_copy_tables(void) { for (const volatile uint32_t* entry = &rsdt->Entry[0]; (uint64_t)entry < (uint64_t)rsdt + rsdt->Length; entry++) { gen = (const volatile struct acpi_gen_header_t*)(uint64_t)*entry; - map_header(gen); + gen = map_table(gen); + + if (!gen) { + continue; + } #define CHECK_FAIL(sig) CHECK_FAIL_RSDPV1(sig) CHECK_AND_COPY("FACP", "FADT", acpi_fadt, FOUND_FADT, (void)0); @@ -337,19 +360,23 @@ void acpi_copy_tables(void) { #endif /* HPET */ CHECK_AND_COPY("MCFG", "MCFG", acpi_mcfg, FOUND_MCFG, (void)0); #undef CHECK_FAIL + + unmap_table(gen); } if (found != FOUND_ALL) { logging_log_error("Could not find all ACPI tables"); + unmap_table(rsdt); panic(PANIC_ACPI); } if (kmemcmp((uint8_t*)rsdt->OEMTableID, (uint8_t*)acpi_fadt->OEMTableID, 8)) { - logging_log_error("Bad ACPI FACP OEM Table ID. Falling back to RSDPV1"); - goto fallback; + logging_log_error("Bad ACPI FACP OEM Table ID"); + unmap_table(rsdt); panic(PANIC_ACPI); } + unmap_table(rsdt); break; default: // backwards compat, so everything else is v2 @@ -362,16 +389,16 @@ void acpi_copy_tables(void) { } found = 0; - const struct acpi_xsdt_t* xsdt = (const struct acpi_xsdt_t*)boot_context.rsdp.XsdtAddress; - map_header(xsdt); - if (kmemcmp(xsdt->Signature, "XSDT", 4)) { - logging_log_warning("Bad ACPI XSDT signature. Falling back to RSDPV1"); + volatile struct acpi_xsdt_t* xsdt = (volatile struct acpi_xsdt_t*)boot_context.rsdp.XsdtAddress; + xsdt = map_table(xsdt); + + if (!xsdt) { + logging_log_warning("Bad ACPI XSDT checksum. Falling back to RSDPV1"); goto fallback; } - map_table(xsdt); - if (verify_checksum(xsdt)) { - logging_log_warning("Bad ACPI XSDT checksum. Falling back to RSDPV1"); + if (kmemcmp((void*)xsdt->Signature, "XSDT", 4)) { + logging_log_warning("Bad ACPI XSDT signature. Falling back to RSDPV1"); goto fallback; } @@ -380,7 +407,11 @@ void acpi_copy_tables(void) { for (const volatile uint64_t* entry = &xsdt->Entry[0]; (uint64_t)entry < (uint64_t)xsdt + xsdt->Length; entry++) { gen = (const volatile struct acpi_gen_header_t*)*entry; - map_header(gen); + gen = map_table(gen); + + if (!gen) { + continue; + } #define CHECK_FAIL(sig) CHECK_FAIL_RSDPV2(sig) CHECK_AND_COPY("FACP", "FADT", acpi_fadt, FOUND_FADT, (void)0); @@ -390,17 +421,23 @@ void acpi_copy_tables(void) { #endif /* HPET */ CHECK_AND_COPY("MCFG", "MCFG", acpi_mcfg, FOUND_MCFG, (void)0); #undef CHECK_FAIL + + unmap_table(gen); } if (found != FOUND_ALL) { logging_log_warning("Could not find all ACPI tables. Falling back to RSDPV1"); + unmap_table(xsdt); goto fallback; } if (kmemcmp((uint8_t*)xsdt->OEMTableID, (uint8_t*)acpi_fadt->OEMTableID, 8)) { logging_log_error("Bad ACPI FACP OEM Table ID. Falling back to RSDPV1"); + unmap_table(xsdt); goto fallback; } + + unmap_table(xsdt); break; } } diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 737b46e..2a77341 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -186,13 +186,13 @@ static void mm_free(uint64_t base, uint64_t size, struct mm_tree_node_t* root, u } else if (base < node->base) { node->less = alloc_node(); - node->base = base; - node->limit = size; + node->less->base = base; + node->less->limit = size; } else { node->more = alloc_node(); - node->base = base; - node->limit = size; + node->more->base = base; + node->more->limit = size; } //TODO: coallese From f6575df50dd03d3e4ff92be5559b7c016a941d4f Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sat, 7 Mar 2026 12:43:25 -0800 Subject: [PATCH 08/11] removed redundant pic and ioapic init in ap --- Makefile | 2 +- kernel/core/kentry.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 379628d..7cb2e53 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -export DEBUG = 1 +#export DEBUG = 1 export DEBUG_LOGGING = 1 # Global options diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 4044f02..f0dae9a 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -126,11 +126,9 @@ void kapentry(uint64_t arb_id) { logging_log_debug("AP TSS and IDT init done"); logging_log_debug("AP APIC init"); - pic_disab(); apic_init_ap(); apic_timer_calib(apic_get_bsp_id()); apic_nmi_enab(); - ioapic_init(); logging_log_debug("AP APIC init done"); logging_log_info("AP init complete"); From f859915c2e239eda573a74bb046935abf86daeee Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sat, 7 Mar 2026 13:00:26 -0800 Subject: [PATCH 09/11] ist2 logging and build output suppression --- Makefile | 2 ++ drivers/acpica/Makefile | 4 ++++ kernel/core/tss.c | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7cb2e53..a75cd7e 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,8 @@ #export DEBUG = 1 export DEBUG_LOGGING = 1 +export SUPPRESS_ACPICA_BUILD_OUTPUT = 1 + # Global options # Optional boot modules diff --git a/drivers/acpica/Makefile b/drivers/acpica/Makefile index 37951cb..144968c 100644 --- a/drivers/acpica/Makefile +++ b/drivers/acpica/Makefile @@ -46,7 +46,11 @@ $(OBJ_DIR)/../acpica.a: $(OBJ_DIR)/acpica.a ln $< $@ $(TARGETS): $(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)/ +ifdef SUPPRESS_ACPICA_BUILD_OUTPUT + $(CC) $(CFLAGS) -I $(SRC_TREE_ROOT)/include/drivers/acpica/ -Wno-error -o $@ $< 2> /dev/null +else $(CC) $(CFLAGS) -I $(SRC_TREE_ROOT)/include/drivers/acpica/ -Wno-error -o $@ $< +endif $(OBJ_DIR)/acpica.a: $(TARGETS) rm -f $@ diff --git a/kernel/core/tss.c b/kernel/core/tss.c index 668d748..800550d 100644 --- a/kernel/core/tss.c +++ b/kernel/core/tss.c @@ -48,8 +48,8 @@ void tss_init(volatile struct gdt_t(* gdt)[GDT_NUM_ENTRIES]) { tss->ist2_lo = ist2 & IST_LO_MASK; tss->ist2_hi = (uint32_t)(ist2 >> IST_HI_SHFT); - logging_log_debug("New TSS @ 0x%lX - 0x%lX 0x%lX (ist1)", - (uint64_t)tss, ist1); + logging_log_debug("New TSS @ 0x%lX - 0x%lX 0x%lX (ist1) 0x%lX (ist2)", + (uint64_t)tss, ist1, ist2); ((struct gdt_sys_t*)&(*gdt)[GDT_TSS_INDEX])->base0 = (uint64_t)tss & GDT_BASE0_MASK; From 5c06f20e8aff78325de99395bf561ad06baacf95 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sat, 7 Mar 2026 21:11:46 -0800 Subject: [PATCH 10/11] ata identify --- Makefile | 4 + drivers/Makefile | 4 + drivers/ahci/{ahci_init.c => ahci.c} | 198 ++++++++++++++++++- drivers/include/ahci/{ahci_init.h => ahci.h} | 9 +- drivers/include/sata/driver_database.h | 33 ++++ drivers/include/sata/fis.h | 121 ++++++++++++ drivers/pcie/generic_database.c | 45 +---- drivers/sata/driver_database.c | 59 ++++++ 8 files changed, 422 insertions(+), 51 deletions(-) rename drivers/ahci/{ahci_init.c => ahci.c} (62%) rename drivers/include/ahci/{ahci_init.h => ahci.h} (79%) create mode 100644 drivers/include/sata/driver_database.h create mode 100644 drivers/include/sata/fis.h create mode 100644 drivers/sata/driver_database.c diff --git a/Makefile b/Makefile index a75cd7e..90b48e8 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,10 @@ export BUILD_DRIVERS_AHCI = 1 # End of options +ifdef BUILD_DRIVERS_AHCI +export BUILD_DRIVERS_SATA = 1 +endif + export SRC_TREE_ROOT = . export OBJ_DIR = build diff --git a/drivers/Makefile b/drivers/Makefile index 99cccf6..1855c04 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -38,6 +38,10 @@ ifdef BUILD_DRIVERS_AHCI $(call add_directory,ahci,AHCI) endif +ifdef BUILD_DRIVERS_SATA +$(call add_directory,sata,SATA) +endif + include $(SRC_TREE_ROOT)/scripts/Makefile.kcflags include $(SRC_TREE_ROOT)/scripts/Makefile.targets diff --git a/drivers/ahci/ahci_init.c b/drivers/ahci/ahci.c similarity index 62% rename from drivers/ahci/ahci_init.c rename to drivers/ahci/ahci.c index 1970972..377bc13 100644 --- a/drivers/ahci/ahci_init.c +++ b/drivers/ahci/ahci.c @@ -1,4 +1,4 @@ -/* ahci_init.c - Advanced Host Controller Interface initialization */ +/* ahci.c - Advanced Host Controller Interface driver */ /* Copyright (C) 2026 Ebrahim Aleem * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,9 @@ #include -#include +#include + +#include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include @@ -40,9 +43,11 @@ #define PXFB_OFF(port) (0x100 + (0x80 * port) + 0x08) #define PXFBU_OFF(port) (0x100 + (0x80 * port) + 0x0C) #define PXCMD_OFF(port) (0x100 + (0x80 * port) + 0x18) +#define PXTFD_OFF(port) (0x100 + (0x80 * port) + 0x20) #define PXSSTS_OFF(port) (0x100 + (0x80 * port) + 0x28) #define PXSCTL_OFF(port) (0x100 + (0x80 * port) + 0x2C) #define PXSERR_OFF(port) (0x100 + (0x80 * port) + 0x30) +#define PXCI_OFF(port) (0x100 + (0x80 * port) + 0x38) #define CAP_NCS_MASK 0x1F00u #define CAP_NCS_SHFT 8 @@ -56,16 +61,62 @@ #define CMD_FR 0x4000u #define CMD_CR 0x8000u +#define TFD_STS_CON_MASK 0x88 + #define SERR_CLEAR 0xFFF0F03 #define SCTL_DET_MSK 0x000Fu #define SCTL_DET_RST 0x0001u +#define SSTS_DET_MASK 0x000Fu #define SSTS_DET_EST 0x0003u #define CL_SIZE 256 #define FIS_SIZE 1024 +#define SLOT_NO_SLOT 0xFF + +#define PRDT_DBC_I 0x80000000u + +struct ahci_recv_fis_t { + struct sata_fis_dma_setup_t dsfis; + uint32_t resv0; + struct sata_fis_pio_setupt_t psfis; + uint32_t resv1[3]; + struct sata_fis_type_d2h_t rfis; + uint32_t resv2; + uint64_t sdbfis; + uint8_t ufis[64]; + uint8_t resv3[96]; +} __attribute__((packed)); + +struct ahci_command_header_t { + uint16_t flg; + uint16_t prdtl; + uint32_t prdbc; + uint32_t ctba0; + uint32_t ctba_u0; + uint32_t resv0; + uint32_t resv1; + uint32_t resv2; + uint32_t resv3; +} __attribute__((packed)); + +struct ahci_command_table_t { + union { + uint8_t _64[64]; + struct sata_fis_type_h2d_t h2d; + } cfis; + uint8_t acmd[16]; + uint8_t resv[48]; + struct { + uint32_t dba; + uint32_t dbau; + uint32_t resv; + uint32_t dbc_i; + } __attribute__((packed)) prdt[]; +} __attribute__((packed)); + struct ahci_t { uint16_t seg; uint8_t bus; @@ -76,10 +127,12 @@ struct ahci_t { uint8_t prog_if; uint8_t rev_id; uint8_t num_com_slots; + uint8_t lock; uint64_t hba_reg; + uint32_t used_com; struct { - uint64_t com_list_base; - uint64_t fis_base; + struct ahci_command_header_t* com_list; + struct ahci_recv_fis_t* recv_fis; }* ports[32]; }; @@ -91,8 +144,110 @@ static inline uint32_t hba_read(struct ahci_t* ahci, uint64_t off) { return *(volatile uint32_t*)(ahci->hba_reg + off); } -static inline void port_clear_errors(struct ahci_t* ahci, uint32_t i) { - hba_write(ahci, PXSERR_OFF(i), SERR_CLEAR); +static inline void port_clear_errors(struct ahci_t* ahci, uint32_t port) { + hba_write(ahci, PXSERR_OFF(port), SERR_CLEAR); +} + +static uint8_t find_slot(struct ahci_t* ahci, uint32_t port) { + uint8_t slot; + uint32_t read; + + read = hba_read(ahci, PXCI_OFF(port)); + + for (slot = 0; slot < ahci->num_com_slots; slot++) { + if (!(ahci->used_com && (1u << slot)) && !(read && (1u << slot))) { + return slot; + } + } + + return SLOT_NO_SLOT; +} + +static void port_identify(struct ahci_t* ahci, uint32_t port) { + uint8_t slot; + uint32_t paddr_table, paddr_identity; + struct ahci_command_table_t* com_table; + uint16_t* identity; + uint8_t model[41]; + + paddr_table = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); + if (!paddr_table) { + logging_log_error("Failed to allocate memory for AHCI command table"); + return; + } + + paddr_identity = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); + if (!paddr_identity) { + logging_log_error("Failed to allocate memory for AHCI identity buffer"); + return; + } + + com_table = (struct ahci_command_table_t*)mm_alloc_v(PAGE_SIZE_4K); + if (!com_table) { + logging_log_error("Failed to allocate memory for AHCI command table"); + return; + } + + identity = (uint16_t*)mm_alloc_v(PAGE_SIZE_4K); + if (!identity) { + logging_log_error("Failed to allocate memory for AHCI identity buffer"); + return; + } + + paging_map((uint64_t)com_table, paddr_table, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + paging_map((uint64_t)identity, paddr_identity, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + + kmemset(com_table, 0, PAGE_SIZE_4K); + kmemset(identity, 0, PAGE_SIZE_4K); + + com_table->prdt[0].dba = paddr_identity; + com_table->prdt[0].dbau = 0; + com_table->prdt[0].dbc_i = 512 - 1; + + com_table->cfis.h2d.fis_type = SATA_FIS_TYPE_H2D; + com_table->cfis.h2d.flag = SATA_FIS_H2D_C; + com_table->cfis.h2d.cmd = SATA_FIS_CMD_IDENT; + + lock_acquire(&ahci->lock); + slot = find_slot(ahci, port); + ahci->used_com |= 1u << slot; + lock_release(&ahci->lock); + + ahci->ports[port]->com_list[slot].flg = 5; + ahci->ports[port]->com_list[slot].prdtl = 1; + ahci->ports[port]->com_list[slot].ctba0 = paddr_table; + ahci->ports[port]->com_list[slot].ctba_u0 = 0; + + while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + } + + hba_write(ahci, PXCI_OFF(port), 1u << slot); + + while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + } + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + + for (int i = 0; i < 20; i++) { + model[i*2] = identity[27 + i] >> 8; + model[i*2+1] = identity[27 + i] & 0xFF; + } + model[40] = 0; + + logging_log_info("Found ATA drive %s", &model[0]); + + paging_unmap((uint64_t)com_table, PAGE_4K); + paging_unmap((uint64_t)identity, PAGE_4K); + + mm_free_v((uint64_t)com_table, PAGE_SIZE_4K); + mm_free_v((uint64_t)identity, PAGE_SIZE_4K); + + mm_free_p(paddr_table, PAGE_SIZE_4K); + mm_free_p(paddr_identity, PAGE_SIZE_4K); } static void port_reset(struct ahci_t* ahci, uint32_t i) { @@ -123,7 +278,7 @@ static void port_reset(struct ahci_t* ahci, uint32_t i) { do { time_busy_wait(10 * TIME_CONV_MS_TO_NS); read = hba_read(ahci, PXSSTS_OFF(i)); - } while ((read & SSTS_DET_EST) != SSTS_DET_EST); + } while ((read & SSTS_DET_MASK) != SSTS_DET_EST); port_clear_errors(ahci, i); logging_log_debug("HBA port %u reset complete", i); @@ -141,6 +296,10 @@ static void ahci_init(void* cntx) { logging_log_info("AHCI driver initialization for %u/%u/%u/%u at %u.%u.%u.%u", ahci->class_code, ahci->subclass, ahci->prog_if, ahci->rev_id, ahci->seg, ahci->bus, ahci->dev, ahci->func); + lock_init(&ahci->lock); + + ahci->used_com = 0; + bar = pcie_read(ahci->seg, ahci->bus, ahci->dev, ahci->func, PCI_BAR5_REG) & PCI_BAR_BA_MAKS; if (!bar) { bar = (uint32_t)mm_alloc_pmax(0x2000, 0x2000, (uint64_t)~((uint32_t)0)); @@ -151,6 +310,8 @@ static void ahci_init(void* cntx) { } pcie_write(ahci->seg, ahci->bus, ahci->dev, ahci->func, PCI_BAR5_REG, bar); + //TODO: support BIOS/OS handoff + ahci->hba_reg = mm_alloc_v(0x2000); if (!ahci->hba_reg) { logging_log_error("Failed to allocate for HBA register space"); @@ -251,10 +412,10 @@ static void ahci_init(void* cntx) { } hba_write(ahci, PXCLB_OFF(i), cl_pool_p); - ahci->ports[i]->com_list_base = cl_pool_v; + ahci->ports[i]->com_list = (struct ahci_command_header_t*)cl_pool_v; hba_write(ahci, PXFB_OFF(i), fis_pool_p); - ahci->ports[i]->fis_base = fis_pool_v; + ahci->ports[i]->recv_fis = (struct ahci_recv_fis_t*)fis_pool_v; kmemset((void*)cl_pool_v, 0, CL_SIZE); kmemset((void*)fis_pool_v, 0, FIS_SIZE); @@ -274,9 +435,26 @@ static void ahci_init(void* cntx) { read = hba_read(ahci, PXCMD_OFF(i)); read |= CMD_FRE; hba_write(ahci, PXCMD_OFF(i), read); - port_clear_errors(ahci, i); + port_clear_errors(ahci, i); // clears X logging_log_debug("AHCI port %u ready", i); + + /* detect for connected device */ + read = hba_read(ahci, PXTFD_OFF(i)); + if (read & TFD_STS_CON_MASK) { + continue; + } + + read = hba_read(ahci, PXSSTS_OFF(i)); + if ((read & SSTS_DET_MASK) != SSTS_DET_EST) { + continue; + } + + read = hba_read(ahci, PXCMD_OFF(i)); + read |= CMD_ST; + hba_write(ahci, PXCMD_OFF(i), read); + + port_identify(ahci, i); } else { ahci->ports[i] = 0; diff --git a/drivers/include/ahci/ahci_init.h b/drivers/include/ahci/ahci.h similarity index 79% rename from drivers/include/ahci/ahci_init.h rename to drivers/include/ahci/ahci.h index 3e58fc6..8f53704 100644 --- a/drivers/include/ahci/ahci_init.h +++ b/drivers/include/ahci/ahci.h @@ -1,4 +1,4 @@ -/* ahci_init.h - Advanced Host Controller Interface initialization interface */ +/* ahci.h - Advanced Host Controller Interface driver interface */ /* Copyright (C) 2026 Ebrahim Aleem * * This program is free software: you can redistribute it and/or modify @@ -15,11 +15,10 @@ * along with this program. If not, see */ -#ifndef DRIVERS_AHCI_AHCI_INIT_H -#define DRIVERS_AHCI_AHCI_INIT_H +#ifndef DRIVERS_AHCI_AHCI_H +#define DRIVERS_AHCI_AHCI_H #include -#include extern void ahci_generic( uint16_t seg, @@ -31,4 +30,4 @@ extern void ahci_generic( uint8_t prog_if, uint8_t rev_id); -#endif /* DRIVERS_AHCI_AHCI_INIT_H */ +#endif /* DRIVERS_AHCI_AHCI_H */ diff --git a/drivers/include/sata/driver_database.h b/drivers/include/sata/driver_database.h new file mode 100644 index 0000000..4cf9981 --- /dev/null +++ b/drivers/include/sata/driver_database.h @@ -0,0 +1,33 @@ +/* driver_database.h - SATA drivers database interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_SATA_DRIVER_DATABASE_H +#define DRIVERS_SATA_DRIVER_DATABASE_H + +#include + +extern void sata_driver_database( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id); + +#endif /* DRIVERS_SATA_DRIVER_DATABASE_H */ diff --git a/drivers/include/sata/fis.h b/drivers/include/sata/fis.h new file mode 100644 index 0000000..040e762 --- /dev/null +++ b/drivers/include/sata/fis.h @@ -0,0 +1,121 @@ +/* fis.h - SATA Frame Information Structure */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_SATA_FIS_H +#define DRIVERS_SATA_FIS_H + +#include + +#define SATA_FIS_TYPE_H2D 0x27 +#define SATA_FIS_TYPE_D2H 0x34 +#define SATA_FIS_TYPE_SMA_SETUP 0x41 +#define SATA_FIS_TYPE_PIO_SETUP 0x5F +#define SATA_FIS_TYPE_SET_DEV 0xA1 + +#define SATA_FIS_H2D_C 0x80 + +#define SATA_FIS_CMD_IDENT 0xEC + +struct sata_fis_type_h2d_t { + uint8_t fis_type; + uint8_t flag; + uint8_t cmd; + uint8_t feat_lo; + + uint8_t lba0; + uint8_t lba1; + uint8_t lba2; + uint8_t dev; + + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t feat_hi; + + uint8_t count_lo; + uint8_t count_hi; + uint8_t icc; + uint8_t cntr; + + uint32_t resv0; +}; + +struct sata_fis_type_d2h_t { + uint8_t fis_type; + uint8_t flag; + uint8_t sts; + uint8_t err; + + uint8_t lba0; + uint8_t lba1; + uint8_t lba2; + uint8_t dev; + + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t resv0; + + uint8_t count_lo; + uint8_t count_hi; + uint16_t resv1; + + uint32_t resv2; +} __attribute__((packed)); + +struct sata_fis_dma_setup_t { + uint8_t fis_type; + uint8_t flag; + uint16_t resv0; + + uint64_t dma_buf_id; + + uint32_t resv1; + + uint32_t dma_buf_off; + + uint32_t trans_count; + + uint32_t resv3; +} __attribute__((packed)); + +struct sata_fis_pio_setupt_t { + uint8_t fis_type; + uint8_t flag; + uint8_t sts; + uint8_t err; + + uint8_t lba0; + uint8_t lba1; + uint8_t lba2; + uint8_t dev; + + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t resv0; + + uint8_t count_lo; + uint8_t count_hi; + uint8_t resv1; + uint8_t e_sts; + + uint16_t trans_count; + uint16_t resv2; +} __attribute__((packed)); + +#endif /* DRIVERS_SATA_FIS_H */ diff --git a/drivers/pcie/generic_database.c b/drivers/pcie/generic_database.c index 784771a..0795dfc 100644 --- a/drivers/pcie/generic_database.c +++ b/drivers/pcie/generic_database.c @@ -20,12 +20,16 @@ #include #ifdef AHCI -#include +#include #endif /* AHCI */ -#define CLASS_LIMIT 0x1 +#ifdef SATA +#include +#endif /* SATA */ -#ifdef AHCI +#define CLASS_LIMIT 0x13 + +#ifdef SATA #ifndef U_MASS_STORAGE_CONTROLLER #define U_MASS_STORAGE_CONTROLLER @@ -35,44 +39,13 @@ #define U_SATA #endif /* U_SATA */ -#ifndef U_AHCI -#define U_AHCI -#endif /* U_AHCI */ - -#endif /* AHCI */ - -#ifdef U_SATA -#define SATA_LIMIT 0x02 -static generic_driver_t sata_table[SATA_LIMIT + 1] = { -#ifdef U_AHCI - [0x01] = ahci_generic -#endif /* U_AHCI */ -}; - -static void u_sata( - uint16_t seg, - uint8_t bus, - uint8_t dev, - uint8_t func, - uint8_t class_code, - uint8_t subclass, - uint8_t prog_if, - uint8_t rev_id) { - if (prog_if > SATA_LIMIT) { - return; - } - - if (sata_table[prog_if]) { - sata_table[prog_if](seg, bus, dev, func, class_code, subclass, prog_if, rev_id); - } -} -#endif /* U_SATA */ +#endif /* SATA */ #ifdef U_MASS_STORAGE_CONTROLLER #define MASS_STORAGE_CONTROLLER_LIMIT 0x06 static generic_driver_t mass_storage_controller_table[MASS_STORAGE_CONTROLLER_LIMIT + 1] = { #ifdef U_SATA - [0x06] = u_sata + [0x06] = sata_driver_database #endif /* U_SATA */ }; diff --git a/drivers/sata/driver_database.c b/drivers/sata/driver_database.c new file mode 100644 index 0000000..50cbc82 --- /dev/null +++ b/drivers/sata/driver_database.c @@ -0,0 +1,59 @@ +/* driver_database.c - SATA drivers database */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +#include + +#ifdef AHCI +#include +#endif + +#ifdef AHCI + +#ifndef U_AHCI +#define U_AHCI +#endif /* U_AHCI */ + +#endif /* AHCI */ + +#define SATA_LIMIT 0x02 +static generic_driver_t sata_table[SATA_LIMIT + 1] = { +#ifdef U_AHCI + [0x01] = ahci_generic +#endif /* U_AHCI */ +}; + +void sata_driver_database( + uint16_t seg, + uint8_t bus, + uint8_t dev, + uint8_t func, + uint8_t class_code, + uint8_t subclass, + uint8_t prog_if, + uint8_t rev_id) { + if (prog_if > SATA_LIMIT) { + return; + } + + if (sata_table[prog_if]) { + sata_table[prog_if](seg, bus, dev, func, class_code, subclass, prog_if, rev_id); + } +} From 482d3ac112258ca68af1a982dfa98a8c91fcebd5 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sun, 8 Mar 2026 11:02:21 -0700 Subject: [PATCH 11/11] ahci lba r/w --- drivers/Makefile | 1 + drivers/ahci/ahci.c | 426 ++++++++++++++++++++++++++++++++---- drivers/disk/disk.c | 88 ++++++++ drivers/include/disk/disk.h | 47 ++++ drivers/include/sata/fis.h | 7 +- kernel/core/kentry.c | 2 + kernel/core/process.c | 2 + scripts/simulate_qemu | 1 + 8 files changed, 535 insertions(+), 39 deletions(-) create mode 100644 drivers/disk/disk.c create mode 100644 drivers/include/disk/disk.h diff --git a/drivers/Makefile b/drivers/Makefile index 1855c04..d39735e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -25,6 +25,7 @@ $(call add_directory,ioapic,IOAPIC) $(call add_directory,acpi,ACPI) $(call add_directory,acpica_osl,ACPICA_OSL) $(call add_directory,pcie,PCIE) +$(call add_directory,disk,DISK) ifdef BUILD_DRIVERS_HPET $(call add_directory,hpet,HPET) diff --git a/drivers/ahci/ahci.c b/drivers/ahci/ahci.c index 377bc13..153667f 100644 --- a/drivers/ahci/ahci.c +++ b/drivers/ahci/ahci.c @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -34,6 +36,7 @@ #include #include +#include #define CAP_OFF 0x00 #define GHC_OFF 0x04 @@ -42,6 +45,7 @@ #define PXCLBU_OFF(port) (0x100 + (0x80 * port) + 0x04) #define PXFB_OFF(port) (0x100 + (0x80 * port) + 0x08) #define PXFBU_OFF(port) (0x100 + (0x80 * port) + 0x0C) +#define PXIS_OFF(port) (0x100 + (0x80 * port) + 0x10) #define PXCMD_OFF(port) (0x100 + (0x80 * port) + 0x18) #define PXTFD_OFF(port) (0x100 + (0x80 * port) + 0x20) #define PXSSTS_OFF(port) (0x100 + (0x80 * port) + 0x28) @@ -56,6 +60,8 @@ #define GHC_AE 0x80000000u #define GHC_IE 0x1u +#define IS_TFES 0x40000000u + #define CMD_ST 0x0001u #define CMD_FRE 0x0010u #define CMD_FR 0x4000u @@ -78,6 +84,8 @@ #define PRDT_DBC_I 0x80000000u +#define SECTOR_SIZE 512 + struct ahci_recv_fis_t { struct sata_fis_dma_setup_t dsfis; uint32_t resv0; @@ -102,6 +110,13 @@ struct ahci_command_header_t { uint32_t resv3; } __attribute__((packed)); +struct ahci_prdt_t { + uint32_t dba; + uint32_t dbau; + uint32_t resv; + uint32_t dbc_i; +} __attribute__((packed)); + struct ahci_command_table_t { union { uint8_t _64[64]; @@ -109,12 +124,7 @@ struct ahci_command_table_t { } cfis; uint8_t acmd[16]; uint8_t resv[48]; - struct { - uint32_t dba; - uint32_t dbau; - uint32_t resv; - uint32_t dbc_i; - } __attribute__((packed)) prdt[]; + struct ahci_prdt_t prdt[]; } __attribute__((packed)); struct ahci_t { @@ -130,12 +140,20 @@ struct ahci_t { uint8_t lock; uint64_t hba_reg; uint32_t used_com; + struct ahci_command_table_t* com_tables_v[32]; + uint32_t com_tables_p[32]; struct { struct ahci_command_header_t* com_list; struct ahci_recv_fis_t* recv_fis; + uint8_t lock; }* ports[32]; }; +struct ahci_disk_t { + struct ahci_t* ahci; + uint32_t port; +}; + static inline void hba_write(struct ahci_t* ahci, uint64_t off, uint32_t val) { *(volatile uint32_t*)(ahci->hba_reg + off) = val; } @@ -146,6 +164,7 @@ static inline uint32_t hba_read(struct ahci_t* ahci, uint64_t off) { static inline void port_clear_errors(struct ahci_t* ahci, uint32_t port) { hba_write(ahci, PXSERR_OFF(port), SERR_CLEAR); + hba_write(ahci, PXIS_OFF(port), ~0u); } static uint8_t find_slot(struct ahci_t* ahci, uint32_t port) { @@ -163,59 +182,363 @@ static uint8_t find_slot(struct ahci_t* ahci, uint32_t port) { return SLOT_NO_SLOT; } -static void port_identify(struct ahci_t* ahci, uint32_t port) { +static enum disk_error_t ahci_read_lba(void* cntx, void* buffer, uint64_t lba, uint16_t count) { + struct ahci_disk_t* ahci_disk = cntx; + struct ahci_t* ahci = ahci_disk->ahci; + uint32_t port = ahci_disk->port; uint8_t slot; - uint32_t paddr_table, paddr_identity; - struct ahci_command_table_t* com_table; - uint16_t* identity; - uint8_t model[41]; + enum disk_error_t error; - paddr_table = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); - if (!paddr_table) { - logging_log_error("Failed to allocate memory for AHCI command table"); - return; + uint64_t vaddr_buf, i; + uint32_t paddr_buf; + + const uint64_t size = (uint64_t)count * SECTOR_SIZE; + + if (size > PAGE_SIZE_2M * 2) { + return DISK_ERROR; + } + + paddr_buf = (uint32_t)mm_alloc_pmax(size, 0, ~0u); + if (!paddr_buf) { + logging_log_error("Failed to allocate memory for AHCI read buffer"); + return DISK_ERROR; + } + + vaddr_buf = mm_alloc_v(size); + if (!vaddr_buf) { + mm_free_p(paddr_buf, size); + + logging_log_error("Failed to allocate memory for AHCI read buffer"); + return DISK_ERROR; } + for (i = 0; i < size; i += PAGE_SIZE_4K) { + paging_map(vaddr_buf + i, paddr_buf + i, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + } + + lock_acquire(&ahci->lock); + slot = find_slot(ahci, port); + ahci->used_com |= 1u << slot; + lock_release(&ahci->lock); + + kmemset(&ahci->ports[port]->com_list[slot], 0, sizeof(struct ahci_command_header_t)); + kmemset(ahci->com_tables_v[slot], 0, PAGE_SIZE_4K); + + ahci->com_tables_v[slot]->cfis.h2d.fis_type = SATA_FIS_TYPE_H2D; + ahci->com_tables_v[slot]->cfis.h2d.flag = SATA_FIS_H2D_C; + ahci->com_tables_v[slot]->cfis.h2d.cmd = SATA_FIS_CMD_DMA_READ_EXT; + ahci->com_tables_v[slot]->cfis.h2d.lba0 = (lba >> 0) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba1 = (lba >> 8) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba2 = (lba >> 16) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba3 = (lba >> 24) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba4 = (lba >> 32) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba5 = (lba >> 40) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.dev = 1u << 6; + ahci->com_tables_v[slot]->cfis.h2d.count_lo = (count) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.count_hi = (count >> 8) & 0xFF; + + ahci->com_tables_v[slot]->prdt[0].dba = paddr_buf; + ahci->com_tables_v[slot]->prdt[0].dbau = 0; + ahci->com_tables_v[slot]->prdt[0].dbc_i = (uint32_t)size - 1; + + lock_acquire(&ahci->ports[port]->lock); + + port_clear_errors(ahci, port); + + kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + + ahci->ports[port]->com_list[slot].flg = 5; + ahci->ports[port]->com_list[slot].prdtl = 1; + ahci->ports[port]->com_list[slot].ctba0 = ahci->com_tables_p[slot]; + ahci->ports[port]->com_list[slot].ctba_u0 = 0; + + + while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + } + + hba_write(ahci, PXCI_OFF(port), 1u << slot); + + while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + + if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { + logging_log_error("AHCI error while reading"); + error = DISK_ERROR; + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + goto cleanup; + } + } + + if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { + logging_log_error("AHCI error while reading"); + error = DISK_ERROR; + + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + goto cleanup; + } + + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + + kmemcpy(buffer, (void*)vaddr_buf, size); + + error = DISK_OK; +cleanup: + for (i = 0; i < size; i += PAGE_SIZE_4K) { + paging_unmap(vaddr_buf + i, PAGE_4K); + } + + mm_free_v(vaddr_buf, size); + mm_free_p(paddr_buf, size); + + return error; +} + +static enum disk_error_t ahci_write_lba(void* cntx, void* buffer, uint64_t lba, uint16_t count) { + struct ahci_disk_t* ahci_disk = cntx; + struct ahci_t* ahci = ahci_disk->ahci; + uint32_t port = ahci_disk->port; + uint8_t slot; + enum disk_error_t error; + + uint64_t vaddr_buf, i; + uint32_t paddr_buf; + + const uint64_t size = (uint64_t)count * SECTOR_SIZE; + + if (size > PAGE_SIZE_2M * 2) { + return DISK_ERROR; + } + + paddr_buf = (uint32_t)mm_alloc_pmax(size, 0, ~0u); + if (!paddr_buf) { + logging_log_error("Failed to allocate memory for AHCI read buffer"); + return DISK_ERROR; + } + + vaddr_buf = mm_alloc_v(size); + if (!vaddr_buf) { + mm_free_p(paddr_buf, size); + + logging_log_error("Failed to allocate memory for AHCI read buffer"); + return DISK_ERROR; + } + + for (i = 0; i < size; i += PAGE_SIZE_4K) { + paging_map(vaddr_buf + i, paddr_buf + i, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + } + + kmemcpy((void*)vaddr_buf, buffer, size); + + lock_acquire(&ahci->lock); + slot = find_slot(ahci, port); + ahci->used_com |= 1u << slot; + lock_release(&ahci->lock); + + kmemset(&ahci->ports[port]->com_list[slot], 0, sizeof(struct ahci_command_header_t)); + kmemset(ahci->com_tables_v[slot], 0, PAGE_SIZE_4K); + + ahci->com_tables_v[slot]->cfis.h2d.fis_type = SATA_FIS_TYPE_H2D; + ahci->com_tables_v[slot]->cfis.h2d.flag = SATA_FIS_H2D_C; + ahci->com_tables_v[slot]->cfis.h2d.cmd = SATA_FIS_CMD_DMA_WRITE_EXT; + ahci->com_tables_v[slot]->cfis.h2d.lba0 = (lba >> 0) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba1 = (lba >> 8) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba2 = (lba >> 16) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba3 = (lba >> 24) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba4 = (lba >> 32) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.lba5 = (lba >> 40) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.dev = 1u << 6; + ahci->com_tables_v[slot]->cfis.h2d.count_lo = (count) & 0xFF; + ahci->com_tables_v[slot]->cfis.h2d.count_hi = (count >> 8) & 0xFF; + + ahci->com_tables_v[slot]->prdt[0].dba = paddr_buf; + ahci->com_tables_v[slot]->prdt[0].dbau = 0; + ahci->com_tables_v[slot]->prdt[0].dbc_i = (uint32_t)size - 1; + + lock_acquire(&ahci->ports[port]->lock); + + port_clear_errors(ahci, port); + + kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + + ahci->ports[port]->com_list[slot].flg = 5 | SATA_FIS_CMD_W; + ahci->ports[port]->com_list[slot].prdtl = 1; + ahci->ports[port]->com_list[slot].ctba0 = ahci->com_tables_p[slot]; + ahci->ports[port]->com_list[slot].ctba_u0 = 0; + + + while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + } + + hba_write(ahci, PXCI_OFF(port), 1u << slot); + + while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + + if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { + logging_log_error("AHCI error while reading"); + error = DISK_ERROR; + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + goto cleanup; + } + } + + if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { + logging_log_error("AHCI error while reading"); + error = DISK_ERROR; + + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + goto cleanup; + } + + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + + error = DISK_OK; +cleanup: + for (i = 0; i < size; i += PAGE_SIZE_4K) { + paging_unmap(vaddr_buf + i, PAGE_4K); + } + + mm_free_v(vaddr_buf, size); + mm_free_p(paddr_buf, size); + + return error; +} + +static enum disk_error_t ahci_flush_cache(void* cntx) { + struct ahci_disk_t* ahci_disk = cntx; + struct ahci_t* ahci = ahci_disk->ahci; + uint32_t port = ahci_disk->port; + uint8_t slot; + + + lock_acquire(&ahci->lock); + slot = find_slot(ahci, port); + ahci->used_com |= 1u << slot; + lock_release(&ahci->lock); + + kmemset(&ahci->ports[port]->com_list[slot], 0, sizeof(struct ahci_command_header_t)); + kmemset(ahci->com_tables_v[slot], 0, PAGE_SIZE_4K); + + ahci->com_tables_v[slot]->cfis.h2d.fis_type = SATA_FIS_TYPE_H2D; + ahci->com_tables_v[slot]->cfis.h2d.flag = SATA_FIS_H2D_C; + ahci->com_tables_v[slot]->cfis.h2d.cmd = SATA_FIS_CMD_FLUSH_CACHE_EXT; + + lock_acquire(&ahci->ports[port]->lock); + + port_clear_errors(ahci, port); + + kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + + ahci->ports[port]->com_list[slot].flg = 5; + ahci->ports[port]->com_list[slot].prdtl = 0; + ahci->ports[port]->com_list[slot].ctba0 = ahci->com_tables_p[slot]; + ahci->ports[port]->com_list[slot].ctba_u0 = 0; + + while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + } + + hba_write(ahci, PXCI_OFF(port), 1u << slot); + + while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { + time_busy_wait(10 * TIME_CONV_MS_TO_NS); + + if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { + logging_log_error("AHCI flush cache error"); + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + + return DISK_ERROR; + } + } + + lock_release(&ahci->ports[port]->lock); + + lock_acquire(&ahci->lock); + ahci->used_com &= ~(1u << slot); + lock_release(&ahci->lock); + + return DISK_OK; +} + +static void port_identify(struct ahci_t* ahci, uint32_t port) { + uint8_t slot; + uint32_t paddr_identity; + volatile uint16_t* identity; + uint8_t model[41]; + uint64_t lba48; + paddr_identity = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); if (!paddr_identity) { logging_log_error("Failed to allocate memory for AHCI identity buffer"); return; } - com_table = (struct ahci_command_table_t*)mm_alloc_v(PAGE_SIZE_4K); - if (!com_table) { - logging_log_error("Failed to allocate memory for AHCI command table"); - return; - } - identity = (uint16_t*)mm_alloc_v(PAGE_SIZE_4K); if (!identity) { + mm_free_p(paddr_identity, PAGE_SIZE_4K); + logging_log_error("Failed to allocate memory for AHCI identity buffer"); return; } - paging_map((uint64_t)com_table, paddr_table, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); paging_map((uint64_t)identity, paddr_identity, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); - kmemset(com_table, 0, PAGE_SIZE_4K); - kmemset(identity, 0, PAGE_SIZE_4K); - - com_table->prdt[0].dba = paddr_identity; - com_table->prdt[0].dbau = 0; - com_table->prdt[0].dbc_i = 512 - 1; - - com_table->cfis.h2d.fis_type = SATA_FIS_TYPE_H2D; - com_table->cfis.h2d.flag = SATA_FIS_H2D_C; - com_table->cfis.h2d.cmd = SATA_FIS_CMD_IDENT; - lock_acquire(&ahci->lock); slot = find_slot(ahci, port); ahci->used_com |= 1u << slot; lock_release(&ahci->lock); + kmemset(&ahci->ports[port]->com_list[slot], 0, sizeof(struct ahci_command_header_t)); + kmemset(ahci->com_tables_v[slot], 0, PAGE_SIZE_4K); + kmemset((void*)identity, 0, PAGE_SIZE_4K); + + ahci->com_tables_v[slot]->prdt[0].dba = paddr_identity; + ahci->com_tables_v[slot]->prdt[0].dbau = 0; + ahci->com_tables_v[slot]->prdt[0].dbc_i = 512 - 1; + + ahci->com_tables_v[slot]->cfis.h2d.fis_type = SATA_FIS_TYPE_H2D; + ahci->com_tables_v[slot]->cfis.h2d.flag = SATA_FIS_H2D_C; + ahci->com_tables_v[slot]->cfis.h2d.cmd = SATA_FIS_CMD_IDENT; + + lock_acquire(&ahci->ports[port]->lock); + + port_clear_errors(ahci, port); + + kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + ahci->ports[port]->com_list[slot].flg = 5; ahci->ports[port]->com_list[slot].prdtl = 1; - ahci->ports[port]->com_list[slot].ctba0 = paddr_table; + ahci->ports[port]->com_list[slot].ctba0 = ahci->com_tables_p[slot]; ahci->ports[port]->com_list[slot].ctba_u0 = 0; while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { @@ -228,6 +551,8 @@ static void port_identify(struct ahci_t* ahci, uint32_t port) { time_busy_wait(10 * TIME_CONV_MS_TO_NS); } + lock_release(&ahci->ports[port]->lock); + lock_acquire(&ahci->lock); ahci->used_com &= ~(1u << slot); lock_release(&ahci->lock); @@ -238,15 +563,14 @@ static void port_identify(struct ahci_t* ahci, uint32_t port) { } model[40] = 0; - logging_log_info("Found ATA drive %s", &model[0]); + lba48 = *(uint64_t*)&identity[100]; + + logging_log_info("Found ATA drive %s 0x%lx", &model[0], lba48); - paging_unmap((uint64_t)com_table, PAGE_4K); paging_unmap((uint64_t)identity, PAGE_4K); - mm_free_v((uint64_t)com_table, PAGE_SIZE_4K); mm_free_v((uint64_t)identity, PAGE_SIZE_4K); - mm_free_p(paddr_table, PAGE_SIZE_4K); mm_free_p(paddr_identity, PAGE_SIZE_4K); } @@ -292,6 +616,7 @@ static void ahci_init(void* cntx) { uint32_t fis_pool_p = 0; uint64_t cl_pool_v = 0; uint64_t fis_pool_v = 0; + struct ahci_disk_t* ahci_disk; logging_log_info("AHCI driver initialization for %u/%u/%u/%u at %u.%u.%u.%u", ahci->class_code, ahci->subclass, ahci->prog_if, ahci->rev_id, ahci->seg, ahci->bus, ahci->dev, ahci->func); @@ -323,6 +648,24 @@ static void ahci_init(void* cntx) { logging_log_debug("AHCI HBA mapped to 0x%lx", ahci->hba_reg); + for (i = 0; i < 32; i++) { + ahci->com_tables_p[i] = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); + + if (!ahci->com_tables_p[i]) { + logging_log_error("Failed to allocate AHCI command table"); + panic(PANIC_NO_MEM); + } + + ahci->com_tables_v[i] = (struct ahci_command_table_t*)mm_alloc_v(PAGE_SIZE_4K); + if (!ahci->com_tables_v[i]) { + logging_log_error("Failed to allocate AHCI command table"); + panic(PANIC_NO_MEM); + } + + paging_map((uint64_t)ahci->com_tables_v[i], ahci->com_tables_p[i], + PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); + } + /* minimal initialization sequence */ read = hba_read(ahci, GHC_OFF); read &= ~GHC_IE; @@ -334,6 +677,7 @@ static void ahci_init(void* cntx) { for (i = 0; i < 32; i++) { if (ports & (1u << i)) { logging_log_debug("AHCI supports port %u", i); + read = hba_read(ahci, PXCMD_OFF(i)); if (read & (CMD_ST | CMD_FRE | CMD_FR | CMD_CR)) { /* stop port execution */ @@ -379,6 +723,8 @@ static void ahci_init(void* cntx) { if (ports & (1u << i)) { ahci->ports[i] = kmalloc(sizeof(*ahci->ports[i])); + lock_init(&ahci->ports[i]->lock); + if (j % (PAGE_SIZE_4K / CL_SIZE) == 0) { cl_pool_p = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); if (!cl_pool_p) { @@ -455,6 +801,10 @@ static void ahci_init(void* cntx) { hba_write(ahci, PXCMD_OFF(i), read); port_identify(ahci, i); + ahci_disk = kmalloc(sizeof(struct ahci_disk_t)); + ahci_disk->ahci = ahci; + ahci_disk->port = i; + disk_add(ahci_disk, ahci_read_lba, ahci_write_lba, ahci_flush_cache); } else { ahci->ports[i] = 0; diff --git a/drivers/disk/disk.c b/drivers/disk/disk.c new file mode 100644 index 0000000..b6dacbe --- /dev/null +++ b/drivers/disk/disk.c @@ -0,0 +1,88 @@ +/* disk.c - Disk Access implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include + +#include +#include + +struct disk_t { + disk_lba_read_t read; + disk_lba_write_t write; + disk_flush_t flush; + void* cntx; + uint64_t id; + struct disk_t* next; +}; + +uint8_t disk_lock; + +static struct disk_t* disk_list; +static uint64_t disk_id; + +void disk_init(void) { + lock_init(&disk_lock); + + disk_list = 0; + disk_id = DISK_ID_FIRST; +} + +struct disk_t* disk_add(void* cntx, disk_lba_read_t read, disk_lba_write_t write, disk_flush_t flush) { + struct disk_t* disk = kmalloc(sizeof(struct disk_t)); + + disk->read = read; + disk->write = write; + disk->flush = flush; + disk->cntx = cntx; + + lock_acquire(&disk_lock); + disk->id = disk_id++; + disk->next = disk_list; + disk_list = disk; + lock_release(&disk_lock); + + return disk; +} + +struct disk_t* disk_get(uint64_t id) { + struct disk_t* disk; + + lock_acquire(&disk_lock); + for (disk = disk_list; disk; disk = disk->next) { + if (disk->id == id) { + break; + } + } + lock_release(&disk_lock); + + return disk; +} + +enum disk_error_t disk_read(struct disk_t* disk, void* buffer, uint64_t lba, uint16_t count) { + return disk->read(disk->cntx, buffer, lba, count); +} + +enum disk_error_t disk_write(struct disk_t* disk, void* buffer, uint64_t lba, uint16_t count) { + return disk->write(disk->cntx, buffer, lba, count); +} + +enum disk_error_t disk_flush(struct disk_t* disk) { + return disk->flush(disk->cntx); +} diff --git a/drivers/include/disk/disk.h b/drivers/include/disk/disk.h new file mode 100644 index 0000000..ef06dae --- /dev/null +++ b/drivers/include/disk/disk.h @@ -0,0 +1,47 @@ +/* disk.h - Disk Access interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_DISK_DISK_H +#define DRIVERS_DISK_DISK_H + +#include +#include + +#define DISK_ID_FIRST 0 + +enum disk_error_t { + DISK_OK, + DISK_ERROR +}; + +struct disk_t; + +typedef enum disk_error_t (*disk_lba_read_t)(void* cntx, void* buffer, uint64_t lba, uint16_t count); +typedef enum disk_error_t (*disk_lba_write_t)(void* cntx, void* pbuffer, uint64_t lba, uint16_t count); +typedef enum disk_error_t (*disk_flush_t)(void* cntx); + +extern void disk_init(void); + +extern struct disk_t* disk_add(void* cntx, disk_lba_read_t read, disk_lba_write_t write, disk_flush_t flush); + +extern struct disk_t* disk_get(uint64_t id); + +extern enum disk_error_t disk_read(struct disk_t* disk, void* pbuffer, uint64_t lba, uint16_t count); +extern enum disk_error_t disk_write(struct disk_t* disk, void* pbuffer, uint64_t lba, uint16_t count); +extern enum disk_error_t disk_flush(struct disk_t* disk); + +#endif /* DRIVERS_DISK_DISK_H */ diff --git a/drivers/include/sata/fis.h b/drivers/include/sata/fis.h index 040e762..0641b29 100644 --- a/drivers/include/sata/fis.h +++ b/drivers/include/sata/fis.h @@ -28,7 +28,12 @@ #define SATA_FIS_H2D_C 0x80 -#define SATA_FIS_CMD_IDENT 0xEC +#define SATA_FIS_CMD_DMA_READ_EXT 0x25 +#define SATA_FIS_CMD_DMA_WRITE_EXT 0x35 +#define SATA_FIS_CMD_FLUSH_CACHE_EXT 0xEA +#define SATA_FIS_CMD_IDENT 0xEC + +#define SATA_FIS_CMD_W 0x40 struct sata_fis_type_h2d_t { uint8_t fis_type; diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index f0dae9a..d1049ba 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -44,6 +44,7 @@ #include #include #include +#include struct boot_context_t boot_context; @@ -87,6 +88,7 @@ void kentry(void) { logging_log_debug("APIC and IOAPIC init done"); logging_log_debug("Early PCIE init"); + disk_init(); pcie_init(); pcie_enumerate(); logging_log_debug("Early PCIE init done"); diff --git a/kernel/core/process.c b/kernel/core/process.c index 1445b92..5a04c9c 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -115,11 +115,13 @@ struct pcb_t* process_from_func(process_function_t func, void* cntx) { } void process_kill_current(void) { + cpu_cli(); lock_acquire(&lock_proc); struct pcb_t* pcb = proc_data_get()->current_process; pcb->sched_cntr = SCHED_KILL; logging_log_debug("Killed %ld", pcb->pid); lock_release(&lock_proc); + cpu_sti(); cpu_wait_loop(); } diff --git a/scripts/simulate_qemu b/scripts/simulate_qemu index bee931a..013438a 100755 --- a/scripts/simulate_qemu +++ b/scripts/simulate_qemu @@ -1,6 +1,7 @@ #!/bin/bash mkdir -p build/test-runtime/ +#dd if=/dev/urandom of=build/test-runtime/disk1.img bs=4096 count=1 status=progress truncate -s 4G build/test-runtime/disk1.img qemu-system-x86_64 \