diff options
49 files changed, 1542 insertions, 616 deletions
diff --git a/doc/assembly-programming.md b/doc/assembly-programming.md new file mode 100644 index 0000000..78f81ac --- /dev/null +++ b/doc/assembly-programming.md @@ -0,0 +1,28 @@ +# Assembly Programming on Portland + +Assembly programming on Portland OS works pretty similarly to other OS's, but the linking phase varies in order to get the proper Portland Executable format for the output. + +## Portland-specific quirks + +The linker script used in the "Compiling and linking" section only recognizes `.text`, `.rodata`, `.data` and `.bss` sections, so please only use these. All of these except `.bss` are treated the same when the executable is loaded, so it doesn't really matter which section you put anything in except for alignment considerations, but it is still helpful for debugging and for readability to put things into the proper sections. This linker script provides a symbol `__pl_length` at the end of the `.data` section, used for generating the PLE header, so don't name any symbols this. + +## Portland ABI + +At program startup¸ we are in 32-bit protected mode in ring 3. The data and stack segments are equal, and these and the code segment refer to a region of memory containing `.text`, `.rodata` and `.data` (all three loaded verbatim from the executable) at address zero, followed by an uninitialized region of memory the size of `.bss`. The stack pointer is initialized to the end of this region, and the instruction pointer is initialized to the `_entry` label. + +See `ints.txt` for information about system calls. + +## Compiling and linking + +The following commands are used to compile and link an (NASM) assembly program into a Portland Executable. Replace the parts in all caps (except the `-O` argument to `objcopy`) with the relevant file names. The `user_elf.ld` file can be found at `src/user-elf.ld` in the kernel repository. + +``` +nasm -f elf32 SOURCE_FILE_1.asm -o SOURCE_FILE_1.o +nasm -f elf32 SOURCE_FILE_2.asm -o SOURCE_FILE_2.o +... + +ld -T user_elf.ld SOURCE_FILE_1.o SOURCE_FILE_2.o ... -o PROGRAM.elf +objcopy -O binary PROGRAM.elf PROGRAM.ple +``` + +After running each of these commands, `PROGRAM.elf` is a regular 32-bit ELF file containing the compiled program, with symbol table and all, useful for debugging. The `.ple_head` section contains the PLE header placed at the start of the executable by `objcopy`, and can be ignored when examining the ELF file. The `PROGRAM.ple` file is an executable file that can be run by Portland OS.
\ No newline at end of file diff --git a/doc/internal/gdt.txt b/doc/internal/gdt.txt index 0a8b5ea..26f7be9 100644 --- a/doc/internal/gdt.txt +++ b/doc/internal/gdt.txt @@ -1,2 +1,5 @@ -0x08: 0x0000.0000 - 0x0007.ffff (code) -0x10: 0x0000.0000 - 0x000f.ffff (data)
\ No newline at end of file +0x08: 0x0000.0000 - 0x0003.7fff (code) +0x10: 0x0000.0000 - 0x1fff.ffff (data) +0x18: task +0x20: user code +0x28: user data
\ No newline at end of file diff --git a/doc/internal/mem.txt b/doc/internal/mem.txt index d8b9913..0819fb7 100644 --- a/doc/internal/mem.txt +++ b/doc/internal/mem.txt @@ -1,6 +1,17 @@ -0x0001.0000 - 0x0001.ffff (64k): unused -0x0002.0000 - 0x0002.7fff (32k): fat -0x0002.8000 - 0x0002.bfff (16k): unused -0x0002.c000 - 0x0002.ffff (16k): 32 file buffers -0x0003.0000 - 0x0003.7fff (32k): kernel -0x0003.8000 - 0x0003.ffff (32k): kernel stack
\ No newline at end of file +0x0000.4000 - 0x0000.4003 (4): bootloader info + 0x0 byte: support flags + 0x80: PCI + 0x1 byte: PCI "hardware characteristics" + 0x2 byte: PCI minor + 0x3 byte: PCI major + 0x4 byte: last PCI bus + +0x0000.4200 - 0x0000.42ff (256): VESA info +0x0000.4300 - 0x0000.43ff (256): VBE strings + +0x0001.0000 - 0x0001.1fff (8k): memory map + +0x0003.0000 - 0x0003.7fff (32k): kernel +0x0003.8000 - 0x0003.ffff (32k): kernel stack + +0x1000.0000 - 0x1fff.ffff (256M): dynamic memory
\ No newline at end of file diff --git a/doc/internal/ple.txt b/doc/internal/ple.txt new file mode 100644 index 0000000..1bcceb4 --- /dev/null +++ b/doc/internal/ple.txt @@ -0,0 +1,12 @@ +Portland Executable Format + +0x00 magic dword 0xb9ba4c50 +0x04 minor version word 0x0000 +0x06 major version word 0x0000 +0x08 payload file offset dword +0x0c payload length dword +0x10 bss length dword +0x14 virtual entry point dword + +Payload loaded at start of cs=ds=ss. +bss after payload, esp set to end of bss.
\ No newline at end of file diff --git a/doc/ints.txt b/doc/ints.txt new file mode 100644 index 0000000..1da08fd --- /dev/null +++ b/doc/ints.txt @@ -0,0 +1,30 @@ +int 0x30 - exit task +int 0x31 - yield to scheduler +int 0x33 - extend data section by eax bytes + actual amount extended returned in eax + +int 0x32 - system call +system call number in eax +args in ebx, ecx, edx, esi, edi +result in eax + + function | eax | eax out | ebx | ecx | edx | esi | edi +---------------|-----|-----------|---------------|--------|--------|-----|----- + vga_blank | 0x0 | | | | | | + vga_set_color | 0x1 | | color | | | | + vga_printch | 0x2 | | char | | | | + vga_printsz | 0x3 | | sz string | | | | + vga_printsn | 0x4 | | non-sz string | length | | | + | | | | | | | + fs_open | 0x5 | handle | path | | | | + fs_open_root | 0x6 | handle | | | | | + fs_new | 0x7 | handle | path | | | | + fs_close | 0x8 | | handle | | | | + fs_delete | 0x9 | | path | | | | + fs_exists | 0xa | does | path | | | | + fs_seek | 0xb | seeked by | handle | by | | | + fs_tell | 0xc | position | handle | | | | + fs_read | 0xd | read | handle | max | buffer | | + fs_write | 0xe | written | handle | max | buffer | | + | | | | | | | + plef_run | 0xf | handle | image path | | | |
\ No newline at end of file diff --git a/fs-skel/sys/startup.rc b/fs-skel/sys/startup.rc new file mode 100644 index 0000000..1535d72 --- /dev/null +++ b/fs-skel/sys/startup.rc @@ -0,0 +1 @@ +/bin/hello.ple
\ No newline at end of file diff --git a/fs/bleh.txt b/fs/bleh.txt deleted file mode 100644 index d6d9d34..0000000 --- a/fs/bleh.txt +++ /dev/null @@ -1 +0,0 @@ -blah
\ No newline at end of file @@ -1,12 +1,12 @@ -disk: kernel boot fs- +disk: kernel boot skel hello mkdir -p obj out - /sbin/mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 17 -s 1 -S 512 obj/shadow.img 8192 + /sbin/mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 65 -s 1 -S 512 obj/shadow.img 8192 echo -n -e '\xeb\x3c' > obj/jmp.bin dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc dd if=out/kernel.bin of=obj/shadow.img seek=1 conv=notrunc mv obj/shadow.img out/disk.img - mcopy -i out/disk.img -s out/fs/bleh.txt ::/ + mcopy -i out/disk.img -s out/fs/* ::/ vdi-file: disk VBoxManage convertfromraw out/disk.img out/disk.vdi --uuid a61929ed-3bf2-45ff-b98a-44f87c616dba @@ -14,27 +14,44 @@ vdi-file: disk debug: disk gdb -x qemu-debug.gdb -fs-: - cp -r fs out/fs +clean: + rm -r obj out + +skel: + mkdir -p out/fs + cp -r fs-skel/* out/fs/ + +kgccargs = -Wall -m32 -Og -ffreestanding -fno-asynchronous-unwind-tables +ugccargs = ${kgccargs} -Isrc/libc/inc +nasmargs = -f elf32 + +hello: + mkdir -p obj/hello out/fs/bin + nasm ${nasmargs} src/user/hello/hello.asm -o obj/hello/hello.o + ld -T src/user-elf.ld obj/hello/hello.o -o obj/hello.elf + objcopy -O binary obj/hello.elf out/fs/bin/hello.ple + +init: + #TODO -kgccargs = -m32 -ffreestanding -fno-asynchronous-unwind-tables kernel: mkdir -p obj/kernel out - gcc ${kgccargs} -c src/kernel/main.c -o obj/kernel/main.o - gcc ${kgccargs} -c src/kernel/vga.c -o obj/kernel/vga.o + gcc ${kgccargs} -c src/kernel/drive.c -o obj/kernel/drive.o gcc ${kgccargs} -c src/kernel/fat.c -o obj/kernel/fat.o - gcc ${kgccargs} -c src/kernel/fs.c -o obj/kernel/fs.o - gcc ${kgccargs} -c src/kernel/ata.c -o obj/kernel/ata.o - gcc ${kgccargs} -c src/kernel/util.c -o obj/kernel/utilc.o + gcc ${kgccargs} -c src/kernel/ide.c -o obj/kernel/ide.o + gcc ${kgccargs} -c src/kernel/main.c -o obj/kernel/main.o + gcc ${kgccargs} -c src/kernel/mem.c -o obj/kernel/mem.o gcc ${kgccargs} -c src/kernel/panic.c -o obj/kernel/panic.o + gcc ${kgccargs} -c src/kernel/pci.c -o obj/kernel/pci.o + gcc ${kgccargs} -c src/kernel/plef.c -o obj/kernel/plef.o gcc ${kgccargs} -c src/kernel/serial.c -o obj/kernel/serial.o - nasm -f elf32 src/kernel/util.asm -o obj/kernel/utila.o - ld -T src/kernel/link.ld obj/kernel/main.o obj/kernel/vga.o obj/kernel/fat.o obj/kernel/fs.o obj/kernel/ata.o obj/kernel/utilc.o obj/kernel/panic.o obj/kernel/utila.o obj/kernel/serial.o -o obj/kernel.elf - objcopy -O binary -j .entry -j .bin obj/kernel.elf out/kernel.bin + gcc ${kgccargs} -c src/kernel/task.c -o obj/kernel/task.o + gcc ${kgccargs} -c src/kernel/util.c -o obj/kernel/util.o + gcc ${kgccargs} -c src/kernel/vesa.c -o obj/kernel/vesa.o + gcc ${kgccargs} -c src/kernel/vga.c -o obj/kernel/vga.o + ld -T src/kernel/elf-link.ld obj/kernel/*.o -o obj/kernel.elf + objcopy -O binary obj/kernel.elf out/kernel.bin boot: mkdir -p out nasm src/boot.asm -o out/boot.bin - -clean: - rm -r obj out diff --git a/qemu-debug.gdb b/qemu-debug.gdb index f8f541f..72b935e 100644 --- a/qemu-debug.gdb +++ b/qemu-debug.gdb @@ -1,4 +1,4 @@ -target remote | qemu-system-i386 -S -gdb stdio out/disk.img +target remote | qemu-system-i386 -m 768 -S -gdb stdio out/disk.img add-symbol-file obj/kernel.elf set disassembly-flavor intel layout reg diff --git a/src/boot.asm b/src/boot.asm index 8e463be..eb3b2c9 100644 --- a/src/boot.asm +++ b/src/boot.asm @@ -1,9 +1,17 @@ bits 16 org 0x7c3e -kernel_sectors equ 16 +kernel_sectors equ 64 kernel_segment equ 0x3000 +support_flags equ 0x4000 +pci_hw_char equ 0x4001 +pci_ver equ 0x4002 + +pci_support equ 0x80 + +vesa_segment equ 0x0420 + in al, 0x92 or al, 0x02 out 0x92, al @@ -24,6 +32,31 @@ kernel_segment equ 0x3000 xor dh, dh int 0x13 + mov ax, 0xb101 + int 0x1a + + cmp edx, 0x20494350 + jne no_pci + + test ah, ah + jnz no_pci + + mov byte [support_flags], pci_support + mov byte [pci_hw_char], al + mov word [pci_ver], bx + +no_pci: + mov dword [vesa_segment * 16], 'V' + 'B' * 256 + 'E' * 65535 + '2' * 16777216 + + mov ax, vesa_segment + mov es, ax + xor di, di + mov ax, 0x4f00 + int 0x10 + + cmp ax, 0x004f + jne no_vbe + cli lgdt [gdt] @@ -34,6 +67,15 @@ kernel_segment equ 0x3000 jmp 0x08:pmode +no_vbe: + ;TODO + + cli + +real_halt: + hlt + jmp real_halt + bits 32 pmode: @@ -49,14 +91,19 @@ halt: hlt jmp halt +times $$ + 0x018a - $ db 0 + +;0x7dc8 gdt: dw .e - .t dd .t .t: dq 0x0000_0000_0000_0000 - dq 0x00c0_9a00_0000_007f - dq 0x00c0_9200_0000_00ff + dq 0x00c0_9a00_0000_0037 + dq 0x00c1_9200_0000_ffff + dq 0x0000_0000_0000_0000;TODO: task + dq 0x0000_0000_0000_0000 + dq 0x0000_0000_0000_0000 .e: -times $$ + 448 - $ db 0 dw 0xaa55
\ No newline at end of file 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/elf-link.ld b/src/kernel/elf-link.ld new file mode 100644 index 0000000..a0d60f9 --- /dev/null +++ b/src/kernel/elf-link.ld @@ -0,0 +1,21 @@ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0x00030000; + .text : { + */main.o(.text) + *(.text) + } + .rodata : { + *(.rodata) + } + .data : { + *(.data) + } + . = 0x10000000; + .bss : { + *(.bss) + kernel_bss_end = .; + } +}
\ No newline at end of file diff --git a/src/kernel/fat.c b/src/kernel/fat.c index b8d1c3b..087d79e 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -1,115 +1,210 @@ #include "fat.h" #include "ata.h" #include "panic.h" -#include "fs.h" +#include "drive.h" +#include "mem.h" +#include "util.h" -void load_fat() { - read_sectors(FAT_INFO->reserved_sectors, FAT_INFO->sectors_per_fat, FAT); +#define MAX_FAT_DRIVES 16 +#define MAX_OPEN_FILES_PER_DRIVE 32 + +enum { + FA_READ_ONLY = 0x01, + FA_HIDDEN = 0x02, + FA_SYSTEM = 0x04, + FA_LABEL = 0x08, + FA_DIRECTORY = 0x10, + FA_ARCHIVE = 0x20, + + FA_LFN = 0x0f +}; + +struct directory_entry { + uint8_t name[11]; + uint8_t attrib; + uint8_t name_case; + uint8_t created_decimal; + uint16_t created_time; + uint16_t created_date; + uint16_t accessed_date; + uint16_t ignore; + uint16_t modified_time; + uint16_t modified_date; + uint16_t first_cluster; + uint32_t length; +} __attribute__ ((packed)); + +struct fat_info { + //3 bytes jump + uint8_t oem[8]; + uint16_t bytes_per_sector;//Assumed to be 512 + uint8_t sectors_per_cluster;//Assumed to be 1 + uint16_t reserved_sectors; + uint8_t fats;//Only first is used + uint16_t root_entries; + uint16_t sectors;//Assumed not to be 0 + uint8_t media_type; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads; + uint32_t hidden_sectors; + uint32_t sectors_long; + uint8_t drive_number; + uint8_t reserved; + uint8_t ext_boot_marker; + uint32_t volume_id; + uint8_t label[11]; + uint8_t fs_type[8]; +} __attribute__ ((packed)); + +#define CTOS(c, fi) ((fi)->reserved_sectors + (fi)->sectors_per_fat * (fi)->fats + ((fi)->root_entries >> 4) + (c) - 2) + +struct fat_drive_info { + struct fat_info *fi; + uint16_t *fat; + struct directory_entry open_files[MAX_OPEN_FILES_PER_DRIVE]; +}; + +struct fat_drive_info infos[MAX_FAT_DRIVES]; +uint8_t next_id = 0; + +#define FI(n) ((struct fat_info *)(infos[n].fi + 3)) +#define FN(n, f) (infos[n].open_files[f - 1]) + +uint8_t fat_driver_buffer[512]; +struct fat_info *next_fi; + +void alloc_next_fi() { + if (!((uint32_t)(next_fi = (struct fat_info *)((uint32_t)next_fi + 64)) & 0xfff)) + if (!(next_fi = allocate_pages(1))) + panic("Out of memory in FAT driver."); } -bool to_fat_name(uint8_t *sname, uint8_t *fname) { - uint8_t *sp = sname, *fp = fname; - while (*sp != '.') { - if (!*sp) { - while (fp != fname + 11) - *(fp++) = ' '; - return false; - } - if (sp == sname + 8) - return true; - *(fp++) = *(sp++); - } - while (fp != fname + 8) - *(fp++) = ' '; - while (*++sp) { - if (fp == fname + 11) - return true; - *(fp++) = *sp; +struct drive *cur_drive; +fs_id_t cur_id; +struct directory_entry *cur_dir; + +//loads cluster `c` +void load_cluster(uint16_t c, void *to) { + if (c == 0) { + *(uint8_t *)to = 0; + return; } - while (fp != fname + 11) - *(fp++) = ' '; - return false; + + uint32_t s = CTOS(c, FI(cur_id)); + cur_drive->read_sectors(cur_drive, s, 1, to); } -bool check_fat_names(uint8_t *lname, uint8_t *rname) { - return (* (uint32_t *)lname == *(uint32_t *)rname) && - (*((uint32_t *)lname + 1) == *((uint32_t *)rname + 1)) && - (*((uint16_t *)lname + 4) == *((uint16_t *)rname + 4)) && - (*( lname + 10) == *( rname + 10)); +uint16_t next_cluster(uint16_t c) { + panic("TODO: compute next sector (or 0 for none)"); } -struct directory_entry buffer[16]; -uint16_t dir_start, buffer_from; +static inline bool check_fat_names(uint8_t *a, uint8_t *b) { + return (((uint32_t *)a)[0] == ((uint32_t *)b)[0]) && + (((uint32_t *)a)[1] == ((uint32_t *)b)[1]) && + (((uint16_t *)a)[8] == ((uint16_t *)b)[8]) && + (((uint8_t *)a)[10] == ((uint8_t *)b)[10]); +} +//after: cur_dir -> specified entry in root +bool try_locate_root_entry(uint8_t *fat_name) { + uint32_t cur_dir_sect = FI(cur_id)->reserved_sectors + FI(cur_id)->sectors_per_fat * FI(cur_id)->fats - 1; + cur_dir = (struct directory_entry *)(fat_driver_buffer + 512); + while (true) { + if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) { + cur_dir = (struct directory_entry *)fat_driver_buffer; + ++cur_dir_sect; + cur_drive->read_sectors(cur_drive, cur_dir_sect, 1, cur_dir); + } + if (!*(uint8_t *)cur_dir) + return false; + if (check_fat_names(cur_dir->name, fat_name)) + return true; + else + ++cur_dir; + } +} -void load_root() { - dir_start = FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat; +//before: cur_dir -> entry of dir to search +//after: cur_dir -> specified entry in dir +bool try_locate_entry(uint8_t *fat_name) { + uint16_t cur_dir_cluster = cur_dir->first_cluster; + load_cluster(cur_dir_cluster, fat_driver_buffer); + cur_dir = (struct directory_entry *)fat_driver_buffer; + while (true) { + if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) { + cur_dir = (struct directory_entry *)fat_driver_buffer; + ++cur_dir_cluster; + load_cluster(cur_dir_cluster = next_cluster(cur_dir_cluster), fat_driver_buffer); + } + if (!*(uint8_t *)cur_dir) + return false; + if (check_fat_names(cur_dir -> name, fat_name)) + return true; + else + ++cur_dir; + } } -struct directory_entry *load_subentry(uint8_t *name) { - uint8_t fname[11]; - if (to_fat_name(name, fname)) - return 0; - struct directory_entry *ptr = buffer; - uint16_t dir_current = dir_start; - read_sectors(buffer_from = dir_current, 1, buffer); - while (*(uint8_t *)ptr) { - if (check_fat_names(ptr->name, fname)) - return ptr; - if (++ptr == buffer + 16) { - read_sectors(buffer_from = ++dir_current, 1, buffer); - ptr = buffer; +drive_file_id_t fat_get_file(struct drive *d, char *path) { + cur_drive = d; + cur_id = d->drive_id; + for (drive_file_id_t n = 1; n != MAX_OPEN_FILES_PER_DRIVE + 1; ++n) + if (!*(uint8_t *)(&FN(d->drive_id, n))) { + panic("TODO: open path at FN(id, n)"); + return n; } - }; - return 0; + panic("Maximum number of files open reached for FAT drive."); } -bool load_subdir(uint8_t *name) { - struct directory_entry *e = load_subentry(name); - if (!e) - return true; - dir_start = CTOS(e->first_cluster); - return false; +void fat_free_file(struct drive *d, drive_file_id_t fid) { + *(uint8_t *)(&FN(d->drive_id, fid)) = 0; } -struct directory_entry *load_entry(uint8_t *path) { - load_root(); - for (uint8_t *ptr = path; *ptr; ++ptr) - if (*ptr == '/') { - *ptr = 0; - if (load_subdir(path)) - return 0; - path = ptr + 1; - } - return load_subentry(path); +void fat_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) { + cur_drive = d; + cur_id = d->drive_id; + uint16_t c = FN(d->drive_id, fid).first_cluster; + for (uint32_t i = 0; i < sector; ++i) + c = next_cluster(c); + load_cluster(c, at); } -bool get_entry(uint8_t *path, struct directory_entry *at) { - struct directory_entry *e = load_entry(path); - if (!e) - return true; - *at = *e; - return false; +uint32_t fat_get_free_sectors(struct drive *d) { + panic("TODO: get free sectors of drive"); } -bool update_entry(uint8_t *path, struct directory_entry *value) { - struct directory_entry *e = load_entry(path); - if (!e) - return true; - *e = *value; - write_sectors(buffer_from, 1, buffer); - return false; +void init_fat() { + next_fi = allocate_pages(1); } -bool create_entry(uint8_t *dir_path, struct directory_entry *value) { - fs_handle h = fs_open(dir_path); - struct directory_entry *check; - while (fs_read(h, 32, check)) - if (check_fat_names(check->name, value->name)) { - fs_close(h); - return true; - } - fs_write(h, 32, value); - fs_close(h); - return false; +bool try_fat_init_drive(struct drive *d) { + if (next_id >= MAX_FAT_DRIVES) + panic("Maximum number of FAT drives reached."); + + if (!d->read_sectors(d, 0, 1, fat_driver_buffer)) + return false; + memcpy(next_fi, fat_driver_buffer + 3, sizeof(struct fat_info)); + uint32_t *fs_type_32 = (uint32_t *)next_fi->fs_type; + if ((fs_type_32[0] != ('F' + 'A' * 256 + 'T' + 65536 + '1' * 16777216)) || + (fs_type_32[1] != ('6' + ' ' * 256 + ' ' + 65536 + ' ' * 16777216))) + return false; + + d->fs_type = "FAT16"; + d->get_file = &fat_get_file; + d->free_file = &fat_free_file; + d->load_sector = &fat_load_sector; + d->get_free_sectors = &fat_get_free_sectors; + + d->fs_id = next_id; + infos[next_id].fi = next_fi; + infos[next_id].fat = allocate_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1); + for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i) + *(uint8_t *)&FN(next_id, i) = 0; + + d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat); + + alloc_next_fi(); + ++next_id; + return true; }
\ No newline at end of file diff --git a/src/kernel/fat.h b/src/kernel/fat.h index 73eaaae..d9db906 100644 --- a/src/kernel/fat.h +++ b/src/kernel/fat.h @@ -1,61 +1,12 @@ +#ifndef FAT_H +#define FAT_H + #include <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 diff --git a/src/kernel/link.ld b/src/lib.ld index 7c7b28d..81cc67b 100644 --- a/src/kernel/link.ld +++ b/src/lib.ld @@ -2,13 +2,13 @@ OUTPUT_FORMAT(elf32-i386) OUTPUT_ARCH(i386) SECTIONS { - . = 0x00030000; - .entry : { - */main.o(.text) - } - .bin : { + .text : { *(.text) + } + .rodata : { *(.rodata) + } + .data : { *(.data) } .bss : { diff --git a/src/user-elf.ld b/src/user-elf.ld new file mode 100644 index 0000000..8b0c102 --- /dev/null +++ b/src/user-elf.ld @@ -0,0 +1,26 @@ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +SECTIONS { + .ple_head : { + /*magic*/ LONG(0xb9ba4c50) + /*version*/ LONG(0x00000000) + /*payload offset*/ LONG(SIZEOF(.ple_head)) + /*payload length*/ LONG(__pl_length) + /*bss length*/ LONG(SIZEOF(.bss)) + /*entry point*/ LONG(_entry) + } + .text 0 : AT(SIZEOF(.ple_head)) { + *(.text) + } + .rodata : { + *(.rodata) + } + .data : { + *(.data) + __pl_length = .; + } + .bss ALIGN(0) : { + *(.bss) + } +}
\ No newline at end of file diff --git a/src/user/hello/hello.asm b/src/user/hello/hello.asm new file mode 100644 index 0000000..345abb4 --- /dev/null +++ b/src/user/hello/hello.asm @@ -0,0 +1,15 @@ +global _entry + +section .text +_entry: + mov eax, 3 + mov ebx, msg + int 0x32 + + int 0x30 + +section .rodata +msg db "Hello, world!", 0x0a, 0x00 + +section .bss +stack resb 8
\ No newline at end of file diff --git a/src/user/include/canyo/file.h b/src/user/include/canyo/file.h new file mode 100644 index 0000000..5f09387 --- /dev/null +++ b/src/user/include/canyo/file.h @@ -0,0 +1,9 @@ +#ifndef CANYO_FILE_H +#define CANYO_FILE_H + +#include <stdint.h> +#include <pland.h> + +uint32_t read_line(fs_handle handle, uint32_t max_length, void *buffer); + +#endif
\ No newline at end of file diff --git a/src/user/include/pland.h b/src/user/include/pland.h new file mode 100644 index 0000000..f174a51 --- /dev/null +++ b/src/user/include/pland.h @@ -0,0 +1,157 @@ +#ifndef PLAND_H +#define PLAND_H + +#include <stdint.h> +#include <stdbool.h> + +typedef uint8_t fs_handle; +typedef uint8_t task_handle; + +static inline void exit() __attribute__ ((noreturn)) { + asm volatile ("int $0x30"); + __builtin_unreachable(); +} + +static inline void yield() { + asm volatile ("int $0x31"); +} + +static inline uint32_t data_extend(uint32_t amount) { + uint32_t actual_amount; + asm volatile ( + "int $0x33" + : "eax" (actual_amount) : "eax" (amount)); + return actual_amount; +} + +static inline void vga_blank() { + asm volatile ( + "xor %%eax, %%eax\n" + "int $0x32" + : : : "eax"); +} + +static inline void vga_set_color(uint8_t color) { + asm volatile ( + "mov $0x1, %%eax\n" + "int $0x32" + : : "ebx" (color) : "eax"); +} + +static inline void vga_printch(uint8_t ch) { + asm volatile ( + "mov $0x2, %%eax\n" + "int $0x32" + : : "ebx" (ch) : "eax"); +} + +static inline void vga_printsz(uint8_t *sz) { + asm volatile ( + "mov $0x3, %%eax\n" + "int $0x32" + : : "ebx" (sz) : "eax"); +} + +static inline void vga_printsn(uint8_t *sn, uint8_t length) { + asm volatile ( + "mov $0x4, %%eax\n" + "int $0x32" + : : "ebx" (sn), "ecx" (length) : "eax"); +} + +static inline fs_handle fs_open(uint8_t *path) { + fs_handle handle; + asm volatile ( + "mov $0x5, %%eax\n" + "int $0x32" + : "eax" (handle) : "ebx" (path)); + return handle; +} + +static inline fs_handle fs_open_root() { + fs_handle handle; + asm volatile ( + "mov $0x6, %%eax\n" + "int $0x32" + : "eax" (handle)); + return handle; +} + +static inline fs_handle fs_new(uint8_t *path) { + fs_handle handle; + asm volatile ( + "mov $0x7, %%eax\n" + "int $0x32" + : "eax" (handle) : "ebx" (path)); + return handle; +} + +static inline void fs_close(fs_handle handle) { + asm volatile ( + "mov $0x8, %%eax\n" + "int $0x32" + : : "ebx" (handle) : "eax"); +} + +static inline void fs_delete(uint8_t *path) { + asm volatile ( + "mov $0x9, %%eax\n" + "int $0x32" + : : "ebx" (path) : "eax"); +} + +static inline bool fs_exists(uint8_t *path) { + bool does; + asm volatile ( + "mov $0xa, %%eax\n" + "int $0x32" + : "eax" (does) : "ebx" (path)); + return does; +} + +static inline int32_t fs_seek(fs_handle handle, int32_t by) { + int32_t seeked_by; + asm volatile ( + "mov $0xb, %%eax\n" + "int $0x32" + : "eax" (seeked_by) : "ebx" (handle), "ecx" (by)); + return seeked_by; +} + +static inline uint32_t fs_tell(fs_handle handle) { + uint32_t position; + asm volatile ( + "mov $0xc, %%eax\n" + "int $0x32" + : "eax" (position) : "ebx" (handle)); + return position; +} + +static inline uint32_t fs_read(fs_handle handle, uint32_t max, void *buffer) { + uint32_t read; + asm volatile ( + "mov %0xd, %%eax\n" + "int $0x32" + : "eax" (read) : "ebx" (handle), "ecx" (max), "edx" (buffer) : "memory"); + return read; +} + +static inline uint32_t fs_write(fs_handle handle, uint32_t max, void *buffer) { + uint32_t written; + asm volatile ( + "mov %0xe, %%eax\n" + "int $0x32" + : "eax" (written) : "ebx" (handle), "ecx" (max), "edx" (buffer)); + return written; +} + +static inline task_handle plef_run(uint8_t *image_path) { + task_handle handle; + asm volatile ( + "mov %0xf, %%eax\n" + "int $0x32" + : "eax" (handle) : "ebx" (image_path)); + return handle; +} + +#endif diff --git a/src/user/init/main.c b/src/user/init/main.c new file mode 100644 index 0000000..002fd92 --- /dev/null +++ b/src/user/init/main.c @@ -0,0 +1,16 @@ +#include <pland.h> +#include <canyo/file.h> + +void main() { + fs_handle f = fs_open("sys/startup.rc"); + if (!f) { + vga_printsz("Couldn't open sys/startup.rc\n"); + return; + } + + uint8_t line_buffer[128]; + while (read_line(f, 128, line_buffer)) + plef_run(line_buffer); + + fs_close(f); +} diff --git a/src/user/libcanyo/file.c b/src/user/libcanyo/file.c new file mode 100644 index 0000000..d314887 --- /dev/null +++ b/src/user/libcanyo/file.c @@ -0,0 +1,15 @@ +#include <stdint.h> +#include <pland.h> + +//max_length and return value include null-terminator +uint32_t read_line(fs_handle handle, uint32_t max_length, void *buffer) { + int index = 0; + + while (++index < max_length) { + if (!fs_read(handle, 1, buffer + index - 1) || (*(uint8_t *)(buffer + index - 1) == '\n')) + break; + } + + *(uint8_t *)(buffer + index - 1) = '\0'; + return index; +}
\ No newline at end of file |