From 1d5e56659af7945daac0f79a06b839bfd59c8f1f Mon Sep 17 00:00:00 2001 From: dzwdz Date: Mon, 4 Oct 2021 21:01:31 +0200 Subject: remove support for processes returning strings on exit This isn't really all that useful, it doesn't enable anything that wasn't possible before. With it removed I'll be able to implement process_exit() in a much simpler way. --- src/init/main.c | 20 ++++++++------------ src/init/syscalls.c | 8 ++++---- src/kernel/proc.c | 10 +++------- src/kernel/proc.h | 5 +---- src/kernel/syscalls.c | 22 ++++++++-------------- src/shared/syscalls.h | 8 ++++---- 6 files changed, 28 insertions(+), 45 deletions(-) diff --git a/src/init/main.c b/src/init/main.c index 5c798d2..71a2d4e 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -23,7 +23,7 @@ int main(void) { tty_fd = _syscall_open("/tty", sizeof("/tty") - 1); if (tty_fd < 0) - _syscall_exit(argify("couldn't open tty")); + _syscall_exit(1); fs_test(); test_await(); @@ -32,7 +32,7 @@ int main(void) { while (_syscall_read(tty_fd, &c, 1, 0)) _syscall_write(tty_fd, &c, 1, 0); - _syscall_exit(argify("my job here is done.")); + _syscall_exit(0); } void read_file(const char *path, size_t len) { @@ -83,19 +83,15 @@ void fs_test(void) { } void test_await(void) { - char buf[16]; - int len; + int ret; - // the child immediately dies - if (!_syscall_fork()) - _syscall_exit(argify("i'm dead")); - if (!_syscall_fork()) - _syscall_exit(argify("i'm also dead")); + if (!_syscall_fork()) _syscall_exit(69); + if (!_syscall_fork()) _syscall_exit(420); - while ((len = _syscall_await(buf, 16)) >= 0) { + while ((ret = _syscall_await()) != ~0) { log("await returned: "); - _syscall_write(tty_fd, buf, len, 0); + //_syscall_write(tty_fd, buf, len, 0); TODO printf log("\n"); } - log("await: negative len\n"); + log("await: no more children\n"); } diff --git a/src/init/syscalls.c b/src/init/syscalls.c index f32594e..57a7344 100644 --- a/src/init/syscalls.c +++ b/src/init/syscalls.c @@ -1,8 +1,8 @@ // this file could probably just get generated by a script #include -_Noreturn void _syscall_exit(const char __user *msg, size_t len) { - _syscall(_SYSCALL_EXIT, (int)msg, len, 0, 0); +_Noreturn void _syscall_exit(int ret) { + _syscall(_SYSCALL_EXIT, ret, 0, 0, 0); __builtin_unreachable(); } @@ -10,8 +10,8 @@ int _syscall_fork(void) { return _syscall(_SYSCALL_FORK, 0, 0, 0, 0); } -int _syscall_await(char __user *buf, int len) { - return _syscall(_SYSCALL_AWAIT, (int)buf, (int)len, 0, 0); +int _syscall_await(void) { + return _syscall(_SYSCALL_AWAIT, 0, 0, 0, 0); } handle_t _syscall_open(const char __user *path, int len) { diff --git a/src/kernel/proc.c b/src/kernel/proc.c index b9f96c8..b1dc5c1 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -115,16 +115,12 @@ int process_try2collect(struct process *dead) { dead->state = PS_DEADER; parent->state = PS_RUNNING; - len = min(parent->death_msg.len, dead->death_msg.len); - res = virt_cpy( - parent->pages, parent->death_msg.buf, - dead->pages, dead->death_msg.buf, len); - - ret = res ? len : 0; + ret = dead->death_msg; regs_savereturn(&parent->regs, ret); return ret; default: - return -1; + return -1; // this return value isn't used anywhere + // TODO enforce that, somehow? idk } } diff --git a/src/kernel/proc.h b/src/kernel/proc.h index 82bb59a..592451c 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -26,10 +26,7 @@ struct process { // saved value, meaning depends on .state union { - struct { // PS_DEAD, PS_WAITS4CHILDDEATH - char __user *buf; - size_t len; - } death_msg; + int death_msg; // PS_DEAD struct vfs_request pending_req; // PS_WAITS4FS struct { char __user *buf; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 1b91eb7..c89efc7 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -8,28 +8,22 @@ #include #include -_Noreturn void _syscall_exit(const char __user *msg, size_t len) { +_Noreturn void _syscall_exit(int ret) { process_current->state = PS_DEAD; - process_current->death_msg.buf = (userptr_t) msg; // discarding const - process_current->death_msg.len = len; + process_current->death_msg = ret; process_try2collect(process_current); process_switch_any(); } -int _syscall_await(char __user *buf, int len) { +int _syscall_await(void) { bool has_children = false; process_current->state = PS_WAITS4CHILDDEATH; - process_current->death_msg.buf = buf; - process_current->death_msg.len = len; // find any already dead children for (struct process *iter = process_current->child; iter; iter = iter->sibling) { - if (iter->state == PS_DEAD) { - int ret = process_try2collect(iter); - assert(ret >= 0); - return ret; - } + if (iter->state == PS_DEAD) + return process_try2collect(iter); if (iter->state != PS_DEADER) has_children = true; } @@ -38,7 +32,7 @@ int _syscall_await(char __user *buf, int len) { process_switch_any(); // wait until a child dies else { process_current->state = PS_RUNNING; - return -1; // error + return ~0; // TODO errno } } @@ -276,9 +270,9 @@ int _syscall_memflag(void __user *addr, size_t len, int flags) { int _syscall(int num, int a, int b, int c, int d) { switch (num) { case _SYSCALL_EXIT: - _syscall_exit((userptr_t)a, b); + _syscall_exit(a); case _SYSCALL_AWAIT: - return _syscall_await((userptr_t)a, b); + return _syscall_await(); case _SYSCALL_FORK: return _syscall_fork(); case _SYSCALL_OPEN: diff --git a/src/shared/syscalls.h b/src/shared/syscalls.h index 44a2f5d..3a21b66 100644 --- a/src/shared/syscalls.h +++ b/src/shared/syscalls.h @@ -27,12 +27,12 @@ int _syscall(int, int, int, int, int); /** Kills the current process. * TODO: what happens to the children? */ -_Noreturn void _syscall_exit(const char __user *msg, size_t len); +_Noreturn void _syscall_exit(int ret); -/** Waits for a child to exit, putting its exit message into *buf. - * @return the length of the message +/** Waits for a child to exit. + * @return the value the child passed to exit() */ -int _syscall_await(char __user *buf, int len); +int _syscall_await(void); /** Creates a copy of the current process, and executes it. * All user memory pages get copied too. -- cgit v1.2.3 From 33ef18732abb1ec03469b7c0fe271a6599318682 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Mon, 4 Oct 2021 21:37:01 +0200 Subject: implement process_kill() --- src/kernel/proc.c | 6 ++++++ src/kernel/proc.h | 2 ++ src/kernel/syscalls.c | 4 +--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/kernel/proc.c b/src/kernel/proc.c index b1dc5c1..47fd2ec 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -103,6 +103,12 @@ handle_t process_find_handle(struct process *proc) { return handle; } +void process_kill(struct process *proc, int ret) { + proc->state = PS_DEAD; + proc->death_msg = ret; + process_try2collect(proc); +} + int process_try2collect(struct process *dead) { struct process *parent = dead->parent; int len, ret; diff --git a/src/kernel/proc.h b/src/kernel/proc.h index 592451c..7c338bb 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -53,6 +53,8 @@ _Noreturn void process_switch_any(void); // switches to any running process struct process *process_find(enum process_state); handle_t process_find_handle(struct process *proc); // finds the first free handle +void process_kill(struct process *proc, int ret); + /** Tries to transistion from PS_DEAD to PS_DEADER. * @return a nonnegative length of the quit message if successful, a negative val otherwise*/ int process_try2collect(struct process *dead); diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index c89efc7..22bf1f6 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -9,9 +9,7 @@ #include _Noreturn void _syscall_exit(int ret) { - process_current->state = PS_DEAD; - process_current->death_msg = ret; - process_try2collect(process_current); + process_kill(process_current, ret); process_switch_any(); } -- cgit v1.2.3 From bb2c65663dd03aaf1948c36c7e6006af7e3840a6 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Mon, 4 Oct 2021 21:37:20 +0200 Subject: remove unused variables in process_try2collect --- src/kernel/proc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/kernel/proc.c b/src/kernel/proc.c index 47fd2ec..17af0cd 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -111,8 +111,7 @@ void process_kill(struct process *proc, int ret) { int process_try2collect(struct process *dead) { struct process *parent = dead->parent; - int len, ret; - bool res; + int ret; assert(dead->state == PS_DEAD); -- cgit v1.2.3 From 8d3ef773f8daea3a0c2b110ab48f235f5d2bf22d Mon Sep 17 00:00:00 2001 From: dzwdz Date: Tue, 5 Oct 2021 20:57:01 +0200 Subject: kill the process that caused an exception instead of panicking --- src/init/main.c | 13 +++++++++++++ src/kernel/arch/i386/interrupts/isr.c | 27 +++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/init/main.c b/src/init/main.c index 71a2d4e..ec6d5be 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -85,9 +85,22 @@ void fs_test(void) { void test_await(void) { int ret; + // regular exit()s if (!_syscall_fork()) _syscall_exit(69); if (!_syscall_fork()) _syscall_exit(420); + // faults + if (!_syscall_fork()) { // invalid memory access + asm volatile("movb $69, 0" ::: "memory"); + log("this shouldn't happen"); + _syscall_exit(-1); + } + if (!_syscall_fork()) { // #GP + asm volatile("hlt" ::: "memory"); + log("this shouldn't happen"); + _syscall_exit(-1); + } + while ((ret = _syscall_await()) != ~0) { log("await returned: "); //_syscall_write(tty_fd, buf, len, 0); TODO printf diff --git a/src/kernel/arch/i386/interrupts/isr.c b/src/kernel/arch/i386/interrupts/isr.c index dacecba..6701d58 100644 --- a/src/kernel/arch/i386/interrupts/isr.c +++ b/src/kernel/arch/i386/interrupts/isr.c @@ -1,29 +1,40 @@ #include #include #include +#include #include #include -#define log_n_panic(x) {tty_const(x); panic_unimplemented();} // TODO kill the current process instead of panicking - bool isr_test_interrupt_called = false; +/** Kills the process that caused the exception */ +_Noreturn static void exception_finish(void) { + // TODO check if the exception was in the kernel + process_kill(process_current, 0); // TODO make the return code mean something + process_switch_any(); +} + void isr_stage3(int interrupt) { switch (interrupt) { - case 0x08: log_n_panic("#DF"); // double fault - case 0x0D: log_n_panic("#GP"); // general protection fault + case 0x08: // double fault + tty_const("#DF"); + panic_invalid_state(); + case 0x0D: // general protection fault + exception_finish(); case 0x0E: { // page fault - int cr2; + /*int cr2; tty_const("#PF at "); asm ("mov %%cr2, %0;" : "=r"(cr2) ::); - _tty_var(cr2); - panic_unimplemented(); + _tty_var(cr2);*/ + exception_finish(); } case 0x34: isr_test_interrupt_called = true; return; - default: log_n_panic("unknown interrupt"); + default: + tty_const("unknown interrupt"); + panic_unimplemented(); } } -- cgit v1.2.3 From 1ee734761a3eecbdaf9631a653dee668d2de26ef Mon Sep 17 00:00:00 2001 From: dzwdz Date: Tue, 5 Oct 2021 21:00:02 +0200 Subject: isr: simplify the exception handler --- src/kernel/arch/i386/interrupts/isr.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/kernel/arch/i386/interrupts/isr.c b/src/kernel/arch/i386/interrupts/isr.c index 6701d58..9d8bb6c 100644 --- a/src/kernel/arch/i386/interrupts/isr.c +++ b/src/kernel/arch/i386/interrupts/isr.c @@ -7,34 +7,18 @@ bool isr_test_interrupt_called = false; -/** Kills the process that caused the exception */ -_Noreturn static void exception_finish(void) { - // TODO check if the exception was in the kernel - process_kill(process_current, 0); // TODO make the return code mean something - process_switch_any(); -} - void isr_stage3(int interrupt) { switch (interrupt) { case 0x08: // double fault tty_const("#DF"); panic_invalid_state(); - case 0x0D: // general protection fault - exception_finish(); - case 0x0E: { // page fault - /*int cr2; - tty_const("#PF at "); - asm ("mov %%cr2, %0;" : "=r"(cr2) ::); - _tty_var(cr2);*/ - exception_finish(); - } - case 0x34: isr_test_interrupt_called = true; return; default: - tty_const("unknown interrupt"); - panic_unimplemented(); + // TODO check if the exception was in the kernel + process_kill(process_current, interrupt); + process_switch_any(); } } -- cgit v1.2.3 From a3469d648a4d0f276d979ceb14b8716b46f4f72e Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 06:28:04 +0000 Subject: init: printf base --- src/init/main.c | 3 +++ src/init/stdlib.c | 18 ++++++++++++++++++ src/init/stdlib.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/src/init/main.c b/src/init/main.c index ec6d5be..a819152 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -28,6 +29,8 @@ int main(void) { fs_test(); test_await(); + printf("printf test\n"); + char c; while (_syscall_read(tty_fd, &c, 1, 0)) _syscall_write(tty_fd, &c, 1, 0); diff --git a/src/init/stdlib.c b/src/init/stdlib.c index 6ed5a0a..ac80c28 100644 --- a/src/init/stdlib.c +++ b/src/init/stdlib.c @@ -1,4 +1,6 @@ #include +#include +#include int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *c1 = s1, *c2 = s2; @@ -10,3 +12,19 @@ int memcmp(const void *s1, const void *s2, size_t n) { } return 0; } + +int printf(const char *fmt, ...) { + const char *seg = fmt; // beginning of the current segment + int total = 0; + va_list argp; + va_start(argp, fmt); + for (;;) { + char c = *fmt++; + switch (c) { + case '\0': + // TODO don't assume that stdout is @ fd 0 + _syscall_write(0, seg, fmt - seg, 0); + return total + (fmt - seg); + } + } +} diff --git a/src/init/stdlib.h b/src/init/stdlib.h index 1cabc7a..357a396 100644 --- a/src/init/stdlib.h +++ b/src/init/stdlib.h @@ -5,3 +5,5 @@ // stb-style header file int memcmp(const void *s1, const void *s2, size_t n); + +int printf(const char *fmt, ...); -- cgit v1.2.3 From 381f9b26bd31072530d795c38c19ce3dd69954a6 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 06:32:29 +0000 Subject: init: implement strlen --- src/init/stdlib.c | 6 ++++++ src/init/stdlib.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/init/stdlib.c b/src/init/stdlib.c index ac80c28..56d6da6 100644 --- a/src/init/stdlib.c +++ b/src/init/stdlib.c @@ -13,6 +13,12 @@ int memcmp(const void *s1, const void *s2, size_t n) { return 0; } +size_t strlen(const char *s) { + size_t c = 0; + while (*s++) c++; + return c; +} + int printf(const char *fmt, ...) { const char *seg = fmt; // beginning of the current segment int total = 0; diff --git a/src/init/stdlib.h b/src/init/stdlib.h index 357a396..3e56beb 100644 --- a/src/init/stdlib.h +++ b/src/init/stdlib.h @@ -6,4 +6,6 @@ int memcmp(const void *s1, const void *s2, size_t n); +size_t strlen(const char *s); + int printf(const char *fmt, ...); -- cgit v1.2.3 From 44d308149282debf314cb48789b9084767c1c288 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 06:34:23 +0000 Subject: init printf: implement %s --- src/init/main.c | 2 +- src/init/stdlib.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/init/main.c b/src/init/main.c index a819152..7c827eb 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -29,7 +29,7 @@ int main(void) { fs_test(); test_await(); - printf("printf test\n"); + printf("%s\n", "printf test"); char c; while (_syscall_read(tty_fd, &c, 1, 0)) diff --git a/src/init/stdlib.c b/src/init/stdlib.c index 56d6da6..876c74c 100644 --- a/src/init/stdlib.c +++ b/src/init/stdlib.c @@ -29,8 +29,22 @@ int printf(const char *fmt, ...) { switch (c) { case '\0': // TODO don't assume that stdout is @ fd 0 - _syscall_write(0, seg, fmt - seg, 0); - return total + (fmt - seg); + _syscall_write(0, seg, fmt - seg - 1, 0); + return total + (fmt - seg - 1); + + case '%': + _syscall_write(0, seg, fmt - seg - 1, 0); + total += fmt - seg - 1; + c = *fmt++; + switch (c) { + case 's': + const char *s = va_arg(argp, char*); + _syscall_write(0, s, strlen(s), 0); + total += strlen(s); + break; + } + seg = fmt; + break; } } } -- cgit v1.2.3 From a41f08402e78e9066551d72a9835a352db4069e4 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 06:43:27 +0000 Subject: init printf: implement %x --- src/init/main.c | 2 +- src/init/stdlib.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/init/main.c b/src/init/main.c index 7c827eb..2029bc9 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -29,7 +29,7 @@ int main(void) { fs_test(); test_await(); - printf("%s\n", "printf test"); + printf("%s %x\n", "printf test", 0xACAB1312); char c; while (_syscall_read(tty_fd, &c, 1, 0)) diff --git a/src/init/stdlib.c b/src/init/stdlib.c index 876c74c..a60854b 100644 --- a/src/init/stdlib.c +++ b/src/init/stdlib.c @@ -42,6 +42,21 @@ int printf(const char *fmt, ...) { _syscall_write(0, s, strlen(s), 0); total += strlen(s); break; + + case 'x': + unsigned int n = va_arg(argp, int); + size_t i = 4; // nibbles * 4 + while (n >> i && i < (sizeof(int) * 8)) + i += 4; + + while (i > 0) { + i -= 4; + char h = '0' + ((n >> i) & 0xf); + if (h > '9') h += 'a' - '9' - 1; + _syscall_write(0, &h, 1, 0); + total++; + } + break; } seg = fmt; break; -- cgit v1.2.3 From 0cd25153a0556b988959c10c5ecab04cbacc9506 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 19:24:18 +0200 Subject: init: use printf for output --- src/init/main.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/init/main.c b/src/init/main.c index 2029bc9..401e4a0 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -5,7 +5,6 @@ #include #define argify(str) str, sizeof(str) - 1 -#define log(str) _syscall_write(tty_fd, argify(str), 0) extern char _bss_start; // provided by the linker extern char _bss_end; @@ -29,8 +28,6 @@ int main(void) { fs_test(); test_await(); - printf("%s %x\n", "printf test", 0xACAB1312); - char c; while (_syscall_read(tty_fd, &c, 1, 0)) _syscall_write(tty_fd, &c, 1, 0); @@ -44,9 +41,9 @@ void read_file(const char *path, size_t len) { int buf_len = 64; _syscall_write(tty_fd, path, len, 0); - log(": "); + printf(": "); if (fd < 0) { - log("couldn't open.\n"); + printf("couldn't open.\n"); return; } @@ -67,7 +64,7 @@ void fs_test(void) { } // parent: accesses the fs - log("\n\n"); + printf("\n\n"); // the trailing slash should be ignored by mount() _syscall_mount(front, argify("/init/")); read_file(argify("/init/fake.txt")); @@ -75,14 +72,14 @@ void fs_test(void) { read_file(argify("/init/2.txt")); read_file(argify("/init/dir/3.txt")); - log("\nshadowing /init/dir...\n"); + printf("\nshadowing /init/dir...\n"); _syscall_mount(-1, argify("/init/dir")); read_file(argify("/init/fake.txt")); read_file(argify("/init/1.txt")); read_file(argify("/init/2.txt")); read_file(argify("/init/dir/3.txt")); - log("\n"); + printf("\n"); } void test_await(void) { @@ -95,19 +92,16 @@ void test_await(void) { // faults if (!_syscall_fork()) { // invalid memory access asm volatile("movb $69, 0" ::: "memory"); - log("this shouldn't happen"); + printf("this shouldn't happen"); _syscall_exit(-1); } if (!_syscall_fork()) { // #GP asm volatile("hlt" ::: "memory"); - log("this shouldn't happen"); + printf("this shouldn't happen"); _syscall_exit(-1); } - while ((ret = _syscall_await()) != ~0) { - log("await returned: "); - //_syscall_write(tty_fd, buf, len, 0); TODO printf - log("\n"); - } - log("await: no more children\n"); + while ((ret = _syscall_await()) != ~0) + printf("await returned: %x\n", ret); + printf("await: no more children\n"); } -- cgit v1.2.3 From 7e326b5039bff4d422f66bb8e51267f785193985 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Wed, 6 Oct 2021 22:15:02 +0200 Subject: kernel/i386: implement part of ATA IDENTIFY --- Makefile | 5 +++- src/kernel/arch/i386/ata.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/kernel/arch/i386/ata.h | 4 +++ src/kernel/arch/i386/boot.c | 7 +++-- 4 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/kernel/arch/i386/ata.c create mode 100644 src/kernel/arch/i386/ata.h diff --git a/Makefile b/Makefile index 08bb5d6..7757c25 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,10 @@ endef all: out/boot.iso check boot: all - qemu-system-i386 -cdrom out/boot.iso $(QFLAGS) -no-shutdown + touch out/disk # TODO this is temporary + qemu-system-i386 -cdrom out/boot.iso $(QFLAGS) -no-shutdown \ + -drive file=out/disk,format=raw,media=disk + debug: all qemu-system-i386 -cdrom out/boot.iso $(QFLAGS) -s -S & diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c new file mode 100644 index 0000000..996fa3a --- /dev/null +++ b/src/kernel/arch/i386/ata.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#include + +enum { + LBAlo = 3, + LBAmid = 4, + LBAhi = 5, + DRV = 6, + CMD = 7, + STATUS = 7, +}; // offsets + +// get I/O port base for drive +static uint16_t ata_iobase(int drive) { + bool secondary = drive&2; + return secondary ? 0x170 : 0x1F0; +} + +static void ata_driveselect(int drive, int block) { + uint8_t v = 0xE0; + if (drive&1) // slave? + v |= 0x10; // set drive number bit + // TODO account for block + port_outb(ata_iobase(drive) + DRV, v); +} + +static bool ata_identify(int drive) { + uint16_t iobase = ata_iobase(drive); + uint8_t v; + + ata_driveselect(drive, 0); + for (int i = 2; i < 6; i++) + port_outb(iobase + i, 0); + port_outb(iobase + CMD, 0xEC); // IDENTIFY + + v = port_inb(iobase + STATUS); + if (v == 0) return false; // nonexistent drive + while (port_inb(iobase + STATUS) & 0x80); + + /* check for uncomformant devices, quit early */ + if (port_inb(iobase + LBAmid) || port_inb(iobase + LBAhi)) { + // TODO atapi + return true; + } + /* pool until bit 3 (DRQ) or 0 (ERR) is set */ + while (!((v = port_inb(iobase + STATUS) & 0x9))); + if (v & 1) return false; /* ERR was set, bail */ + + // now I can read 512 bytes of data, TODO + return true; +} + +void ata_init(void) { + tty_const("\n"); + for (int i = 0; i < 4; i++) { + tty_const("probing drive "); + _tty_var(i); + if (ata_identify(i)) + tty_const(" - exists"); + tty_const("\n"); + } +} diff --git a/src/kernel/arch/i386/ata.h b/src/kernel/arch/i386/ata.h new file mode 100644 index 0000000..9137cdb --- /dev/null +++ b/src/kernel/arch/i386/ata.h @@ -0,0 +1,4 @@ +#pragma once +#include + +void ata_init(void); diff --git a/src/kernel/arch/i386/boot.c b/src/kernel/arch/i386/boot.c index bd2a00b..94e9e2f 100644 --- a/src/kernel/arch/i386/boot.c +++ b/src/kernel/arch/i386/boot.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -15,7 +16,9 @@ void kmain_early(struct multiboot_info *multiboot) { gdt_init(); tty_const("idt..."); idt_init(); - + tty_const("ata..."); + ata_init(); + { // find the init module struct multiboot_mod *module = &multiboot->mods[0]; if (multiboot->mods_count < 1) { @@ -25,6 +28,6 @@ void kmain_early(struct multiboot_info *multiboot) { info.init.at = module->start; info.init.size = module->end - module->start; } - + kmain(info); } -- cgit v1.2.3 From fbf6183ef8c9d49a14bd3ff01f378d67eaebc300 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 06:25:02 +0000 Subject: kernel/i386: rename the port io functions with their bit length --- src/kernel/arch/i386/ata.c | 14 +++++++------- src/kernel/arch/i386/port_io.h | 4 ++-- src/kernel/arch/i386/tty/serial.c | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 996fa3a..aaf05ff 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -24,7 +24,7 @@ static void ata_driveselect(int drive, int block) { if (drive&1) // slave? v |= 0x10; // set drive number bit // TODO account for block - port_outb(ata_iobase(drive) + DRV, v); + port_out8(ata_iobase(drive) + DRV, v); } static bool ata_identify(int drive) { @@ -33,20 +33,20 @@ static bool ata_identify(int drive) { ata_driveselect(drive, 0); for (int i = 2; i < 6; i++) - port_outb(iobase + i, 0); - port_outb(iobase + CMD, 0xEC); // IDENTIFY + port_out8(iobase + i, 0); + port_out8(iobase + CMD, 0xEC); // IDENTIFY - v = port_inb(iobase + STATUS); + v = port_in8(iobase + STATUS); if (v == 0) return false; // nonexistent drive - while (port_inb(iobase + STATUS) & 0x80); + while (port_in8(iobase + STATUS) & 0x80); /* check for uncomformant devices, quit early */ - if (port_inb(iobase + LBAmid) || port_inb(iobase + LBAhi)) { + if (port_in8(iobase + LBAmid) || port_in8(iobase + LBAhi)) { // TODO atapi return true; } /* pool until bit 3 (DRQ) or 0 (ERR) is set */ - while (!((v = port_inb(iobase + STATUS) & 0x9))); + while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ // now I can read 512 bytes of data, TODO diff --git a/src/kernel/arch/i386/port_io.h b/src/kernel/arch/i386/port_io.h index a4d640f..bcf2358 100644 --- a/src/kernel/arch/i386/port_io.h +++ b/src/kernel/arch/i386/port_io.h @@ -1,10 +1,10 @@ #include -static inline void port_outb(uint16_t port, uint8_t val) { +static inline void port_out8(uint16_t port, uint8_t val) { asm volatile("outb %0, %1" : : "a" (val), "Nd" (port)); } -static inline uint8_t port_inb(uint16_t port) { +static inline uint8_t port_in8(uint16_t port) { uint8_t val; asm volatile("inb %1, %0" : "=a" (val) : "Nd" (port)); return val; diff --git a/src/kernel/arch/i386/tty/serial.c b/src/kernel/arch/i386/tty/serial.c index 2b89ecf..f9bb252 100644 --- a/src/kernel/arch/i386/tty/serial.c +++ b/src/kernel/arch/i386/tty/serial.c @@ -7,37 +7,37 @@ static const int COM1 = 0x3f8; static void serial_selftest(void) { char b = 0x69; - port_outb(COM1 + 4, 0b00011110); // enable loopback mode - port_outb(COM1, b); - assert(port_inb(COM1) == b); + port_out8(COM1 + 4, 0b00011110); // enable loopback mode + port_out8(COM1, b); + assert(port_in8(COM1) == b); } void serial_init(void) { // see https://www.sci.muni.cz/docs/pc/serport.txt - port_outb(COM1 + 1, 0x00); // disable interrupts, we won't be using them + port_out8(COM1 + 1, 0x00); // disable interrupts, we won't be using them // set baud rate divisor - port_outb(COM1 + 3, 0b10000000); // enable DLAB - port_outb(COM1 + 0, 0x01); // divisor = 1 (low byte) - port_outb(COM1 + 1, 0x00); // (high byte) + port_out8(COM1 + 3, 0b10000000); // enable DLAB + port_out8(COM1 + 0, 0x01); // divisor = 1 (low byte) + port_out8(COM1 + 1, 0x00); // (high byte) - port_outb(COM1 + 3, 0b00000011); // 8 bits, no parity, one stop bit - port_outb(COM1 + 2, 0b11000111); // enable FIFO with 14-bit trigger level (???) + port_out8(COM1 + 3, 0b00000011); // 8 bits, no parity, one stop bit + port_out8(COM1 + 2, 0b11000111); // enable FIFO with 14-bit trigger level (???) serial_selftest(); - port_outb(COM1 + 4, 0b00001111); // enable everything in the MCR + port_out8(COM1 + 4, 0b00001111); // enable everything in the MCR } static void serial_putchar(char c) { - while ((port_inb(COM1 + 5) & 0x20) == 0); // wait for THRE - port_outb(COM1, c); + while ((port_in8(COM1 + 5) & 0x20) == 0); // wait for THRE + port_out8(COM1, c); } char serial_read(void) { - while ((port_inb(COM1 + 5) & 0x01) == 0); // wait for DR - return port_inb(COM1); + while ((port_in8(COM1 + 5) & 0x01) == 0); // wait for DR + return port_in8(COM1); } void serial_write(const char *buf, size_t len) { -- cgit v1.2.3 From 12ac8f2134d0ca0b103e70515acad3d6ccf9b9c0 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 06:37:07 +0000 Subject: kernel/i386: add 16bit port io functions --- src/kernel/arch/i386/port_io.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/kernel/arch/i386/port_io.h b/src/kernel/arch/i386/port_io.h index bcf2358..1938c97 100644 --- a/src/kernel/arch/i386/port_io.h +++ b/src/kernel/arch/i386/port_io.h @@ -4,9 +4,19 @@ static inline void port_out8(uint16_t port, uint8_t val) { asm volatile("outb %0, %1" : : "a" (val), "Nd" (port)); } +static inline void port_out16(uint16_t port, uint16_t val) { + asm volatile("outw %0, %1" : : "a" (val), "Nd" (port)); +} + static inline uint8_t port_in8(uint16_t port) { uint8_t val; asm volatile("inb %1, %0" : "=a" (val) : "Nd" (port)); return val; } +static inline uint8_t port_in16(uint16_t port) { + uint16_t val; + asm volatile("inw %1, %0" : "=a" (val) : "Nd" (port)); + return val; +} + -- cgit v1.2.3 From 53d3fd65b47a3e0f9c4f439022f10852d765a9ba Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 21:22:10 +0200 Subject: kernel/i386: fix port_in16's return value size --- src/kernel/arch/i386/port_io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/arch/i386/port_io.h b/src/kernel/arch/i386/port_io.h index 1938c97..eac9331 100644 --- a/src/kernel/arch/i386/port_io.h +++ b/src/kernel/arch/i386/port_io.h @@ -14,7 +14,7 @@ static inline uint8_t port_in8(uint16_t port) { return val; } -static inline uint8_t port_in16(uint16_t port) { +static inline uint16_t port_in16(uint16_t port) { uint16_t val; asm volatile("inw %1, %0" : "=a" (val) : "Nd" (port)); return val; -- cgit v1.2.3 From c52451dbe1628839c26500db42a05cfdb454afde Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 21:33:21 +0200 Subject: make: create a 70000 sector long fake disk image --- Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7757c25..886de4b 100644 --- a/Makefile +++ b/Makefile @@ -18,10 +18,9 @@ endef .PHONY: all boot debug lint check clean all: out/boot.iso check -boot: all - touch out/disk # TODO this is temporary +boot: all out/hdd qemu-system-i386 -cdrom out/boot.iso $(QFLAGS) -no-shutdown \ - -drive file=out/disk,format=raw,media=disk + -drive file=out/hdd,format=raw,media=disk debug: all @@ -62,6 +61,9 @@ out/fs/boot/grub/grub.cfg: grub.cfg @mkdir -p $(@D) @cp $< $@ +out/hdd: + @dd if=/dev/zero of=$@ bs=512 count=70000 + out/obj/%.s.o: src/%.s @mkdir -p $(@D) -- cgit v1.2.3 From 1ad3593c1b97027ffae0f1a97f58508d2980df00 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 21:53:35 +0200 Subject: ATA: read identify data, detect drive size --- src/kernel/arch/i386/ata.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index aaf05ff..e33b5af 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -4,6 +4,10 @@ #include +static struct { + uint32_t sectors; +} ata_drives[4]; + enum { LBAlo = 3, LBAmid = 4, @@ -29,8 +33,11 @@ static void ata_driveselect(int drive, int block) { static bool ata_identify(int drive) { uint16_t iobase = ata_iobase(drive); + uint16_t data[256]; uint8_t v; + // TODO test for float + ata_driveselect(drive, 0); for (int i = 2; i < 6; i++) port_out8(iobase + i, 0); @@ -49,7 +56,9 @@ static bool ata_identify(int drive) { while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ - // now I can read 512 bytes of data, TODO + for (int i = 0; i < 256; i++) + data[i] = port_in16(iobase); + ata_drives[drive].sectors = data[60] | (data[61] << 16); return true; } @@ -58,8 +67,11 @@ void ata_init(void) { for (int i = 0; i < 4; i++) { tty_const("probing drive "); _tty_var(i); - if (ata_identify(i)) - tty_const(" - exists"); + if (ata_identify(i)) { + tty_const(" - "); + _tty_var(ata_drives[i].sectors); + tty_const(" sectors (512b)"); + } tty_const("\n"); } } -- cgit v1.2.3 From 574d2cf63006cabbf9db4a80c55a407b5b33a700 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 7 Oct 2021 21:59:22 +0200 Subject: ATA: detect device type --- src/kernel/arch/i386/ata.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index e33b5af..4bc4293 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -5,6 +5,11 @@ #include static struct { + enum { + DEV_UNKNOWN, + DEV_PATA, + DEV_PATAPI, + } type; uint32_t sectors; } ata_drives[4]; @@ -47,11 +52,19 @@ static bool ata_identify(int drive) { if (v == 0) return false; // nonexistent drive while (port_in8(iobase + STATUS) & 0x80); - /* check for uncomformant devices, quit early */ - if (port_in8(iobase + LBAmid) || port_in8(iobase + LBAhi)) { - // TODO atapi - return true; + /* detect device type */ + switch (port_in8(iobase + LBAmid)) { + case 0: + ata_drives[drive].type = DEV_PATA; + break; + case 0x14: + ata_drives[drive].type = DEV_PATAPI; + return true; + default: + ata_drives[drive].type = DEV_UNKNOWN; + return false; } + /* pool until bit 3 (DRQ) or 0 (ERR) is set */ while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ -- cgit v1.2.3 From 0c000a03560eeab06154c1fb80b7a59a5c0f9ac7 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 8 Oct 2021 13:06:42 +0000 Subject: ata: proper drive type detection; soft reset; 400ns delay function --- src/kernel/arch/i386/ata.c | 67 +++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 4bc4293..916b918 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -20,6 +20,10 @@ enum { DRV = 6, CMD = 7, STATUS = 7, + + /* note: the OSDev wiki uses a different base port for the control port + * however i can just use this offset and stuff will just work tm */ + CTRL = 0x206, }; // offsets // get I/O port base for drive @@ -28,6 +32,12 @@ static uint16_t ata_iobase(int drive) { return secondary ? 0x170 : 0x1F0; } +static void ata_400ns(void) { + uint16_t base = ata_iobase(0); // doesn't matter + for (int i = 0; i < 4; i++) + port_in8(base + STATUS); +} + static void ata_driveselect(int drive, int block) { uint8_t v = 0xE0; if (drive&1) // slave? @@ -36,6 +46,38 @@ static void ata_driveselect(int drive, int block) { port_out8(ata_iobase(drive) + DRV, v); } +static void ata_softreset(int drive) { + uint16_t iobase = ata_iobase(drive); + port_out8(iobase + CTRL, 4); + port_out8(iobase + CTRL, 0); + ata_400ns(); + + uint16_t timeout = 10000; + while (--timeout) { // TODO separate polling function + uint8_t v = port_in8(iobase + STATUS); + if (v & 0x80) continue; // still BSY, continue + if (v & 0x40) break; // RDY, break + // TODO check for ERR + } +} + +static void ata_detecttype(int drive) { + ata_softreset(drive); + ata_driveselect(drive, 0); + ata_400ns(); + switch (port_in8(ata_iobase(drive) + LBAmid)) { + case 0: + ata_drives[drive].type = DEV_PATA; + break; + case 0x14: + ata_drives[drive].type = DEV_PATAPI; + return true; + default: + ata_drives[drive].type = DEV_UNKNOWN; + return false; + } +} + static bool ata_identify(int drive) { uint16_t iobase = ata_iobase(drive); uint16_t data[256]; @@ -52,19 +94,6 @@ static bool ata_identify(int drive) { if (v == 0) return false; // nonexistent drive while (port_in8(iobase + STATUS) & 0x80); - /* detect device type */ - switch (port_in8(iobase + LBAmid)) { - case 0: - ata_drives[drive].type = DEV_PATA; - break; - case 0x14: - ata_drives[drive].type = DEV_PATAPI; - return true; - default: - ata_drives[drive].type = DEV_UNKNOWN; - return false; - } - /* pool until bit 3 (DRQ) or 0 (ERR) is set */ while (!((v = port_in8(iobase + STATUS) & 0x9))); if (v & 1) return false; /* ERR was set, bail */ @@ -80,11 +109,13 @@ void ata_init(void) { for (int i = 0; i < 4; i++) { tty_const("probing drive "); _tty_var(i); - if (ata_identify(i)) { - tty_const(" - "); - _tty_var(ata_drives[i].sectors); - tty_const(" sectors (512b)"); - } + ata_detecttype(i); + _tty_var(ata_drives[i].type); + // if (ata_identify(i)) { + // tty_const(" - "); + // _tty_var(ata_drives[i].sectors); + // tty_const(" sectors (512b)"); + // } tty_const("\n"); } } -- cgit v1.2.3 From 6a90401ccb0d5a830772b8669113e1a17b6f40b7 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 8 Oct 2021 13:18:18 +0000 Subject: remove return statements from void function --- src/kernel/arch/i386/ata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 916b918..60dbb15 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -71,10 +71,10 @@ static void ata_detecttype(int drive) { break; case 0x14: ata_drives[drive].type = DEV_PATAPI; - return true; + break; default: ata_drives[drive].type = DEV_UNKNOWN; - return false; + break; } } -- cgit v1.2.3 From acf41ff6fee44dd24f9383d96fecd992dcb072e2 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 8 Oct 2021 19:29:12 +0200 Subject: ATA: implement the IDENTIFY PACKET DEVICE command --- src/kernel/arch/i386/ata.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 60dbb15..9224ed6 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -83,12 +84,18 @@ static bool ata_identify(int drive) { uint16_t data[256]; uint8_t v; - // TODO test for float - ata_driveselect(drive, 0); for (int i = 2; i < 6; i++) port_out8(iobase + i, 0); - port_out8(iobase + CMD, 0xEC); // IDENTIFY + switch (ata_drives[drive].type) { + case DEV_PATA: + port_out8(iobase + CMD, 0xEC); // IDENTIFY + break; + case DEV_PATAPI: + port_out8(iobase + CMD, 0xA1); // IDENTIFY PACKET DEVICE + break; + default: panic_invalid_state(); + } v = port_in8(iobase + STATUS); if (v == 0) return false; // nonexistent drive @@ -110,12 +117,15 @@ void ata_init(void) { tty_const("probing drive "); _tty_var(i); ata_detecttype(i); - _tty_var(ata_drives[i].type); - // if (ata_identify(i)) { - // tty_const(" - "); - // _tty_var(ata_drives[i].sectors); - // tty_const(" sectors (512b)"); - // } + if (ata_drives[i].type != DEV_UNKNOWN) { + if (ata_identify(i)) { + tty_const(" - "); + _tty_var(ata_drives[i].sectors); + tty_const(" sectors (512b)"); + } else { + tty_const(" identify failed"); + } + } tty_const("\n"); } } -- cgit v1.2.3