added preliminary support for FAT32

This commit is contained in:
Hopeless Tyromancy 2026-02-19 03:22:01 -05:00
parent c6b416d2d4
commit a83b935482
21 changed files with 838 additions and 52 deletions

BIN
bin/os

Binary file not shown.

BIN
check.img Normal file

Binary file not shown.

2
fortune Normal file
View File

@ -0,0 +1,2 @@
Many hands make light work.
-- John Heywood

BIN
image.hdd

Binary file not shown.

View File

@ -16,13 +16,14 @@ make -C limine
./limine/limine bios-install image.hdd ./limine/limine bios-install image.hdd
# Format the image as fat32. # Format the image as fat32.
mformat -i image.hdd@@1M mformat -i image.hdd@@1M -F
# Make relevant subdirectories. # 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. # Copy over the relevant files.
mcopy -i image.hdd@@1M bin/os ::/boot 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.conf limine/limine-bios.sys ::/boot/limine
mcopy -i image.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT 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 limine/BOOTIA32.EFI ::/EFI/BOOT
mcopy -i image.hdd@@1M fortune ::/fort/fortu.ne

BIN
mnt/EFI/BOOT/BOOTIA32.EFI Normal file

Binary file not shown.

BIN
mnt/EFI/BOOT/BOOTX64.EFI Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
timeout: 5
/LispOS
protocol: limine
path: boot():/boot/os

BIN
mnt/boot/os Executable file

Binary file not shown.

Binary file not shown.

View File

@ -1,19 +1,19 @@
obj/src/main.c.o: src/main.c src/../include/limine.h src/prompt/lex.h \ 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/prompt/file.h src/acpi.h src/common.h src/ahci.h src/alloc.h \
src/kbd.h src/map.h src/print.h src/lib/stdio.h src/lib/malloc.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/lib/../common.h src/lib/../kbd.h src/lib/../print.h src/print.h
src/../include/limine.h: src/../include/limine.h:
src/prompt/lex.h: src/prompt/lex.h:
src/prompt/file.h: src/prompt/file.h:
src/acpi.h: src/acpi.h:
src/common.h: src/common.h:
src/ahci.h:
src/alloc.h: src/alloc.h:
src/apic.h: src/apic.h:
src/kbd.h: src/fat32.h:
src/map.h:
src/print.h:
src/lib/stdio.h: src/lib/stdio.h:
src/lib/malloc.h: src/lib/malloc.h:
src/lib/../common.h: src/lib/../common.h:
src/lib/../kbd.h: src/lib/../kbd.h:
src/lib/../print.h: src/lib/../print.h:
src/print.h:

Binary file not shown.

6
run.sh
View File

@ -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 #/mnt/c/'Program Files'/qemu/qemu-system-x86_64.exe image.hdd

492
src/ahci.c Normal file
View File

@ -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);
}
}
}

9
src/ahci.h Normal file
View File

@ -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();

View File

@ -2,6 +2,7 @@
#include "../include/limine.h" #include "../include/limine.h"
#include "common.h" #include "common.h"
#include "print.h" #include "print.h"
#include "lib/stdio.h"
#ifdef DBG #ifdef DBG
#define dprint(x) print(x) #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) { static void usepage(size_t page) {
size_t idx = page / 64; size_t idx = page / 64;
size_t bit = page & 63; size_t bit = page & 63;
alloc_bitmap[idx] |= (1 << bit); alloc_bitmap[idx] |= (1ULL << bit);
} }
static void usepagerange(size_t page, size_t len) { 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) { static void unusepage(size_t page) {
size_t idx = page / 64; size_t idx = page / 64;
size_t bit = page & 63; size_t bit = page & 63;
alloc_bitmap[idx] &= ~(1 << bit); alloc_bitmap[idx] &= ~(1ULL << bit);
} }
static void unusepagerange(size_t page, size_t len) { static void unusepagerange(size_t page, size_t len) {
@ -190,6 +191,7 @@ void *alloc(size_t size) {
if (++consecutive >= pages) { if (++consecutive >= pages) {
usepagerange(page, pages); usepagerange(page, pages);
dprint("succeeded!\n"); dprint("succeeded!\n");
return addr(page); return addr(page);
} }
} else { } else {

View File

@ -34,12 +34,12 @@ static inline u8 inb(u16 port) {
} }
static inline u16 inw(u16 port) { static inline u16 inw(u16 port) {
u16 value; u16 value;
asm volatile("inw %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); asm volatile("inw %w1, %0" : "=a"(value) : "Nd"(port) : "memory");
return value; return value;
} }
static inline u32 ind(u16 port) { static inline u32 ind(u16 port) {
u32 value; u32 value;
asm volatile("ind %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); asm volatile("inl %w1, %0" : "=a"(value) : "Nd"(port) : "memory");
return value; return value;
} }

143
src/fat32.h Normal file
View File

@ -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;
}

View File

@ -9,11 +9,11 @@
void print_tok(struct token* tok); void print_tok(struct token* tok);
#include "acpi.h" #include "acpi.h"
#include "ahci.h"
#include "alloc.h" #include "alloc.h"
#include "apic.h" #include "apic.h"
#include "common.h" #include "common.h"
#include "kbd.h" #include "fat32.h"
#include "map.h"
#include "print.h" #include "print.h"
#include "lib/stdio.h" #include "lib/stdio.h"
@ -108,11 +108,11 @@ void hang() {
struct limine_framebuffer *fb; struct limine_framebuffer *fb;
void draw(u8 vect) { void draw() {
for (size_t y = 0; y < fb->height; y++) { for (size_t y = 0; y < fb->height; y++) {
for (size_t x = 0; x < fb->width; x++) { for (size_t x = 0; x < fb->width; x++) {
volatile u32 *fb_ptr = fb->address; 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); fb_ptr[y * fb->width + x] = (tone << 16);
} }
} }
@ -142,6 +142,64 @@ void enable_ps2_keyboard_interrupts(void) {
outb(0x64, 0xAE); 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() { void kmain() {
if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
hang(); hang();
@ -153,7 +211,7 @@ void kmain() {
fb = fb_req.response->framebuffers[0]; fb = fb_req.response->framebuffers[0];
draw(1); draw();
print_init(fb); print_init(fb);
init_idt(); init_idt();
fg = 0xFFFFFF; fg = 0xFFFFFF;
@ -203,42 +261,112 @@ void kmain() {
asm volatile("sti"); asm volatile("sti");
#define LINES 40
size_t max_len = MAX_LINE_LEN;
char* lines[LINES];
size_t n_lines = 0; ahci_init();
for(n_lines = 0; n_lines < LINES; n_lines++) {
char* line = getline_alloc(max_len); i8 port = -1;
if(!line) for(u8 i = 0; i < 32; i++) {
break; if(ahci_port_active(i)) {
if(line[0] == 'F' && line[1] == 'I' && line[2] == '\n') // assume we want the first port
break; if(port < 0)
lines[n_lines] = line; port = i;
printf("Port %d is active!\n", i);
}
} }
const char* name = "stdin"; if(port < 0) {
struct file input = { printf("Couldn't find a port to read the FS from :(\n");
.row = 0, hang();
.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);
} }
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(); hang();
} }

View File

@ -75,7 +75,7 @@ void put(int ch) {
size_t off = (py + y) * fb_width + (px + x); size_t off = (py + y) * fb_width + (px + x);
bool padding = bool padding =
(y == 0 || y == GLYPH_HEIGHT - 1 || x == 0 || x == GLYPH_WIDTH - 1); (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; glyph >>= !padding;
} }
} }