Эх сурвалжийг харах

Merge branch 'open_working' into open

greatbridf 2 жил өмнө
parent
commit
b74163b1d5

+ 9 - 9
CMakeLists.txt

@@ -49,19 +49,19 @@ if (NOT DEFINED FDISK_BIN)
 endif()
 
 set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
-                        src/kernel_main.c
+                        src/kernel_main.cpp
                         src/kernel/errno.c
                         src/kernel/interrupt.cpp
                         src/kernel/process.cpp
-                        src/kernel/tty.c
-                        src/kernel/stdio.c
+                        src/kernel/tty.cpp
+                        src/kernel/stdio.cpp
                         src/kernel/syscall.cpp
                         src/kernel/mem.cpp
                         src/kernel/vfs.cpp
-                        src/kernel/vga.c
+                        src/kernel/vga.cpp
                         src/kernel/hw/ata.cpp
                         src/kernel/hw/keyboard.cpp
-                        src/kernel/hw/serial.c
+                        src/kernel/hw/serial.cpp
                         src/kernel/hw/timer.c
                         src/kernel/event/event.cpp
                         src/types/bitmap.c
@@ -73,15 +73,15 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/kernel/event/event.h
                         include/kernel/event/evtqueue.hpp
                         include/kernel/errno.h
-                        include/kernel/tty.h
+                        include/kernel/tty.hpp
                         include/kernel/interrupt.h
                         include/kernel/process.hpp
-                        include/kernel/stdio.h
+                        include/kernel/stdio.hpp
                         include/kernel/syscall.hpp
                         include/kernel/mem.h
                         include/kernel/mm.hpp
                         include/kernel/vfs.hpp
-                        include/kernel/vga.h
+                        include/kernel/vga.hpp
                         include/kernel/hw/ata.hpp
                         include/kernel/hw/keyboard.h
                         include/kernel/hw/port.hpp
@@ -106,7 +106,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/lock.hpp
                         include/types/string.hpp
                         include/types/vector.hpp
-                        include/kernel_main.h
+                        include/kernel_main.hpp
                         )
 add_library(kernel_main STATIC ${KERNEL_MAIN_SOURCES})
 

+ 0 - 2
include/asm/boot.h

@@ -12,8 +12,6 @@ struct __attribute__((__packed__)) gdt_descriptor {
 
 extern struct gdt_descriptor asm_gdt_descriptor;
 
-extern uint32_t check_a20_on(void);
-
 extern struct mem_size_info asm_mem_size_info;
 
 extern uint8_t asm_e820_mem_map[1024];

+ 1 - 1
include/kernel/mm.hpp

@@ -124,7 +124,7 @@ public:
     {
         v.m_pd = nullptr;
     }
-    constexpr ~mm_list()
+    ~mm_list()
     {
         if (!m_pd)
             return;

+ 1 - 1
include/kernel/process.hpp

@@ -405,7 +405,7 @@ public:
     }
 };
 
-extern "C" void NORETURN init_scheduler();
+void NORETURN init_scheduler(void);
 void schedule(void);
 
 constexpr uint32_t push_stack(uint32_t** stack, uint32_t val)

+ 2 - 0
include/kernel/stdio.h → include/kernel/stdio.hpp

@@ -33,6 +33,8 @@ snprintf(
     const char* fmt,
     ...);
 
+void kmsg(const char* msg);
+
 #ifdef __cplusplus
 }
 #endif

+ 0 - 34
include/kernel/tty.h

@@ -1,34 +0,0 @@
-#pragma once
-#include <asm/port_io.h>
-
-#define STRUCT_TTY_NAME_LEN (32)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct tty;
-
-struct tty_operations
-{
-    void (*put_char)(struct tty* p_tty, char c);
-};
-
-struct tty
-{
-    char name[STRUCT_TTY_NAME_LEN];
-    struct tty_operations* ops;
-    char data[12];
-};
-
-// in kernel_main.c
-extern struct tty* console;
-
-void tty_print(struct tty* p_tty, const char* str);
-
-int make_serial_tty(struct tty* p_tty, int id);
-int make_vga_tty(struct tty* p_tty);
-
-#ifdef __cplusplus
-}
-#endif

+ 45 - 0
include/kernel/tty.hpp

