Quellcode durchsuchen

fix bugs, add serial module

greatbridf vor 9 Monaten
Ursprung
Commit
dfcbe573b1

+ 1 - 0
Makefile.src

@@ -43,6 +43,7 @@ clean-all: clean
 .PHONY: debug
 debug:
 	$(GDB_BIN) --symbols=build/kernel.out --init-eval-command 'source pretty-print.py' --init-eval-command 'set pagination off' --init-eval-command 'target remote:1234' --init-eval-command 'layout regs' --eval-command 'hbr _kernel_init' --eval-command 'c'
+	-killall $(QEMU_BIN)
 
 build/boot.vdi: build/boot.img
 	-rm build/boot.vdi

+ 1 - 2
doc/mem_layout.txt

@@ -24,8 +24,7 @@ virtual address space
 0xffff ff8 140 000 000 - 0xffff ff8 17f fff fff    1GB unused
 0xffff ff8 180 000 000 - 0xffff ffb fff fff fff  250GB kernel heap
 
-0xffff ffc 000 000 000 - 0xffff ffc 03f fff fff    1GB unused
-0xffff ffc 040 000 000 - 0xffff fff fbf fff fff  254GB kernel stack
+0xffff ffc 000 000 000 - 0xffff fff fbf fff fff  255GB unused
 
 0xffff fff fc0 000 000 - 0xffff fff fc0 1ff fff    2MB unused
 0xffff fff fc0 200 000 - 0xffff fff fff 9ff fff 1016MB kernel bss

+ 2 - 2
include/kernel/log.hpp

@@ -8,7 +8,7 @@
     if (1) {\
         char buf[512]; \
         snprintf(buf, sizeof(buf), fmt "\n" __VA_OPT__(,) __VA_ARGS__); \
-        if (console) console->print(buf); \
+        if (kernel::tty::console) kernel::tty::console->print(buf); \
     }
 
-#define kmsg(msg) if (console) console->print(msg "\n")
+#define kmsg(msg) if (kernel::tty::console) kernel::tty::console->print(msg "\n")

+ 4 - 1
include/kernel/mem/paging.hpp

@@ -45,12 +45,15 @@ constexpr psattr_t PA_MASK = 0xfff0000000000fffULL;
 
 constexpr psattr_t PA_DATA = PA_P | PA_RW | PA_NXE;
 constexpr psattr_t PA_KERNEL_DATA = PA_DATA | PA_G;
+constexpr psattr_t PA_USER_DATA = PA_DATA | PA_G | PA_US;
 
-constexpr psattr_t PA_PAGE_TABLE = PA_DATA;
+constexpr psattr_t PA_PAGE_TABLE = PA_P | PA_RW;
 constexpr psattr_t PA_KERNEL_PAGE_TABLE = PA_PAGE_TABLE | PA_G;
+constexpr psattr_t PA_USER_PAGE_TABLE = PA_PAGE_TABLE | PA_US;
 
 constexpr psattr_t PA_DATA_HUGE = PA_DATA | PA_PS;
 constexpr psattr_t PA_KERNEL_DATA_HUGE = PA_DATA_HUGE | PA_G;
+constexpr psattr_t PA_USER_DATA_HUGE = PA_DATA_HUGE | PA_US;
 
 constexpr psattr_t PA_ANONYMOUS_PAGE = PA_P | PA_US | PA_COW | PA_ANON;
 constexpr psattr_t PA_MMAPPED_PAGE = PA_US | PA_COW | PA_ANON | PA_MMAP;

+ 3 - 2
include/kernel/process.hpp

@@ -24,6 +24,7 @@
 #include <kernel/async/waitlist.hpp>
 #include <kernel/interrupt.hpp>
 #include <kernel/mem/mm_list.hpp>
+#include <kernel/mem/paging.hpp>
 #include <kernel/signal.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/user/thread_local.hpp>
@@ -187,7 +188,7 @@ public:
     pid_t pgid {};
     pid_t sid {};
 
-    tty* control_tty {};
+    kernel::tty::tty* control_tty {};
     fs::dentry* root { fs::fs_root };
     std::set<pid_t> children;
 
@@ -289,7 +290,7 @@ public:
     void kill(pid_t pid, int exit_code);
 };
 
