diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/ata.c | 113 | ||||
-rw-r--r-- | src/kernel/ata.h | 77 | ||||
-rw-r--r-- | src/kernel/boot.h | 26 | ||||
-rw-r--r-- | src/kernel/drive.c | 38 | ||||
-rw-r--r-- | src/kernel/drive.h | 34 | ||||
-rw-r--r-- | src/kernel/elf-link.ld (renamed from src/kernel/link.ld) | 12 | ||||
-rw-r--r-- | src/kernel/fat.c | 271 | ||||
-rw-r--r-- | src/kernel/fat.h | 63 | ||||
-rw-r--r-- | src/kernel/fs.c | 144 | ||||
-rw-r--r-- | src/kernel/fs.h | 11 | ||||
-rw-r--r-- | src/kernel/ide.c | 189 | ||||
-rw-r--r-- | src/kernel/ide.h | 12 | ||||
-rw-r--r-- | src/kernel/main.c | 155 | ||||
-rw-r--r-- | src/kernel/mem.c | 63 | ||||
-rw-r--r-- | src/kernel/mem.h | 13 | ||||
-rw-r--r-- | src/kernel/panic.c | 27 | ||||
-rw-r--r-- | src/kernel/panic.h | 8 | ||||
-rw-r--r-- | src/kernel/pci.c | 77 | ||||
-rw-r--r-- | src/kernel/pci.h | 38 | ||||
-rw-r--r-- | src/kernel/plef.c | 33 | ||||
-rw-r--r-- | src/kernel/plef.h | 22 | ||||
-rw-r--r-- | src/kernel/serial.c | 16 | ||||
-rw-r--r-- | src/kernel/serial.h | 17 | ||||
-rw-r--r-- | src/kernel/task.c | 14 | ||||
-rw-r--r-- | src/kernel/task.h | 14 | ||||
-rw-r--r-- | src/kernel/util.asm | 37 | ||||
-rw-r--r-- | src/kernel/util.c | 58 | ||||
-rw-r--r-- | src/kernel/util.h | 61 | ||||
-rw-r--r-- | src/kernel/vesa.c | 5 | ||||
-rw-r--r-- | src/kernel/vesa.h | 24 | ||||
-rw-r--r-- | src/kernel/vga.c | 8 | ||||
-rw-r--r-- | src/kernel/vga.h | 11 |
32 files changed, 1107 insertions, 584 deletions
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 <stdint.h> -#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 <stdint.h> +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 <stdint.h> + +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 <stdint.h> + +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/link.ld b/src/kernel/elf-link.ld index 7c7b28d..a0d60f9 100644 --- a/src/kernel/link.ld +++ b/src/kernel/elf-link.ld @@ -3,15 +3,19 @@ OUTPUT_ARCH(i386) SECTIONS { . = 0x00030000; - .entry : { + .text : { */main.o(.text) - } - .bin : { *(.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 <stdint.h> #include <stdbool.h> +#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 <stdint.h> -#include "fs.h" -#include "ata.h" -#include "fat.h" -#include <stdbool.h> -#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 <stdint.h> - -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 <stdint.h> +#include <stdbool.h> +#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 <stdint.h> +#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/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 <stdint.h> #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 <stdint.h> +#include <stdbool.h> +#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 <stdint.h> + +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 <stdint.h> -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 <stdint.h> + +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 <stdint.h> +#include <stdbool.h> +#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 <stdint.h> +#include <stdbool.h> +#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 <stdint.h> #include <stdbool.h> 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 <stdint.h> +#include <stdbool.h> + +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 <stdint.h> #include "panic.h" #include <stdbool.h> +#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 <stdint.h> +#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 <stdint.h> 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 |