diff --git a/Makefile b/Makefile index 5856b4e..90b48e8 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 @@ -38,8 +40,14 @@ export BUILD_KERNEL_MEM_TEST = 1 export BUILD_DRIVERS_SERIAL = 1 export BUILD_DRIVERS_HPET = 1 +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 7ce23f3..d39735e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -24,18 +24,25 @@ $(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) +$(call add_directory,disk,DISK) ifdef BUILD_DRIVERS_HPET $(call add_directory,hpet,HPET) endif - -#TODO: switch to PCIe - + ifdef BUILD_DRIVERS_SERIAL $(call add_directory,serial,SERIAL) endif +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/acpi/tables.c b/drivers/acpi/tables.c index d3f3121..376701f 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,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 +170,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 +217,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; @@ -207,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; \ @@ -220,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); +} - 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); +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; + + 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) { @@ -283,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); } @@ -301,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); @@ -309,20 +358,25 @@ 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 + + unmap_table(gen); } - if (found != (FOUND_FADT | FOUND_MADT | FOUND_HPET )) { + 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 @@ -335,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; } @@ -353,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); @@ -361,18 +419,25 @@ 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 + + unmap_table(gen); } - 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"); + 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; } } @@ -396,6 +461,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 + sizeof(struct acpi_mcfg_conf_entry_t) > (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/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/drivers/acpica_osl/osl.c b/drivers/acpica_osl/osl.c index 54fb10d..a5abacc 100644 --- a/drivers/acpica_osl/osl.c +++ b/drivers/acpica_osl/osl.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -285,23 +285,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/ahci/ahci.c b/drivers/ahci/ahci.c new file mode 100644 index 0000000..153667f --- /dev/null +++ b/drivers/ahci/ahci.c @@ -0,0 +1,838 @@ +/* ahci.c - Advanced Host Controller Interface driver */ +/* 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 +#include +#include +#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 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) +#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 +#define CAP_S64A 0x80000000u + +#define GHC_AE 0x80000000u +#define GHC_IE 0x1u + +#define IS_TFES 0x40000000u + +#define CMD_ST 0x0001u +#define CMD_FRE 0x0010u +#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 + +#define SECTOR_SIZE 512 + +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_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]; + struct sata_fis_type_h2d_t h2d; + } cfis; + uint8_t acmd[16]; + uint8_t resv[48]; + struct ahci_prdt_t prdt[]; +} __attribute__((packed)); + +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; + uint8_t num_com_slots; + 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; +} + +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 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) { + 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 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; + 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); + } + + 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; + } + + 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)identity, paddr_identity, 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); + 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 = 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); + } + + lock_release(&ahci->ports[port]->lock); + + 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; + + lba48 = *(uint64_t*)&identity[100]; + + logging_log_info("Found ATA drive %s 0x%lx", &model[0], lba48); + + paging_unmap((uint64_t)identity, PAGE_4K); + + mm_free_v((uint64_t)identity, PAGE_SIZE_4K); + + mm_free_p(paddr_identity, PAGE_SIZE_4K); +} + +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_MASK) != 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; + 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); + + 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)); + 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); + + //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"); + 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); + + 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; + 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])); + + 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) { + 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 = (struct ahci_command_header_t*)cl_pool_v; + + hba_write(ahci, PXFB_OFF(i), fis_pool_p); + 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); + + 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); // 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); + 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; + } + } + + logging_log_info("AHCI init done"); +} + +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/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/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/ahci/ahci.h b/drivers/include/ahci/ahci.h new file mode 100644 index 0000000..8f53704 --- /dev/null +++ b/drivers/include/ahci/ahci.h @@ -0,0 +1,33 @@ +/* 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 +* 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_H +#define DRIVERS_AHCI_AHCI_H + +#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_H */ 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/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/include/pcie/pcie.h b/drivers/include/pcie/pcie.h new file mode 100644 index 0000000..6ee320f --- /dev/null +++ b/drivers/include/pcie/pcie.h @@ -0,0 +1,44 @@ +/* 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 + +#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 + +#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); + +#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..88422d5 --- /dev/null +++ b/drivers/include/pcie/pcie_init.h @@ -0,0 +1,25 @@ +/* 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/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..0641b29 --- /dev/null +++ b/drivers/include/sata/fis.h @@ -0,0 +1,126 @@ +/* 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_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; + 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/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/pcie/generic_database.c b/drivers/pcie/generic_database.c new file mode 100644 index 0000000..0795dfc --- /dev/null +++ b/drivers/pcie/generic_database.c @@ -0,0 +1,93 @@ +/* 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 */ + +#ifdef SATA +#include +#endif /* SATA */ + +#define CLASS_LIMIT 0x13 + +#ifdef SATA + +#ifndef U_MASS_STORAGE_CONTROLLER +#define U_MASS_STORAGE_CONTROLLER +#endif /* U_MASS_STORAGE_CONTROLLER */ + +#ifndef U_SATA +#define U_SATA +#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] = sata_driver_database +#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/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..1e1d869 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,16 @@ * 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 + +uint64_t**** ecam; -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[segment][bus][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[segment][bus][dev][fun] + off) = val; +} diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c new file mode 100644 index 0000000..ce4a954 --- /dev/null +++ b/drivers/pcie/pcie_init.c @@ -0,0 +1,209 @@ +/* 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 +#include +#include +#include + +#include + +#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) + +#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 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; + +static void enumerate_bus(uint16_t seg, uint8_t bus); + +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 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 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 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_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) { + 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_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_function(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; + uint16_t max_seg = 0; + uint16_t j; + uint16_t max_bus; + uint16_t i; + uint8_t k, l; + uint64_t vaddr; + + acpi_parse_mcfg_conf_start(&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); + } + + max_seg++; + + ecam = 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) { + 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[i] = 0; + continue; + } + + 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[i][j] = kmalloc(32 * sizeof(uint64_t*)); + for (k = 0; k < 32; k++) { + vaddr = mm_alloc_v(PAGE_SIZE_4K); + if (!vaddr) { + logging_log_error("Failed to allocate memory for PCIE configuration space"); + panic(PANIC_NO_MEM); + } + 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); + if (!vaddr) { + logging_log_error("Failed to allocation memory for PCIE configuration space"); + panic(PANIC_NO_MEM); + } + 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; + } + + } + } + } + + acpi_parse_mcfg_conf(&conf, &mcfg_handle); + } + } +} + +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/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); + } +} diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 16b2fb8..d1049ba 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include struct boot_context_t boot_context; @@ -85,6 +87,12 @@ void kentry(void) { ioapic_init(); 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"); + logging_log_debug("ACPICA init"); acpica_init(); logging_log_debug("ACPICA init done"); @@ -120,11 +128,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"); 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 diff --git a/kernel/core/paging.c b/kernel/core/paging.c index 6f15452..974e902 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/core/process.c b/kernel/core/process.c index df889eb..5a04c9c 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,12 +105,23 @@ 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) { + 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/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/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; 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/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)); 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); diff --git a/scripts/simulate_qemu b/scripts/simulate_qemu index 5fd0b45..013438a 100755 --- a/scripts/simulate_qemu +++ b/scripts/simulate_qemu @@ -1,9 +1,28 @@ #!/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 \ - -device VGA +#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 \ + -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 \ + -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