-void NORETURN init_scheduler(void);
+void NORETURN init_scheduler(kernel::mem::paging::pfn_t kernel_stack_pfn);
 /// @return true if returned normally, false if being interrupted
 bool schedule(void);
 void NORETURN schedule_noreturn(void);

+ 2 - 0
include/kernel/task/thread.hpp

@@ -38,6 +38,8 @@ private:
 
         uint64_t pushq(uint64_t val);
         uint32_t pushl(uint32_t val);
+
+        void load_interrupt_stack() const;
     };
 
 public:

+ 12 - 5
include/kernel/tty.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <string>
+
 #include <stdint.h>
 #include <sys/types.h>
 #include <termios.h>
@@ -11,10 +13,11 @@
 #include <kernel/async/waitlist.hpp>
 #include <kernel/async/lock.hpp>
 
+namespace kernel::tty {
+
 class tty : public types::non_copyable {
 public:
     static constexpr size_t BUFFER_SIZE = 4096;
-    static constexpr size_t NAME_SIZE = 32;
 
 private:
     void _real_commit_char(int c);
@@ -23,7 +26,7 @@ private:
     int _do_erase(bool should_echo);
 
 public:
-    tty();
+    explicit tty(std::string name);
     virtual void putchar(char c) = 0;
     void print(const char* str);
     ssize_t read(char* buf, size_t buf_size, size_t n);
@@ -52,13 +55,13 @@ public:
         return fg_pgroup;
     }
 
-    char name[NAME_SIZE];
     termios termio;
+    std::string name;
 
 protected:
-    kernel::async::mutex mtx_buf;
+    async::mutex mtx_buf;
     types::buffer buf;
-    kernel::async::wait_list waitlist;
+    async::wait_list waitlist;
 
     pid_t fg_pgroup;
 };
@@ -70,3 +73,7 @@ public:
 };
 
 inline tty* console;
+
+int register_tty(tty* tty_dev);
+
+} // namespace kernel::tty

+ 53 - 57
src/kernel/hw/serial.cc

@@ -3,35 +3,46 @@
 
 #include <kernel/hw/port.hpp>
 #include <kernel/irq.hpp>
+#include <kernel/log.hpp>
 #include <kernel/module.hpp>
 #include <kernel/tty.hpp>
 
+using namespace kernel::tty;
+using namespace kernel::hw;
+
 constexpr int PORT0 = 0x3f8;
 constexpr int PORT1 = 0x2f8;
 
-using port_group = kernel::hw::p8[6];
+using port_group = const p8[6];
 