@@ -0,0 +1,45 @@
+#pragma once
+#include <kernel/event/evtqueue.hpp>
+#include <types/allocator.hpp>
+#include <types/buffer.hpp>
+#include <types/cplusplus.hpp>
+#include <types/stdint.h>
+
+class tty : public types::non_copyable {
+public:
+    static constexpr size_t BUFFER_SIZE = 4096;
+    static constexpr size_t NAME_SIZE = 32;
+
+public:
+    tty();
+    virtual void putchar(char c) = 0;
+    virtual void recvchar(char c) = 0;
+    void print(const char* str);
+    size_t read(char* buf, size_t buf_size, size_t n);
+
+    char name[NAME_SIZE];
+    bool echo = true;
+
+protected:
+    types::buffer<types::kernel_ident_allocator> buf;
+    kernel::evtqueue blocklist;
+};
+
+class vga_tty : public virtual tty {
+public:
+    vga_tty();
+    virtual void putchar(char c) override;
+    virtual void recvchar(char c) override;
+};
+
+class serial_tty : public virtual tty {
+public:
+    serial_tty(int id);
+    virtual void putchar(char c) override;
+    virtual void recvchar(char c) override;
+
+public:
+    uint16_t id;
+};
+
+inline tty* console;

+ 0 - 8
include/kernel/vga.h → include/kernel/vga.hpp

@@ -4,10 +4,6 @@
 
 #include <types/stdint.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define VGA_CHAR_COLOR_WHITE (0x0fU)
 
 struct vga_char {
@@ -22,8 +18,4 @@ struct vga_char {
 void vga_put_char(struct vga_char* c);
 void vga_print(const char* str, uint8_t color);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif // _KERNEL_VGA_H_

+ 1 - 8
include/kernel_main.h → include/kernel_main.hpp

@@ -6,12 +6,5 @@
 
 #define KERNEL_START_ADDR (0x00100000)
 
-void NORETURN kernel_main(void);
-
-#ifdef __cplusplus
-// in kernel_main.c
-extern "C" struct tss32_t tss;
-#else
-// in kernel_main.c
+// in kernel_main.cpp
 extern struct tss32_t tss;
-#endif

+ 40 - 11
include/types/buffer.hpp

@@ -18,10 +18,10 @@ private:
     size_t count;
 
 private:
-    constexpr char _get_char(void)
+    constexpr char _get_char(char* ptr)
     {
         --count;
-        return *base;
+        return *ptr;
     }
 
     constexpr void _put_char(char c)
@@ -30,12 +30,20 @@ private:
         ++count;
     }
 
-    constexpr void _forward(char*& ptr)
+    constexpr char* _forward(char* ptr)
     {
         if (ptr == end)
-            ptr = start;
+            return start;
+        else
+            return ptr + 1;
+    }
+
+    constexpr char* _backward(char* ptr)
+    {
+        if (ptr == start)
+            return end;
         else
-            ++ptr;
+            return ptr - 1;
     }
 
 public:
@@ -50,9 +58,9 @@ public:
 
     constexpr buffer(const buffer& buf)
         : start { types::allocator_traits<allocator_type>::allocate(buf.end + 1 - buf.start) }
-        , end { start + buf.end - buf.start }
-        , base { start + buf.base - buf.start }
-        , head { start + buf.base - buf.start }
+        , end { (uint32_t)start + (uint32_t)buf.end - (uint32_t)buf.start }
+        , base { (uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start }
+        , head { (uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start }
         , count { buf.count }
     {
     }
@@ -82,14 +90,35 @@ public:
         return count == static_cast<size_t>(end - start + 1);
     }
 
+    constexpr char front(void)
+    {
+        return *base;
+    }
+
+    constexpr char back(void)
+    {
+        return *_backward(head);
+    }
+
     constexpr char get(void)
     {
         // TODO: set error flag
         if (empty())
             return 0xff;
 
-        char c = _get_char();
-        _forward(base);
+        char c = _get_char(base);
+        base = _forward(base);
+        return c;
+    }
+
+    constexpr char pop(void)
+    {
+        // TODO: set error flag
+        if (empty())
+            return 0xff;
+
+        char c = _get_char(_backward(head));
+        head = _backward(head);
         return c;
     }
 
@@ -100,7 +129,7 @@ public:
             return 0xff;
 
         _put_char(c);
-        _forward(head);
+        head = _forward(head);
         return c;
     }
 };

+ 7 - 0
include/types/cplusplus.hpp

