diff --git a/boot/stage2/attr.h b/boot/stage2/defs.h similarity index 69% rename from boot/stage2/attr.h rename to boot/stage2/defs.h index 870eeeb..4e7d216 100644 --- a/boot/stage2/attr.h +++ b/boot/stage2/defs.h @@ -1,9 +1,10 @@ -#ifndef ATTR_H -#define ATTR_H +#ifndef _DEFS_H +#define _DEFS_H #define __packed __attribute__((packed)) #define __naked __attribute__((naked)) #define __section(_sect) __attribute__((section(_sect))) #define noreturn __attribute__((noreturn)) +#define sizeof_array(_a) (sizeof(_a) / sizeof(_a[0])) #endif diff --git a/boot/stage2/disk.c b/boot/stage2/disk.c index b46267d..d34469f 100644 --- a/boot/stage2/disk.c +++ b/boot/stage2/disk.c @@ -19,6 +19,20 @@ void readSectors(uint32_t lba, size_t count, void* dst) { } } -/* TODO */ -void writeSectors(uint32_t lba, size_t count, void* src) {} +void writeSectors(uint32_t lba, size_t count, void* src) { + outb(PIO_PORT + 6, ((lba >> 24) & 0x0f) | 0xe0); + outb(PIO_PORT + 2, count); + outb(PIO_PORT + 3, lba & 0xff); + outb(PIO_PORT + 4, (lba >> 8) & 0xff); + outb(PIO_PORT + 5, (lba >> 16) & 0xff); + outb(PIO_PORT + 7, PIO_CMD_WRITE); + + uint16_t* buf = (uint16_t*)src; + + for (size_t i = 0; i < count; i++) { + while (inb(PIO_PORT + 7) & (1 << 7)); // Wait until BSY is cleared + for (size_t j = 0; j < SECTOR_SIZE / 2; j++) outw(PIO_PORT, *buf++); + for (uint8_t wait = 0; wait < 4; wait++) inb(PIO_ALT_STATUS); + } +} diff --git a/boot/stage2/disk.h b/boot/stage2/disk.h index 0c36bab..b53a614 100644 --- a/boot/stage2/disk.h +++ b/boot/stage2/disk.h @@ -2,7 +2,7 @@ #define DISK_H #include "stdint.h" -#include "attr.h" +#include "defs.h" #define SECTOR_SIZE 512 #define PIO_PORT 0x1f0 @@ -14,6 +14,8 @@ #define BOOTABLE 0x80 +#define LBA_TO_OFFSET(_a) ((_a) * SECTOR_SIZE) + struct partition { uint8_t bootable; uint8_t startCHS[3]; diff --git a/boot/stage2/entry.c b/boot/stage2/entry.c index 6e7c91d..623c3dd 100644 --- a/boot/stage2/entry.c +++ b/boot/stage2/entry.c @@ -1,24 +1,46 @@ #include "stdint.h" +#include "fat32.h" #include "stdio.h" -#include "attr.h" +#include "defs.h" #include "disk.h" #include "menu.h" #include "kbd.h" +noreturn void panic() { + setAttr(0x04); + text(COLS/2, ROWS/2, "[ PANIC ]"); + while (1) __asm__ volatile ("cli; hlt"); +} + void drawPartitions(struct MBR* mbr, uint8_t sel); void partitonInfo(struct partition* part); +struct partition* menu(struct MBR* mbr); __section("entry") noreturn void main() { keyboardInit(); - struct MBR mbr; readSectors(0, 1, &mbr); + struct partition* bootpart = menu(&mbr); + setAttr(0x0f); + cls(); + showCursor(); + + if (fat32_init(bootpart) != 0) { + setAttr(0x0c); + printf("Failed to initialize FAT32."); + panic(); + } + + while (1); +} + +struct partition* menu(struct MBR* mbr) { // Select bootable partition by default uint8_t selected = 0; for (size_t i = 0; i < 4; i++) { - if (mbr.partitions[i].bootable != BOOTABLE) continue; + if (mbr->partitions[i].bootable != BOOTABLE) continue; selected = i; break; } @@ -31,14 +53,14 @@ noreturn void main() { hline(0, 2, COLS); setAttr(0x02); text(COLS / 2, 1, "KBOOT"); - drawPartitions(&mbr, selected); - partitonInfo(&mbr.partitions[selected]); + drawPartitions(mbr, selected); + partitonInfo(&mbr->partitions[selected]); while (1) { // Check for up/down arrow keys or enter uint8_t scancode = getScancode(); if (scancode == SC_ENTER) { // Boot selected - if (mbr.partitions[selected].type != 0) break; + if (mbr->partitions[selected].type != 0) break; // Don't allow booting an unused partition setAttr(0x4f); @@ -54,16 +76,11 @@ noreturn void main() { else if (selected == 4) selected = 0; // Redraw - drawPartitions(&mbr, selected); - partitonInfo(&mbr.partitions[selected]); + drawPartitions(mbr, selected); + partitonInfo(&mbr->partitions[selected]); } - - setAttr(0x0f); - cls(); - showCursor(); - printf("Booting from Partition %d...", selected); - - while (1); + + return &mbr->partitions[selected]; } void drawPartitions(struct MBR* mbr, uint8_t sel) { diff --git a/boot/stage2/fat32.c b/boot/stage2/fat32.c new file mode 100644 index 0000000..9bb048a --- /dev/null +++ b/boot/stage2/fat32.c @@ -0,0 +1,33 @@ +#include "stdint.h" +#include "string.h" +#include "disk.h" +#include "fat32.h" + +// Local context +struct fat32_ctx ctx; + +int fat32_init(struct partition* p) { + readSectors(p->startLBA, 1, &ctx.bpb); + ctx.offsetBase = p->startLBA; + + if (ctx.bpb.bytesPerSect != SECTOR_SIZE) return 1; + + ctx.offsetFats = ctx.offsetBase + ctx.bpb.reservedSects; + ctx.offsetClusts = ctx.offsetFats + ctx.bpb.fatCount * ctx.bpb.sectsPerFat_32; + + return 0; +} + +int fat32_open(char* filename, int flags, ...) { + // TODO: flags + + //struct fat32_traversed res = fat32_traverse(ctx, filename); + //if (!res.dir) return -1; + + +} + +void fat32_close(void* file) {} + +int fat32_read(const void* buf, size_t size, size_t count, void* file) {} + diff --git a/boot/stage2/fat32.h b/boot/stage2/fat32.h new file mode 100644 index 0000000..3205571 --- /dev/null +++ b/boot/stage2/fat32.h @@ -0,0 +1,124 @@ +#ifndef _FAT32_H +#define _FAT32_H + +#include "stdint.h" +#include "defs.h" +#include "disk.h" + +// Macros +#define FAT32_PTR(_p) ((struct fat32_ctx*)(_p)) +#define FAT32_DIR_PTR(_p) ((struct fat32_fd*)(_p)) +#define FAT32_FULL_CLUST(_hi, _lo) (((uint32_t)(_hi) << 16) | (_lo)) +#define FAT32_INODE_GEN(_dir, _i) ((_dir) * 100 + (_i)) + +// Long File Name (LFN) +#define LFN_MAX 20 +#define LFN_MAX_CHARS 256 + +// Attributes +#define FAT32_ATTR_READ_ONLY (1 << 0) +#define FAT32_ATTR_HIDDEN (1 << 1) +#define FAT32_ATTR_SYSTEM (1 << 2) +#define FAT32_ATTR_VOLUME_ID (1 << 3) +#define FAT32_ATTR_DIRECTORY (1 << 4) +#define FAT32_ATTR_ARCHIVE (1 << 5) +#define FAT32_ATTR_LFN \ + (FAT32_ATTR_READ_ONLY | FAT32_ATTR_HIDDEN \ + FAT32_ATTR_SYSTEM | FAT32_ATTR_VOLUME_ID) + +/* On-disk structures */ + +// FAT32 Bios Parameter Block & Extended BPB +struct fat32_bpb { + uint8_t bootjmp[3]; + char oemName[8]; + uint16_t bytesPerSect; + uint8_t sectsPerClust; + uint16_t reservedSects; + uint8_t fatCount; + uint16_t rootEntryCount; + uint16_t totalSects_16; + uint8_t mediaType; + uint16_t sectsPerFat_16; + uint16_t sectsPerTrack; + uint16_t headCount; + uint32_t hiddenSects; + uint32_t sectCount_32; + // Extended + uint32_t sectsPerFat_32; + uint16_t flags; + uint16_t fatVersion; + uint32_t rootClust; + uint16_t fsinfoSect; + uint16_t backupBootsect; + uint8_t _reserved[12]; + uint8_t driveNum; + uint8_t winNTFlags; + uint8_t signature; + uint32_t volumeID; + char volumeLabel[11]; + char systemID[8]; + uint8_t bootcode[420]; + uint16_t bootsig; +} __packed; + +// FAT32 Directory Entry +struct fat32_dentry { + char name[8]; + char ext[3]; + uint8_t attr; + uint8_t userattr; + char undelete; + uint16_t createTime; + uint16_t createDate; + uint16_t accessDate; + uint16_t clustHigh; + uint16_t modifyTime; + uint16_t modifyDate; + uint16_t clustLow; + uint32_t size; +} __packed; + +// FAT32 Long File Name entry +struct fat32_lfn { + uint8_t order; + uint8_t name1[10]; + uint8_t attr; + uint8_t type; + uint8_t checksum; + uint8_t name2[12]; + uint16_t zero; + uint8_t name3[4]; +} __packed; + +/* In memory structures */ +struct fat32_ctx { + size_t offsetBase; + size_t offsetFats; + size_t offsetClusts; + + struct fat32_bpb bpb; +}; + +struct fat32_fd { + uint32_t ptr; + uint8_t index; + uint32_t dirStart; + uint32_t dirCurrent; + struct fat32_dentry dentry; +}; + +// Handlers +int fat32_init(struct partition* p); +int fat32_open(char* filename, int flags, ...); /* We won't use the va_args */ + + +void* fat32_fopen(const char* path, const char* mode); +void fat32_fclose(void* file); +int fat32_fgetc(void* file); +char* fat32_fgets(char* s, size_t n, void* file); +int fat32_fread(const void* buf, size_t size, size_t count, void* file); +int fat32_fseek(void* file, size_t offset, int whence); +long fat32_ftell(void* file); + +#endif diff --git a/boot/stage2/kbd.c b/boot/stage2/kbd.c index 111db1b..a3f0cfc 100644 --- a/boot/stage2/kbd.c +++ b/boot/stage2/kbd.c @@ -6,7 +6,7 @@ int keyboardInit() { return 0; } uint8_t getScancode() { - while (inb(PS2_STAT_PORT) & 0x01 == 0); + while ((inb(PS2_STAT_PORT) & 0x01) == 0); return inb(PS2_DATA_PORT); } diff --git a/boot/stage2/stdio.c b/boot/stage2/stdio.c index 3b75ee6..90786ed 100644 --- a/boot/stage2/stdio.c +++ b/boot/stage2/stdio.c @@ -8,9 +8,7 @@ static uint32_t xpos; static uint32_t ypos; static uint8_t attr; -void setAttr(uint8_t newattr) { - attr = newattr; -} +void setAttr(uint8_t newattr) { attr = newattr; } void setCursor(uint32_t row, uint32_t col) { xpos = col; @@ -98,7 +96,6 @@ int vsnprintf(void* buf, size_t len, char* fmt, va_list args) { char pad = ' '; int width = 0; - // TODO: padding if (*fmt == '0') pad = '0'; while (*fmt >= '0' && *fmt <= '9') { width *= 10; @@ -110,14 +107,19 @@ int vsnprintf(void* buf, size_t len, char* fmt, va_list args) { switch (*fmt++) { case 'd': s = itoa(va_arg(args, int), 10); goto string; case 'x': s = itoa(va_arg(args, int), 16); goto string; - case 's': s = va_arg(args, char*); - string: while (*s != '\0' && pos < len - 1) str[pos++] = *s++; break; + case 's': s = va_arg(args, char*); goto string; case 'c': if (pos < len - 1) str[pos++] = va_arg(args, char); break; case '%': if (pos < len - 1) str[pos++] = '%'; break; default: if (pos < len - 1) str[pos++] = '%'; if (pos < len - 1) str[pos++] = *(fmt - 1); break; + string: + width -= strlen(s) - 1; + if (width < 0) width = 0; + while (width-- && pos < len - 1) str[pos++] = pad; + while (*s && pos < len - 1) str[pos++] = *s++; + break; } }