From 63167f223e1f54910f6b80e698390ee60aec79ee Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Tue, 11 Aug 2020 11:33:21 -0400 Subject: lots of progress currently, BAR fields of IDE drives are all returning zero, and the ATA read function isn't working. i'm not sure why. i'm going to work on VESA next, and come back to the IDE driver later --- src/kernel/ata.c | 113 --------------------- src/kernel/ata.h | 77 +++++++++++++- src/kernel/boot.h | 26 +++++ src/kernel/drive.c | 38 +++++++ src/kernel/drive.h | 34 +++++++ src/kernel/elf-link.ld | 21 ++++ src/kernel/fat.c | 271 +++++++++++++++++++++++++++++++++---------------- src/kernel/fat.h | 63 ++---------- src/kernel/fs.c | 144 -------------------------- src/kernel/fs.h | 11 -- src/kernel/ide.c | 189 ++++++++++++++++++++++++++++++++++ src/kernel/ide.h | 12 +++ src/kernel/link.ld | 17 ---- src/kernel/main.c | 155 +++++++++++++++++----------- src/kernel/mem.c | 63 ++++++++++++ src/kernel/mem.h | 13 +++ src/kernel/panic.c | 27 +---- src/kernel/panic.h | 8 +- src/kernel/pci.c | 77 ++++++++++++++ src/kernel/pci.h | 38 +++++++ src/kernel/plef.c | 33 ++++++ src/kernel/plef.h | 22 ++++ src/kernel/serial.c | 16 +-- src/kernel/serial.h | 17 ++-- src/kernel/task.c | 14 +++ src/kernel/task.h | 14 +++ src/kernel/util.asm | 37 ------- src/kernel/util.c | 58 ++++++++--- src/kernel/util.h | 61 +++++++++-- src/kernel/vesa.c | 5 + src/kernel/vesa.h | 24 +++++ src/kernel/vga.c | 8 +- src/kernel/vga.h | 11 +- 33 files changed, 1120 insertions(+), 597 deletions(-) delete mode 100644 src/kernel/ata.c create mode 100644 src/kernel/boot.h create mode 100644 src/kernel/drive.c create mode 100644 src/kernel/drive.h create mode 100644 src/kernel/elf-link.ld delete mode 100644 src/kernel/fs.c delete mode 100644 src/kernel/fs.h create mode 100644 src/kernel/ide.c create mode 100644 src/kernel/ide.h delete mode 100644 src/kernel/link.ld create mode 100644 src/kernel/mem.c create mode 100644 src/kernel/mem.h create mode 100644 src/kernel/pci.c create mode 100644 src/kernel/pci.h create mode 100644 src/kernel/plef.c create mode 100644 src/kernel/plef.h create mode 100644 src/kernel/task.c create mode 100644 src/kernel/task.h delete mode 100644 src/kernel/util.asm create mode 100644 src/kernel/vesa.c create mode 100644 src/kernel/vesa.h (limited to 'src/kernel') diff --git a/src/kernel/ata.c b/src/kernel/ata.c deleted file mode 100644 index 0e6cc4e..0000000 --- a/src/kernel/ata.c +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include "panic.h" -#include "util.h" -#include "ata.h" - -enum { - AP_PRIMARY = 0x01f0, - AP_SECONDARY = 0x0170, - - AP_DATA = 0x0, - AP_ERROR = 0x1, - AP_FEAT = 0x1, - AP_COUNT = 0x2, - AP_SEC = 0x3, - AP_CYL_L = 0x4, - AP_CYL_H = 0x5, - AP_HD_DR = 0x6, - AP_LBA0 = 0x3, - AP_LBA1 = 0x4, - AP_LBA2 = 0x5, - AP_L3_DR = 0x6, - AP_STAT = 0x7, - AP_CMD = 0x7, - - APC_STAT = 0x0206, - APC_CTRL = 0x0206, - APC_ADDR = 0x0207 -}; - -enum { - ADR_BASE = 0xa0, - ADR_CASCD = 0x10, - ADR_LBA = 0x40 -}; - -enum { - AS_ERROR = 0x01, - AS_INDEX = 0x02, - AS_CORRECT = 0x04, - AS_DREADY = 0x08, - AS_SERVICE = 0x10, - AS_FAULT = 0x20, - AS_READY = 0x40, - AS_BUSY = 0x80 -}; - -enum { - AC_READ = 0x20, - AC_WRITE = 0x30, - AC_FLUSH = 0xe7 -}; - -void ata_ldelay() { - uint16_t i = 65535; - while (i--) - ; -} - -void ata_sdelay() { - uint8_t i = 255; - while (i--) - ; -} - -void ata_dpoll() { - uint8_t s; - while ((s = inb(AP_PRIMARY | AP_STAT) & (AS_BUSY | AS_DREADY)) != AS_DREADY) - if (s & (AS_ERROR | AS_FAULT)) - panic("ATA controller error or fault."); -} - -uint8_t read_sectors(uint16_t start, uint8_t count, void *buffer) { - outb(AP_PRIMARY | AP_L3_DR, ADR_BASE | ADR_LBA); - outb(AP_PRIMARY | AP_LBA2, 0); - outb(AP_PRIMARY | AP_LBA1, start >> 8); - outb(AP_PRIMARY | AP_LBA0, start & 0xff); - outb(AP_PRIMARY | AP_COUNT, count); - outb(AP_PRIMARY | AP_CMD, AC_READ); - uint8_t i = count - 1; - uint16_t *ptr = buffer; - do { - ata_dpoll(); - uint8_t j = 255; - do - *(ptr++) = inw(AP_PRIMARY | AP_DATA); - while (j--); - ata_ldelay(); - } while (i--); - return count;//TODO: return early if necessary -} - -uint8_t write_sectors(uint16_t start, uint8_t count, void *buffer) { - outb(AP_PRIMARY | AP_L3_DR, ADR_BASE | ADR_LBA); - outb(AP_PRIMARY | AP_LBA2, 0); - outb(AP_PRIMARY | AP_LBA1, start >> 8); - outb(AP_PRIMARY | AP_LBA0, start & 0xff); - outb(AP_PRIMARY | AP_COUNT, count); - outb(AP_PRIMARY | AP_CMD, AC_WRITE); - uint8_t i = 0; - uint16_t *ptr = buffer; - do { - ata_dpoll(); - uint8_t j = 0; - do { - ata_sdelay(); - outw(AP_PRIMARY | AP_DATA, *(ptr++)); - } - while (++j); - ata_ldelay(); - } while (++i != count); - outb(AP_PRIMARY | AP_CMD, AC_FLUSH); - return count;//TODO: return early if necessary -} \ No newline at end of file diff --git a/src/kernel/ata.h b/src/kernel/ata.h index 605f991..7c42cdb 100644 --- a/src/kernel/ata.h +++ b/src/kernel/ata.h @@ -1,6 +1,75 @@ -#include +enum { + ATA_STATUS_BUSY = 0x80, + ATA_STATUS_DRIVE_READY = 0x40, + ATA_STATUS_DRIVE_FAULT = 0x20, + ATA_STATUS_SEEK_DONE = 0x10, + ATA_STATUS_DATA_READY = 0x08, + ATA_STATUS_CORRECTED = 0x04, + ATA_STATUS_INDEX = 0x02, + ATA_STATUS_ERROR = 0x01 +}; -void init_ata(); +enum { + ATA_ERROR_BAD_BLOCK = 0x80, + ATA_ERROR_UNCORRECTABLE = 0x40, + ATA_ERROR_MEDIA_SWAPPED = 0x20, + ATA_ERROR_NO_ID_MARK = 0x10, + ATA_ERROR_MEDIA_SWAPPING = 0x08, + ATA_ERROR_ABORTED_CMD = 0x04, + ATA_ERROR_NO_TRACK_ZERO = 0x02, + ATA_ERROR_NO_ADDR_MARK = 0x01 +}; -uint8_t read_sectors(uint16_t start, uint8_t count, void *buffer); -uint8_t write_sectors(uint16_t start, uint8_t count, void *buffer); \ No newline at end of file +enum { + ATA_CMD_READ = 0x20, + ATA_CMD_WRITE = 0x30, + ATA_CMD_WRITE_EXT = 0x34, + ATA_CMD_READ_EXT = 0x40, + ATAPI_CMD = 0xa0, + ATAPI_CMD_ID = 0xa1, + ATA_CMD_FLUSH = 0xe7, + ATA_CMD_FLUSH_EXT = 0xea, + ATA_CMD_ID = 0xec, +}; + +enum { + ATAPI_CMD_EJECT = 0x1b, + ATAPI_CMD_READ = 0xa8 +}; + +enum { + ATA_REG_DATA = 0x0, + ATA_REG_ERROR = 0x1, + ATA_REG_FEAT = 0x1, + ATA_REG_COUNT_LOW = 0x2, + ATA_REG_LBA0 = 0x3, + ATA_REG_LBA1 = 0x4, + ATA_REG_LBA2 = 0x5, + ATA_REG_SELECT = 0x6, + ATA_REG_CMD = 0x7, + ATA_REG_STATUS = 0x7, + ATA_REG_COUNT_HIGH = 0x8, + ATA_REG_LBA3 = 0x9, + ATA_REG_LBA4 = 0xa, + ATA_REG_LBA5 = 0xb, + ATA_REG_CONTROL = 0xc, + ATA_REG_ALT_STATUS = 0xc, + ATA_REG_ADDR = 0xd +}; + +enum { + ATA_MASTER_SELECT = 0xa0, + ATA_SLAVE_SELECT = 0xb0 +}; + +enum { + ATA_SET_EXT = 0x04000000 +}; + +enum { + ATA_CAP_LBA = 0x00000200 +}; + +enum { + ATA_CONTROL_NO_IRQS = 0x02 +}; \ No newline at end of file diff --git a/src/kernel/boot.h b/src/kernel/boot.h new file mode 100644 index 0000000..b3d3e76 --- /dev/null +++ b/src/kernel/boot.h @@ -0,0 +1,26 @@ +#ifndef BOOT_H +#define BOOT_H + +#include + +enum { + BIS_PCI = 0x80 +}; + +enum { + PHC_CS_M1 = 0x01, + PHC_CS_M2 = 0x02, + PHC_SC_M1 = 0x10, + PHC_SC_M2 = 0x20 +}; + +#define BOOT_INFO \ + ((struct { \ + uint8_t support_flags; \ + uint8_t pci_hw_char; \ + uint8_t pci_minor_bcd; \ + uint8_t pci_major_bcd; \ + uint8_t last_pci_bus; \ + } __attribute__ ((__packed__)) *)0x4000) + +#endif \ No newline at end of file diff --git a/src/kernel/drive.c b/src/kernel/drive.c new file mode 100644 index 0000000..bf27ec6 --- /dev/null +++ b/src/kernel/drive.c @@ -0,0 +1,38 @@ +#include "drive.h" +#include "fat.h" +#include "panic.h" + +uint8_t n_drives = 0; +struct drive drives[256]; + +drive_file_id_t unknown_get_file(struct drive *d, char *path) { + return 0; +} + +void unknown_free_file(struct drive *d, drive_file_id_t fid) { + panic("Free file called on unknown file system"); +} + +void unknown_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) { + panic("Load sector called on unknown file system"); +} + +uint32_t unknown_get_free_sectors(struct drive *d) { + return d->n_sectors; +} + +void determine_fs(struct drive *d) { + if (try_fat_init_drive(d)) + return; + + d->fs_type = "Unknown"; + d->get_file = &unknown_get_file; + d->free_file = &unknown_free_file; + d->load_sector = &unknown_load_sector; + d->get_free_sectors = &unknown_get_free_sectors; +} + +void commit_drive(struct drive data) { + determine_fs(&data); + drives[n_drives++] = data; +} \ No newline at end of file diff --git a/src/kernel/drive.h b/src/kernel/drive.h new file mode 100644 index 0000000..8d3f3b2 --- /dev/null +++ b/src/kernel/drive.h @@ -0,0 +1,34 @@ +#ifndef DRIVE_H +#define DRIVE_H + +#include + +typedef uint8_t drive_file_id_t; + +typedef uint8_t fs_id_t; +typedef uint8_t drive_id_t; + +#define MAX_DRIVES 256 + +struct drive { + char *drive_type; + char *fs_type; + + uint8_t (*read_sectors)(struct drive *d, uint32_t start, uint32_t count, void *buffer); + uint8_t (*write_sectors)(struct drive *d, uint32_t start, uint32_t count, void *buffer); + uint32_t n_sectors; + drive_id_t drive_id; + + drive_file_id_t (*get_file)(struct drive *d, char *path); + void (*free_file)(struct drive *d, drive_file_id_t fid); + void (*load_sector)(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at); + uint32_t (*get_free_sectors)(struct drive *d); + fs_id_t fs_id; +}; + +extern uint8_t n_drives; +extern struct drive drives[MAX_DRIVES]; + +void commit_drive(struct drive data); + +#endif \ No newline at end of file diff --git a/src/kernel/elf-link.ld b/src/kernel/elf-link.ld new file mode 100644 index 0000000..a0d60f9 --- /dev/null +++ b/src/kernel/elf-link.ld @@ -0,0 +1,21 @@ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0x00030000; + .text : { + */main.o(.text) + *(.text) + } + .rodata : { + *(.rodata) + } + .data : { + *(.data) + } + . = 0x10000000; + .bss : { + *(.bss) + kernel_bss_end = .; + } +} \ No newline at end of file diff --git a/src/kernel/fat.c b/src/kernel/fat.c index b8d1c3b..087d79e 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -1,115 +1,210 @@ #include "fat.h" #include "ata.h" #include "panic.h" -#include "fs.h" +#include "drive.h" +#include "mem.h" +#include "util.h" -void load_fat() { - read_sectors(FAT_INFO->reserved_sectors, FAT_INFO->sectors_per_fat, FAT); +#define MAX_FAT_DRIVES 16 +#define MAX_OPEN_FILES_PER_DRIVE 32 + +enum { + FA_READ_ONLY = 0x01, + FA_HIDDEN = 0x02, + FA_SYSTEM = 0x04, + FA_LABEL = 0x08, + FA_DIRECTORY = 0x10, + FA_ARCHIVE = 0x20, + + FA_LFN = 0x0f +}; + +struct directory_entry { + uint8_t name[11]; + uint8_t attrib; + uint8_t name_case; + uint8_t created_decimal; + uint16_t created_time; + uint16_t created_date; + uint16_t accessed_date; + uint16_t ignore; + uint16_t modified_time; + uint16_t modified_date; + uint16_t first_cluster; + uint32_t length; +} __attribute__ ((packed)); + +struct fat_info { + //3 bytes jump + uint8_t oem[8]; + uint16_t bytes_per_sector;//Assumed to be 512 + uint8_t sectors_per_cluster;//Assumed to be 1 + uint16_t reserved_sectors; + uint8_t fats;//Only first is used + uint16_t root_entries; + uint16_t sectors;//Assumed not to be 0 + uint8_t media_type; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads; + uint32_t hidden_sectors; + uint32_t sectors_long; + uint8_t drive_number; + uint8_t reserved; + uint8_t ext_boot_marker; + uint32_t volume_id; + uint8_t label[11]; + uint8_t fs_type[8]; +} __attribute__ ((packed)); + +#define CTOS(c, fi) ((fi)->reserved_sectors + (fi)->sectors_per_fat * (fi)->fats + ((fi)->root_entries >> 4) + (c) - 2) + +struct fat_drive_info { + struct fat_info *fi; + uint16_t *fat; + struct directory_entry open_files[MAX_OPEN_FILES_PER_DRIVE]; +}; + +struct fat_drive_info infos[MAX_FAT_DRIVES]; +uint8_t next_id = 0; + +#define FI(n) ((struct fat_info *)(infos[n].fi + 3)) +#define FN(n, f) (infos[n].open_files[f - 1]) + +uint8_t fat_driver_buffer[512]; +struct fat_info *next_fi; + +void alloc_next_fi() { + if (!((uint32_t)(next_fi = (struct fat_info *)((uint32_t)next_fi + 64)) & 0xfff)) + if (!(next_fi = allocate_pages(1))) + panic("Out of memory in FAT driver."); } -bool to_fat_name(uint8_t *sname, uint8_t *fname) { - uint8_t *sp = sname, *fp = fname; - while (*sp != '.') { - if (!*sp) { - while (fp != fname + 11) - *(fp++) = ' '; - return false; - } - if (sp == sname + 8) - return true; - *(fp++) = *(sp++); - } - while (fp != fname + 8) - *(fp++) = ' '; - while (*++sp) { - if (fp == fname + 11) - return true; - *(fp++) = *sp; +struct drive *cur_drive; +fs_id_t cur_id; +struct directory_entry *cur_dir; + +//loads cluster `c` +void load_cluster(uint16_t c, void *to) { + if (c == 0) { + *(uint8_t *)to = 0; + return; } - while (fp != fname + 11) - *(fp++) = ' '; - return false; + + uint32_t s = CTOS(c, FI(cur_id)); + cur_drive->read_sectors(cur_drive, s, 1, to); } -bool check_fat_names(uint8_t *lname, uint8_t *rname) { - return (* (uint32_t *)lname == *(uint32_t *)rname) && - (*((uint32_t *)lname + 1) == *((uint32_t *)rname + 1)) && - (*((uint16_t *)lname + 4) == *((uint16_t *)rname + 4)) && - (*( lname + 10) == *( rname + 10)); +uint16_t next_cluster(uint16_t c) { + panic("TODO: compute next sector (or 0 for none)"); } -struct directory_entry buffer[16]; -uint16_t dir_start, buffer_from; +static inline bool check_fat_names(uint8_t *a, uint8_t *b) { + return (((uint32_t *)a)[0] == ((uint32_t *)b)[0]) && + (((uint32_t *)a)[1] == ((uint32_t *)b)[1]) && + (((uint16_t *)a)[8] == ((uint16_t *)b)[8]) && + (((uint8_t *)a)[10] == ((uint8_t *)b)[10]); +} +//after: cur_dir -> specified entry in root +bool try_locate_root_entry(uint8_t *fat_name) { + uint32_t cur_dir_sect = FI(cur_id)->reserved_sectors + FI(cur_id)->sectors_per_fat * FI(cur_id)->fats - 1; + cur_dir = (struct directory_entry *)(fat_driver_buffer + 512); + while (true) { + if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) { + cur_dir = (struct directory_entry *)fat_driver_buffer; + ++cur_dir_sect; + cur_drive->read_sectors(cur_drive, cur_dir_sect, 1, cur_dir); + } + if (!*(uint8_t *)cur_dir) + return false; + if (check_fat_names(cur_dir->name, fat_name)) + return true; + else + ++cur_dir; + } +} -void load_root() { - dir_start = FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat; +//before: cur_dir -> entry of dir to search +//after: cur_dir -> specified entry in dir +bool try_locate_entry(uint8_t *fat_name) { + uint16_t cur_dir_cluster = cur_dir->first_cluster; + load_cluster(cur_dir_cluster, fat_driver_buffer); + cur_dir = (struct directory_entry *)fat_driver_buffer; + while (true) { + if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) { + cur_dir = (struct directory_entry *)fat_driver_buffer; + ++cur_dir_cluster; + load_cluster(cur_dir_cluster = next_cluster(cur_dir_cluster), fat_driver_buffer); + } + if (!*(uint8_t *)cur_dir) + return false; + if (check_fat_names(cur_dir -> name, fat_name)) + return true; + else + ++cur_dir; + } } -struct directory_entry *load_subentry(uint8_t *name) { - uint8_t fname[11]; - if (to_fat_name(name, fname)) - return 0; - struct directory_entry *ptr = buffer; - uint16_t dir_current = dir_start; - read_sectors(buffer_from = dir_current, 1, buffer); - while (*(uint8_t *)ptr) { - if (check_fat_names(ptr->name, fname)) - return ptr; - if (++ptr == buffer + 16) { - read_sectors(buffer_from = ++dir_current, 1, buffer); - ptr = buffer; +drive_file_id_t fat_get_file(struct drive *d, char *path) { + cur_drive = d; + cur_id = d->drive_id; + for (drive_file_id_t n = 1; n != MAX_OPEN_FILES_PER_DRIVE + 1; ++n) + if (!*(uint8_t *)(&FN(d->drive_id, n))) { + panic("TODO: open path at FN(id, n)"); + return n; } - }; - return 0; + panic("Maximum number of files open reached for FAT drive."); } -bool load_subdir(uint8_t *name) { - struct directory_entry *e = load_subentry(name); - if (!e) - return true; - dir_start = CTOS(e->first_cluster); - return false; +void fat_free_file(struct drive *d, drive_file_id_t fid) { + *(uint8_t *)(&FN(d->drive_id, fid)) = 0; } -struct directory_entry *load_entry(uint8_t *path) { - load_root(); - for (uint8_t *ptr = path; *ptr; ++ptr) - if (*ptr == '/') { - *ptr = 0; - if (load_subdir(path)) - return 0; - path = ptr + 1; - } - return load_subentry(path); +void fat_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) { + cur_drive = d; + cur_id = d->drive_id; + uint16_t c = FN(d->drive_id, fid).first_cluster; + for (uint32_t i = 0; i < sector; ++i) + c = next_cluster(c); + load_cluster(c, at); } -bool get_entry(uint8_t *path, struct directory_entry *at) { - struct directory_entry *e = load_entry(path); - if (!e) - return true; - *at = *e; - return false; +uint32_t fat_get_free_sectors(struct drive *d) { + panic("TODO: get free sectors of drive"); } -bool update_entry(uint8_t *path, struct directory_entry *value) { - struct directory_entry *e = load_entry(path); - if (!e) - return true; - *e = *value; - write_sectors(buffer_from, 1, buffer); - return false; +void init_fat() { + next_fi = allocate_pages(1); } -bool create_entry(uint8_t *dir_path, struct directory_entry *value) { - fs_handle h = fs_open(dir_path); - struct directory_entry *check; - while (fs_read(h, 32, check)) - if (check_fat_names(check->name, value->name)) { - fs_close(h); - return true; - } - fs_write(h, 32, value); - fs_close(h); - return false; +bool try_fat_init_drive(struct drive *d) { + if (next_id >= MAX_FAT_DRIVES) + panic("Maximum number of FAT drives reached."); + + if (!d->read_sectors(d, 0, 1, fat_driver_buffer)) + return false; + memcpy(next_fi, fat_driver_buffer + 3, sizeof(struct fat_info)); + uint32_t *fs_type_32 = (uint32_t *)next_fi->fs_type; + if ((fs_type_32[0] != ('F' + 'A' * 256 + 'T' + 65536 + '1' * 16777216)) || + (fs_type_32[1] != ('6' + ' ' * 256 + ' ' + 65536 + ' ' * 16777216))) + return false; + + d->fs_type = "FAT16"; + d->get_file = &fat_get_file; + d->free_file = &fat_free_file; + d->load_sector = &fat_load_sector; + d->get_free_sectors = &fat_get_free_sectors; + + d->fs_id = next_id; + infos[next_id].fi = next_fi; + infos[next_id].fat = allocate_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1); + for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i) + *(uint8_t *)&FN(next_id, i) = 0; + + d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat); + + alloc_next_fi(); + ++next_id; + return true; } \ No newline at end of file diff --git a/src/kernel/fat.h b/src/kernel/fat.h index 73eaaae..d9db906 100644 --- a/src/kernel/fat.h +++ b/src/kernel/fat.h @@ -1,61 +1,12 @@ +#ifndef FAT_H +#define FAT_H + #include #include +#include "drive.h" -#define FAT_INFO ((struct fat_info *)0x7c03) - -struct fat_info { - uint8_t oem[8]; - uint16_t bytes_per_sector;//Assumed to be 512 - uint8_t sectors_per_cluster;//Assumed to be 1 - uint16_t reserved_sectors; - uint8_t fats;//Assumed to be 1 - uint16_t root_entries; - uint16_t sectors;//Assumed not to be 0 - uint8_t media_type; - uint16_t sectors_per_fat; - uint16_t sectors_per_track; - uint16_t heads; - uint32_t hidden_sectors; - uint32_t sectors_long; - uint8_t drive_number; - uint8_t reserved; - uint8_t ext_boot_marker; - uint32_t volume_id; - uint8_t label[11]; - uint8_t fs_type[8]; -} __attribute__ ((packed)); - -enum { - FA_READ_ONLY = 0x01, - FA_HIDDEN = 0x02, - FA_SYSTEM = 0x04, - FA_LABEL = 0x08, - FA_DIRECTORY = 0x10, - FA_ARCHIVE = 0x20, - - FA_LFN = 0x0f -}; - -struct directory_entry { - uint8_t name[11]; - uint8_t attrib; - uint8_t name_case; - uint8_t created_decimal; - uint16_t created_time; - uint16_t created_date; - uint16_t accessed_date; - uint16_t ignore; - uint16_t modified_time; - uint16_t modified_date; - uint16_t first_cluster; - uint32_t length; -} __attribute__ ((packed)); - -#define FAT ((uint16_t *)0x00020000) -void load_fat(); +void init_fat(); -#define CTOS(c) (FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat + (FAT_INFO->root_entries >> 4) + (c) - 2) +bool try_fat_init_drive(struct drive *d); -bool get_entry(uint8_t *path, struct directory_entry *at); -bool update_entry(uint8_t *path, struct directory_entry *value); -bool create_entry(uint8_t *path, struct directory_entry *value); \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/kernel/fs.c b/src/kernel/fs.c deleted file mode 100644 index 0d51c22..0000000 --- a/src/kernel/fs.c +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include "fs.h" -#include "ata.h" -#include "fat.h" -#include -#include "panic.h" -#include "util.h" - -#define MAX_HANDLES 32 -#define FILE_BUFFER(h) ((void *)(0x0002be00 + (h << 9))) -#define HANDLE(h) ((handles - 1)[h]) -#define HEAD(h) (FILE_BUFFER(h) + HANDLE(h).seek % 512) - -enum { - FH_DIRTY = 0x01, - FH_NO_WRITE = 0x02, - FH_NO_EXPAND = 0x04, - FH_ROOT = 0x08 -}; - -struct handle_info { - uint16_t first_cluster; - uint16_t loaded_cluster; - uint32_t seek; - uint32_t length; - uint8_t flags; -}; - -struct handle_info handles[MAX_HANDLES]; - -void clear_fs_handles() { - struct handle_info *f = handles; - while (f < handles + MAX_HANDLES) - (f++)->first_cluster = 0; -} - -fs_handle next_handle() { - fs_handle r = 0; - while (HANDLE(++r).first_cluster) - if (r == MAX_HANDLES) - return 0; - return r; -} - -void write_buffer(fs_handle handle) { - HANDLE(handle).flags &= ~FH_DIRTY; - if (HANDLE(handle).flags & FH_ROOT) - write_sectors(HANDLE(handle).loaded_cluster, 1, FILE_BUFFER(handle)); - else - write_sectors(CTOS(HANDLE(handle).loaded_cluster), 1, FILE_BUFFER(handle)); -} - -void read_buffer(fs_handle handle) { - if (HANDLE(handle).flags & FH_DIRTY) - write_buffer(handle); - uint16_t s = HANDLE(handle).seek >> 9; - if (HANDLE(handle).flags & FH_ROOT) { - HANDLE(handle).loaded_cluster = HANDLE(handle).first_cluster + s; - read_sectors(HANDLE(handle).first_cluster + s, 1, FILE_BUFFER(handle)); - } - else { - uint16_t c = HANDLE(handle).first_cluster; - while (s--) - c = FAT[c]; - HANDLE(handle).loaded_cluster = c; - read_sectors(CTOS(c), 1, FILE_BUFFER(handle)); - } -} - -fs_handle fs_open(uint8_t *path) { - fs_handle next = next_handle(); - if (!next) - return 0; - struct directory_entry e; - if (get_entry(path, &e)) - return 0; - HANDLE(next).first_cluster = e.first_cluster; - HANDLE(next).seek = 0; - HANDLE(next).length = e.length; - HANDLE(next).flags = (e.attrib & FA_READ_ONLY ? FH_NO_WRITE : 0) | - (e.attrib & FA_SYSTEM ? FH_NO_EXPAND : 0); - read_buffer(next); - return next; -} - -fs_handle fs_open_root() { - fs_handle next = next_handle(); - if (!next) - return 0; - HANDLE(next).first_cluster = FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat; - HANDLE(next).seek = 0; - HANDLE(next).length = FAT_INFO->root_entries * 32; - HANDLE(next).flags = FH_NO_EXPAND | FH_ROOT; - read_buffer(next); - return next; -} - -int32_t fs_seek(fs_handle handle, int32_t by) { - uint32_t old = HANDLE(handle).seek; - uint32_t to = -by > old ? 0 : old + by > HANDLE(handle).length ? HANDLE(handle).length : old + by; - HANDLE(handle).seek = to; - if ((to ^ old) & 0xfe00) - read_buffer(handle); - return to - old; -} - -uint32_t fs_read(fs_handle handle, uint32_t max, void *buffer) { - max = HANDLE(handle).seek + max > HANDLE(handle).length ? HANDLE(handle).length - HANDLE(handle).seek : max; - uint32_t left = max, eos = 512 - (HANDLE(handle).seek & 0x1ff); - if (left < eos) { - memcpy(buffer, FILE_BUFFER(handle) + (HANDLE(handle).seek & 0x1ff), left); - HANDLE(handle).seek += left; - return max; - } - memcpy(buffer, FILE_BUFFER(handle) + (HANDLE(handle).seek & 0x1ff), eos); - left -= eos; - buffer += eos; - HANDLE(handle).seek += eos; - while (left >= 512) { - read_buffer(handle); - memcpy(buffer, FILE_BUFFER(handle), 512); - left -= 512; - buffer += 512; - HANDLE(handle).seek += 512; - } - if (left) { - read_buffer(handle); - memcpy(buffer, FILE_BUFFER(handle), left); - HANDLE(handle).seek += left; - } - return max; -} - -uint32_t fs_write(fs_handle handle, uint32_t max, void *buffer) { - if (HANDLE(handle).flags & FH_NO_WRITE) - return 0; - panic("Not implemented (fs_write)."); -} - -void fs_close(fs_handle handle) { - if (HANDLE(handle).flags & FH_DIRTY) - write_buffer(handle); - HANDLE(handle).first_cluster = 0; -} \ No newline at end of file diff --git a/src/kernel/fs.h b/src/kernel/fs.h deleted file mode 100644 index e2b14c0..0000000 --- a/src/kernel/fs.h +++ /dev/null @@ -1,11 +0,0 @@ -#include - -void clear_fs_handles(); - -typedef uint8_t fs_handle; -fs_handle fs_open(uint8_t *path); -fs_handle fs_open_root(); -int32_t fs_seek(fs_handle handle, int32_t by); -uint32_t fs_read(fs_handle handle, uint32_t max, void *buffer); -uint32_t fs_write(fs_handle handle, uint32_t max, void *buffer); -void fs_close(fs_handle handle); \ No newline at end of file diff --git a/src/kernel/ide.c b/src/kernel/ide.c new file mode 100644 index 0000000..a2d3895 --- /dev/null +++ b/src/kernel/ide.c @@ -0,0 +1,189 @@ +#include +#include +#include "panic.h" +#include "util.h" +#include "drive.h" +#include "pci.h" +#include "ata.h" + +#define MAX_IDE_DRIVES 8 + +struct ide_drive_info { + uint16_t base_port; + uint16_t control_port; + bool slave; +}; + +struct ide_drive_info ide_drives[MAX_IDE_DRIVES]; +drive_id_t n_ide_drives = 0; + +void spin_delay() { + for (uint32_t i = -1; i; --i) + ; +} + +//return true on error condition +bool poll(struct ide_drive_info *info) { + spin_delay(); + + uint8_t status; + + while ((status = inb(info->base_port | ATA_REG_STATUS)) & ATA_STATUS_BUSY) + ; + + return (status & (ATA_STATUS_ERROR | ATA_STATUS_DRIVE_FAULT)) || !(status & ATA_STATUS_DRIVE_READY); +} + +uint8_t ide_ata_rs(struct drive *d, uint32_t start, uint32_t count, void *buffer) { + if (start & 0xf0000000) + panic("IDE ATA driver only supports LBA28 addressing currently."); + + struct ide_drive_info *info = ide_drives + d->drive_id; + + if (start + count > d->n_sectors) + count = d->n_sectors - start; + + if (count & 0xffffff00) + panic("IDE ATA driver only supports reading up to 128k at a time currently."); + + uint32_t lba = start & 0x00ffffff; + + uint32_t spin = -1; + while (inb(info->base_port | ATA_REG_STATUS) & ATA_STATUS_BUSY) + if (!spin--) + panic("Spun out in IDE ATA reading"); + + outb(info->base_port | ATA_REG_SELECT, (info->slave ? 0xf0 : 0xe0) | (start >> 24)); + outb(info->base_port | ATA_REG_COUNT_LOW, count); + outb(info->base_port | ATA_REG_LBA0, lba); + outb(info->base_port | ATA_REG_LBA1, lba >> 8); + outb(info->base_port | ATA_REG_LBA2, lba >> 16); + + uint16_t *buffer_16 = buffer; + + for (uint16_t i = 0; i < count; ++i) { + if (poll(info)) + return i; + for (uint16_t j = 0; j < 256; ++j) + *buffer_16++ = inw(info->base_port + ATA_REG_DATA); + } + + return count; +} + +uint8_t ide_ata_ws(struct drive *d, uint32_t start, uint32_t count, void *buffer) { + panic("IDE ATA writing not implemented yet"); + return 0; +} + +uint8_t ide_atapi_rs(struct drive *d, uint32_t start, uint32_t count, void *buffer) { + //panic("IDE ATAPI reading not implemented yet"); + return 0; +} + +uint8_t ide_atapi_ws(struct drive *d, uint32_t start, uint32_t count, void *buffer) { + panic("IDE ATAPI writing not implemented yet"); + return 0; +} + +struct id_space { + uint16_t device_type;//0 + uint8_t skip1[98 - 2]; + uint16_t capabilities;//98 + uint8_t skip2[120 - (98 + 2)]; + uint32_t max_lba;//120 + uint8_t skip3[164 - (120 + 4)]; + uint32_t command_sets;//164 + uint8_t skip4[200 - (164 + 4)]; + uint32_t max_lba_ext;//200 + uint8_t skip5[512 - (200 + 4)]; +} __attribute__ ((__packed__)); + +void read_id_space(uint16_t base_port, struct id_space *to) { + uint32_t *to_32 = (uint32_t *)to; + for (uint8_t i = 0; i < 128; ++i) + *(to_32++) = ind(base_port | ATA_REG_DATA); +} + +void test_drive(uint16_t base_port, uint16_t control_port, bool slave) { + outb(base_port | ATA_REG_SELECT, slave ? ATA_SLAVE_SELECT : ATA_MASTER_SELECT); + spin_delay(); + + outb(base_port | ATA_REG_CMD, ATA_CMD_ID); + spin_delay(); + + if (!inb(base_port | ATA_REG_STATUS)) + return; + + if (n_ide_drives == MAX_IDE_DRIVES) + panic("Maximum IDE drives reached"); + + outb(base_port | ATA_REG_CONTROL, ATA_CONTROL_NO_IRQS); + + struct ide_drive_info *this_drive = ide_drives + n_ide_drives; + this_drive->base_port = base_port; + this_drive->control_port = control_port; + this_drive->slave = slave; + + struct drive data; + data.drive_id = n_ide_drives; + + uint32_t spin_out = -1; + while (1) {//wait for identify to complete + uint8_t status = inb(base_port | ATA_REG_STATUS); + if (status & ATA_STATUS_ERROR) { + uint16_t type = inb(base_port | ATA_REG_LBA1) + + (inb(base_port | ATA_REG_LBA2) << 8); + + //These two are listed on OSDev Wiki + // as being ATAPI device types. + if ((type != 0xeb14) && (type != 0x9669)) + return; + + outb(base_port | ATA_REG_CMD, ATAPI_CMD_ID); + + data.read_sectors = &ide_atapi_rs; + data.write_sectors = &ide_atapi_ws; + data.drive_type = "IDE ATAPI"; + break; + } + if (!(status & ATA_STATUS_BUSY) && (status & ATA_STATUS_DATA_READY)) { + data.read_sectors = &ide_ata_rs; + data.write_sectors = &ide_ata_ws; + data.drive_type = "IDE ATA"; + break; + } + if (!spin_out--) + panic("IDE ATA identify won't complete"); + } + + struct id_space id; + read_id_space(base_port, &id); + + if (!(id.capabilities & ATA_CAP_LBA)) + //TODO: CHS compability driver? + return; + data.n_sectors = (id.command_sets & ATA_SET_EXT) ? id.max_lba_ext : id.max_lba; + + commit_drive(data); + ++n_ide_drives; +} + +void init_ide() { + uint16_t check_from = 0; + struct pci_device *device; + //double parentheses to let gcc know this assignment isn't a mistake + while ((device = find_pci_device_from_class_and_subclass(PCI_MASS_STORAGE, PCI_IDE, check_from, &check_from))) { + ++check_from; + + uint16_t primary_base_port = device->bar0 <= 1 ? 0x01f0 : device->bar0; + uint16_t primary_control_port = device->bar1 <= 1 ? 0x03f6 : device->bar1; + uint16_t secondary_base_port = device->bar2 <= 1 ? 0x0170 : device->bar2; + uint16_t secondary_control_port = device->bar3 <= 1 ? 0x0376 : device->bar3; + + test_drive(primary_base_port, primary_control_port, false); + test_drive(primary_base_port, primary_control_port, true); + test_drive(secondary_base_port, secondary_control_port, false); + test_drive(secondary_base_port, secondary_control_port, true); + } +} \ No newline at end of file diff --git a/src/kernel/ide.h b/src/kernel/ide.h new file mode 100644 index 0000000..44b02ec --- /dev/null +++ b/src/kernel/ide.h @@ -0,0 +1,12 @@ +#ifndef IDE_H +#define IDE_H + +#include +#include "drive.h" + +void init_ide(); + +uint8_t ide_read_sectors(drive_id_t id, uint32_t start, uint32_t count, void *buffer); +uint8_t ide_write_sectors(drive_id_t id, uint32_t start, uint32_t count, void *buffer); + +#endif \ No newline at end of file diff --git a/src/kernel/link.ld b/src/kernel/link.ld deleted file mode 100644 index 7c7b28d..0000000 --- a/src/kernel/link.ld +++ /dev/null @@ -1,17 +0,0 @@ -OUTPUT_FORMAT(elf32-i386) -OUTPUT_ARCH(i386) - -SECTIONS { - . = 0x00030000; - .entry : { - */main.o(.text) - } - .bin : { - *(.text) - *(.rodata) - *(.data) - } - .bss : { - *(.bss) - } -} diff --git a/src/kernel/main.c b/src/kernel/main.c index 92e778c..e5c0013 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -1,72 +1,113 @@ #include #include "vga.h" #include "fat.h" -#include "fs.h" -#include "ata.h" +#include "ide.h" #include "panic.h" #include "serial.h" #include "util.h" +#include "mem.h" +#include "pci.h" +#include "boot.h" +#include "vesa.h" -uint8_t nbuf[11]; +char nbuf[11]; + +#define SOTL(field) field = (void *)((*((uint16_t *)(&field) + 1) << 16) + *(uint16_t *)(&field)); + +__attribute__ ((noreturn)) void main() { + SOTL(VESA_INFO->oem) + SOTL(VESA_INFO->modes) + SOTL(VESA_INFO->vendor) + SOTL(VESA_INFO->pname) + SOTL(VESA_INFO->prev) + + init_mmap(); + + init_vesa(); + + init_serial(); -void main() { vga_blank(); - vga_printsz("Initializing drivers..."); - sinit(); - vga_printsz("\n Serial ready."); - load_fat(); - clear_fs_handles(); - vga_printsz("\n File system ready.\n\nDisk info:\n Disk label: "); - vga_printsn(FAT_INFO->label, 11); - vga_printsz("\n Disk size: "); - u16_dec(FAT_INFO->sectors >> 1, nbuf); - vga_printsz(nbuf); - vga_printsz("k\n FAT size: "); - u16_dec(FAT_INFO->sectors_per_fat >> 1, nbuf); - vga_printsz(nbuf); - vga_printsz("k\n Root size: "); - u16_dec(FAT_INFO->root_entries >> 5, nbuf); + vga_printsz("Portland v0.0.11\n\n"); + + //list vesa modes? + + pci_init(); + + u16_dec(n_pci_devices, nbuf); vga_printsz(nbuf); - vga_printsz("k\n\nRoot directory:"); - fs_handle root = fs_open_root(); - struct directory_entry e; - while(1) { - fs_read(root, 32, &e); - if (!e.name[0]) - break; - if (e.attrib == FA_LFN) - continue; - uint8_t *p = (uint8_t *)&e; - nbuf[3] = 0; - vga_printsz("\n "); - vga_printsn((uint8_t *)&e.name, 11); - vga_printsz(" | 0x"); - u8_hex(e.attrib, nbuf); + vga_printsz(" PCI device(s) found:\n"); + + for (uint16_t n = 0; n < n_pci_devices; ++n) { + struct pci_device *pd = nth_pci_device(n); + + u16_hex(pd->number, nbuf); + vga_printsz(" "); + vga_printsz(nbuf); + vga_printsz(": "); + + u16_hex(pd->id_vendor, nbuf); + nbuf[4] = '.'; + u16_hex(pd->id_device, nbuf + 5); vga_printsz(nbuf); - vga_printch(' '); - vga_printch(e.attrib & FA_READ_ONLY ? 'R' : '_'); - vga_printch(e.attrib & FA_HIDDEN ? 'H' : '_'); - vga_printch(e.attrib & FA_SYSTEM ? 'S' : '_'); - vga_printch(e.attrib & FA_LABEL ? 'L' : '_'); - vga_printch(e.attrib & FA_DIRECTORY ? 'D' : '_'); - vga_printch(e.attrib & FA_ARCHIVE ? 'A' : '_'); - vga_printsz(" | "); - u32_dec(e.length, nbuf); + + u8_hex(pd->class, nbuf); + nbuf[2] = '.'; + u8_hex(pd->subclass, nbuf + 3); + nbuf[5] = '.'; + u8_hex(pd->iface, nbuf + 6); + vga_printsz(" ("); vga_printsz(nbuf); + vga_printsz(")\n"); } - fs_close(root); - if (root = fs_open("BLEH.TXT")) { - vga_printsz("\n\nContents of BLEH.TXT:"); - uint8_t l; - uint8_t line[82]; - line[0] = '\n'; - line[1] = ' '; - line[2] = ' '; - while (l = fs_read(root, 78, line + 3)) { - line[l + 3] = 0; - vga_printsz(line); - } - fs_close(root); + + vga_printch('\n'); + + init_fat(); + + init_ide(); + + u8_dec(n_drives, nbuf); + vga_printsz(nbuf); + vga_printsz(" drive(s) found:\n"); + + for (uint8_t n = 0; n < n_drives; ++n) { + struct drive *d = drives + n; + + u8_dec(n, nbuf); + vga_printsz(" sd"); + vga_printsz(nbuf); + vga_printsz(" ("); + vga_printsz(d->drive_type); + vga_printsz("): "); + + vga_printsz(d->fs_type); + vga_printsz(", "); + + u32_dec(d->n_sectors / 2, nbuf); + vga_printsz(nbuf); + if (d->n_sectors % 2) + vga_printsz(".5"); + vga_printsz("k, "); + + uint32_t free_sectors = d->get_free_sectors(d); + + u32_dec(free_sectors / 2, nbuf); + vga_printsz(nbuf); + if (d->n_sectors % 2) + vga_printsz(".5"); + vga_printsz("k free.\n"); } - halt(); + + vga_printch('\n'); + + u32_dec(pages_left * 4, nbuf); + vga_printsz(nbuf); + vga_printsz("k dynamic memory free.\n\n"); + + vga_printsz("Loading init process."); + + vga_printsz("\n\nTODO: load and switch to init process"); + while (1) + asm ("hlt"); } \ No newline at end of file diff --git a/src/kernel/mem.c b/src/kernel/mem.c new file mode 100644 index 0000000..2e8173d --- /dev/null +++ b/src/kernel/mem.c @@ -0,0 +1,63 @@ +#include +#include +#include "panic.h" + +#define DYNAMIC_START (0x10000000) +#define DYNAMIC_END (DYNAMIC_START + 65536 * 4096) +#define PAGE_TO_ADDR(n) ((void *)(DYNAMIC_START | ((n) << 12))) +#define ADDR_TO_PAGE(n) (((uint32_t)(n) & ~DYNAMIC_START) >> 12) + +#define MMAP_START (0x00010000) +#define PAGE_USED(n) ((*(uint8_t *)(MMAP_START + (n >> 3)) >> (n & 7)) & 1) +#define CLEAR_PAGE(n) *(uint8_t *)(MMAP_START + (n >> 3)) &= ~(1 << (n & 7)) +#define SET_PAGE(n) *(uint8_t *)(MMAP_START + (n >> 3)) |= 1 << (n & 7) + +extern const void kernel_bss_end; + +uint16_t pages_left; + +void init_mmap() { + volatile uint8_t *end_ptr = (uint8_t *)(DYNAMIC_END - 1); + uint8_t end_val = *end_ptr; + *end_ptr = (uint8_t)~end_val; + if (*end_ptr != (uint8_t)~end_val) + panic("Not enough memory. Must have at least 512MiB."); + + for (uint32_t *m = (uint32_t *)MMAP_START; m < (uint32_t *)(MMAP_START + (65536 / 8)); ++m) + *m = 0; + + uint16_t kernel_bss_pages = (((uint32_t)&kernel_bss_end - DYNAMIC_START - 1) >> 12) + 1; + for (uint16_t i = 0; i < kernel_bss_pages; ++i) + SET_PAGE(i); + + pages_left = 65536 - kernel_bss_pages; +} + +//very inneficient algorithm, just returns first hole big enough. +//a smarter algorithm might pick the smallest one available, +//and go by bytes (or dwords) instead of bits where possible. +void *allocate_pages(uint16_t n) { + uint16_t run = 0; + + for (uint32_t page = 0; page < 65536; ++page) { + if (PAGE_USED(page)) + run = 0; + else if (++run == n) { + uint16_t start = page - run + 1; + for (uint32_t i = start; i <= page; ++i) + SET_PAGE(i); + pages_left -= n; + return PAGE_TO_ADDR(start); + } + } + + return 0; +} + +//in the future, change this to go by bytes or dwords instead of bits. +void free_pages(void *ptr, uint16_t n) { + uint16_t page = ADDR_TO_PAGE(ptr); + for (uint32_t i = page; i < page + n; ++i) + CLEAR_PAGE(i); + pages_left += n; +} \ No newline at end of file diff --git a/src/kernel/mem.h b/src/kernel/mem.h new file mode 100644 index 0000000..913f70b --- /dev/null +++ b/src/kernel/mem.h @@ -0,0 +1,13 @@ +#ifndef MEM_H +#define MEM_H + +#include + +extern uint16_t pages_left; + +void init_mmap(); + +void *allocate_pages(uint16_t n); +void free_pages(void *ptr, uint16_t n); + +#endif \ No newline at end of file diff --git a/src/kernel/panic.c b/src/kernel/panic.c index a463a2a..93944ff 100644 --- a/src/kernel/panic.c +++ b/src/kernel/panic.c @@ -2,31 +2,14 @@ #include "vga.h" #include "serial.h" #include "util.h" +#include "panic.h" -void halt() { - vga_printsz("\n\nHalting..."); - while (1) - asm volatile ("hlt"); -} - -void panic(uint8_t *message) { - uint32_t frame; - asm ( - "movl %%ebp, %0" - : "=r" (frame)); +void panic(char *message) { vga_set_color(0x4f); vga_blank(); vga_printsz("Kernel panic: "); vga_printsz(message); - vga_printsz("\n\nStack trace:"); - uint8_t stb[6]; - while (1) { - uint32_t ip = *((uint32_t *)frame + 1); - if (!ip) - halt(); - vga_printsz("\n 0x"); - u16_hex(ip - 0x30000 - 5, stb);//assumes would return to just after a call instruction - vga_printsz(stb); - frame = *(uint32_t *)frame; - } + vga_printsz("\nHalting."); + while (1) + asm volatile ("hlt"); } \ No newline at end of file diff --git a/src/kernel/panic.h b/src/kernel/panic.h index 8972814..7d2e9df 100644 --- a/src/kernel/panic.h +++ b/src/kernel/panic.h @@ -1,4 +1,8 @@ +#ifndef PANIC_H +#define PANIC_H + #include -void panic(uint8_t *message) __attribute__ ((noreturn)); -void halt() __attribute__ ((noreturn)); \ No newline at end of file +void panic(char *message) __attribute__ ((noreturn)); + +#endif \ No newline at end of file diff --git a/src/kernel/pci.c b/src/kernel/pci.c new file mode 100644 index 0000000..fe96c4c --- /dev/null +++ b/src/kernel/pci.c @@ -0,0 +1,77 @@ +#include "boot.h" +#include "mem.h" +#include "util.h" +#include "pci.h" +#include "panic.h" + +enum { + PCP_SELECT = 0x0cf8, + PCP_READ = 0x0cfc +}; + +uint16_t n_pci_devices = 0; +struct pci_device *pci_device_pages[256]; + +#define PCI_DEVICES_PER_PAGE (4096 / sizeof(struct pci_device)) + +struct pci_device *nth_pci_device(uint16_t n) { + return pci_device_pages[n / PCI_DEVICES_PER_PAGE] + (n % PCI_DEVICES_PER_PAGE); +} + +struct pci_device *find_pci_device_from_class_and_subclass(uint8_t class, uint8_t subclass, uint16_t start, uint16_t *index) { + for (uint16_t n = start; n < n_pci_devices; ++n) { + struct pci_device *p = nth_pci_device(n); + if ((p->class == class) && (p->subclass == subclass)) { + *index = n; + return p; + } + } + return 0; +} + +struct pci_device *next_pci_device() { + if (!(n_pci_devices % PCI_DEVICES_PER_PAGE)) + pci_device_pages[n_pci_devices / PCI_DEVICES_PER_PAGE] = allocate_pages(1); + return nth_pci_device(n_pci_devices++); +} + +static inline uint32_t pci_read_config(uint16_t number, uint8_t reg) { + uint32_t cspace_addr = 0x80000000 | (number << 8) | (reg << 2); + outd(PCP_SELECT, cspace_addr); + + return ind(PCP_READ); +} + +void pci_device_check(uint16_t number) { + uint32_t id = pci_read_config(number, 0); + if ((id & 0xffff) == 0xffff) + return; + + struct pci_device *next_device = next_pci_device(); + + next_device->number = number; + + next_device->id_vendor = id; + next_device->id_device = id >> 16; + + uint32_t class = pci_read_config(number, 2); + + next_device->class = class >> 24; + next_device->subclass = class >> 16; + next_device->iface = class >> 8; + + next_device->bar0 = pci_read_config(number, 4); + next_device->bar1 = pci_read_config(number, 5); + next_device->bar2 = pci_read_config(number, 6); + next_device->bar3 = pci_read_config(number, 7); +} + +void pci_init() { + if (!(BOOT_INFO->support_flags & BIS_PCI)) + panic("No PCI support detected."); + if (!(BOOT_INFO->pci_hw_char & PHC_CS_M1)) + panic("No PCI Mechanism 1 support"); + + for (uint32_t number = 0; number < (BOOT_INFO->last_pci_bus + 1) * 256; ++number) + pci_device_check(number); +} \ No newline at end of file diff --git a/src/kernel/pci.h b/src/kernel/pci.h new file mode 100644 index 0000000..1ab5936 --- /dev/null +++ b/src/kernel/pci.h @@ -0,0 +1,38 @@ +#ifndef PCI_H +#define PCI_H + +#include + +enum { + PCI_MASS_STORAGE = 0x01 +}; + +enum { + PCI_IDE = 0x01 +}; + +struct pci_device { + uint16_t number; + + uint16_t id_vendor; + uint16_t id_device; + + uint8_t class; + uint8_t subclass; + uint8_t iface; + + uint32_t bar0; + uint32_t bar1; + uint32_t bar2; + uint32_t bar3; + //etc +}; + +extern uint16_t n_pci_devices; +struct pci_device *nth_pci_device(uint16_t n); + +struct pci_device *find_pci_device_from_class_and_subclass(uint8_t class, uint8_t subclass, uint16_t start, uint16_t *index); + +void pci_init(); + +#endif \ No newline at end of file diff --git a/src/kernel/plef.c b/src/kernel/plef.c new file mode 100644 index 0000000..2cba843 --- /dev/null +++ b/src/kernel/plef.c @@ -0,0 +1,33 @@ +#include +#include +#include "plef.h" +#include "drive.h" +#include "util.h" +#include "task.h" + +#define PLEF_MAGIC 0xb9ba4c50 + +task_handle plef_run(struct drive *d, char *path) { + drive_file_id_t h = d->get_file(d, path); + if (!h) + return 0; + + uint8_t start[512]; + d->load_sector(d, h, 0, start); + + struct plef_header head = *(struct plef_header *)start; + if ((head.magic != PLEF_MAGIC) || (head.version_high)) { + d->free_file(d, h); + return 0; + } + + uint32_t payload_addr; + segment_id cs = new_segment(true, head.payload_length + head.bss_length, &payload_addr); + segment_id ds = mirror_segment(false, cs); + + fmcpy((void *)payload_addr, d, h, head.payload_offset, head.payload_length); + + d->free_file(d, h); + + return new_task(cs, ds, head.entry_point, head.payload_length + head.bss_length); +} \ No newline at end of file diff --git a/src/kernel/plef.h b/src/kernel/plef.h new file mode 100644 index 0000000..29100ee --- /dev/null +++ b/src/kernel/plef.h @@ -0,0 +1,22 @@ +#ifndef PLEF_H +#define PLEF_H + +#include +#include +#include "drive.h" + +typedef uint8_t task_handle; + +struct plef_header { + uint32_t magic; + uint16_t version_low; + uint16_t version_high; + uint32_t payload_offset; + uint32_t payload_length; + uint32_t bss_length; + uint32_t entry_point; +} __attribute__ ((packed)); + +task_handle plef_run(struct drive *d, char *path); + +#endif \ No newline at end of file diff --git a/src/kernel/serial.c b/src/kernel/serial.c index b88c7ec..0f7abe6 100644 --- a/src/kernel/serial.c +++ b/src/kernel/serial.c @@ -54,7 +54,7 @@ bool serr() { return error; } -void sinit() { +void init_serial() { error = false; outb(CP_1 | CP_INT, 0); outb(CP_1 | CP_LINE, CL_BAUD); @@ -64,7 +64,7 @@ void sinit() { outb(CP_1 | CP_FIFO, 0xc7);//? } -void sout(uint8_t b) { +void sout(char b) { if (error) return; uint16_t s = SERIAL_SPIN_LIMIT; @@ -73,28 +73,28 @@ void sout(uint8_t b) { error = true; return; } - outb(CP_1 | CP_DATA, b); + outb(CP_1 | CP_DATA, (uint8_t)b); } -void soutsz(uint8_t *s) { +void soutsz(char *s) { while (*s) sout(*(s++)); } -void soutsn(uint8_t *s, uint8_t n) { +void soutsn(char *s, uint8_t n) { while (n--) sout(*(s++)); } -uint8_t sin() { +char sin() { if (error) return 0; while (!(inb(CP_1 | CP_LINE_S) & CLS_READ)) ;//spin - return inb(CP_1 | CP_DATA); + return (char)inb(CP_1 | CP_DATA); } -void sinsn(uint8_t *s, uint8_t n) { +void sinsn(char *s, uint8_t n) { while (n--) *(s++) = sin(); } \ No newline at end of file diff --git a/src/kernel/serial.h b/src/kernel/serial.h index f0465d0..bb12edb 100644 --- a/src/kernel/serial.h +++ b/src/kernel/serial.h @@ -1,10 +1,15 @@ +#ifndef SERIAL_H +#define SERIAL_H + #include #include bool serr(); -void sinit(); -void sout(uint8_t b); -void soutsz(uint8_t *s); -void soutsn(uint8_t *s, uint8_t n); -uint8_t sin(); -void sinsn(uint8_t *s, uint8_t n); \ No newline at end of file +void init_serial(); +void sout(char b); +void soutsz(char *s); +void soutsn(char *s, uint8_t n); +char sin(); +void sinsn(char *s, uint8_t n); + +#endif \ No newline at end of file diff --git a/src/kernel/task.c b/src/kernel/task.c new file mode 100644 index 0000000..c08a195 --- /dev/null +++ b/src/kernel/task.c @@ -0,0 +1,14 @@ +#include "task.h" +#include "panic.h" + +segment_id new_segment(bool is_code, uint32_t length, uint32_t *location_out) { + panic("TODO: make new segment"); +} + +segment_id mirror_segment(bool is_code, segment_id other) { + panic("TODO: make new segment with same base and limit"); +} + +task_handle new_task(segment_id cs, segment_id ds, uint32_t eip, uint32_t esp) { + panic("TODO: add task to scheduler"); +} \ No newline at end of file diff --git a/src/kernel/task.h b/src/kernel/task.h new file mode 100644 index 0000000..add668b --- /dev/null +++ b/src/kernel/task.h @@ -0,0 +1,14 @@ +#ifndef TASK_H +#define TASK_H + +#include +#include + +typedef uint8_t segment_id; +typedef uint8_t task_handle; + +segment_id new_segment(bool is_code, uint32_t length, uint32_t *location_out); +segment_id mirror_segment(bool is_code, segment_id other); +task_handle new_task(segment_id cs, segment_id ds, uint32_t eip, uint32_t esp); + +#endif \ No newline at end of file diff --git a/src/kernel/util.asm b/src/kernel/util.asm deleted file mode 100644 index acac17f..0000000 --- a/src/kernel/util.asm +++ /dev/null @@ -1,37 +0,0 @@ -bits 32 - -global outb -global inb -global outw -global inw - -section .text -outb: - ;word [esp + 4] = port - ;byte [esp + 8] = value - mov dx, word [esp + 4] - mov al, byte [esp + 8] - out dx, al - ret - -inb: - ;word [esp + 4] = port - ;al out = value - mov dx, word [esp + 4] - in al, dx - ret - -outw: - ;word [esp + 4] = port - ;word [esp + 8] = value - mov dx, word [esp + 4] - mov ax, word [esp + 8] - out dx, ax - ret - -inw: - ;word [esp + 4] = port - ;ax out = value - mov dx, word [esp + 4] - in ax, dx - ret \ No newline at end of file diff --git a/src/kernel/util.c b/src/kernel/util.c index c7a5035..1531f83 100644 --- a/src/kernel/util.c +++ b/src/kernel/util.c @@ -1,6 +1,7 @@ #include #include "panic.h" #include +#include "drive.h" void memcpy(void *to, void *from, uint32_t n) { uint32_t *tp = to, *fp = from; @@ -13,9 +14,36 @@ void memcpy(void *to, void *from, uint32_t n) { *(tpp++) = *(fpp++); } -void u32_dec(uint32_t n, uint8_t *b) { +void fmcpy(void *to, struct drive *d, drive_file_id_t f, uint32_t from, uint32_t n) { + uint8_t buf[512]; + d->load_sector(d, f, from >> 9, buf); + uint16_t from_low = from & 511; + if (!((from_low + n) & ~511)) { + memcpy(to, buf + from_low, n); + return; + } + + uint32_t i = 512 - from_low; + memcpy(to, buf + from_low, i); + + n -= i; + uint32_t fsi = (from + i) >> 9; + + while (n & ~511) { + d->load_sector(d, f, fsi, buf); + memcpy(to + i, buf, 512); + i += 512; + n -= 512; + ++fsi; + } + + d->load_sector(d, f, fsi, buf); + memcpy(to + i, buf, n); +} + +void u32_dec(uint32_t n, char *b) { if (!n) { - *(uint16_t *)b = '0'; + *(uint16_t *)b = (uint16_t)'0'; return; } bool zero = false; @@ -28,12 +56,12 @@ void u32_dec(uint32_t n, uint8_t *b) { *(b++) = d + '0'; } } - *b = 0; + *b = '\0'; } -void u16_dec(uint16_t n, uint8_t *b) { +void u16_dec(uint16_t n, char *b) { if (!n) { - *(uint16_t *)b = '0'; + *(uint16_t *)b = (uint16_t)'0'; return; } bool zero = false; @@ -46,12 +74,12 @@ void u16_dec(uint16_t n, uint8_t *b) { *(b++) = d + '0'; } } - *b = 0; + *b = '\0'; } -void u8_dec(uint8_t n, uint8_t *b) { +void u8_dec(uint8_t n, char *b) { if (!n) { - *(uint16_t *)b = '0'; + *(uint16_t *)b = (uint16_t)'0'; return; } bool zero = false; @@ -64,42 +92,42 @@ void u8_dec(uint8_t n, uint8_t *b) { *(b++) = d + '0'; } } - *b = 0; + *b = '\0'; } -void u32_hex(uint32_t n, uint8_t *b) { +void u32_hex(uint32_t n, char *b) { uint8_t m = 28; while (1) { uint8_t d = (n >> m) & 0xf; *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d; if (!m) { - *b = 0; + *b = '\0'; return; } m -= 4; } } -void u16_hex(uint16_t n, uint8_t *b) { +void u16_hex(uint16_t n, char *b) { uint8_t m = 12; while (1) { uint8_t d = (n >> m) & 0xf; *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d; if (!m) { - *b = 0; + *b = '\0'; return; } m -= 4; } } -void u8_hex(uint8_t n, uint8_t *b) { +void u8_hex(uint8_t n, char *b) { uint8_t m = 4; while (1) { uint8_t d = (n >> m) & 0xf; *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d; if (!m) { - *b = 0; + *b = '\0'; return; } m -= 4; diff --git a/src/kernel/util.h b/src/kernel/util.h index e02c819..243541c 100644 --- a/src/kernel/util.h +++ b/src/kernel/util.h @@ -1,13 +1,54 @@ +#ifndef UTIL_H +#define UTIL_H + #include +#include "drive.h" + +static inline void outb(uint16_t port, uint8_t value) { + asm ( + "outb %0, %1" + : : "a"(value), "Nd"(port)); +} +static inline uint8_t inb(uint16_t port) { + uint8_t value; + asm volatile ( + "inb %1, %0" + : "=a"(value) : "Nd"(port)); + return value; +} +static inline void outw(uint16_t port, uint16_t value) { + asm ( + "outw %0, %1" + : : "a"(value), "Nd"(port)); +} +static inline uint16_t inw(uint16_t port) { + uint16_t value; + asm volatile ( + "inw %1, %0" + : "=a"(value) : "Nd"(port)); + return value; +} +static inline void outd(uint16_t port, uint32_t value) { + asm ( + "outl %0, %1" + : : "a"(value), "Nd"(port)); +} +static inline uint32_t ind(uint16_t port) { + uint32_t value; + asm volatile ( + "inl %1, %0" + : "=a"(value) : "Nd"(port)); + return value; +} void memcpy(void *to, void *from, uint32_t n); -void outb(uint16_t port, uint8_t value); -uint8_t inb(uint16_t port); -void outw(uint16_t port, uint16_t value); -uint16_t inw(uint16_t port); -void u32_dec(uint32_t n, uint8_t *b); -void u16_dec(uint16_t n, uint8_t *b); -void u8_dec(uint8_t n, uint8_t *b); -void u32_hex(uint32_t n, uint8_t *b); -void u16_hex(uint16_t n, uint8_t *b); -void u8_hex(uint8_t n, uint8_t *b); \ No newline at end of file +void fmcpy(void *to, struct drive *d, drive_file_id_t f, uint32_t from, uint32_t n); + +void u32_dec(uint32_t n, char *b); +void u16_dec(uint16_t n, char *b); +void u8_dec(uint8_t n, char *b); +void u32_hex(uint32_t n, char *b); +void u16_hex(uint16_t n, char *b); +void u8_hex(uint8_t n, char *b); + +#endif \ No newline at end of file diff --git a/src/kernel/vesa.c b/src/kernel/vesa.c new file mode 100644 index 0000000..e781249 --- /dev/null +++ b/src/kernel/vesa.c @@ -0,0 +1,5 @@ +#include "vesa.h" + +void init_vesa() { + +} \ No newline at end of file diff --git a/src/kernel/vesa.h b/src/kernel/vesa.h new file mode 100644 index 0000000..495b593 --- /dev/null +++ b/src/kernel/vesa.h @@ -0,0 +1,24 @@ +#ifndef VESA_H +#define VESA_H + +struct video_mode { + //TODO +}; + +#define VESA_INFO \ + ((struct { \ + uint32_t sig; \ + uint16_t vbe_ver; \ + char *oem; \ + uint32_t capabilities; \ + struct video_mode *modes; \ + uint16_t vram_size_high; \ + uint16_t soft_ver; \ + char *vendor; \ + char *pname; \ + char *prev; \ + } *)0x4200) + +void init_vesa(); + +#endif \ No newline at end of file diff --git a/src/kernel/vga.c b/src/kernel/vga.c index c387b22..788ce6c 100644 --- a/src/kernel/vga.c +++ b/src/kernel/vga.c @@ -33,7 +33,7 @@ void vga_blank() { cursor = VGA_START; } -void vga_printch(uint8_t ch) { +void vga_printch(char ch) { if (ch == '\n') { #ifdef VGA_COM_MIRROR soutsz("\r\n"); @@ -45,17 +45,17 @@ void vga_printch(uint8_t ch) { #ifdef VGA_COM_MIRROR sout(ch); #endif - *(cursor++) = color | ch; + *(cursor++) = color | (uint8_t)ch; if (cursor == VGA_END) vga_scroll(); } -void vga_printsz(uint8_t *sz) { +void vga_printsz(char *sz) { while (*sz) vga_printch(*(sz++)); } -void vga_printsn(uint8_t *sn, uint8_t n) { +void vga_printsn(char *sn, uint8_t n) { while (n--) vga_printch(*(sn++)); } \ No newline at end of file diff --git a/src/kernel/vga.h b/src/kernel/vga.h index 1e041df..1be2131 100644 --- a/src/kernel/vga.h +++ b/src/kernel/vga.h @@ -1,8 +1,13 @@ +#ifndef VGA_H +#define VGA_H + #include void vga_set_color(uint8_t color); void vga_blank(); void vga_scroll(); -void vga_printch(uint8_t ch); -void vga_printsz(uint8_t *sz); -void vga_printsn(uint8_t *sn, uint8_t n); \ No newline at end of file +void vga_printch(char ch); +void vga_printsz(char *sz); +void vga_printsn(char *sn, uint8_t n); + +#endif \ No newline at end of file -- cgit v1.2.3