-constexpr kernel::hw::p8 port0[] = {
-    kernel::hw::p8{PORT0+0},
-    kernel::hw::p8{PORT0+1},
-    kernel::hw::p8{PORT0+2},
-    kernel::hw::p8{PORT0+3},
-    kernel::hw::p8{PORT0+4},
-    kernel::hw::p8{PORT0+5},
+constexpr p8 port0[] = {
+    p8{PORT0+0},
+    p8{PORT0+1},
+    p8{PORT0+2},
+    p8{PORT0+3},
+    p8{PORT0+4},
+    p8{PORT0+5},
 };
 
-constexpr kernel::hw::p8 port1[] = {
-    kernel::hw::p8{PORT1+0},
-    kernel::hw::p8{PORT1+1},
-    kernel::hw::p8{PORT1+2},
-    kernel::hw::p8{PORT1+3},
-    kernel::hw::p8{PORT1+4},
-    kernel::hw::p8{PORT1+5},
+constexpr p8 port1[] = {
+    p8{PORT1+0},
+    p8{PORT1+1},
+    p8{PORT1+2},
+    p8{PORT1+3},
+    p8{PORT1+4},
+    p8{PORT1+5},
 };
 
-static inline bool _serial_has_data(port_group ports)
+static void _serial0_receive_data_interrupt()
+{
+    while (*port0[5] & 1)
+        console->commit_char(*port0[0]);
+}
+
+static void _serial1_receive_data_interrupt()
 {
-    return *ports[5] & 1;
+    while (*port1[5] & 1)
+        console->commit_char(*port1[0]);
 }
 
 static inline int _init_port(port_group ports)
@@ -60,55 +71,25 @@ static inline int _init_port(port_group ports)
 
     ports[1] = 0x01; // Enable interrupts #0: Received Data Available
 
-    // TODO: LONG MODE
-    // kernel::irq::register_handler(4, serial_receive_data_interrupt);
-
     return 0;
 }
 
-// TODO: LONG MODE
-// static void serial_receive_data_interrupt(void)
-// {
-//     while (_serial_has_data(PORT_SERIAL0)) {
-//         uint8_t data = serial_read_data(PORT_SERIAL0);
-//         console->commit_char(data);
-//     }
-// }
-// 
-// uint8_t serial_read_data(port_id_t port)
-// {
-//     while (is_serial_has_data(port) == 0)
-//         ;
-//     return asm_inb(port);
-// }
-// 
-// int32_t is_serial_ready_for_transmition(port_id_t port)
-// {
-//     return asm_inb(port + 5) & 0x20;
-// }
-// 
-// void serial_send_data(port_id_t port, uint8_t data)
-// {
-//     while (is_serial_ready_for_transmition(port) == 0)
-//         ;
-//     return asm_outb(port, data);
-// }
-
 class serial_tty : public virtual tty {
+    const p8* ports;
+
 public:
-    serial_tty(int id): id(id)
+    serial_tty(port_group ports, int id)
+        : tty{"ttyS"}, ports(ports)
     {
-        snprintf(name, sizeof(name), "ttyS%d", id);
+        name += '0'+id;
     }
 
     virtual void putchar(char c) override
     {
-        // TODO: LONG MODE
-        // serial_send_data(id, c);
+        while (!(*ports[5] & 0x20))
+            ; // nop
+        ports[0] = c;
     }
-
-public:
-    uint16_t id;
 };
 
 class serial_module : public virtual kernel::module::module {
@@ -117,8 +98,23 @@ public:
 
     virtual int init() override
     {
-        // TODO: LONG MODE
-        return kernel::module::MODULE_FAILED;
+        if (int ret = _init_port(port0); ret == 0) {
+            auto* dev = new serial_tty(port0, 0);
+            kernel::irq::register_handler(4, _serial0_receive_data_interrupt);
+
+            if (int ret = register_tty(dev); ret != 0)
+                kmsg("[serial] cannot register ttyS0");
+        }
+
+        if (int ret = _init_port(port1); ret == 0) {
+            auto* dev = new serial_tty(port1, 0);
+            kernel::irq::register_handler(3, _serial1_receive_data_interrupt);
+
+            if (int ret = register_tty(dev); ret != 0)
+                kmsg("[serial] cannot register ttyS1");
+        }
+
+        return kernel::module::MODULE_SUCCESS;
     }
 
 };

+ 3 - 1
src/kernel/mem/mm_list.cc

@@ -289,7 +289,9 @@ int mm_list::mmap(const map_args& args)
 
     // PA_RW is set during page fault while PA_NXE is preserved
     // so we set PA_NXE now
-    psattr_t attributes = (flags & MM_EXECUTE) ? 0 : PA_NXE;
+    psattr_t attributes = PA_US;
+    if (!(flags & MM_EXECUTE))
+        attributes |= PA_NXE;
 
     if (flags & MM_MAPPED) {
         assert(finode);

+ 1 - 1
src/kernel/mem/paging.cc

@@ -24,7 +24,7 @@ static inline void __page_fault_die(uintptr_t vaddr)
 
 static inline PSE __parse_pse(PSE pse, bool priv)
 {
-    auto attr = priv ? PA_KERNEL_PAGE_TABLE : PA_PAGE_TABLE;
+    auto attr = priv ? PA_KERNEL_PAGE_TABLE : PA_USER_PAGE_TABLE;
     if (!(pse.attributes() & PA_P))
         pse.set(attr, alloc_page_table());
 

+ 9 - 10
src/kernel/process.cpp

@@ -279,10 +279,7 @@ proclist::proclist()
 
     kernel::task::dispatcher::enqueue(current_thread);
 
-    // TODO: LONG MODE
-    // tss.ss0 = KERNEL_DATA_SEGMENT;
-    // tss.esp0 = (uint32_t)current_thread->kstack.esp;
-
+    current_thread->kstack.load_interrupt_stack();
     current_process->mms.switch_pd();
 
     if (1) {
@@ -388,19 +385,20 @@ static void release_kinit()
 {
     // free .kinit
     using namespace kernel::mem::paging;
-    extern uintptr_t KINIT_START_ADDR, KINIT_END_ADDR, KINIT_PAGES;
+    extern uintptr_t volatile KINIT_START_ADDR, KINIT_END_ADDR, KINIT_PAGES;
 
+    std::size_t pages = KINIT_PAGES;
     auto range = vaddr_range{KERNEL_PAGE_TABLE_ADDR,
         KINIT_START_ADDR, KINIT_END_ADDR, true};
-
     for (auto pte : range)
         pte.clear();
 
-    create_zone(0x2000, 0x2000 + 0x1000 * KINIT_PAGES);
+    create_zone(0x2000, 0x2000 + 0x1000 * pages);
 }
 
-void NORETURN _kernel_init(void)
+void NORETURN _kernel_init(kernel::mem::paging::pfn_t kernel_stack_pfn)
 {
+    kernel::mem::paging::free_pages(kernel_stack_pfn, 9);
     release_kinit();
 
     asm volatile("sti");
@@ -485,11 +483,12 @@ void k_new_thread(void (*func)(void*), void* data)
 }
 
 SECTION(".text.kinit")
-void NORETURN init_scheduler(void)
+void NORETURN init_scheduler(kernel::mem::paging::pfn_t kernel_stack_pfn)
 {
     procs = new proclist;
 
     asm volatile(
+        "mov %2, %%rdi\n"
         "mov %0, %%rsp\n"
         "sub $24, %%rsp\n"
         "mov %=f, %%rbx\n"
@@ -516,7 +515,7 @@ void NORETURN init_scheduler(void)
         "%=:\n"
         "ud2"
         :
-        : "a"(current_thread->kstack.sp), "c"(_kernel_init)
+        : "a"(current_thread->kstack.sp), "c"(_kernel_init), "g"(kernel_stack_pfn)
         : "memory");
 
     freeze();

+ 18 - 0
src/kernel/task/thread.cc

@@ -2,6 +2,8 @@
 
 #include <stdint.h>
 
+#include <types/types.h>
+
 #include <kernel/async/lock.hpp>
 #include <kernel/log.hpp>
 #include <kernel/mem/paging.hpp>
@@ -13,8 +15,19 @@
 constexpr std::size_t KERNEL_STACK_ORDER = 3; // 2^3 * 4096 = 32KB
 
 using namespace kernel::task;
+using namespace kernel::mem;
 using namespace kernel::mem::paging;
 
+struct PACKED tss64_t {
+    uint32_t _reserved1;
+    uint64_t rsp[3];
+    uint64_t _reserved2;
+    uint64_t ist[7];
+    uint64_t _reserved3;
+    uint32_t _reserved4;
+};
+constexpr physaddr<tss64_t> tss{0x00000070};
+
 thread::thread(std::string name, pid_t owner)
     : owner { owner }, attr { READY | SYSTEM }, name { name } { }
 
@@ -82,6 +95,11 @@ uint32_t thread::kernel_stack::pushl(uint32_t val)
     return val;
 }
 
+void thread::kernel_stack::load_interrupt_stack() const
+{
+    tss->rsp[0] = sp;
+}
+
 void thread::set_attr(thd_attr_t new_attr)
 {
     switch (new_attr) {

+ 14 - 5
src/kernel/tty.cpp

@@ -19,7 +19,9 @@
 
 #define TERMIOS_TESTCC(c, termios, cc) ((c != 0xff) && (c == ((termios).c_cc[cc])))
 
-tty::tty()
+using namespace kernel::tty;
+
+tty::tty(std::string name)
     : termio {
         .c_iflag = ICRNL | IXOFF,
         .c_oflag = OPOST | ONLCR,
@@ -31,6 +33,7 @@ tty::tty()
         .c_ispeed = 38400,
         .c_ospeed = 38400,
     }
+    , name{name}
     , buf(BUFFER_SIZE)
     , fg_pgroup { 0 }
 {
@@ -279,10 +282,7 @@ void tty::show_char(int c)
     this->putchar(c);
 }
 
-vga_tty::vga_tty()
-{
-    snprintf(this->name, sizeof(this->name), "ttyVGA");
-}
+vga_tty::vga_tty(): tty{"ttyVGA"} { }
 
 void vga_tty::putchar(char c)
 {
@@ -295,3 +295,12 @@ void tty::clear_read_buf(void)
 {
     this->buf.clear();
 }
+
+int kernel::tty::register_tty(tty* tty_dev)
+{
+    // TODO: manage all ttys
+    if (!console)
+        console = tty_dev;
+
+    return 0;
+}

+ 3 - 2
src/kernel/vfs.cpp

@@ -783,13 +783,14 @@ ssize_t b_null_write(const char*, size_t n)
 
 static ssize_t console_read(char* buf, size_t buf_size, size_t n)
 {
-    return console->read(buf, buf_size, n);
+    return kernel::tty::console->read(buf, buf_size, n);
 }
+
 static ssize_t console_write(const char* buf, size_t n)
 {
     size_t orig_n = n;
     while (n--)
-        console->putchar(*(buf++));
+        kernel::tty::console->putchar(*(buf++));
 
     return orig_n;
 }

+ 14 - 29
src/kinit.cpp

@@ -67,7 +67,7 @@ static inline void set_uname()
 }
 
 SECTION(".text.kinit")
-void NORETURN real_kernel_init()
+void NORETURN real_kernel_init(mem::paging::pfn_t kernel_stack_pfn)
 {
     // call global constructors
     // NOTE: the initializer of global objects MUST NOT contain
@@ -86,7 +86,7 @@ void NORETURN real_kernel_init()
     init_vfs();
     // init_syscall();
 
-    init_scheduler();
+    init_scheduler(kernel_stack_pfn);
 }
 
 SECTION(".text.kinit")
@@ -112,23 +112,6 @@ static inline void setup_early_kernel_page_table()
     memset(mem::physaddr<void>{EMPTY_PAGE_PFN}, 0x00, 0x1000);
 }
 
-SECTION(".text.kinit")
-static inline void make_early_kernel_stack()
-{
-    using namespace kernel::mem;
-    using namespace kernel::mem::paging;
-
-    constexpr auto idx = idx_all(0xffffffc040000000ULL);
-
-    // early kernel stack
-    auto pdpte = KERNEL_PAGE_TABLE[std::get<1>(idx)].parse()[std::get<2>(idx)];
-    pdpte.set(PA_KERNEL_PAGE_TABLE, alloc_page_table());
-
-    auto pd = pdpte.parse();
-    pd[std::get<3>(idx)].set(PA_KERNEL_DATA_HUGE,
-        page_to_pfn(alloc_pages(9)));
-}
-
 SECTION(".text.kinit")
 static inline void setup_buddy(uintptr_t addr_max)
 {
@@ -209,11 +192,11 @@ void setup_gdt()
 
     // TSS descriptor
     mem::gdt[8]  = 0x0000'8900'0070'0067;
-    mem::gdt[9]  = 0x0000'0000'0000'0000;
+    mem::gdt[9]  = 0x0000'0000'ffff'ff00;
 
     // LDT descriptor
     mem::gdt[10] = 0x0000'8200'0060'000f;
-    mem::gdt[11] = 0x0000'0000'0000'0000;
+    mem::gdt[11] = 0x0000'0000'ffff'ff00;
 
     // thread local
     mem::gdt[12] = 0x0000'0000'0000'0000;
@@ -253,18 +236,20 @@ void NORETURN kernel_init(bootloader_data* data)
     setup_buddy(addr_max);
     init_allocator();
 
-    make_early_kernel_stack();
+    using namespace mem::paging;
+    auto kernel_stack_pfn = page_to_pfn(alloc_pages(9));
+    auto kernel_stack_ptr =
+        mem::physaddr<std::byte>{kernel_stack_pfn} + (1<<9) * 0x1000;
 
     asm volatile(
-            "mov $0xffffffc040200000, %%rsp\n\t"
+            "mov %1, %%rdi\n\t"
+            "mov %2, %%rsp\n\t"
             "xor %%rbp, %%rbp\n\t"
             "call *%0\n\t"
-            :
-            : "r"(real_kernel_init)
-            :
-            );
-    for (;;)
-        asm volatile("cli\n\thlt");
+            : : "r"(real_kernel_init), "g"(kernel_stack_pfn), "g"(kernel_stack_ptr):
+    );
+
+    freeze();
 }
 
 } // namespace kernel::kinit