@@ -175,6 +175,13 @@ concept PointerType = traits::is_pointer<T>::value;
 template <typename A, typename B>
 concept same_as = is_same<A, B>::value;
 
+class non_copyable {
+public:
+    non_copyable() = default;
+    non_copyable(const non_copyable&) = delete;
+    non_copyable& operator=(const non_copyable&) = delete;
+};
+
 } // namespace types
 
 #endif

+ 1 - 5
include/types/string.hpp

@@ -1,12 +1,10 @@
 #pragma once
 
-#include <kernel/stdio.h>
+#include <kernel/stdio.hpp>
 #include <types/allocator.hpp>
 #include <types/types.h>
 #include <types/vector.hpp>
 
-#ifdef __cplusplus
-
 namespace types {
 template <template <typename _value_type> class Allocator = kernel_allocator>
 class string : public types::vector<char, Allocator> {
@@ -114,5 +112,3 @@ public:
     }
 };
 } // namespace types
-
-#endif

+ 2 - 3
src/kernel/event/event.cpp

@@ -3,8 +3,7 @@
 #include <kernel/event/evtqueue.hpp>
 #include <kernel/input/input_event.h>
 #include <kernel/process.hpp>
-#include <kernel/stdio.h>
-#include <kernel/tty.h>
+#include <kernel/stdio.hpp>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/cplusplus.hpp>
@@ -40,7 +39,7 @@ void dispatch_event(void)
         for (auto iter = input_event_queue.begin(); iter != input_event_queue.end(); ++iter) {
             const auto& item = *iter;
             snprintf(buf, 1024, "\rinput event: type%x, data%x, code%x\r", item.type, item.data, item.code);
-            tty_print(console, buf);
+            kmsg(buf);
             input_event_queue.erase(iter);
         }
     }

+ 3 - 3
src/kernel/hw/ata.cpp

@@ -1,9 +1,8 @@
 #include <asm/port_io.h>
 #include <fs/fat.hpp>
 #include <kernel/hw/ata.hpp>
-#include <kernel/stdio.h>
+#include <kernel/stdio.hpp>
 #include <kernel/syscall.hpp>
-#include <kernel/tty.h>
 #include <kernel/vfs.hpp>
 #include <types/allocator.hpp>
 #include <types/assert.h>
