diff options
30 files changed, 603 insertions, 234 deletions
diff --git a/doc/ints.txt b/doc/ints.txt index d8abd6d..45c09b3 100644 --- a/doc/ints.txt +++ b/doc/ints.txt @@ -24,19 +24,23 @@ invalid system call numbers change eax to -1, and have no other effect. table 1: - function | eax | eax out | ebx | ecx | edx | esi | edi ----------------|-----|---------------|---------------|-------------|-------------|--------|----- - open file | 0x0 | handle | drive number | path | | | - close file | 0x1 | | handle | | | | - file read | 0x2 | read | handle | file offset | count | buffer | - get file size | 0x3 | size | handle | | | | - start task | 0x4 | handle | drive number | path | passed sz | | - log string | 0x5 | | sz string | | | | - get key | 0x6 | keycode | | | | | - allocate ram | 0x7 | start pointer | pages | | | | - memory info | 0x8 | see table 2 | see table 2 | | | | - wait for task | 0x9 | | handle | | | | - enumerate dir | 0xa | count | drive number | path | see table 3 | max | + function | eax | eax out | ebx | ecx | edx | esi | edi +----------------|-----|-----------------|----------------|-------------|-------------|--------|----- + open file | 0x0 | handle | drive number | path | | | + close file | 0x1 | | handle | | | | + file read | 0x2 | read | handle | file offset | count | buffer | + get file size | 0x3 | size | handle | | | | + start task | 0x4 | handle | drive number | path | passed sz | | + log string | 0x5 | | sz string | | | | + get key | 0x6 | keycode | | | | | + allocate ram | 0x7 | start pointer | pages | | | | + memory info | 0x8 | see table 2 | see table 2 | | | | + wait for task | 0x9 | | handle | | | | + enumerate dir | 0xa | count | drive number | path | see table 3 | max | + vga print at | 0xb | | row << 8 | col | sz string | | | + count of dir | 0xc | number of files | drive number | path | | | + clear screen | 0xd | | | | | | + set color | 0xe | | VGA color code | | | | table 2: @@ -55,12 +59,7 @@ eax -1 indicates unrecognized ebx table 3: edx of "enumerate dir" is a pointer to a buffer where an array of "directory info"s can be put. esi is the maximum number of "directory info"s to be placed in the buffer. -the "directory info" structure is defined as follows: - struct { - bool is_dir; - char name[100]; - uint32_t size; - } -"is_dir" here indicates whether or not the entry is another directory. -"name" is a null-terminated string, up to 99 characters, indicating the name of the entry. -"size" is the size of the file this entry refers to, in bytes.
\ No newline at end of file +the "directory info" structure is 128 bytes long. The first 100 bytes are a null-terminated string + indicating the name of the file represented by this entry. The next four bytes are a 32-bit integer + indicating the size of the file represented in bytes. The next byte's lowest bit is a one if this + entry is a directory, and a zero if this entry is not. The remainder of the structure is reserved.
\ No newline at end of file @@ -1,5 +1,6 @@ kgccargs = -Wall -Wsuggest-attribute=pure -Wsuggest-attribute=const -m32 -Og -ffreestanding -fno-asynchronous-unwind-tables ugccargs = ${kgccargs} -Isrc/user/include +ugppargs = ${kgccargs} -Isrc/user/include/cpp -Isrc/user/include nasmargs = -f elf32 partlink = -r -m elf_i386 @@ -30,7 +31,7 @@ out/fs/bin/%: obj/%.elf out/fs: out/fs/bin/init out/fs/bin/meminfo out/fs/bin/highway \ out/fs/bin/hello out/fs/bin/dumptext out/fs/bin/dumphex \ - out/fs/bin/dirinfo + out/fs/bin/dirinfo out/fs/bin/fileman mkdir -p out/fs cp -r fs-skel/* out/fs/ @@ -42,14 +43,14 @@ obj/kernel/%.kao: src/kernel/%.asm mkdir -p $(shell dirname $@) nasm ${nasmargs} $< -o $@ -out/kernel.bin: obj/kernel/drive.ko obj/kernel/fat.ko obj/kernel/ide.ko \ - obj/kernel/idt.ko obj/kernel/log.ko obj/kernel/main.ko \ - obj/kernel/main2.ko obj/kernel/pmap.ko obj/kernel/paging.ko \ - obj/kernel/panic.ko obj/kernel/pci.ko obj/kernel/elf.ko \ - obj/kernel/serial.ko obj/kernel/task.ko obj/kernel/util.ko \ - obj/kernel/vga.ko obj/kernel/isrs.kao obj/kernel/kbd.ko +out/kernel.bin: obj/kernel/drive.ko obj/kernel/fat.ko obj/kernel/ide.ko \ + obj/kernel/idt.ko obj/kernel/log.ko obj/kernel/main.ko \ + obj/kernel/panic.ko obj/kernel/pci.ko obj/kernel/elf.ko \ + obj/kernel/serial.ko obj/kernel/task.ko obj/kernel/util.ko \ + obj/kernel/vga.ko obj/kernel/isrs.kao obj/kernel/kbd.ko \ + obj/kernel/pmap.ko obj/kernel/paging.ko mkdir -p out - ld -T src/kernel/elf-link.ld obj/kernel/* -o obj/kernel.elf + ld -T src/kernel/elf-link.ld $^ -o obj/kernel.elf objcopy -O binary obj/kernel.elf out/kernel.bin out/boot.bin: src/boot.asm @@ -64,29 +65,46 @@ obj/%.ao: src/user/%.asm mkdir -p $(shell dirname $@) nasm ${nasmargs} $< -o $@ -obj/knob.so: obj/knob/env.o obj/knob/file.o obj/knob/format.o \ - obj/knob/heap.o obj/knob/quit.o obj/knob/user.o \ - obj/knob/task.o obj/knob/entry.ao obj/knob/block.o - ld ${partlink} obj/knob/* -o obj/knob.so +obj/%.po: src/user/%.cpp + mkdir -p $(shell dirname $@) + g++ ${ugppargs} -c $< -o $@ + +obj/c.rto: obj/runtimes/c/entry.ao + ld ${partlink} obj/runtimes/c/* -o obj/c.rto + +obj/cpp.rto: + #TODO -obj/init.elf: obj/init/init.o obj/knob.so - ld -T src/user/elf.ld obj/init/* obj/knob.so -o obj/init.elf +obj/knob.so: obj/knob/env.o obj/knob/file.o obj/knob/format.o \ + obj/knob/heap.o obj/knob/user.o obj/knob/task.o \ + obj/knob/block.o + ld ${partlink} $^ -o $@ -obj/meminfo.elf: obj/meminfo/meminfo.o obj/knob.so - ld -T src/user/elf.ld obj/meminfo/* obj/knob.so -o obj/meminfo.elf +obj/cove.so: obj/cove/cove.po obj/cove/buttons.po obj/cove/label.po \ + obj/cove/vlist.po + ld ${partlink} $^ -o $@ + +obj/init.elf: obj/init/init.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@ + +obj/meminfo.elf: obj/meminfo/meminfo.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@ obj/highway.elf: obj/highway/main.o obj/highway/cmds.o obj/highway/line.o \ - obj/highway/vars.o obj/knob.so - ld -T src/user/elf.ld obj/highway/* obj/knob.so -o obj/highway.elf + obj/highway/vars.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@ obj/hello.elf: obj/hello/hello.ao - ld -T src/user/elf.ld obj/hello/* -o obj/hello.elf + ld -T src/user/runtimes/asm/elf.ld $^ -o $@ + +obj/dumptext.elf: obj/dumptext/dumptext.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@ -obj/dumptext.elf: obj/dumptext/dumptext.o obj/knob.so - ld -T src/user/elf.ld obj/dumptext/* obj/knob.so -o obj/dumptext.elf +obj/dumphex.elf: obj/dumphex/dumphex.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@ -obj/dumphex.elf: obj/dumphex/dumphex.o obj/knob.so - ld -T src/user/elf.ld obj/dumphex/* obj/knob.so -o obj/dumphex.elf +obj/dirinfo.elf: obj/dirinfo/dirinfo.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@ -obj/dirinfo.elf: obj/dirinfo/dirinfo.o obj/knob.so - ld -T src/user/elf.ld obj/dirinfo/* obj/knob.so -o obj/dirinfo.elf
\ No newline at end of file +obj/fileman.elf: obj/fileman/fileman.o obj/knob.so obj/c.rto + ld -T src/user/runtimes/c/elf.ld $^ -o $@
\ No newline at end of file diff --git a/src/kernel/drive.c b/src/kernel/drive.c index 731088c..2ae050f 100644 --- a/src/kernel/drive.c +++ b/src/kernel/drive.c @@ -36,6 +36,11 @@ static uint32_t unknown_enumerate_dir(const struct drive *d, const char *path, s return 0; } +__attribute__ ((const)) +static uint32_t unknown_n_dir_entries(const struct drive *d, const char *path) { + return 0; +} + static inline void determine_fs(struct drive *d) { if (try_fat_init_drive(d)) return; @@ -46,6 +51,7 @@ static inline void determine_fs(struct drive *d) { d->load_sector = &unknown_load_sector; d->get_file_length = &unknown_get_file_length; d->enumerate_dir = &unknown_enumerate_dir; + d->n_dir_entries = &unknown_n_dir_entries; d->get_free_sectors = &unknown_get_free_sectors; } diff --git a/src/kernel/drive.h b/src/kernel/drive.h index b02b4ad..03fe4b6 100644 --- a/src/kernel/drive.h +++ b/src/kernel/drive.h @@ -13,10 +13,11 @@ typedef uint8_t drive_id_t; #define DCI_NAME_LEN 100 struct directory_content_info { - bool is_dir; char name[DCI_NAME_LEN]; uint32_t size; -}; + bool is_dir; + uint8_t pad[23]; +} __attribute__ ((packed)); struct drive { char *drive_type; @@ -34,6 +35,7 @@ struct drive { void (*load_sector) (const struct drive *d, file_id_t fid, uint32_t sector, void *at); uint32_t (*get_file_length) (const struct drive *d, file_id_t fid); uint32_t (*enumerate_dir) (const struct drive *d, const char *path, struct directory_content_info *info, uint32_t max); + uint32_t (*n_dir_entries) (const struct drive *d, const char *path); uint32_t (*get_free_sectors)(const struct drive *d); fs_id_t fs_id; }; diff --git a/src/kernel/fat.c b/src/kernel/fat.c index c4461de..362539c 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -365,6 +365,72 @@ static uint32_t fat_enumerate_dir(const struct drive *d, const char *path, struc } } +static uint32_t n_root_entries(const struct drive *d) { + uint32_t sect = infos[d->drive_id].root_start - 1; + struct directory_entry *entry = (struct directory_entry *)(fat_driver_buffer + 512); + + uint32_t count = 0; + + while (true) { + if (entry == (struct directory_entry *)(fat_driver_buffer + 512)) { + entry = (struct directory_entry *)fat_driver_buffer; + ++sect; + d->read_sectors(d, sect, 1, entry); + } + + if (!*(uint8_t *)entry) { + d->done(d); + return count; + } + + if (entry-> attrib & FA_LABEL) { + ++entry; + continue; + } + + ++entry; + ++count; + } +} + +static uint32_t fat_n_dir_entries(const struct drive *d, const char *path) { + d->ready(d); + + if (!*path) + return n_root_entries(d); + + if (!try_load_from_path(d, path)) { + d->done(d); + return 0; + } + + uint16_t cluster = cur_dir->first_cluster; + load_cluster(cluster, fat_driver_buffer); + struct directory_entry *entry = (struct directory_entry *)fat_driver_buffer; + + uint32_t count = 0; + + while (true) { + if (entry == (struct directory_entry *)(fat_driver_buffer + 512)) { + entry = (struct directory_entry *)fat_driver_buffer; + load_cluster(cluster = next_cluster(cluster), fat_driver_buffer); + } + + if (!*(uint8_t *)entry) { + d->done(d); + return count; + } + + if (check_fat_names(entry->name, this_dir) || check_fat_names(entry->name, parent_dir)) { + ++entry; + continue; + } + + ++entry; + ++count; + } +} + void init_fat() { next_fi = allocate_kernel_pages(1); next_id = 0; @@ -388,6 +454,7 @@ bool try_fat_init_drive(struct drive *d) { d->load_sector = &fat_load_sector; d->get_file_length = &fat_get_file_length; d->enumerate_dir = &fat_enumerate_dir; + d->n_dir_entries = &fat_n_dir_entries; d->get_free_sectors = &fat_get_free_sectors; d->fs_id = next_id; diff --git a/src/kernel/idt.c b/src/kernel/idt.c index 90d8dc3..1b8e548 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -8,6 +8,7 @@ #include "paging.h" #include "pmap.h" #include "kbd.h" +#include "vga.h" enum { IDT_PRESENT = 0x80, @@ -100,6 +101,10 @@ static uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries); } +static uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { + return drives[drive_number].n_dir_entries(drives + drive_number, path); +} + void const *syscall_table[] = { &sc_open_file, &sc_close_file, @@ -111,7 +116,11 @@ void const *syscall_table[] = { &sc_allocate_ram, &sc_memory_info, &sc_wait_for_task, - &sc_enumerate_dir + &sc_enumerate_dir, + &vga_print_at, + &sc_count_of_dir, + &vga_blank, + &vga_set_color }; //these aren't really void ()'s, but gcc complains if we take an address of a void, so we give it a type diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm index 6ad469d..e7573ae 100644 --- a/src/kernel/isrs.asm +++ b/src/kernel/isrs.asm @@ -23,7 +23,7 @@ extern on_kbd_isr extern make_sure_tasks extern exception_halt -n_syscalls equ 0xb +n_syscalls equ 0xf ;section .bss ;_debug_is_start_task resb 1 diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c index f3eb323..c251db7 100644 --- a/src/kernel/kbd.c +++ b/src/kernel/kbd.c @@ -226,19 +226,34 @@ static const uint8_t codes_e0[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#include "log.h" + +uint8_t get_code_byte() { + for (uint32_t spin = 0; spin < 10000000; ++spin) + ; + return inb(PS2_DATA); +} + void on_kbd_isr() { while (inb(PS2_CMD) & PS2S_CODE_READY) { - uint8_t code = inb(PS2_DATA); + //char nbuf[11]; + uint8_t code = get_code_byte(); + //logsz("code: 0x"); + //u8_hex(code, nbuf); + //logsz(nbuf); if (code == 0xe1) { - code = inb(PS2_DATA); + code = get_code_byte(); + //logsz(" 0x"); + //u8_hex(code, nbuf); + //logsz(nbuf); if (code == 0x1d) { - if (inb(PS2_DATA) != 0x45) + if (get_code_byte() != 0x45) code = 0; else code = CODE_PAUSE; } else if (code == 0x9d) { - if (inb(PS2_DATA) != 0xc5) + if (get_code_byte() != 0xc5) code = 0; else code = 0xff; @@ -247,17 +262,20 @@ void on_kbd_isr() { code = 0; } else if (code == 0xe0) { - code = inb(PS2_DATA); + code = get_code_byte(); + //logsz(" 0x"); + //u8_hex(code, nbuf); + //logsz(nbuf); if (code == 0x2a) { - if ((inb(PS2_DATA) != 0xe0) || - (inb(PS2_DATA) != 0x37)) + if ((get_code_byte() != 0xe0) || + (get_code_byte() != 0x37)) code = 0; else code = CODE_PRSCR; } else if (code == 0xb7) { - if ((inb(PS2_DATA) != 0xe0) || - (inb(PS2_DATA) != 0xaa)) + if ((get_code_byte() != 0xe0) || + (get_code_byte() != 0xaa)) code = 0; else code = 0xff; @@ -268,6 +286,8 @@ void on_kbd_isr() { else code = codes[code]; + //logch('\n'); + if (!code) PANIC("Unknown scancode."); diff --git a/src/kernel/main.c b/src/kernel/main.c index 06b83d1..b34f816 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -15,9 +15,6 @@ #include "vga.h" #include "kbd.h" -void reset_tree(); -void tree(struct drive *d); - void _start_user_mode() __attribute__ ((noreturn)); __attribute__ ((noreturn)) @@ -35,6 +32,7 @@ void main() { pci_init(); +/* u16_dec(n_pci_devices, nbuf); logsz(nbuf); logsz(" PCI device(s) found:\n"); @@ -63,6 +61,7 @@ void main() { } logch('\n'); +*/ init_fat(); //other fs drivers @@ -72,6 +71,7 @@ void main() { init_ide(); //other drive drivers +/* u8_dec(n_drives, nbuf); logsz(nbuf); logsz(" drive(s) found:\n"); @@ -108,20 +108,7 @@ void main() { } logch('\n'); - - for (uint8_t n = 0; n < n_drives; ++n) { - if (drives[n].get_free_sectors(drives + n) == -1) - continue; - - u32_dec(n, nbuf); - logsz("sd"); - logsz(nbuf); - logsz(" tree:\n"); - - reset_tree(); - tree(drives + n); - logch('\n'); - } +*/ if (BOOT_INFO->support_flags & BIS_PAE) logsz("Processor supports PAE (but Portland OS does not yet).\n"); diff --git a/src/kernel/main2.c b/src/kernel/main2.c deleted file mode 100644 index 27ef8de..0000000 --- a/src/kernel/main2.c +++ /dev/null @@ -1,69 +0,0 @@ -#include <stdint.h> -#include "drive.h" -#include "util.h" -#include "log.h" - -static char nbuf2[11]; - -static char path_builder[200]; -static uint8_t path_builder_len; - -static char indent_builder[20]; -static uint8_t indent_builder_len; - -void reset_tree() { - path_builder[0] = '\0'; - path_builder_len = 0; - - indent_builder[0] = ' '; - indent_builder[1] = ' '; - indent_builder[2] = '\0'; - indent_builder_len = 2; -} - -void tree(struct drive *d) { - struct directory_content_info infos[100]; - uint8_t n_infos = d->enumerate_dir(d, path_builder, infos, 100); - - if (!n_infos) { - logsz(indent_builder); - logsz("(empty)\n"); - return; - } - - for (uint8_t i = 0; i < n_infos; ++i) { - logsz(indent_builder); - logsz(infos[i].name); - - if (infos[i].is_dir) { - logsz(":\n"); - - indent_builder[indent_builder_len] = ' '; - indent_builder[indent_builder_len + 1] = ' '; - indent_builder[indent_builder_len + 2] = '\0'; - indent_builder_len += 2; - - uint8_t name_length = 0; - while (infos[i].name[name_length]) - ++name_length; - - memcpy(path_builder + path_builder_len, infos[i].name, name_length + 1); - path_builder_len += name_length; - - tree(d); - - path_builder_len -= name_length; - path_builder[path_builder_len] = '\0'; - - indent_builder_len -= 2; - indent_builder[indent_builder_len] = '\0'; - } - - else { - u32_dec(infos[i].size, nbuf2); - logsz(" ("); - logsz(nbuf2); - logsz(" bytes)\n"); - } - } -}
\ No newline at end of file diff --git a/src/kernel/vga.c b/src/kernel/vga.c index daa92fe..42da312 100644 --- a/src/kernel/vga.c +++ b/src/kernel/vga.c @@ -2,8 +2,9 @@ #include <stdint.h> #define VGA_COLUMNS 80 +#define VGA_ROWS 25 #define VGA_START (uint16_t *)0x000b8000 -#define VGA_END (VGA_START + VGA_COLUMNS * 25) +#define VGA_END (VGA_START + VGA_COLUMNS * VGA_ROWS) static uint16_t *cursor = VGA_START; static uint16_t mask; @@ -25,7 +26,7 @@ void vga_blank() { uint32_t *p = (uint32_t *)VGA_START; while (p < (uint32_t *)VGA_END) *p++ = f; - cursor = VGA_START; + cursor = VGA_END - VGA_COLUMNS; } void vga_printch(char ch) { @@ -37,4 +38,10 @@ void vga_printch(char ch) { *cursor++ = mask | (uint8_t)ch; if (cursor == VGA_END) vga_scroll(); +} + +void vga_print_at(uint16_t pos, const char *sz) { + cursor = VGA_START + (pos >> 8) * VGA_COLUMNS + (pos & 0xff); + while (*sz) + vga_printch(*sz++); }
\ No newline at end of file diff --git a/src/kernel/vga.h b/src/kernel/vga.h index bfc9fe6..fa97e11 100644 --- a/src/kernel/vga.h +++ b/src/kernel/vga.h @@ -3,6 +3,7 @@ #include <stdint.h> +void vga_print_at(uint16_t pos, const char *sz); void vga_set_color(uint8_t color); void vga_blank(); void vga_printch(char ch); diff --git a/src/user/dirinfo/dirinfo.c b/src/user/dirinfo/dirinfo.c index 7484eb8..21afcc7 100644 --- a/src/user/dirinfo/dirinfo.c +++ b/src/user/dirinfo/dirinfo.c @@ -13,7 +13,7 @@ void main(const char *arg) { tell_user_sz(*arg ? arg : "drive root"); tell_user_sz("\n"); - _dir_info_entry infos[MAX_DIR_ENTRIES]; + _dir_info_entry_t infos[MAX_DIR_ENTRIES]; uint8_t count = _enumerate_dir(dn, path, infos, MAX_DIR_ENTRIES); tell_user_sz( count == MAX_DIR_ENTRIES diff --git a/src/user/fileman/fileman.c b/src/user/fileman/fileman.c new file mode 100644 index 0000000..0b28d1d --- /dev/null +++ b/src/user/fileman/fileman.c @@ -0,0 +1,130 @@ +#include <pland/syscall.h> +#include <knob/block.h> +#include <knob/file.h> +#include <knob/heap.h> +#include <knob/task.h> + +char path_sz[1024] = ""; +uint32_t path_len = 0; + +_dir_info_entry_t *dir_info; +uint32_t dir_info_len; + +uint32_t scroll; +uint32_t selected; +#define MAX_PER_SCREEN 18 + +void paint_screen() { + _clear_screen(); + + _set_color(0x70); + _print_at(0, 0, path_sz); + _log_string("/"); + _set_color(0x07); + + for (uint32_t i = scroll, row = 2; (i < dir_info_len) && (row < MAX_PER_SCREEN + 2); ++i, ++row) { + if (i == selected) + _set_color(0x17); + _print_at(row, 0, dir_info[i].name); + if (dir_info[i].is_dir) + _log_string("/"); + if (i == selected) + _set_color(0x07); + } + + _print_at(21, 0, "keybindings:\n" + "UP, DOWN, PAGE UP, PAGE DOWN, HOME, END: move selection\n" + "ENTER: enter selected directory, run selected program\n" + "ESC: go up a directory Q: quit"); +} + +void load_dir() { + free_block(dir_info); + dir_info = get_directory_info(path_sz, &dir_info_len); + scroll = 0; + selected = 0; +} + +void main(const char *sz) { + path_len = strcpy(path_sz, sz); + dir_info = get_directory_info(sz, &dir_info_len); + + paint_screen(); + + while (true) { + _key_code_t key; + switch (key = _get_key()) { + case 0: + _yield_task(); + continue; + case '\n': + { + uint32_t old_len = path_len; + if (path_len) + path_sz[path_len++] = '/'; + path_len += strcpy(path_sz + path_len, dir_info[selected].name); + if (dir_info[selected].is_dir) + load_dir(); + else { + try_run_command_blocking(path_sz); + //TODO: handle error + path_sz[old_len] = '\0'; + path_len = old_len; + } + } + break; + case _KEY_ESC: + { + char *cutoff = path_sz; + for (char *i = path_sz + path_len - 1; i >= path_sz; --i) + if (*i == '/') { + cutoff = i; + break; + } + *cutoff = '\0'; + path_len = cutoff - path_sz; + load_dir(); + } + break; + case _KEY_HOME: + scroll = 0; + selected = 0; + break; + case _KEY_END: + selected = dir_info_len - 1; + scroll = dir_info_len >= MAX_PER_SCREEN + ? dir_info_len - MAX_PER_SCREEN : 0; + break; + case _KEY_UP: + if (!selected) + continue; + if (--selected < scroll) + scroll = selected; + break; + case _KEY_DOWN: + if (selected == dir_info_len - 1) + continue; + if (++selected >= scroll + MAX_PER_SCREEN) + ++scroll; + break; + case _KEY_PUP: + selected = selected >= MAX_PER_SCREEN + ? selected - MAX_PER_SCREEN : 0; + scroll = scroll >= MAX_PER_SCREEN + ? scroll - MAX_PER_SCREEN : 0; + break; + case _KEY_PDOWN: + if ((selected += MAX_PER_SCREEN) >= dir_info_len) + selected = dir_info_len - 1; + if ((scroll += MAX_PER_SCREEN) > selected) + scroll = selected; + break; + case 'q': + _clear_screen(); + return; + default: + continue; + } + paint_screen(); + } +}
\ No newline at end of file diff --git a/src/user/highway/line.c b/src/user/highway/line.c index ca38c9b..40dccfa 100644 --- a/src/user/highway/line.c +++ b/src/user/highway/line.c @@ -1,5 +1,5 @@ +#include <pland/pcrt.h> #include <knob/block.h> -#include <knob/quit.h> #include <knob/task.h> #include <knob/user.h> #include "cmds.h" @@ -68,7 +68,7 @@ void run_line(const char *original_line) { else if (blockequ(line, "vars", space - line)) dump_vars(); else if (blockequ(line, "quit", space - line)) - quit(space + 1); + __pcrt_quit(); else if (blockequ(line, "help", space - line)) tell_user_sz("Highway is a command shell for Portland OS. It includes variables and a couple\n" "of pseudo-commands. Variables are addressed by surrounding with \"$\". The\n" @@ -78,7 +78,7 @@ void run_line(const char *original_line) { " echo STRING print STRING\n" " vars dump variables\n" " quit exit highway\n" - " help show this\n\n"); + " help show this\n"); else if (!try_run_command_blocking(line)) { struct no_null_sn arg = { .data = "_path", diff --git a/src/user/highway/main.c b/src/user/highway/main.c index 1934920..61f736e 100644 --- a/src/user/highway/main.c +++ b/src/user/highway/main.c @@ -9,7 +9,7 @@ void main(const char *arg) { yield_task(); tell_user_sz("Portland Highway\nType \"help\" for help.\n"); while (1) { - tell_user_sz("> "); + tell_user_sz("\n> "); ask_user_line_sz(cmd_buf, 127); run_line(cmd_buf); } diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h index 4625577..43137e1 100644 --- a/src/user/include/knob/block.h +++ b/src/user/include/knob/block.h @@ -7,4 +7,7 @@ void blockcpy(void *to, const void *from, uint32_t size); bool blockequ(const void *a, const void *b, uint32_t size) __attribute__ ((__pure__)); +//returns length without null-terminator +uint32_t strcpy(char *to, const char *from); + #endif
\ No newline at end of file diff --git a/src/user/include/knob/file.h b/src/user/include/knob/file.h index a0d084f..8862098 100644 --- a/src/user/include/knob/file.h +++ b/src/user/include/knob/file.h @@ -2,6 +2,7 @@ #define KNOB_FILE_H #include <stdint.h> +#include <pland/syscall.h> struct file; @@ -9,7 +10,6 @@ const char *remove_prefix(const char *path, uint8_t *dn_out); struct file *open_file(const char *path); void close_file(struct file *f); -void _close_all_files(); uint32_t read_from_file(struct file *f, uint32_t max, void *buf); //return value and max_length don't include null terminator @@ -19,4 +19,7 @@ int32_t seek_file_by(struct file *f, int32_t by); uint32_t file_size(struct file *f) __attribute__ ((pure)); +//return value must be manually freed, unless it is a null pointer +_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out); + #endif
\ No newline at end of file diff --git a/src/user/include/knob/quit.h b/src/user/include/knob/quit.h deleted file mode 100644 index 7b10d09..0000000 --- a/src/user/include/knob/quit.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef KNOB_QUIT_H -#define KNOB_QUIT_H - -void on_quit(void (*run_f)()); -void quit() __attribute__ ((noreturn)); - -#endif
\ No newline at end of file diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h index 479a731..cd7676c 100644 --- a/src/user/include/knob/user.h +++ b/src/user/include/knob/user.h @@ -2,6 +2,9 @@ #define KNOB_USER_H #include <stdint.h> +#include <pland/syscall.h> + +char key_to_char(_key_code_t key) __attribute__ ((const)); void tell_user_sz(const char *sz); diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h new file mode 100644 index 0000000..07ad453 --- /dev/null +++ b/src/user/include/pland/pcrt.h @@ -0,0 +1,16 @@ +#ifndef PLAND_PCRT_H +#define PLAND_PCRT_H + +#define BEFORE_MAIN(f) \ + __attribute__ ((section (".__pcrt_before_main"))) \ + __attribute__ ((unused)) \ + void (*const __pcrt_bm_##f)() = &f; + +#define BEFORE_QUIT(f) \ + __attribute__ ((section (".__pcrt_before_quit"))) \ + __attribute__ ((unused)) \ + void (*const __pcrt_bq_##f)() = &f; + +void __pcrt_quit() __attribute__ ((noreturn)); + +#endif
\ No newline at end of file diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h index e16a7fb..331002e 100644 --- a/src/user/include/pland/syscall.h +++ b/src/user/include/pland/syscall.h @@ -7,14 +7,9 @@ typedef uint32_t _file_handle_t; typedef uint32_t _task_handle_t; typedef uint32_t _drive_number_t; -typedef uint32_t _pages_t; typedef uint32_t _process_handle_t; typedef enum { - _KEY_BACKSPACE = '\b', - _KEY_RETURN = '\n', - //etc. - _KEY_LSHIFT = 0x00000100, _KEY_RSHIFT = 0x00000200, _KEY_CAPS = 0x00000400, @@ -33,8 +28,103 @@ typedef enum { _KEY_ALT = 0x0000c000, _KEY_CTRL = 0x00030000, _KEY_META = 0x000c0000, + + _KEY_BEGIN_CAPS = 0x80, + _KEY_BEGIN_INSERT, + _KEY_BEGIN_NUM, + _KEY_BEGIN_SCROLL, + _KEY_BEGIN_LSHIFT, + _KEY_BEGIN_RSHIFT, + _KEY_BEGIN_LALT, + _KEY_BEGIN_RALT, + _KEY_BEGIN_LCTRL, + _KEY_BEGIN_RCTRL, + _KEY_BEGIN_LMETA, + _KEY_BEGIN_RMETA, + /* 0x8c - 0x97 reserved */ + /* 0x98 - 0x9f unassigned */ + _KEY_F1 = 0xa0, + _KEY_F2, + _KEY_F3, + _KEY_F4, + _KEY_F5, + _KEY_F6, + _KEY_F7, + _KEY_F8, + _KEY_F9, + _KEY_F10, + _KEY_F11, + _KEY_F12, + /* 0xac - 0xaf unassigned */ + _KEY_NUM0 = 0xb0, + _KEY_NUM1, + _KEY_NUM2, + _KEY_NUM3, + _KEY_NUM4, + _KEY_NUM5, + _KEY_NUM6, + _KEY_NUM7, + _KEY_NUM8, + _KEY_NUM9, + _KEY_NTIMES, + _KEY_NPLUS, + _KEY_NENTER, + _KEY_NMINUS, + _KEY_NDOT, + _KEY_NSLASH, + /* 0xc0 unassigned */ + _KEY_DELETE, + _KEY_HOME, + _KEY_END, + _KEY_PUP, + _KEY_PDOWN, + _KEY_UP, + _KEY_DOWN, + _KEY_LEFT, + _KEY_RIGHT, + _KEY_ESC, + _KEY_MENU, + _KEY_PAUSE, + _KEY_PRSCR, + /* 0xce - 0xef unassigned */ } _key_code_t; +typedef enum { + _COLOR_FG_BLACK = 0x00, + _COLOR_FG_BLUE = 0x01, + _COLOR_FG_GREEN = 0x02, + _COLOR_FG_CYAN = 0x03, + _COLOR_FG_RED = 0x04, + _COLOR_FG_MAGENTA = 0x05, + _COLOR_FG_BROWN = 0x06, + _COLOR_FG_LGRAY = 0x07, + + _COLOR_FG_DGRAY = 0x08, + _COLOR_FG_LBLUE = 0x09, + _COLOR_FG_LGREEN = 0x0a, + _COLOR_FG_LCYAN = 0x0b, + _COLOR_FG_LRED = 0x0c, + _COLOR_FG_PINK = 0x0d, + _COLOR_FG_YELLOW = 0x0e, + _COLOR_FG_WHITE = 0x0f, + + _COLOR_BG_BLACK = 0x00, + _COLOR_BG_BLUE = 0x10, + _COLOR_BG_GREEN = 0x20, + _COLOR_BG_CYAN = 0x30, + _COLOR_BG_RED = 0x40, + _COLOR_BG_MAGENTA = 0x50, + _COLOR_BG_BROWN = 0x60, + _COLOR_BG_LGRAY = 0x70 +} _vga_color_t; + +typedef struct __attribute__ ((packed)) { + char name[100]; + uint32_t size; + bool is_dir; + uint8_t pad[23]; +} _dir_info_entry_t; + enum _scn { _SCN_OPEN_FILE, _SCN_CLOSE_FILE, @@ -46,72 +136,74 @@ enum _scn { _SCN_ALLOCATE_RAM, _SCN_MEMORY_INFO, _SCN_WAIT_FOR_TASK, - _SCN_ENUMERATE_DIR + _SCN_ENUMERATE_DIR, + _SCN_PRINT_AT, + _SCN_COUNT_OF_DIR, + _SCN_CLEAR_SCREEN, + _SCN_SET_COLOR }; -typedef struct { - bool is_dir; - char name[100]; - uint32_t size; -} _dir_info_entry; - static inline uint32_t _sc0(enum _scn eax) { - volatile uint32_t out; - asm ( + uint32_t out; + asm volatile ( "int $0x30" : "=a" (out) : "a" (eax) : "ecx", "edx"); return out; } static inline uint32_t _sc1(enum _scn eax, uint32_t ebx) { - volatile uint32_t out; - asm ( + uint32_t out; + asm volatile ( "int $0x30" : "=a" (out) : "a" (eax), "b" (ebx) : "ecx", "edx"); return out; } static inline uint32_t _sc2(enum _scn eax, uint32_t ebx, uint32_t ecx) { - volatile uint32_t out; - asm ( + uint32_t out; + uint32_t dummy; + asm volatile ( "int $0x30" - : "=a" (out) : "a" (eax), "b" (ebx), "c" (ecx) : "edx"); + : "=a" (out), "=c" (dummy) : "a" (eax), "b" (ebx), "c" (ecx) : "edx"); return out; } static inline uint32_t _sc3(enum _scn eax, uint32_t ebx, uint32_t ecx, uint32_t edx) { - volatile uint32_t out; - asm ( + uint32_t out; + uint32_t dummy; + asm volatile ( "int $0x30" - : "=a" (out) : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx)); + : "=a" (out), "=c" (dummy), "=d" (dummy) : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx)); return out; } static inline uint32_t _sc4(enum _scn eax, uint32_t ebx, uint32_t ecx, uint32_t edx, uint32_t esi) { - volatile uint32_t out; - asm ( + uint32_t out; + uint32_t dummy; + asm volatile ( "int $0x30" - : "=a" (out) : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi)); + : "=a" (out), "=c" (dummy), "=d" (dummy) : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi)); return out; } static inline uint32_t _sc5(enum _scn eax, uint32_t ebx, uint32_t ecx, uint32_t edx, uint32_t esi, uint32_t edi) { - volatile uint32_t out; - asm ( + uint32_t out; + uint32_t dummy; + asm volatile ( "int $0x30" - : "=a" (out) : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi)); + : "=a" (out), "=c" (dummy), "=d" (dummy) : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi)); return out; } static inline void _yield_task() { - asm ( + asm volatile ( "int $0x39" : : : "eax"); } __attribute__ ((noreturn)) static inline void _exit_task() { - asm ( + asm volatile ( "int $0x38" ); __builtin_unreachable(); @@ -145,27 +237,27 @@ static inline _key_code_t _get_key() { return _sc0(_SCN_GET_KEY); } -static inline void *_allocate_ram(_pages_t pages) { +static inline void *_allocate_ram(uint32_t pages) { return (void *)_sc1(_SCN_ALLOCATE_RAM, pages); } -static inline _pages_t _kernel_dynamic_area_size() { +static inline uint32_t _kernel_dynamic_area_size() { return _sc1(_SCN_MEMORY_INFO, 0x0); } -static inline _pages_t _kernel_dynamic_area_left() { +static inline uint32_t _kernel_dynamic_area_left() { return _sc1(_SCN_MEMORY_INFO, 0x1); } -static inline _pages_t _total_userspace_size() { +static inline uint32_t _total_userspace_size() { return _sc1(_SCN_MEMORY_INFO, 0x2); } -static inline _pages_t _total_userspace_left() { +static inline uint32_t _total_userspace_left() { return _sc1(_SCN_MEMORY_INFO, 0x3); } -static inline _pages_t _this_process_memory_left() { +static inline uint32_t _this_process_memory_left() { return _sc1(_SCN_MEMORY_INFO, 0x4); } @@ -173,8 +265,24 @@ static inline void _wait_for_task(_process_handle_t handle) { _sc1(_SCN_WAIT_FOR_TASK, handle); } -static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char *path, _dir_info_entry *buffer, uint32_t max_count) { +static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char *path, _dir_info_entry_t *buffer, uint32_t max_count) { return _sc4(_SCN_ENUMERATE_DIR, drive_number, (uint32_t)path, (uint32_t)buffer, max_count); } +static inline void _print_at(uint8_t row, uint8_t col, const char *sz) { + _sc2(_SCN_PRINT_AT, (row << 8) | col, (uint32_t)sz); +} + +static inline uint32_t _count_of_dir(uint8_t drive_number, const char *path) { + return _sc2(_SCN_COUNT_OF_DIR, drive_number, (uint32_t)path); +} + +static inline void _clear_screen() { + _sc0(_SCN_CLEAR_SCREEN); +} + +static inline void _set_color(_vga_color_t color) { + _sc1(_SCN_SET_COLOR, color); +} + #endif
\ No newline at end of file diff --git a/src/user/knob/block.c b/src/user/knob/block.c index 7524ad3..4ec0564 100644 --- a/src/user/knob/block.c +++ b/src/user/knob/block.c @@ -14,4 +14,13 @@ bool blockequ(const void *a, const void *b, uint32_t size) { if (*(uint8_t *)(a++) != *(uint8_t *)(b++)) return false; return true; +} + +//returns length without null-terminator +uint32_t strcpy(char *to, const char *from) { + uint32_t i = 0; + do + to[i] = from[i]; + while (from[i++]); + return i - 1; }
\ No newline at end of file diff --git a/src/user/knob/entry.asm b/src/user/knob/entry.asm deleted file mode 100644 index e9548d4..0000000 --- a/src/user/knob/entry.asm +++ /dev/null @@ -1,23 +0,0 @@ -bits 32 - -global _entry - -extern main -extern quit - -extern current_disk - -section .text -_entry: - mov esp, stack - push edx - - ;TODO: determine current_disk - ;any further needed initialization - - push quit - jmp main - -section .stack nobits alloc noexec write align=16 -resb 4096 -stack:
\ No newline at end of file diff --git a/src/user/knob/file.c b/src/user/knob/file.c index 23b7564..f1a039d 100644 --- a/src/user/knob/file.c +++ b/src/user/knob/file.c @@ -1,4 +1,5 @@ #include <pland/syscall.h> +#include <pland/pcrt.h> #include <knob/format.h> #include <knob/heap.h> #include <knob/env.h> @@ -11,11 +12,13 @@ struct ofl_node { static struct ofl_node *head_ofl_node = 0; -void _close_all_files() { +static void _close_all_files() { for (struct ofl_node *i = head_ofl_node; i; i = i->next) _close_file(i->handle); } +BEFORE_QUIT(_close_all_files) + struct file { struct ofl_node *node; _file_handle_t handle; @@ -121,4 +124,20 @@ int32_t seek_file_by(struct file *f, int32_t by) { __attribute__ ((pure)) uint32_t file_size(struct file *f) { return f->length; +} + +//return value must be manually freed, unless it is a null pointer +_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out) { + uint8_t dn; + path = remove_prefix(path, &dn); + + uint32_t count = _count_of_dir(dn, path); + if (!count) { + *count_out = 0; + return 0; + } + + _dir_info_entry_t *buffer = get_block(count * sizeof(_dir_info_entry_t)); + *count_out = _enumerate_dir(dn, path, buffer, count); + return buffer; }
\ No newline at end of file diff --git a/src/user/knob/quit.c b/src/user/knob/quit.c deleted file mode 100644 index 98881b7..0000000 --- a/src/user/knob/quit.c +++ /dev/null @@ -1,8 +0,0 @@ -#include <pland/syscall.h> -#include <knob/file.h> - -__attribute__ ((noreturn)) -void quit() { - _close_all_files(); - _exit_task(); -}
\ No newline at end of file diff --git a/src/user/knob/user.c b/src/user/knob/user.c index b642f79..dfcb791 100644 --- a/src/user/knob/user.c +++ b/src/user/knob/user.c @@ -116,10 +116,8 @@ static const uint8_t shifted[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static char get_key_char() { - _key_code_t key; - while (!(key = _get_key())) - _yield_task(); +__attribute__ ((const)) +char key_to_char(_key_code_t key) { return key & _KEY_CAPS ? key & _KEY_SHIFT @@ -130,6 +128,13 @@ static char get_key_char() { : key & 0xff; } +static char get_key_char() { + _key_code_t key; + while (!(key = _get_key())) + _yield_task(); + return key_to_char(key); +} + void tell_user_sz(const char *sz) { _log_string(sz); } diff --git a/src/user/elf.ld b/src/user/runtimes/asm/elf.ld index aaef517..aaef517 100644 --- a/src/user/elf.ld +++ b/src/user/runtimes/asm/elf.ld diff --git a/src/user/runtimes/c/elf.ld b/src/user/runtimes/c/elf.ld new file mode 100644 index 0000000..f321be2 --- /dev/null +++ b/src/user/runtimes/c/elf.ld @@ -0,0 +1,22 @@ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) +ENTRY(__pcrt_entry) + +MEMORY { + kernel (!a) : ORIGIN = 0x00000000, LENGTH = 0x08000000 + user (awx) : ORIGIN = 0x08000000, LENGTH = 0xf8000000 +} + +SECTIONS { + .__pcrt_before_main : { + __pcrt_before_main_start = .; + *(.__pcrt_before_main) + __pcrt_before_main_end = .; + } + + .__pcrt_before_quit : { + __pcrt_before_quit_start = .; + *(.__pcrt_before_quit) + __pcrt_before_quit_end = .; + } +}
\ No newline at end of file diff --git a/src/user/runtimes/c/entry.asm b/src/user/runtimes/c/entry.asm new file mode 100644 index 0000000..bba8060 --- /dev/null +++ b/src/user/runtimes/c/entry.asm @@ -0,0 +1,42 @@ +bits 32 + +global __pcrt_entry +global __pcrt_quit + +extern main +extern __pcrt_before_main_start +extern __pcrt_before_main_end +extern __pcrt_before_quit_start +extern __pcrt_before_quit_end + +section .text +__pcrt_entry: + mov esp, stack + push edx + + mov ebx, __pcrt_before_main_start +.before_main_loop: + cmp ebx, __pcrt_before_main_end + je .call_main + call dword [ebx] + add ebx, 4 + jmp .before_main_loop + +.call_main: + call main + +__pcrt_quit: + mov ebx, __pcrt_before_quit_start +.before_quit_loop: + cmp ebx, __pcrt_before_quit_end + je .end_task + call dword [ebx] + add ebx, 4 + jmp .before_quit_loop + +.end_task: + int 0x38 + +section .stack nobits alloc noexec write align=16 +resb 4096 +stack:
\ No newline at end of file |