summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/ata.c113
-rw-r--r--src/kernel/ata.h77
-rw-r--r--src/kernel/boot.h26
-rw-r--r--src/kernel/drive.c38
-rw-r--r--src/kernel/drive.h34
-rw-r--r--src/kernel/elf-link.ld (renamed from src/kernel/link.ld)12
-rw-r--r--src/kernel/fat.c271
-rw-r--r--src/kernel/fat.h63
-rw-r--r--src/kernel/fs.c144
-rw-r--r--src/kernel/fs.h11
-rw-r--r--src/kernel/ide.c189
-rw-r--r--src/kernel/ide.h12
-rw-r--r--src/kernel/main.c155
-rw-r--r--src/kernel/mem.c63
-rw-r--r--src/kernel/mem.h13
-rw-r--r--src/kernel/panic.c27
-rw-r--r--src/kernel/panic.h8
-rw-r--r--src/kernel/pci.c77
-rw-r--r--src/kernel/pci.h38
-rw-r--r--src/kernel/plef.c33
-rw-r--r--src/kernel/plef.h22
-rw-r--r--src/kernel/serial.c16
-rw-r--r--src/kernel/serial.h17
-rw-r--r--src/kernel/task.c14
-rw-r--r--src/kernel/task.h14
-rw-r--r--src/kernel/util.asm37
-rw-r--r--src/kernel/util.c58
-rw-r--r--src/kernel/util.h61
-rw-r--r--src/kernel/vesa.c5
-rw-r--r--src/kernel/vesa.h24
-rw-r--r--src/kernel/vga.c8
-rw-r--r--src/kernel/vga.h11
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