diff --git a/bin/os b/bin/os index e2fa090..7f55763 100755 Binary files a/bin/os and b/bin/os differ diff --git a/check.img b/check.img new file mode 100644 index 0000000..6dcc0ac Binary files /dev/null and b/check.img differ diff --git a/fortune b/fortune new file mode 100644 index 0000000..ddad7f5 --- /dev/null +++ b/fortune @@ -0,0 +1,2 @@ +Many hands make light work. + -- John Heywood diff --git a/image.hdd b/image.hdd index 4851914..83dddff 100644 Binary files a/image.hdd and b/image.hdd differ diff --git a/limine.sh b/limine.sh index 0e26ae1..ca98929 100644 --- a/limine.sh +++ b/limine.sh @@ -16,13 +16,14 @@ make -C limine ./limine/limine bios-install image.hdd # Format the image as fat32. -mformat -i image.hdd@@1M +mformat -i image.hdd@@1M -F # Make relevant subdirectories. -mmd -i image.hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine +mmd -i image.hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine ::/fort # Copy over the relevant files. mcopy -i image.hdd@@1M bin/os ::/boot mcopy -i image.hdd@@1M limine.conf limine/limine-bios.sys ::/boot/limine mcopy -i image.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT mcopy -i image.hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT +mcopy -i image.hdd@@1M fortune ::/fort/fortu.ne diff --git a/mnt/EFI/BOOT/BOOTIA32.EFI b/mnt/EFI/BOOT/BOOTIA32.EFI new file mode 100644 index 0000000..3246181 Binary files /dev/null and b/mnt/EFI/BOOT/BOOTIA32.EFI differ diff --git a/mnt/EFI/BOOT/BOOTX64.EFI b/mnt/EFI/BOOT/BOOTX64.EFI new file mode 100644 index 0000000..671fef4 Binary files /dev/null and b/mnt/EFI/BOOT/BOOTX64.EFI differ diff --git a/mnt/boot/limine/limine-bios.sys b/mnt/boot/limine/limine-bios.sys new file mode 100644 index 0000000..bb3c952 Binary files /dev/null and b/mnt/boot/limine/limine-bios.sys differ diff --git a/mnt/boot/limine/limine.conf b/mnt/boot/limine/limine.conf new file mode 100644 index 0000000..ec26b22 --- /dev/null +++ b/mnt/boot/limine/limine.conf @@ -0,0 +1,5 @@ +timeout: 5 + +/LispOS + protocol: limine + path: boot():/boot/os diff --git a/mnt/boot/os b/mnt/boot/os new file mode 100755 index 0000000..e51b8cd Binary files /dev/null and b/mnt/boot/os differ diff --git a/obj/src/int.c.o b/obj/src/int.c.o index 1906873..cb5e576 100644 Binary files a/obj/src/int.c.o and b/obj/src/int.c.o differ diff --git a/obj/src/main.c.d b/obj/src/main.c.d index 1efc91c..5b08ec0 100644 --- a/obj/src/main.c.d +++ b/obj/src/main.c.d @@ -1,19 +1,19 @@ obj/src/main.c.o: src/main.c src/../include/limine.h src/prompt/lex.h \ - src/prompt/file.h src/acpi.h src/common.h src/alloc.h src/apic.h \ - src/kbd.h src/map.h src/print.h src/lib/stdio.h src/lib/malloc.h \ - src/lib/../common.h src/lib/../kbd.h src/lib/../print.h + src/prompt/file.h src/acpi.h src/common.h src/ahci.h src/alloc.h \ + src/apic.h src/fat32.h src/lib/stdio.h src/lib/malloc.h \ + src/lib/../common.h src/lib/../kbd.h src/lib/../print.h src/print.h src/../include/limine.h: src/prompt/lex.h: src/prompt/file.h: src/acpi.h: src/common.h: +src/ahci.h: src/alloc.h: src/apic.h: -src/kbd.h: -src/map.h: -src/print.h: +src/fat32.h: src/lib/stdio.h: src/lib/malloc.h: src/lib/../common.h: src/lib/../kbd.h: src/lib/../print.h: +src/print.h: diff --git a/obj/src/main.c.o b/obj/src/main.c.o index 1711cd5..5767244 100644 Binary files a/obj/src/main.c.o and b/obj/src/main.c.o differ diff --git a/run.sh b/run.sh index 4feec7f..d71d485 100644 --- a/run.sh +++ b/run.sh @@ -1,2 +1,6 @@ -qemu-system-x86_64 image.hdd +qemu-system-x86_64 \ + -drive id=disk0,file=image.hdd,format=raw,if=none \ + -device ich9-ahci,id=ahci0 \ + -device ide-hd,drive=disk0,bus=ahci0.0 + #/mnt/c/'Program Files'/qemu/qemu-system-x86_64.exe image.hdd diff --git a/src/ahci.c b/src/ahci.c new file mode 100644 index 0000000..3568651 --- /dev/null +++ b/src/ahci.c @@ -0,0 +1,492 @@ +#include "alloc.h" +#include "common.h" +#include "map.h" +#include "print.h" +#include "lib/stdio.h" +#include "map.h" +#include "lib/malloc.h" + +#define PCI_CONFIG_ADDR 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +static u32 pci_read(u8 bus, u8 slot, u8 func, u8 offset) { + u32 addr = (1u << 31) | ((u32)bus << 16) | ((u32)slot << 11) | + ((u32)func << 8) | (offset & 0xFC); + outd(PCI_CONFIG_ADDR, addr); + return ind(PCI_CONFIG_DATA); +} + +static void pci_write(u8 bus, u8 slot, u8 func, u8 offset, u32 value) { + u32 addr = (1u << 31) | ((u32)bus << 16) | ((u32)slot << 11) | + ((u32)func << 8) | (offset & 0xFC); + outd(PCI_CONFIG_ADDR, addr); + outd(PCI_CONFIG_DATA, value); +} + +typedef struct { + u32 dba; + u32 dbau; + u32 reserved; + u32 dbc; // byte count - 1, bit 31 = interrupt on completion +} hba_prdt_t; + +#define AHCI_PRDT_PER_TABLE 8 + +typedef struct { + u8 cfis[64]; + u8 acmd[16]; + u8 reserved[48]; + hba_prdt_t prdt[AHCI_PRDT_PER_TABLE]; +} hba_cmd_table_t; + +// hba_cmd_table_t size = 64 + 16 + 48 + (8 * 16) = 256 bytes +// two fit per 4KiB page +typedef struct { + u16 flags; // [4:0] FIS len in DWORDs, [6] write + u16 prdtl; + u32 prdbc; + u32 ctba; + u32 ctbau; + u32 reserved[4]; +} hba_cmd_header_t; + +typedef struct { + u8 dsfis[28]; + u8 pad0[4]; + u8 psfis[20]; + u8 pad1[12]; + u8 rfis[20]; + u8 pad2[4]; + u8 sdbfis[8]; + u8 ufis[64]; + u8 reserved[96]; +} hba_fis_t; + +// sizeof(hba_fis_t) = 256 bytes + +typedef volatile struct { + u32 clb, clbu; + u32 fb, fbu; + u32 is; + u32 ie; + u32 cmd; + u32 reserved0; + u32 tfd; + u32 sig; + u32 ssts; + u32 sctl; + u32 serr; + u32 sact; + u32 ci; + u32 sntf; + u32 fbs; + u32 reserved1[11]; + u32 vendor[4]; +} hba_port_t; + +typedef volatile struct { + u32 cap; + u32 ghc; + u32 is; + u32 pi; + u32 vs; + u32 ccc_ctl; + u32 ccc_pts; + u32 em_loc; + u32 em_ctl; + u32 cap2; + u32 bohc; + u8 reserved[0xA0 - 0x2C]; + u8 vendor[0x100 - 0xA0]; + hba_port_t ports[32]; +} hba_mem_t; + +typedef struct { + u8 fis_type; // 0x27 + u8 c; // bit 7 = command + u8 command; + u8 featurel; + u8 lba0, lba1, lba2; + u8 device; + u8 lba3, lba4, lba5; + u8 featureh; + u8 countl, counth; + u8 icc; + u8 control; + u8 reserved[4]; +} fis_reg_h2d_t; + +#define ATA_CMD_READ_DMA_EXT 0x25 +#define ATA_CMD_WRITE_DMA_EXT 0x35 +#define ATA_CMD_IDENTIFY 0xEC +#define ATA_DEV_BUSY 0x80 +#define ATA_DEV_DRQ 0x08 + + +#define HBA_GHC_AE (1u << 31) +#define HBA_CMD_ST (1u << 0) +#define HBA_CMD_FRE (1u << 4) +#define HBA_CMD_FR (1u << 14) +#define HBA_CMD_CR (1u << 15) +#define HBA_IS_TFES (1u << 30) // task file error status + + +#define AHCI_MAX_PORTS 32 +#define AHCI_CMD_SLOTS 32 + +typedef struct { + hba_cmd_header_t *cmd_list; // virtual, 1 page (1KB used) + hba_fis_t *fis; // virtual, fits after cmd_list + hba_cmd_table_t *cmd_tables[AHCI_CMD_SLOTS]; // virtual pointers + int active; + u64 sector_count; + u64 sector_size; +} ahci_port_t; + +static hba_mem_t *hba; +static ahci_port_t ports[AHCI_MAX_PORTS]; + +static void port_stop(hba_port_t *port) { + port->cmd &= ~HBA_CMD_ST; + port->cmd &= ~HBA_CMD_FRE; + while (port->cmd & (HBA_CMD_CR | HBA_CMD_FR)) + ; +} + +static void port_start(hba_port_t *port) { + while (port->cmd & HBA_CMD_CR) + ; + port->cmd |= HBA_CMD_FRE; + port->cmd |= HBA_CMD_ST; +} + +static int find_free_slot(hba_port_t *port) { + u32 slots = port->sact | port->ci; + for (int i = 0; i < AHCI_CMD_SLOTS; i++) + if (!(slots & (1u << i))) + return i; + return -1; +} + +static void port_init(int idx) { + hba_port_t *port = &hba->ports[idx]; + ahci_port_t *p = &ports[idx]; + + port_stop(port); + + // + // Page 0: command list (1024 bytes) + FIS buffer (256 bytes) + // + // [0 .. 1023] : hba_cmd_header_t[32] (command list) + // [1024.. 1279] : hba_fis_t (received FIS) + // + // Both fit in one 4KiB page. FIS is 256-byte aligned because 1024 + // is a multiple of 256. + // + u8 *page0 = (u8 *)alloc(4096); + memset(page0, 0, 4096); + + p->cmd_list = (hba_cmd_header_t *)page0; + p->fis = (hba_fis_t *)(page0 + 1024); + + u64 phys0 = virt_to_phys(page0); + u64 phys_fis = phys0 + 1024; + + port->clb = (u32)(phys0); + port->clbu = (u32)(phys0 >> 32); + port->fb = (u32)(phys_fis); + port->fbu = (u32)(phys_fis >> 32); + + // + // Command tables: 256 bytes each, two per 4KiB page. + // 32 slots → 16 pages. + // + for (int i = 0; i < AHCI_CMD_SLOTS; i += 2) { + u8 *page = (u8 *)alloc(4096); + memset(page, 0, 4096); + + u64 phys = virt_to_phys(page); + + for (int j = 0; j < 2 && (i + j) < AHCI_CMD_SLOTS; j++) { + int slot = i + j; + hba_cmd_table_t *tbl = (hba_cmd_table_t *)(page + j * 256); + p->cmd_tables[slot] = tbl; + + u64 tbl_phys = phys + j * 256; + p->cmd_list[slot].ctba = (u32)(tbl_phys); + p->cmd_list[slot].ctbau = (u32)(tbl_phys >> 32); + p->cmd_list[slot].prdtl = AHCI_PRDT_PER_TABLE; + } + } + + // Clear pending errors and interrupts + port->serr = 0xFFFFFFFF; + port->is = 0xFFFFFFFF; + + // Enable D2H register FIS interrupt + task file error + port->ie = (1u << 0) | HBA_IS_TFES; + + port_start(port); + p->active = 1; + + + printf("AHCI: port %d initialized, sig=%x\n", idx, port->sig); +} + +static void port_identify(int idx) { + ahci_port_t *p = &ports[idx]; + hba_port_t *port = &hba->ports[idx]; + + // IDENTIFY needs a 512-byte buffer; alloc gives us a page + u16 *buf = (u16 *)alloc(4096); + u64 phys = virt_to_phys(buf); + + int slot = find_free_slot(port); + if (slot < 0) return; + + hba_cmd_header_t *hdr = &p->cmd_list[slot]; + hdr->flags = sizeof(fis_reg_h2d_t) / 4; // FIS length, no write bit + hdr->prdtl = 1; + hdr->prdbc = 0; + + hba_cmd_table_t *tbl = p->cmd_tables[slot]; + memset(tbl, 0, sizeof(hba_cmd_table_t)); + + tbl->prdt[0].dba = (u32)(phys); + tbl->prdt[0].dbau = (u32)(phys >> 32); + tbl->prdt[0].dbc = 511; // 512 bytes - 1, no interrupt bit needed + + fis_reg_h2d_t *fis = (fis_reg_h2d_t *)tbl->cfis; + fis->fis_type = 0x27; + fis->c = (1 << 7); + fis->command = ATA_CMD_IDENTIFY; + fis->device = 0; + + // Wait for idle + int spin = 0; + while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && ++spin < 1000000) + ; + + port->ci = (1u << slot); + + while (port->ci & (1u << slot)) { + if (port->is & HBA_IS_TFES) { + printf("AHCI: identify error on port %d\n", idx); + return; + } + } + + // Word 100-103: 48-bit LBA sector count + p->sector_count = ((u64)buf[103] << 48) | ((u64)buf[102] << 32) | + ((u64)buf[101] << 16) | ((u64)buf[100]); + + + // word 106 contains sector size info + u16 w106 = buf[106]; + + if (w106 & (1 << 14) && !(w106 & (1 << 15))) { + // words 117-118: logical sector size in words (if bit 12 of w106 is set) + if (w106 & (1 << 12)) { + u32 logical_size = ((u32)buf[118] << 16) | buf[117]; + logical_size *= 2; // words to bytes + p->sector_size = logical_size; + } + } + + printf("AHCI: port %d sections = %d\n", idx, p->sector_count); +} + +// buf must be physically contiguous. For >AHCI_PRDT_PER_TABLE*4MB you'd need +// to split the request; at 8 PRDT entries of up to 4MB each that's 32MB max +// per call which is plenty for now. +static int ahci_rw(int idx, u64 lba, u32 sector_count, void *buf, int write) { + ahci_port_t *p = &ports[idx]; + hba_port_t *port = &hba->ports[idx]; + + if (!p->active) { + print("AHCI: port not active\n"); + return -1; + } + + int slot = find_free_slot(port); + if (slot < 0) { + print("AHCI: no free command slots\n"); + return -1; + } + + hba_cmd_header_t *hdr = &p->cmd_list[slot]; + hdr->flags = (u16)(sizeof(fis_reg_h2d_t) / 4); + if (write) hdr->flags |= (1 << 6); + hdr->prdbc = 0; + + hba_cmd_table_t *tbl = p->cmd_tables[slot]; + memset(tbl, 0, sizeof(hba_cmd_table_t)); + + // Fill PRDT — each entry covers up to 4MB (0x3FFFFF bytes + 1). + // We use 512KB chunks to stay conservative and keep entry count low. + #define CHUNK_SIZE (512 * 1024) + + u32 remaining = sector_count * 512; + u64 buff_phys = virt_to_phys(buf); + u16 prdt_count = 0; + + while (remaining > 0 && prdt_count < AHCI_PRDT_PER_TABLE) { + u32 chunk = remaining < CHUNK_SIZE ? remaining : CHUNK_SIZE; + + tbl->prdt[prdt_count].dba = (u32)(buff_phys); + tbl->prdt[prdt_count].dbau = (u32)(buff_phys >> 32); + // dbc is bytes - 1; set interrupt on completion only on last entry + tbl->prdt[prdt_count].dbc = (chunk - 1); + + buff_phys += chunk; + remaining -= chunk; + prdt_count++; + } + + // Interrupt on last PRDT entry + tbl->prdt[prdt_count - 1].dbc |= (1u << 31); + + hdr->prdtl = prdt_count; + + // Build the command FIS + fis_reg_h2d_t *fis = (fis_reg_h2d_t *)tbl->cfis; + fis->fis_type = 0x27; + fis->c = (1 << 7); + fis->command = write ? ATA_CMD_WRITE_DMA_EXT : ATA_CMD_READ_DMA_EXT; + fis->device = (1 << 6); // LBA mode + + fis->lba0 = (u8)(lba >> 0); + fis->lba1 = (u8)(lba >> 8); + fis->lba2 = (u8)(lba >> 16); + fis->lba3 = (u8)(lba >> 24); + fis->lba4 = (u8)(lba >> 32); + fis->lba5 = (u8)(lba >> 40); + + fis->countl = (u8)(sector_count >> 0); + fis->counth = (u8)(sector_count >> 8); + + // Wait until port is not busy + int spin = 0; + while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && ++spin < 1000000) + ; + if (spin >= 1000000) { + print("AHCI: port hung before issue\n"); + return -1; + } + + port->is = 0xFFFFFFFF; // clear interrupts before issuing + port->ci = (1u << slot); + + // Poll for completion + while (1) { + if (!(port->ci & (1u << slot))) + break; + if (port->is & HBA_IS_TFES) { + print("AHCI: task file error (port "); + print32(idx); + print(")\n"); + return -1; + } + } + + // Final error check after CI clears + if (port->is & HBA_IS_TFES) { + print("AHCI: task file error after completion\n"); + return -1; + } + + return 0; +} + +int ahci_read(int port, u64 lba, u32 count, void *buf) { + int ret = ahci_rw(port, lba, count, buf, 0); + if(ret < 0) { + printf("Failed ahci read (%d, 0x", port); + print64(lba); + printf(", %u, %u)\n", count, buf); + } + return ret; +} + +int ahci_write(int port, u64 lba, u32 count, void *buf) { + return ahci_rw(port, lba, count, buf, 1); +} + +u64 ahci_sector_count(int port) { + return ports[port].sector_count; +} + +int ahci_port_active(int port) { + return ports[port].active; +} + +void ahci_init() { + // Scan PCI for AHCI controller (class=0x01, subclass=0x06) + u8 found_bus = 0, found_slot = 0, found_func = 0; + int found = 0; + + for (u32 bus = 0; bus < 256 && !found; bus++) { + for (u8 slot = 0; slot < 32 && !found; slot++) { + for (u8 func = 0; func < 8 && !found; func++) { + u32 id = pci_read(bus, slot, func, 0x00); + if ((id & 0xFFFF) == 0xFFFF) continue; + + u32 class = pci_read(bus, slot, func, 0x08); + if (((class >> 24) & 0xFF) == 0x01 && + ((class >> 16) & 0xFF) == 0x06) { + found_bus = bus; + found_slot = slot; + found_func = func; + found = 1; + } + } + } + } + + if (!found) { + print("AHCI: no controller found\n"); + return; + } + + // Enable bus mastering + memory space + u32 pcicmd = pci_read(found_bus, found_slot, found_func, 0x04); + pcicmd |= (1 << 1) | (1 << 2); + pci_write(found_bus, found_slot, found_func, 0x04, pcicmd); + + // BAR5 = ABAR + u32 bar5 = pci_read(found_bus, found_slot, found_func, 0x24); + u64 abar_phys = (u64)(bar5 & 0xFFFFF000); + + hba = (hba_mem_t *)map_mmio(abar_phys, 1<<12); + if (!hba) { + print("AHCI: failed to map HBA\n"); + return; + } + + printf("AHCI: HBA mapped, version=%d", hba->vs); + + // Take AHCI ownership from BIOS if BOHC is supported (CAP2.BOH) + if (hba->cap2 & (1 << 0)) { + hba->bohc |= (1 << 1); // set OOS + while (hba->bohc & (1 << 0)) // wait for BOS to clear + ; + } + + // Enable AHCI mode + hba->ghc |= HBA_GHC_AE; + + // Init all ports that have a device attached + u32 pi = hba->pi; + for (int i = 0; i < AHCI_MAX_PORTS; i++) { + if (!(pi & (1u << i))) continue; + + u32 ssts = hba->ports[i].ssts; + u8 det = (ssts >> 0) & 0xF; // device detection + u8 ipm = (ssts >> 8) & 0xF; // interface power management + + if (det == 3 && ipm == 1) { + port_init(i); + port_identify(i); + } + } +} diff --git a/src/ahci.h b/src/ahci.h new file mode 100644 index 0000000..93deac4 --- /dev/null +++ b/src/ahci.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common.h" + +int ahci_read(int port, u64 lba, u32 count, void *buf); +int ahci_write(int port, u64 lba, u32 count, void *buf); +u64 ahci_sector_count(int port); +int ahci_port_active(int port); +void ahci_init(); diff --git a/src/alloc.c b/src/alloc.c index 0deb914..af1a838 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -2,6 +2,7 @@ #include "../include/limine.h" #include "common.h" #include "print.h" +#include "lib/stdio.h" #ifdef DBG #define dprint(x) print(x) @@ -115,7 +116,7 @@ static void *addr(size_t page) { return alloc_start + page * PAGE_SIZE; } static void usepage(size_t page) { size_t idx = page / 64; size_t bit = page & 63; - alloc_bitmap[idx] |= (1 << bit); + alloc_bitmap[idx] |= (1ULL << bit); } static void usepagerange(size_t page, size_t len) { @@ -127,7 +128,7 @@ static void usepagerange(size_t page, size_t len) { static void unusepage(size_t page) { size_t idx = page / 64; size_t bit = page & 63; - alloc_bitmap[idx] &= ~(1 << bit); + alloc_bitmap[idx] &= ~(1ULL << bit); } static void unusepagerange(size_t page, size_t len) { @@ -190,6 +191,7 @@ void *alloc(size_t size) { if (++consecutive >= pages) { usepagerange(page, pages); dprint("succeeded!\n"); + return addr(page); } } else { diff --git a/src/common.h b/src/common.h index 829193e..738c498 100644 --- a/src/common.h +++ b/src/common.h @@ -34,12 +34,12 @@ static inline u8 inb(u16 port) { } static inline u16 inw(u16 port) { u16 value; - asm volatile("inw %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); + asm volatile("inw %w1, %0" : "=a"(value) : "Nd"(port) : "memory"); return value; } static inline u32 ind(u16 port) { u32 value; - asm volatile("ind %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); + asm volatile("inl %w1, %0" : "=a"(value) : "Nd"(port) : "memory"); return value; } diff --git a/src/fat32.h b/src/fat32.h new file mode 100644 index 0000000..ba75555 --- /dev/null +++ b/src/fat32.h @@ -0,0 +1,143 @@ +#pragma once + +#include "ahci.h" +#include "alloc.h" +#include "common.h" +#include "lib/stdio.h" + +// FAT32 BPB (BIOS Parameter Block) sits at the start of sector 0 +typedef pstruct { + u8 jump[3]; + u8 oem[8]; + u16 bytes_per_sector; + u8 sectors_per_cluster; + u16 reserved_sectors; + u8 fat_count; + u16 root_entry_count; // 0 for FAT32 + u16 total_sectors_16; // 0 for FAT32 + u8 media_type; + u16 fat_size_16; // 0 for FAT32 + u16 sectors_per_track; + u16 head_count; + u32 hidden_sectors; + u32 total_sectors_32; + + // FAT32 extended fields + u32 fat_size_32; + u16 ext_flags; + u16 fs_version; // must be 0x0000 + u32 root_cluster; // usually 2 + u16 fs_info_sector; + u16 backup_boot_sector; + u8 reserved[12]; + u8 drive_number; + u8 reserved1; + u8 boot_signature; // 0x29 + u32 volume_id; + u8 volume_label[11]; + u8 fs_type[8]; // "FAT32 " + } fat32_bpb_t; + + +typedef pstruct { + u8 status; // 0x80 = bootable + u8 chs_first[3]; // legacy + u8 type; // partition type + u8 chs_last[3]; // legacy + u32 lba_start; // first sector of the partition + u32 sector_count; // size in sectors +} fat32_mbr_partition_t; + +typedef pstruct { + u8 bootcode[446]; + fat32_mbr_partition_t partitions[4]; + u16 signature; + } fat32_mbr_t; + + typedef pstruct { + u32 fat_start; + u32 data_start; + u32 sectors_per_cluster; + u32 root_cluster; + u32 part_start; + } fat32_vol_t; + + static fat32_vol_t vol_from_bpb(fat32_bpb_t* bpb, u32 part_start) { + fat32_vol_t vol; + vol.part_start = part_start; + vol.sectors_per_cluster = bpb->sectors_per_cluster; + vol.fat_start = part_start + bpb->reserved_sectors; + vol.data_start = vol.fat_start + bpb->fat_count * bpb->fat_size_32; + vol.root_cluster = bpb->root_cluster; + + return vol; + } + +#define TODO_MAKE_ME_DYNAMIC_BLOCK_SIZE 512 + +static u32 fat32_next(int port, fat32_vol_t* vol, u32 cluster) { + u32 fat_off = cluster*4; + u32 fat_sect = vol->fat_start + fat_off / TODO_MAKE_ME_DYNAMIC_BLOCK_SIZE; + u32 fat_idx = (fat_off & (TODO_MAKE_ME_DYNAMIC_BLOCK_SIZE-1)); + + printf("fat_next: cluster=%u fat_off=%u fat_sect=%u byte_off=%u\n", + cluster, fat_off, fat_sect, fat_off); + + u8* buff = (u8*) alloc(4096); + if(ahci_read(port, fat_sect, 2, buff) < 0) { + printf("fat_next: read failed at lba=%u\n", fat_sect); + return 0x0FFFFFFF; + } + + u32* tbl = (u32*) (buff + fat_idx); + // mask top 4 + return *tbl & 0x0FFFFFFF; +} + +static bool fat32_is_eof(u32 cluster) { + return cluster >= 0x0FFFFFF8; +} + +static u64 fat32_cluster_to_lba(fat32_vol_t* vol, u32 cluster) { + // first 2 are resv. + + u64 lba = vol->data_start + (u64)(cluster-2) * vol->sectors_per_cluster; + + return lba; +} + +static int fat32_read_cluster(int port, fat32_vol_t* vol, u32 cluster, u8* buff) { + u64 lba = fat32_cluster_to_lba(vol, cluster); + return ahci_read(port, lba, vol->sectors_per_cluster, buff); +} + +/* directory entries and files */ +typedef pstruct { + u8 name[8]; + u8 ext[3]; + u8 attr; + u8 resv; + u8 creation_time_tenth; + u16 creation_time; + u16 creation_date; + u16 access_date; + u16 cluster_high; // high 16 bits of first cluster + u16 modify_time; + u16 modify_date; + u16 cluster_low; // low 16 bits of first cluster + u32 file_size; +} fat32_dirent_t; + +enum fat32_attr { + ATTR_READ_ONLY = 1 << 0, + ATTR_HIDDEN = 1 << 1, + ATTR_SYSTEM = 1 << 2, + ATTR_VOL_ID = 1 << 3, + ATTR_DIR = 1 << 4, + ATTR_ARCH = 1 << 5, + ATTR_LFN = 0xF, // long file name entry +}; + +static u32 fat32_dirent_cluster(fat32_dirent_t* dirent) { + return ((u32)dirent->cluster_high << 16) | dirent->cluster_low; +} diff --git a/src/main.c b/src/main.c index 9f7e76e..c7445a3 100644 --- a/src/main.c +++ b/src/main.c @@ -9,11 +9,11 @@ void print_tok(struct token* tok); #include "acpi.h" +#include "ahci.h" #include "alloc.h" #include "apic.h" #include "common.h" -#include "kbd.h" -#include "map.h" +#include "fat32.h" #include "print.h" #include "lib/stdio.h" @@ -108,11 +108,11 @@ void hang() { struct limine_framebuffer *fb; -void draw(u8 vect) { +void draw() { for (size_t y = 0; y < fb->height; y++) { for (size_t x = 0; x < fb->width; x++) { volatile u32 *fb_ptr = fb->address; - int tone = ((x ^ y) & 0xFF) >> 6; + int tone = ((x ^ y) & 0xFF); fb_ptr[y * fb->width + x] = (tone << 16); } } @@ -142,6 +142,64 @@ void enable_ps2_keyboard_interrupts(void) { outb(0x64, 0xAE); } + +void ls(int port, int indent, fat32_vol_t* vol, u32 cluster) { + u32 cluster_size = vol->sectors_per_cluster * TODO_MAKE_ME_DYNAMIC_BLOCK_SIZE; + + u8* lsbuff = alloc(4096); + do { + fat32_read_cluster(port, vol, cluster, lsbuff); + fat32_dirent_t* dir = (fat32_dirent_t*) lsbuff; + u32 cnt = cluster_size / sizeof(fat32_dirent_t); + for(size_t i = 0; i < cnt; i++) { + if(dir[i].name[0] == 0x00) { + return; + } + + for(int i = 0; i < indent; i++) { + printf("----"); + } + + printf("[%d] ", i); + + if(dir[i].name[0] == 0xE5) { + printf("[DELETED]\n"); + continue; + } + + if((dir[i].attr & 0x3F) == ATTR_LFN) { + printf("Long File Name\n", i); + continue; + } + if(dir[i].attr & ATTR_VOL_ID) { + printf("Volume ID\n"); + continue; + } + + + for(size_t c = 0; c < 8 && dir[i].name[c] != ' '; c++) { + put(dir[i].name[c]); + } + if(dir[i].ext[0] && dir[i].ext[0] != ' ') { + put('.'); + for(size_t c = 0; c < 8 && dir[i].ext[c] != ' '; c++) { + put(dir[i].ext[c]); + } + } + put('\n'); + + if(dir[i].attr & ATTR_DIR) { + if(dir[i].name[0] != '.') + ls(port, indent + 1, vol, dir[i].cluster_low + ((u32)(dir[i].cluster_high) << 16)); + } + } + + cluster = fat32_next(port, vol, cluster); + } while(!fat32_is_eof(cluster)); + + printf("All Done\n"); +} + void kmain() { if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { hang(); @@ -153,7 +211,7 @@ void kmain() { fb = fb_req.response->framebuffers[0]; - draw(1); + draw(); print_init(fb); init_idt(); fg = 0xFFFFFF; @@ -203,42 +261,112 @@ void kmain() { asm volatile("sti"); -#define LINES 40 - size_t max_len = MAX_LINE_LEN; - char* lines[LINES]; - size_t n_lines = 0; - for(n_lines = 0; n_lines < LINES; n_lines++) { - char* line = getline_alloc(max_len); - if(!line) - break; - if(line[0] == 'F' && line[1] == 'I' && line[2] == '\n') - break; - lines[n_lines] = line; + ahci_init(); + + i8 port = -1; + for(u8 i = 0; i < 32; i++) { + if(ahci_port_active(i)) { + // assume we want the first port + if(port < 0) + port = i; + printf("Port %d is active!\n", i); + } } - const char* name = "stdin"; - struct file input = { - .row = 0, - .col = 0, - .rows = n_lines, - .lines = (char**)lines, - .name = name, - .tokens = NULL, - .tail = &input.tokens, - }; - - int res = lex(&input); - - print("Number of Errors: "); - print8(res); - - printf("\n# of Tokens: %d\n", input.tokens->len); - struct token* token = input.tokens; - - for(;token; token = token->next) { - print_tok(token); + if(port < 0) { + printf("Couldn't find a port to read the FS from :(\n"); + hang(); } + + + fat32_mbr_t* mbr = alloc(1<<12); + ahci_read(port, 0, 1, mbr); + + i8 bootpart = -1; + fat32_mbr_partition_t bpart; + printf("Fat32 Partitions:\n"); + for(size_t i = 0; i < 4; i++) { + fat32_mbr_partition_t* part = &mbr->partitions[i]; + u32 lba_start = part->lba_start; + u32 lba_end = lba_start + part->sector_count; + + if(bootpart < 0 && part->status == 0x80) { + bootpart = i; + bpart = *part; + } + + printf("\t%s, %d Sectors [0x%x-0x%x]\n", + (part->status == 0x80)? "[BOOTABLE]" : "[UNBOOTABLE]", + part->sector_count, + lba_start, lba_end); + } + + if(bootpart < 0) { + printf("Failed to find boot partition :(\n"); + } + + + // reuse buffer + fat32_bpb_t* bpb = (fat32_bpb_t*) mbr; + mbr = NULL; + + // hardcode for now :( + u32 part_lba = 2048; + ahci_read(port, part_lba, 1, bpb); + + fat32_vol_t vol = vol_from_bpb(bpb, part_lba); + + u64 root_lba = fat32_cluster_to_lba(&vol, vol.root_cluster); + printf("root_lba=%u\n", (u32)root_lba); + + u8 *raw = alloc(4096); + ahci_read(port, root_lba, vol.sectors_per_cluster, raw); + printf("raw: "); + for(int i = 0; i < 64; i++) + printf("%x ", raw[i]); + printf("\n"); + + ls(port, 0, &vol, vol.root_cluster); + + //dealloc((void*) bpb, 1<<12); + +// #define LINES 40 +// size_t max_len = MAX_LINE_LEN; +// char* lines[LINES]; + +// size_t n_lines = 0; +// for(n_lines = 0; n_lines < LINES; n_lines++) { +// char* line = getline_alloc(max_len); +// if(!line) +// break; +// if(line[0] == 'F' && line[1] == 'I' && line[2] == '\n') +// break; +// lines[n_lines] = line; +// } + +// const char* name = "stdin"; +// struct file input = { +// .row = 0, +// .col = 0, +// .rows = n_lines, +// .lines = (char**)lines, +// .name = name, +// .tokens = NULL, +// .tail = &input.tokens, +// }; + +// int res = lex(&input); + +// print("Number of Errors: "); +// print8(res); + +// printf("\n# of Tokens: %d\n", input.tokens->len); +// struct token* token = input.tokens; + +// for(;token; token = token->next) { +// print_tok(token); +// } hang(); } diff --git a/src/print.c b/src/print.c index 13dd1f4..1d53c92 100644 --- a/src/print.c +++ b/src/print.c @@ -75,7 +75,7 @@ void put(int ch) { size_t off = (py + y) * fb_width + (px + x); bool padding = (y == 0 || y == GLYPH_HEIGHT - 1 || x == 0 || x == GLYPH_WIDTH - 1); - fb_scr[off] = ((~glyph & 1) | padding) ? bg : fg; + fb_scr[off] = ((~glyph & 1) | padding) ? ((fb_scr[off] == fg) ? bg : fb_scr[off]) : fg; glyph >>= !padding; } } @@ -132,4 +132,4 @@ void unput(void) { for (size_t y = 0; y < GLYPH_HEIGHT; y++) for (size_t x = 0; x < GLYPH_WIDTH; x++) fb_scr[(py + y) * fb_width + (px + x)] = bg; -} \ No newline at end of file +}