@@ -180,7 +179,8 @@ struct PACKED mbr {
 
 static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t minor)
 {
-    struct mbr hda_mbr { };
+    struct mbr hda_mbr {
+    };
     auto* dev = fs::vfs_open("/dev");
 
     fs::vfs_read(drive, (char*)&hda_mbr, 512, 0, 512);

+ 4 - 27
src/kernel/hw/serial.c → src/kernel/hw/serial.cpp

@@ -1,8 +1,8 @@
-#include <types/status.h>
 #include <asm/port_io.h>
 #include <kernel/hw/serial.h>
-#include <kernel/stdio.h>
-#include <kernel/tty.h>
+#include <kernel/stdio.hpp>
+#include <kernel/tty.hpp>
+#include <types/status.h>
 
 int32_t init_serial_port(port_id_t port)
 {
@@ -61,29 +61,6 @@ void serial_receive_data_interrupt(void)
 {
     while (is_serial_has_data(PORT_SERIAL0)) {
         uint8_t data = serial_read_data(PORT_SERIAL0);
-        char buf[64] = { 0 };
-        switch (data) {
-        case '\r':
-            serial_send_data(PORT_SERIAL0, '\r');
-            serial_send_data(PORT_SERIAL0, '\n');
-            break;
-        // ^?
-        case 0x7f:
-            serial_send_data(PORT_SERIAL0, 0x08);
-            serial_send_data(PORT_SERIAL0, '\x1b');
-            serial_send_data(PORT_SERIAL0, '[');
-            serial_send_data(PORT_SERIAL0, 'K');
-            break;
-        // ^U
-        case 0x15:
-            serial_send_data(PORT_SERIAL0, '\r');
-            serial_send_data(PORT_SERIAL0, '\x1b');
-            serial_send_data(PORT_SERIAL0, '[');
-            serial_send_data(PORT_SERIAL0, '2');
-            serial_send_data(PORT_SERIAL0, 'K');
-        default:
-            serial_send_data(PORT_SERIAL0, data);
-            break;
-        }
+        console->recvchar(data);
     }
 }

+ 0 - 1
src/kernel/hw/timer.c

@@ -1,5 +1,4 @@
 #include <asm/port_io.h>
-#include <kernel/tty.h>
 #include <kernel/hw/timer.h>
 
 static time_t _current_ticks = 0;

+ 11 - 11
src/kernel/interrupt.cpp

@@ -8,12 +8,11 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.h>
+#include <kernel/stdio.hpp>
 #include <kernel/syscall.hpp>
-#include <kernel/tty.h>
 #include <kernel/vfs.hpp>
-#include <kernel/vga.h>
-#include <kernel_main.h>
+#include <kernel/vga.hpp>
+#include <kernel_main.hpp>
 #include <types/assert.h>
 #include <types/size.h>
 #include <types/stdint.h>
@@ -91,7 +90,7 @@ extern "C" void int6_handler(
 {
     char buf[512];
 
-    tty_print(console, "\n---- INVALID OPCODE ----\n");
+    kmsg("\n---- INVALID OPCODE ----\n");
 
     snprintf(
         buf, 512,
@@ -102,9 +101,9 @@ extern "C" void int6_handler(
         s_regs.edx, s_regs.esp, s_regs.ebp,
         s_regs.esi, s_regs.edi, eip,
         cs, eflags);
-    tty_print(console, buf);
+    kmsg(buf);
 
-    tty_print(console, "----   HALTING SYSTEM   ----\n");
+    kmsg("----   HALTING SYSTEM   ----\n");
 
     asm_cli();
     asm_hlt();
@@ -120,7 +119,7 @@ extern "C" void int13_handler(
 {
     char buf[512];
 
-    tty_print(console, "\n---- SEGMENTATION FAULT ----\n");
+    kmsg("\n---- SEGMENTATION FAULT ----\n");
 
     snprintf(
         buf, 512,
@@ -132,9 +131,9 @@ extern "C" void int13_handler(
         s_regs.edx, s_regs.esp, s_regs.ebp,
         s_regs.esi, s_regs.edi, eip,
         cs, error_code, eflags);
-    tty_print(console, buf);
+    kmsg(buf);
 
-    tty_print(console, "----   HALTING SYSTEM   ----\n");
+    kmsg("----   HALTING SYSTEM   ----\n");
 
     asm_cli();
     asm_hlt();
@@ -155,7 +154,7 @@ static inline void _int14_panic(void* eip, void* cr2, struct page_fault_error_co
     snprintf(
         buf, 256,
         "\nkilled: segmentation fault (eip: %x, cr2: %x, error_code: %x)\n", eip, cr2, error_code);
-    tty_print(console, buf);
+    kmsg(buf);
     assert(false);
 }
 
@@ -238,6 +237,7 @@ extern "C" void irq3_handler(void)
 }
 extern "C" void irq4_handler(void)
 {
+    // TODO: register interrupt handler in serial port driver
     serial_receive_data_interrupt();
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }

+ 3 - 3
src/kernel/mem.cpp

@@ -5,10 +5,10 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.h>
+#include <kernel/stdio.hpp>
 #include <kernel/task.h>
-#include <kernel/vga.h>
-#include <kernel_main.h>
+#include <kernel/vga.hpp>
+#include <kernel_main.hpp>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/bitmap.h>

+ 4 - 5
src/kernel/process.cpp

@@ -6,10 +6,9 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
-#include <kernel/stdio.h>
-#include <kernel/tty.h>
+#include <kernel/stdio.hpp>
 #include <kernel/vfs.hpp>
-#include <kernel_main.h>
+#include <kernel_main.hpp>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/cplusplus.hpp>
@@ -92,7 +91,7 @@ inline void NORETURN _noreturn_crash(void)
 
 void kernel_threadd_main(void)
 {
-    tty_print(console, "kernel thread daemon started\n");
+    kmsg("kernel thread daemon started\n");
 
     for (;;) {
         if (kthreadd_new_thd_func) {
@@ -203,7 +202,7 @@ void k_new_thread(void (*func)(void*), void* data)
     kthreadd_new_thd_data = data;
 }
 
-void NORETURN init_scheduler()
+void NORETURN init_scheduler(void)
 {
     procs = types::pnew<types::kernel_allocator>(procs);
     readythds = types::pnew<types::kernel_allocator>(readythds);

+ 16 - 7
src/kernel/stdio.c → src/kernel/stdio.cpp

@@ -1,4 +1,5 @@
-#include <kernel/stdio.h>
+#include <kernel/stdio.hpp>
+#include <kernel/tty.hpp>
 
 #include <types/size.h>
 #include <types/stdint.h>
@@ -46,12 +47,12 @@ int64_t do_div_s(int64_t a, int64_t b, uint64_t* remainder)
     return quotient;
 }
 
-int64_t __divdi3(int64_t a, int64_t b)
+extern "C" int64_t __divdi3(int64_t a, int64_t b)
 {
     return do_div_s(a, b, (uint64_t*)0);
 }
 
-int64_t __moddi3(int64_t a, int64_t b)
+extern "C" int64_t __moddi3(int64_t a, int64_t b)
 {
     uint64_t remainder = 0;
     do_div_s(a, b, &remainder);
@@ -301,7 +302,7 @@ snprintf(
     ...)
 {
     ssize_t n_write = 0;
-    void* arg_ptr = ((void*)&buf) + sizeof(char*) + sizeof(size_t) + sizeof(const char*);
+    uint8_t* arg_ptr = ((uint8_t*)&buf) + sizeof(char*) + sizeof(size_t) + sizeof(const char*);
 
     for (char c; (c = *fmt) != 0x00; ++fmt) {
         if (c == '%') {
@@ -413,9 +414,11 @@ snprintf(
 }
 
 #define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
-void* memcpy(void* dst, const void* src, size_t n)
+void* memcpy(void* _dst, const void* _src, size_t n)
 {
-    void* orig_dst = dst;
+    void* orig_dst = _dst;
+    uint8_t* dst = (uint8_t*)_dst;
+    const uint8_t* src = (const uint8_t*)_src;
     for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
         *(uint32_t*)dst = *(uint32_t*)src;
         dst += BYTES_PER_MAX_COPY_UNIT;
@@ -427,8 +430,9 @@ void* memcpy(void* dst, const void* src, size_t n)
     return orig_dst;
 }
 
-void* memset(void* dst, int c, size_t n)
+void* memset(void* _dst, int c, size_t n)
 {
+    uint8_t* dst = (uint8_t*)_dst;
     c &= 0xff;
     int cc = (c + (c << 8) + (c << 16) + (c << 24));
     for (size_t i = 0; i < n / BYTES_PER_MAX_COPY_UNIT; ++i) {
@@ -472,3 +476,8 @@ int strcmp(const char* s1, const char* s2)
     }
     return c;
 }
+
+void kmsg(const char* msg)
+{
+    console->print(msg);
+}

+ 22 - 4
src/kernel/syscall.cpp

@@ -5,10 +5,10 @@
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
+#include <kernel/stdio.hpp>
 #include <kernel/syscall.hpp>
-#include <kernel/tty.h>
 #include <kernel/vfs.hpp>
-#include <kernel_main.h>
+#include <kernel_main.hpp>
 #include <types/allocator.hpp>
 #include <types/assert.h>
 #include <types/elf.hpp>
@@ -91,6 +91,24 @@ void _syscall_write(interrupt_stack* data)
     SYSCALL_SET_RETURN_VAL(n_wrote, 0);
 }
 
+void _syscall_read(interrupt_stack* data)
+{
+    int fd = data->s_regs.edi;
+    char* buf = reinterpret_cast<char*>(data->s_regs.esi);
+    size_t n = data->s_regs.edx;
+
+    auto* file = current_process->files[fd];
+    if (file->type != fs::file::types::regular_file) {
+        SYSCALL_SET_RETURN_VAL(GB_FAILED, EINVAL);
+        return;
+    }
+
+    // TODO: copy to user function !IMPORTANT
+    int n_wrote = fs::vfs_read(file->impl.ind, buf, n, file->cursor, n);
+    file->cursor += n_wrote;
+    SYSCALL_SET_RETURN_VAL(n_wrote, 0);
+}
+
 void _syscall_sleep(interrupt_stack* data)
 {
     current_thread->attr.ready = 0;
@@ -103,7 +121,7 @@ void _syscall_sleep(interrupt_stack* data)
 
 void _syscall_crash(interrupt_stack*)
 {
-    tty_print(console, "\nan error occurred while executing command\n");
+    kmsg("\nan error occurred while executing command\n");
     asm_cli();
     asm_hlt();
 }
@@ -224,5 +242,5 @@ void init_syscall(void)
     syscall_handlers[4] = _syscall_exec;
     syscall_handlers[5] = _syscall_exit;
     syscall_handlers[6] = _syscall_wait;
-    syscall_handlers[7] = _syscall_not_impl;
+    syscall_handlers[7] = _syscall_read;
 }

+ 0 - 49
src/kernel/tty.c

@@ -1,49 +0,0 @@
-#include <asm/port_io.h>
-#include <kernel/hw/serial.h>
-#include <kernel/mem.h>
-#include <kernel/stdio.h>
-#include <kernel/tty.h>
-#include <kernel/vga.h>
-
-static void serial_tty_put_char(struct tty* p_tty, char c)
-{
-    serial_send_data(*(port_id_t*)&p_tty->data, c);
-}
-
-static void vga_tty_put_char(struct tty* _unused, char c)
-{
-    static struct vga_char vc = { .c = '\0', .color = VGA_CHAR_COLOR_WHITE };
-    vc.c = c;
-    vga_put_char(&vc);
-}
-
-static struct tty_operations serial_tty_ops = {
-    .put_char = serial_tty_put_char,
-};
-
-static struct tty_operations vga_tty_ops = {
-    .put_char = vga_tty_put_char,
-};
-
-void tty_print(struct tty* p_tty, const char* str)
-{
-    while (*str != '\0') {
-        p_tty->ops->put_char(p_tty, *str);
-        ++str;
-    }
-}
-
-int make_serial_tty(struct tty* p_tty, int id)
-{
-    *(port_id_t*)&p_tty->data = id;
-    snprintf(p_tty->name, sizeof(p_tty->name), "ttyS%x", id);
-    p_tty->ops = &serial_tty_ops;
-    return GB_OK;
-}
-
-int make_vga_tty(struct tty* p_tty)
-{
-    snprintf(p_tty->name, sizeof(p_tty->name), "ttyVGA");
-    p_tty->ops = &vga_tty_ops;
-    return GB_OK;
-}

+ 114 - 0
src/kernel/tty.cpp

@@ -0,0 +1,114 @@
+#include <kernel/hw/serial.h>
+#include <kernel/process.hpp>
+#include <kernel/stdio.hpp>
+#include <kernel/tty.hpp>
+#include <kernel/vga.hpp>
+#include <types/stdint.h>
+
+tty::tty()
+    : buf(BUFFER_SIZE)
+{
+}
+
+void tty::print(const char* str)
+{
+    while (*str != '\0')
+        this->putchar(*(str++));
+}
+
+size_t tty::read(char* buf, size_t buf_size, size_t n)
+{
+    size_t orig_n = n;
+
+    while (buf_size && n) {
+        while (this->buf.empty()) {
+            current_thread->attr.ready = 0;
+            current_thread->attr.wait = 1;
+            this->blocklist.subscribe(current_thread);
+            schedule();
+            this->blocklist.unsubscribe(current_thread);
+        }
+
+        *buf = this->buf.get();
+        --buf_size;
+        --n;
+
+        if (*(buf++) == '\n')
+            break;
+    }
+
+    return orig_n - n;
+}
+
+vga_tty::vga_tty()
+{
+    snprintf(this->name, sizeof(this->name), "ttyVGA");
+}
+
+serial_tty::serial_tty(int id)
+    : id(id)
+{
+    snprintf(this->name, sizeof(this->name), "ttyS%x", (int)id);
+}
+
+void serial_tty::putchar(char c)
+{
+    serial_send_data(id, c);
+}
+
+void vga_tty::putchar(char c)
+{
+    static struct vga_char vc = { .c = '\0', .color = VGA_CHAR_COLOR_WHITE };
+    vc.c = c;
+    vga_put_char(&vc);
+}
+
+void vga_tty::recvchar(char c)
+{
+    // TODO: keyboard scan code
+    buf.put(c);
+}
+
+void serial_tty::recvchar(char c)
+{
+    switch (c) {
+    case '\r':
+        buf.put('\n');
+        if (echo) {
+            serial_send_data(PORT_SERIAL0, '\r');
+            serial_send_data(PORT_SERIAL0, '\n');
+        }
+        this->blocklist.notify();
+        break;
+    // ^?: backspace
+    case 0x7f:
+        if (!buf.empty() && buf.back() != '\n')
+            buf.pop();
+
+        if (echo) {
+            serial_send_data(PORT_SERIAL0, 0x08);
+            serial_send_data(PORT_SERIAL0, '\x1b');
+            serial_send_data(PORT_SERIAL0, '[');
+            serial_send_data(PORT_SERIAL0, 'K');
+        }
+        break;
+    // ^U: clear the line
+    case 0x15:
+        while (!buf.empty() && buf.back() != '\n')
+            buf.pop();
+
+        if (echo) {
+            serial_send_data(PORT_SERIAL0, '\r');
+            serial_send_data(PORT_SERIAL0, '\x1b');
+            serial_send_data(PORT_SERIAL0, '[');
+            serial_send_data(PORT_SERIAL0, '2');
+            serial_send_data(PORT_SERIAL0, 'K');
+        }
+        break;
+    default:
+        buf.put(c);
+        if (echo)
+            serial_send_data(PORT_SERIAL0, c);
+        break;
+    }
+}

+ 8 - 4
src/kernel/vfs.cpp

@@ -1,7 +1,7 @@
 #include <kernel/errno.h>
 #include <kernel/mem.h>
-#include <kernel/stdio.h>
-#include <kernel/tty.h>
+#include <kernel/stdio.hpp>
+#include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
 #include <types/allocator.hpp>
 #include <types/assert.h>
@@ -473,11 +473,15 @@ size_t b_null_write(fs::special_node*, const char*, size_t, size_t n)
 {
     return n;
 }
+static size_t console_read(fs::special_node*, char* buf, size_t buf_size, size_t, size_t n)
+{
+    return console->read(buf, buf_size, n);
+}
 static size_t console_write(fs::special_node*, const char* buf, size_t, size_t n)
 {
     size_t orig_n = n;
     while (n--)
-        console->ops->put_char(console, *(buf++));
+        console->putchar(*(buf++));
 
     return orig_n;
 }
@@ -489,7 +493,7 @@ void init_vfs(void)
     register_special_block(0, 0, b_null_read, b_null_write, 0, 0);
     // console (supports serial console only for now)
     // TODO: add interface to bind console device to other devices
-    register_special_block(1, 0, nullptr, console_write, 0, 0);
+    register_special_block(1, 0, console_read, console_write, 0, 0);
 
     fs_es = types::pnew<types::kernel_ident_allocator>(fs_es);
 

+ 2 - 2
src/kernel/vga.c → src/kernel/vga.cpp

@@ -1,8 +1,8 @@
 #define _KERNEL_VGA_C_
 #include <types/stdint.h>
 
-#include <kernel/stdio.h>
-#include <kernel/vga.h>
+#include <kernel/stdio.hpp>
+#include <kernel/vga.hpp>
 
 static struct vga_char* p_vga_head = VGA_MEM;
 

+ 47 - 41
src/kernel_main.c → src/kernel_main.cpp

@@ -1,4 +1,4 @@
-#include "kernel_main.h"
+#include "kernel_main.hpp"
 
 #include <asm/boot.h>
 #include <asm/port_io.h>
@@ -9,26 +9,22 @@
 #include <kernel/hw/timer.h>
 #include <kernel/interrupt.h>
 #include <kernel/mem.h>
-#include <kernel/stdio.h>
+#include <kernel/process.hpp>
+#include <kernel/stdio.hpp>
 #include <kernel/task.h>
-#include <kernel/tty.h>
-#include <kernel/vga.h>
+#include <kernel/tty.hpp>
+#include <kernel/vga.hpp>
 #include <types/assert.h>
 #include <types/bitmap.h>
 #include <types/status.h>
+#include <types/stdint.h>
 #include <types/types.h>
 
 #define KERNEL_MAIN_BUF_SIZE (128)
 
-struct tty* console = NULL;
 #define printkf(x...)                       \
     snprintf(buf, KERNEL_MAIN_BUF_SIZE, x); \
-    tty_print(console, buf)
-
-#define EVE_START(x) printkf(x "... ")
-#define INIT_START(x) EVE_START("initializing " x)
-#define INIT_OK() printkf("ok\n")
-#define INIT_FAILED() printkf("failed\n")
+    console->print(buf)
 
 typedef void (*constructor)(void);
 extern constructor start_ctors;
@@ -123,12 +119,32 @@ void init_bss_section(void)
     memset(bss_addr, 0x00, bss_size);
 }
 
-static struct tty early_console;
+int init_console(const char* name)
+{
+    if (name[0] == 't' && name[1] == 't' && name[2] == 'y') {
+        if (name[3] == 'S' || name[3] == 's') {
+            if (name[4] == '0') {
+                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL0);
+                return GB_OK;
+            }
+            if (name[4] == '1') {
+                console = types::_new<types::kernel_ident_allocator, serial_tty>(PORT_SERIAL1);
+                return GB_OK;
+            }
+        }
+        if (name[3] == 'V' && name[3] == 'G' && name[3] == 'A') {
+            console = types::_new<types::kernel_ident_allocator, vga_tty>();
+            return GB_OK;
+        }
+    }
+    crash();
+    return GB_FAILED;
+}
 
 extern void init_vfs();
-extern void NORETURN init_scheduler();
+extern "C" uint32_t check_a20_on(void);
 
-void NORETURN kernel_main(void)
+extern "C" void NORETURN kernel_main(void)
 {
     assert(check_a20_on());
 
@@ -140,49 +156,39 @@ void NORETURN kernel_main(void)
 
     load_new_gdt();
 
-    char buf[KERNEL_MAIN_BUF_SIZE] = { 0 };
-
-    assert(init_serial_port(PORT_SERIAL0) == GB_OK);
-    assert(make_serial_tty(&early_console, PORT_SERIAL0) == GB_OK);
-    console = &early_console;
-
-    show_mem_info(buf);
-
-    INIT_START("exception handlers");
-    init_idt();
-    INIT_OK();
-
     // NOTE:
     // the initializer of c++ global objects MUST NOT contain
     // all kinds of memory allocations
-    INIT_START("C++ global objects");
     call_constructors_for_cpp();
-    INIT_OK();
 
-    INIT_START("memory allocation");
-    init_mem();
-    INIT_OK();
+    char buf[KERNEL_MAIN_BUF_SIZE] = { 0 };
+
+    assert(init_serial_port(PORT_SERIAL0) == GB_OK);
 
-    INIT_START("programmable interrupt controller and timer");
+    init_idt();
+    init_mem();
     init_pic();
     init_pit();
-    INIT_OK();
 
-    printkf("Testing k_malloc...\n");
-    char* k_malloc_buf = (char*)k_malloc(sizeof(char) * 4097);
-    snprintf(k_malloc_buf, 4097, "This text is printed on the heap!\n");
-    tty_print(console, k_malloc_buf);
-    k_free(k_malloc_buf);
+    assert(init_console("ttyS0") == GB_OK);
+
+    show_mem_info(buf);
 
     init_vfs();
 
-    printkf("switching execution to the scheduler...\n");
-    init_scheduler(&tss);
+    kmsg("switching execution to the scheduler...\n");
+    init_scheduler();
 }
 
 void NORETURN __stack_chk_fail(void)
 {
-    tty_print(console, "***** stack smashing detected! *****\n");
+    kmsg("***** stack smashing detected! *****\n");
+    for (;;)
+        assert(0);
+}
+
+extern "C" void NORETURN __cxa_pure_virtual(void)
+{
     for (;;)
         assert(0);
 }

+ 1 - 1
src/types/elf.cpp

@@ -1,5 +1,5 @@
 #include <kernel/errno.h>
-#include <kernel/stdio.h>
+#include <kernel/stdio.hpp>
 #include <types/assert.h>
 #include <types/elf.hpp>
 #include <types/stdint.h>

+ 4 - 0
user-space-program/basic-lib.h

@@ -47,6 +47,10 @@ static inline uint32_t write(int fd, const char* buf, size_t count)
 {
     return syscall(0x01, fd, (uint32_t)buf, count);
 }
+static inline uint32_t read(int fd, char* buf, size_t count)
+{
+    return syscall(0x07, fd, (uint32_t)buf, count);
+}
 static inline void sleep(void)
 {
     syscall(0x02, 0, 0, 0);

+ 14 - 0
user-space-program/init.c

@@ -15,6 +15,20 @@ int main(int argc, char** argv)
         write(0, "parent\n", 7);
     }
 
+    char buf[128] = {};
+    for (;;) {
+        int n = read(0, buf, 5);
+        if (n)
+            write(0, buf, n);
+        else
+            write(0, "fuck!\n", 6);
+        
+        if (buf[0] == 'e' && buf[1] == 'x' && buf[2] == 'i' && buf[3] == 't') {
+            write(0, "\nexited echo mode!\n", 19);
+            break;
+        }
+    }
+
     for (;;) {
         int ret;
         pid_t pid = wait(&ret);