feat: experimental tty console with scrollback buffer.
authorMinep <zelong56@gmail.com>
Fri, 24 Jun 2022 10:08:17 +0000 (11:08 +0100)
committerMinep <zelong56@gmail.com>
Fri, 24 Jun 2022 10:08:17 +0000 (11:08 +0100)
14 files changed:
lunaix-os/includes/klibc/string.h
lunaix-os/includes/lunaix/ds/fifobuf.h [new file with mode: 0644]
lunaix-os/includes/lunaix/lxconsole.h [new file with mode: 0644]
lunaix-os/includes/lunaix/mm/pmm.h
lunaix-os/includes/lunaix/mm/vmm.h
lunaix-os/includes/lunaix/tty/console.h [new file with mode: 0644]
lunaix-os/includes/lunaix/tty/tty.h
lunaix-os/kernel/k_init.c
lunaix-os/kernel/kprintf.c
lunaix-os/kernel/lxconsole.c [new file with mode: 0644]
lunaix-os/kernel/lxinit.c
lunaix-os/kernel/mm/pmm.c
lunaix-os/kernel/proc0.c
lunaix-os/kernel/tty/tty.c

index 9cbcb31d06ae7a8501dc7862ac5fb7793343673c..8337ef188278663813ec1b4dcdd04d1281906256 100644 (file)
@@ -4,16 +4,16 @@
 #include <stddef.h>
 
 int
-memcmp(const void*, const void*, size_t);
+memcmp(const void* dest, const void* src, size_t size);
 
 void*
-memcpy(void* __restrict, const void* __restrict, size_t);
+memcpy(void* dest, const void* src, size_t size);
 
 void*
-memmove(void*, const void*, size_t);
+memmove(void* dest, const void* src, size_t size);
 
 void*
-memset(void*, int, size_t);
+memset(void* dest, int val, size_t size);
 
 size_t
 strlen(const char* str);
diff --git a/lunaix-os/includes/lunaix/ds/fifobuf.h b/lunaix-os/includes/lunaix/ds/fifobuf.h
new file mode 100644 (file)
index 0000000..f5f08c1
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __LUNAIX_FIFO_BUF_H
+#define __LUNAIX_FIFO_BUF_H
+
+#include <lunaix/ds/mutex.h>
+
+#define FIFO_DIRTY 1
+
+struct fifo_buffer
+{
+    void* data;
+    unsigned int wr_pos;
+    unsigned int rd_pos;
+    unsigned int size;
+    unsigned int flags;
+    mutex_t lock;
+};
+
+#endif /* __LUNAIX_FIFO_BUF_H */
diff --git a/lunaix-os/includes/lunaix/lxconsole.h b/lunaix-os/includes/lunaix/lxconsole.h
new file mode 100644 (file)
index 0000000..a264766
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __LUNAIX_LXCONSOLE_H
+#define __LUNAIX_LXCONSOLE_H
+
+void
+lxconsole_init();
+
+void
+console_write_str(char* str);
+
+void
+console_write_char(char chr);
+
+void
+console_start_flushing();
+#endif /* __LUNAIX_LXCONSOLE_H */
index d45af82653481d13ed7247ea1f91b0e2193b86f3..44aa99d7b0f2e8120b970ecc1343aedd45031320 100644 (file)
@@ -2,19 +2,29 @@
 #define __LUNAIX_PMM_H
 // Physical memory manager
 
-#include <stdint.h>
-#include <stddef.h>
 #include <lunaix/process.h>
+#include <stddef.h>
+#include <stdint.h>
 
-#define PM_PAGE_SIZE            4096
-#define PM_BMP_MAX_SIZE        (1024 * 1024)
+#define PM_PAGE_SIZE 4096
+#define PM_BMP_MAX_SIZE (1024 * 1024)
 
+/**
+ * @brief 长久页:不会被缓存,但允许释放
+ *
+ */
+#define PP_FGPERSIST 0x1
 
-#define PP_FGPERSIST            0x1
+/**
+ * @brief 锁定页:不会被缓存,不能被释放
+ *
+ */
+#define PP_FGLOCKED 0x2
 
 typedef uint32_t pp_attr_t;
 
-struct pp_struct {
+struct pp_struct
+{
     pid_t owner;
     uint32_t ref_counts;
     pp_attr_t attr;
@@ -22,70 +32,81 @@ struct pp_struct {
 
 /**
  * @brief 标注物理页为可使用
- * 
+ *
  * @param ppn page number
  */
-void pmm_mark_page_free(uintptr_t ppn);
+void
+pmm_mark_page_free(uintptr_t ppn);
 
 /**
  * @brief 标注物理页为已占用
- * 
- * @param ppn 
+ *
+ * @param ppn
  */
-void pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr);
+void
+pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr);
 
 /**
  * @brief 标注多个连续的物理页为可用
- * 
+ *
  * @param start_ppn 起始PPN
  * @param page_count 数量
  */
-void pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count);
+void
+pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count);
 
 /**
  * @brief 标注多个连续的物理页为已占用
- * 
+ *
  * @param start_ppn 起始PPN
  * @param page_count 数量
  */
-void pmm_mark_chunk_occupied(pid_t owner, uintptr_t start_ppn, size_t page_count, pp_attr_t attr);
+void
+pmm_mark_chunk_occupied(pid_t owner,
+                        uintptr_t start_ppn,
+                        size_t page_count,
+                        pp_attr_t attr);
 
 /**
  * @brief 分配一个可用的物理页
- * 
+ *
  * @return void* 可用的页地址,否则为 NULL
  */
-void* pmm_alloc_page(pid_t owner, pp_attr_t attr);
+void*
+pmm_alloc_page(pid_t owner, pp_attr_t attr);
 
 /**
  * @brief 分配一个连续的物理内存区域
- * 
- * @param owner 
+ *
+ * @param owner
  * @param num_pages 区域大小,单位为页
- * @param attr 
- * @return void* 
+ * @param attr
+ * @return void*
  */
 void*
 pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr);
 
 /**
  * @brief 初始化物理内存管理器
- * 
+ *
  * @param mem_upper_lim 最大可用内存地址
  */
-void pmm_init(uintptr_t mem_upper_lim);
+void
+pmm_init(uintptr_t mem_upper_lim);
 
-struct pp_struct* pmm_query(void* pa);
+struct pp_struct*
+pmm_query(void* pa);
 
 /**
  * @brief 释放一个已分配的物理页,假若页地址不存在,则无操作。
- * 
+ *
  * @param page 页地址
  * @return 是否成功
  */
-int pmm_free_page(pid_t owner, void* page);
-
+int
+pmm_free_page(pid_t owner, void* page);
 
-int pmm_ref_page(pid_t owner, void* page);
+int
+pmm_ref_page(pid_t owner, void* page);
 
 #endif /* __LUNAIX_PMM_H */
index bd074c54d41b2466e1455fa7c0e8aee365d6384a..eab731589745221569db2354440449e4727ab41d 100644 (file)
  */
 #define VMAP_NOMAP 2
 
+/**
+ * @brief 规定下一个可用页映射应当限定在指定的4MB地址空间内
+ *
+ */
+#define VALLOC_PDE 1
+
 /**
  * @brief 初始化虚拟内存管理器
  *
@@ -97,4 +103,7 @@ vmm_mount_pd(uintptr_t mnt, void* pde);
 void*
 vmm_unmount_pd(uintptr_t mnt);
 
+void*
+vmm_next_free(uintptr_t start, int options);
+
 #endif /* __LUNAIX_VMM_H */
diff --git a/lunaix-os/includes/lunaix/tty/console.h b/lunaix-os/includes/lunaix/tty/console.h
new file mode 100644 (file)
index 0000000..5e0ffcc
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __LUNAIX_CONSOLE_H
+#define __LUNAIX_CONSOLE_H
+
+#include <lunaix/ds/fifobuf.h>
+#include <lunaix/timer.h>
+
+struct console
+{
+    struct lx_timer* flush_timer;
+    struct fifo_buffer buffer;
+};
+
+#endif /* __LUNAIX_CONSOLE_H */
index cbb39248a02564de6182aee1a27987cfa7db48b7..518d3760a8def0797976d627417ddeb38b60400d 100644 (file)
@@ -9,8 +9,8 @@ typedef unsigned short vga_attribute;
 #define VGA_COLOR_RED 4
 #define VGA_COLOR_MAGENTA 5
 #define VGA_COLOR_BROWN 6
-#define VGA_COLOR_LIGHT_GREY 7
 #define VGA_COLOR_DARK_GREY 8
+#define VGA_COLOR_LIGHT_GREY 7
 #define VGA_COLOR_LIGHT_BLUE 9
 #define VGA_COLOR_LIGHT_GREEN 10
 #define VGA_COLOR_LIGHT_CYAN 11
@@ -19,42 +19,25 @@ typedef unsigned short vga_attribute;
 #define VGA_COLOR_LIGHT_BROWN 14
 #define VGA_COLOR_WHITE 15
 
-void 
-tty_init(void* vga_buf);
+#define TTY_WIDTH 80
+#define TTY_HEIGHT 25
 
 void
-tty_set_buffer(void* vga_buf);
+tty_init(void* vga_buf);
 
 void
 tty_set_theme(vga_attribute fg, vga_attribute bg);
 
-void
-tty_put_char(char chr);
-
-void
-tty_put_str(char* str);
-
-void
-tty_scroll_up();
-
-void
-tty_clear();
-
-void 
-tty_clear_line(unsigned int y);
-
-void
-tty_set_cpos(unsigned int x, unsigned int y);
-
-void
-tty_get_cpos(unsigned int* x, unsigned int* y);
-
 vga_attribute
 tty_get_theme();
 
-void tty_set_cursor(unsigned char x, unsigned char y);
+size_t
+tty_flush_buffer(char* data, size_t pos, size_t limit, size_t buf_size);
 
-void tty_sync_cursor();
+void
+tty_clear_line(int line_num);
 
+void
+tty_put_str_at(char* str, int x, int y);
 
 #endif /* __LUNAIX_TTY_H */
index c173ad9621ae8c39002454daa6dacf2562cf08b7..7acd3065b15c73f86b57e81a70dcce86d9b1805f 100644 (file)
@@ -2,6 +2,7 @@
 #include <lunaix/tty/tty.h>
 
 #include <lunaix/clock.h>
+#include <lunaix/lxconsole.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/page.h>
 #include <lunaix/mm/pmm.h>
@@ -58,7 +59,12 @@ _kernel_pre_init()
     vmm_init();
     rtc_init();
 
-    tty_init((void*)VGA_BUFFER_PADDR);
+    unsigned int map_size =
+      _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t);
+
+    setup_memory((multiboot_memory_map_t*)_k_init_mb_info->mmap_addr, map_size);
+
+    tty_init((void*)VGA_BUFFER_VADDR);
     tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
 
     __kernel_ptd = cpu_rcr3();
@@ -71,14 +77,7 @@ _kernel_pre_init()
 void
 _kernel_init()
 {
-    kprintf("[MM] Mem: %d KiB, Extended Mem: %d KiB\n",
-            _k_init_mb_info->mem_lower,
-            _k_init_mb_info->mem_upper);
-
-    unsigned int map_size =
-      _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t);
-
-    setup_memory((multiboot_memory_map_t*)_k_init_mb_info->mmap_addr, map_size);
+    lxconsole_init();
 
     kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n",
             KSTACK_SIZE >> PG_SIZE_BITS,
@@ -181,31 +180,23 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size)
     // First pass, to mark the physical pages
     for (unsigned int i = 0; i < map_size; i++) {
         multiboot_memory_map_t mmap = map[i];
-        kprintf("[MM] Base: 0x%x, len: %u KiB, type: %u\n",
-                map[i].addr_low,
-                map[i].len_low >> 10,
-                map[i].type);
         if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE) {
             // 整数向上取整除法
             uintptr_t pg = map[i].addr_low + 0x0fffU;
             pmm_mark_chunk_free(pg >> PG_SIZE_BITS,
                                 map[i].len_low >> PG_SIZE_BITS);
-            kprintf(KINFO "[MM] Freed %u pages start from 0x%x\n",
-                    map[i].len_low >> PG_SIZE_BITS,
-                    pg & ~0x0fffU);
         }
     }
 
     // 将内核占据的页,包括前1MB,hhk_init 设为已占用
     size_t pg_count = V2P(&__kernel_end) >> PG_SIZE_BITS;
     pmm_mark_chunk_occupied(KERNEL_PID, 0, pg_count, 0);
-    kprintf(KINFO "[MM] Allocated %d pages for kernel.\n", pg_count);
 
     size_t vga_buf_pgs = VGA_BUFFER_SIZE >> PG_SIZE_BITS;
 
-    // 首先,标记VGA部分为已占用
+    // 首先,标记VGA部分为已占用,并且锁定
     pmm_mark_chunk_occupied(
-      KERNEL_PID, VGA_BUFFER_PADDR >> PG_SIZE_BITS, vga_buf_pgs, 0);
+      KERNEL_PID, VGA_BUFFER_PADDR >> PG_SIZE_BITS, vga_buf_pgs, PP_FGLOCKED);
 
     // 重映射VGA文本缓冲区(以后会变成显存,i.e., framebuffer)
     for (size_t i = 0; i < vga_buf_pgs; i++) {
@@ -216,16 +207,7 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size)
                         VMAP_NULL);
     }
 
-    assert_msg(!((uintptr_t)&__usrtext_start & 0xfff) &&
-                 !((uintptr_t)&__usrtext_end & 0xfff),
-               "Bad usrtext alignment");
-
     for (uintptr_t i = &__usrtext_start; i < &__usrtext_end; i += PG_SIZE) {
         vmm_set_mapping(PD_REFERENCED, i, V2P(i), PG_PREM_UR, VMAP_NULL);
     }
-
-    // 更新VGA缓冲区位置至虚拟地址
-    tty_set_buffer((void*)VGA_BUFFER_VADDR);
-
-    kprintf(KINFO "[MM] Mapped VGA to %p.\n", VGA_BUFFER_VADDR);
 }
index a862bcc7db97a873d0735348ac99aaa3a74cff79..374fff2993c8f6ef35376883f0a3e5265db18b3d 100644 (file)
@@ -1,6 +1,7 @@
+#include <klibc/stdio.h>
+#include <lunaix/lxconsole.h>
 #include <lunaix/syslog.h>
 #include <lunaix/tty/tty.h>
-#include <klibc/stdio.h>
 
 #define MAX_KPRINTF_BUF_SIZE 1024
 #define MAX_XFMT_SIZE 1024
@@ -8,57 +9,81 @@
 static char buf[MAX_KPRINTF_BUF_SIZE];
 
 void
-__kprintf(const char* component, const char* fmt, va_list args) {
-    if (!fmt) return;
+__kprintf(const char* component, const char* fmt, va_list args)
+{
+    if (!fmt)
+        return;
     char log_level = '0';
     char expanded_fmt[MAX_XFMT_SIZE];
-    vga_attribute current_theme = tty_get_theme();
 
     if (*fmt == '\x1b') {
         log_level = *(++fmt);
         fmt++;
     }
 
-    switch (log_level)
-    {
-    case '0':
-        snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "INFO", component, fmt);
-        break;
-    case '1':
-        tty_set_theme(VGA_COLOR_BROWN, current_theme >> 12);
-        snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "WARN", component, fmt);
-        break;
-    case '2':
-        tty_set_theme(VGA_COLOR_LIGHT_RED, current_theme >> 12);
-        snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "EROR", component, fmt);
-        break;
-    case '3':
-        tty_set_theme(VGA_COLOR_LIGHT_BLUE, current_theme >> 12);
-        snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "DEBG", component, fmt);
-        break;
-    default:
-        snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "LOG", component, fmt);
-        break;
+    switch (log_level) {
+        case '0':
+            snprintf(expanded_fmt,
+                     MAX_XFMT_SIZE,
+                     "[%s] (%s) %s",
+                     "INFO",
+                     component,
+                     fmt);
+            break;
+        case '1':
+            // tty_set_theme(VGA_COLOR_BROWN, current_theme >> 12);
+            snprintf(expanded_fmt,
+                     MAX_XFMT_SIZE,
+                     "\x033[6;0m[%s] (%s) %s\x033[39;49m",
+                     "WARN",
+                     component,
+                     fmt);
+            break;
+        case '2':
+            // tty_set_theme(VGA_COLOR_LIGHT_RED, current_theme >> 12);
+            snprintf(expanded_fmt,
+                     MAX_XFMT_SIZE,
+                     "\x033[12;0m[%s] (%s) %s\x033[39;49m",
+                     "EROR",
+                     component,
+                     fmt);
+            break;
+        case '3':
+            // tty_set_theme(VGA_COLOR_LIGHT_BLUE, current_theme >> 12);
+            snprintf(expanded_fmt,
+                     MAX_XFMT_SIZE,
+                     "\x033[9;0m[%s] (%s) %s\x033[39;49m",
+                     "DEBG",
+                     component,
+                     fmt);
+            break;
+        default:
+            snprintf(expanded_fmt,
+                     MAX_XFMT_SIZE,
+                     "[%s] (%s) %s",
+                     "LOG",
+                     component,
+                     fmt);
+            break;
     }
 
     __sprintf_internal(buf, expanded_fmt, MAX_KPRINTF_BUF_SIZE, args);
-    tty_put_str(buf);
-    tty_set_theme(current_theme >> 8, current_theme >> 12);
+    console_write_str(buf);
 }
 
 void
-kprint_panic(const char* fmt, ...) {
+kprint_panic(const char* fmt, ...)
+{
     va_list args;
     va_start(args, fmt);
-    
+
     tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_RED);
     tty_clear_line(10);
     tty_clear_line(11);
     tty_clear_line(12);
-    tty_set_cpos(0, 11);
 
     __sprintf_internal(buf, fmt, MAX_KPRINTF_BUF_SIZE, args);
-    tty_put_str(buf);
+    tty_put_str_at(buf, 0, 11);
 
     va_end(args);
 }
\ No newline at end of file
diff --git a/lunaix-os/kernel/lxconsole.c b/lunaix-os/kernel/lxconsole.c
new file mode 100644 (file)
index 0000000..25c4faa
--- /dev/null
@@ -0,0 +1,136 @@
+#include <klibc/string.h>
+#include <lunaix/lxconsole.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/tty/console.h>
+#include <lunaix/tty/tty.h>
+
+static struct console lx_console;
+
+volatile int can_flush = 0;
+
+void
+lxconsole_init()
+{
+    memset(&lx_console, 0, sizeof(lx_console));
+    lx_console.buffer.data = VGA_BUFFER_VADDR + 0x1000;
+    lx_console.buffer.size = 8192;
+    mutex_init(&lx_console.buffer.lock);
+
+    // 分配控制台缓存
+    for (size_t i = 0; i < PG_ALIGN(lx_console.buffer.size); i += PG_SIZE) {
+        uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
+        vmm_set_mapping(PD_REFERENCED,
+                        (uintptr_t)lx_console.buffer.data + i,
+                        pa,
+                        PG_PREM_URW,
+                        0);
+    }
+
+    memset(lx_console.buffer.data, 0, lx_console.buffer.size);
+
+    lx_console.flush_timer = NULL;
+}
+
+void
+console_schedule_flush()
+{
+    // TODO make the flush on-demand rather than periodic
+}
+
+void
+console_view_up(struct fifo_buffer* buffer)
+{
+    // mutex_lock(&buffer->lock);
+    size_t p = buffer->rd_pos - 2;
+    while (p < buffer->rd_pos && p != buffer->wr_pos &&
+           ((char*)buffer->data)[p] != '\n') {
+        p--;
+    }
+    p++;
+
+    if (p < buffer->rd_pos) {
+        p = 0;
+    }
+
+    buffer->rd_pos = p;
+    // mutex_unlock(&buffer->lock);
+}
+
+void
+console_view_down(struct fifo_buffer* buffer)
+{
+    // mutex_lock(&buffer->lock);
+    size_t p = buffer->rd_pos;
+    while (p != buffer->wr_pos && ((char*)buffer->data)[p] != '\n') {
+        p = (p + 1) % buffer->size;
+    }
+
+    buffer->rd_pos = p + 1;
+    // mutex_unlock(&buffer->lock);
+}
+
+void
+__flush_cb(void* arg)
+{
+    if (mutex_on_hold(&lx_console.buffer.lock)) {
+        return;
+    }
+    if (!(lx_console.buffer.flags & FIFO_DIRTY)) {
+        return;
+    }
+
+    size_t pos = tty_flush_buffer(lx_console.buffer.data,
+                                  lx_console.buffer.rd_pos,
+                                  lx_console.buffer.wr_pos,
+                                  lx_console.buffer.size);
+    lx_console.flush_timer = NULL;
+    if (pos < lx_console.buffer.wr_pos) {
+        console_view_down(&lx_console.buffer);
+    } else {
+        // clear the dirty bit only if we have flush all the data
+        //  that means: read pointer == write pointer
+        lx_console.buffer.flags &= ~FIFO_DIRTY;
+    }
+}
+
+void
+console_write(struct console* console, uint8_t* data, size_t size)
+{
+    mutex_lock(&console->buffer.lock);
+    uint8_t* buffer = console->buffer.data;
+    uintptr_t ptr = console->buffer.wr_pos;
+    uintptr_t rd_ptr = console->buffer.rd_pos;
+
+    for (size_t i = 0; i < size; i++) {
+        buffer[(ptr + i) % console->buffer.size] = data[i];
+    }
+
+    uintptr_t new_ptr = (ptr + size) % console->buffer.size;
+    console->buffer.wr_pos = new_ptr;
+    if (new_ptr < ptr + size && new_ptr > rd_ptr) {
+        console->buffer.rd_pos = new_ptr;
+    }
+    console->buffer.flags |= FIFO_DIRTY;
+    mutex_unlock(&console->buffer.lock);
+}
+
+void
+console_write_str(char* str)
+{
+    console_write(&lx_console, str, strlen(str));
+}
+
+void
+console_write_char(char str)
+{
+    console_write(&lx_console, &str, 1);
+}
+
+void
+console_start_flushing()
+{
+    struct lx_timer* timer =
+      timer_run_ms(20, __flush_cb, NULL, TIMER_MODE_PERIODIC);
+    lx_console.flush_timer = timer;
+}
\ No newline at end of file
index 91a4e504192401162709b8dafad6d11b266e8b38..8a19841f5c87c88b0e48b528a7e6a29a5fe01d73 100644 (file)
@@ -2,6 +2,7 @@
 #include <lunaix/clock.h>
 #include <lunaix/keyboard.h>
 #include <lunaix/lunistd.h>
+#include <lunaix/lxconsole.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/proc.h>
@@ -9,7 +10,6 @@
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
 #include <lunaix/timer.h>
-#include <lunaix/tty/tty.h>
 
 extern uint8_t __kernel_start;
 
@@ -94,8 +94,7 @@ _lxinit_main()
             if (i == 3) {
                 i = *(int*)0xdeadc0de; // seg fault!
             }
-            tty_put_char('0' + i);
-            tty_put_char('\n');
+            kprintf(KINFO "%d\n", i);
             _exit(0);
         }
         kprintf(KINFO "Forked %d\n", pid);
@@ -133,7 +132,7 @@ _lxinit_main()
         }
         if ((keyevent.state & KBD_KEY_FPRESSED) &&
             (keyevent.keycode & 0xff00) <= KEYPAD) {
-            tty_put_char((char)(keyevent.keycode & 0x00ff));
+            console_write_char((char)(keyevent.keycode & 0x00ff));
             // FIXME: io to vga port is privileged and cause #GP in user mode
             // tty_sync_cursor();
         }
index ad80dbf95394c0aafcc4b8fa56c045d87839434d..9c0d3eb44272bda83e4fbe931408261a6801ba75 100644 (file)
@@ -16,32 +16,27 @@ pmm_mark_page_free(uintptr_t ppn)
 void
 pmm_mark_page_occupied(pid_t owner, uintptr_t ppn, pp_attr_t attr)
 {
-    pm_table[ppn] = (struct pp_struct) {
-        .owner = owner,
-        .ref_counts = 1,
-        .attr = attr
-    };
+    pm_table[ppn] =
+      (struct pp_struct){ .owner = owner, .ref_counts = 1, .attr = attr };
 }
 
 void
 pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
 {
-    for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++)
-    {
+    for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
         pm_table[i].ref_counts = 0;
     }
 }
 
 void
-pmm_mark_chunk_occupied(pid_t owner, uint32_t start_ppn, size_t page_count, pp_attr_t attr)
+pmm_mark_chunk_occupied(pid_t owner,
+                        uint32_t start_ppn,
+                        size_t page_count,
+                        pp_attr_t attr)
 {
-    for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++)
-    {
-        pm_table[i] = (struct pp_struct) {
-            .owner = owner,
-            .ref_counts = 1,
-            .attr = attr
-        };
+    for (size_t i = start_ppn; i < start_ppn + page_count && i < max_pg; i++) {
+        pm_table[i] =
+          (struct pp_struct){ .owner = owner, .ref_counts = 1, .attr = attr };
     }
 }
 
@@ -59,21 +54,18 @@ pmm_init(uintptr_t mem_upper_lim)
 
     // mark all as occupied
     for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
-        pm_table[i] = (struct pp_struct) {
-            .owner = 0,
-            .attr = 0,
-            .ref_counts = 1
-        };
+        pm_table[i] =
+          (struct pp_struct){ .owner = 0, .attr = 0, .ref_counts = 1 };
     }
 }
 
 void*
-pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr) {
+pmm_alloc_cpage(pid_t owner, size_t num_pages, pp_attr_t attr)
+{
     size_t p1 = 0;
     size_t p2 = 0;
 
-    while (p2 < max_pg && p2 - p1 < num_pages)
-    {
+    while (p2 < max_pg && p2 - p1 < num_pages) {
         (!(&pm_table[p2])->ref_counts) ? (p2++) : (p1 = p2);
     }
 
@@ -98,11 +90,9 @@ pmm_alloc_page(pid_t owner, pp_attr_t attr)
         pm = &pm_table[pg_lookup_ptr];
 
         if (!pm->ref_counts) {
-            *pm = (struct pp_struct) {
-                .attr = attr,
-                .owner = owner,
-                .ref_counts = 1
-            };
+            *pm = (struct pp_struct){ .attr = attr,
+                                      .owner = owner,
+                                      .ref_counts = 1 };
             good_page_found = pg_lookup_ptr << 12;
             break;
         } else {
@@ -128,22 +118,30 @@ int
 pmm_free_page(pid_t owner, void* page)
 {
     struct pp_struct* pm = &pm_table[(intptr_t)page >> 12];
-    
+
     // Is this a MMIO mapping or double free?
     if (((intptr_t)page >> 12) >= max_pg || !(pm->ref_counts)) {
         return 0;
     }
 
-    // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放; 2) 内核可释放所有页。
+    // 如果是锁定页,则不作处理
+    if ((pm->attr & PP_FGLOCKED)) {
+        return 0;
+    }
+
+    // TODO: 检查权限,保证:1) 只有正在使用该页(包括被分享者)的进程可以释放;
+    // 2) 内核可释放所有页。
     pm->ref_counts--;
     return 1;
 }
 
-int pmm_ref_page(pid_t owner, void* page) {
-    (void*) owner;      // TODO: do smth with owner
-    
+int
+pmm_ref_page(pid_t owner, void* page)
+{
+    (void*)owner; // TODO: do smth with owner
+
     uint32_t ppn = (uintptr_t)page >> 12;
-    
+
     if (ppn >= PM_BMP_MAX_SIZE) {
         return 0;
     }
@@ -157,9 +155,11 @@ int pmm_ref_page(pid_t owner, void* page) {
     return 1;
 }
 
-struct pp_struct* pmm_query(void* pa) {
+struct pp_struct*
+pmm_query(void* pa)
+{
     uint32_t ppn = (uintptr_t)pa >> 12;
-    
+
     if (ppn >= PM_BMP_MAX_SIZE) {
         return NULL;
     }
index 4cc414c4d28cd92b8b91ae66b40bc2b496ecf6ab..cece3687e4abd30e0c9949d87e34ccedf49498a9 100644 (file)
@@ -1,6 +1,7 @@
 #include <arch/x86/boot/multiboot.h>
 #include <lunaix/common.h>
 #include <lunaix/lunistd.h>
+#include <lunaix/lxconsole.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/peripheral/ps2kbd.h>
@@ -84,12 +85,6 @@ init_platform()
 {
     assert_msg(kalloc_init(), "Fail to initialize heap");
 
-    // Fuck it, I will no longer bother this little 1MiB
-    // I just release 4 pages for my APIC & IOAPIC remappings
-    // for (size_t i = 0; i < 3; i++) {
-    //     vmm_del_mapping(PD_REFERENCED, (void*)(i << PG_SIZE_BITS));
-    // }
-
     // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射
     lock_reserved_memory();
 
@@ -112,6 +107,8 @@ init_platform()
 
     syscall_install();
 
+    console_start_flushing();
+
     unlock_reserved_memory();
 
     for (size_t i = 0; i < (uintptr_t)(&__init_hhk_end); i += PG_SIZE) {
index 41642390ecdd4c03e4231699010243e2a3d9dbc7..b4913559410ffb7993a85fe04979ef5d240c5571 100644 (file)
@@ -1,24 +1,27 @@
 #include <hal/io.h>
 #include <klibc/string.h>
 #include <lunaix/common.h>
+#include <lunaix/spike.h>
+#include <lunaix/tty/console.h>
 #include <lunaix/tty/tty.h>
 #include <stdint.h>
 
-#define TTY_WIDTH 80
-#define TTY_HEIGHT 25
+vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR;
 
-static vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR;
+vga_attribute tty_theme_color = VGA_COLOR_BLACK;
 
-static vga_attribute tty_theme_color = VGA_COLOR_BLACK;
-
-static uint32_t tty_x = 0;
-static uint32_t tty_y = 0;
+#define TTY_CLEAR                                                              \
+    asm volatile("rep stosw" ::"D"(tty_vga_buffer),                            \
+                 "c"(TTY_HEIGHT * TTY_WIDTH),                                  \
+                 "a"(tty_theme_color)                                          \
+                 : "memory");
 
 void
 tty_init(void* vga_buf)
 {
     tty_vga_buffer = (vga_attribute*)vga_buf;
-    tty_clear();
+
+    TTY_CLEAR
 
     io_outb(0x3D4, 0x0A);
     io_outb(0x3D5, (io_inb(0x3D5) & 0xC0) | 13);
@@ -27,56 +30,85 @@ tty_init(void* vga_buf)
     io_outb(0x3D5, (io_inb(0x3D5) & 0xE0) | 15);
 }
 
-void
-tty_set_buffer(void* vga_buf)
-{
-    tty_vga_buffer = (vga_attribute*)vga_buf;
-}
-
 void
 tty_set_theme(vga_attribute fg, vga_attribute bg)
 {
     tty_theme_color = (bg << 4 | fg) << 8;
 }
 
-void
-tty_put_char(char chr)
+size_t
+tty_flush_buffer(char* data, size_t pos, size_t limit, size_t buf_size)
 {
-    switch (chr) {
-        case '\t':
-            tty_x += 4;
-            break;
-        case '\n':
-            tty_y++;
-            // fall through
-        case '\r':
-            tty_x = 0;
-            break;
-        case '\x08':
-            tty_x = tty_x ? tty_x - 1 : 0;
-            *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) =
-              (tty_theme_color | 0x20);
-            break;
-        default:
-            *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) =
-              (tty_theme_color | chr);
-            tty_x++;
-            break;
-    }
+    int x = 0, y = 0;
 
-    if (tty_x >= TTY_WIDTH) {
-        tty_x = 0;
-        tty_y++;
-    }
-    if (tty_y >= TTY_HEIGHT) {
-        tty_scroll_up();
-    }
-}
+    // Clear screen
+    TTY_CLEAR
 
-void
-tty_sync_cursor()
-{
-    tty_set_cursor(tty_x, tty_y);
+    int state = 0;
+    int g[2] = { 0, 0 };
+    vga_attribute current_theme = tty_theme_color;
+    while (1) {
+        size_t ptr = pos % buf_size;
+        if (pos == limit) {
+            break;
+        }
+        char chr = data[pos];
+        if (state == 0 && chr == '\x033') {
+            state = 1;
+        } else if (state == 1 && chr == '[') {
+            state = 2;
+        } else if (state > 1) {
+            if ('0' <= chr && chr <= '9') {
+                g[state - 2] = (chr - '0') + g[state - 2] * 10;
+            } else if (chr == ';' && state == 2) {
+                state = 3;
+            } else {
+                if (g[0] == 39 && g[1] == 49) {
+                    current_theme = tty_theme_color;
+                } else {
+                    current_theme = (g[1] << 4 | g[0]) << 8;
+                }
+                g[0] = 0;
+                g[1] = 0;
+                state = 0;
+            }
+        } else {
+            state = 0;
+            switch (chr) {
+                case '\t':
+                    x += 4;
+                    break;
+                case '\n':
+                    y++;
+                    // fall through
+                case '\r':
+                    x = 0;
+                    break;
+                case '\x08':
+                    x = x ? x - 1 : 0;
+                    *(tty_vga_buffer + x + y * TTY_WIDTH) =
+                      (current_theme | 0x20);
+                    break;
+                default:
+                    *(tty_vga_buffer + x + y * TTY_WIDTH) =
+                      (current_theme | chr);
+                    (x)++;
+                    break;
+            }
+
+            if (x >= TTY_WIDTH) {
+                x = 0;
+                y++;
+            }
+            if (y >= TTY_HEIGHT) {
+                y--;
+                break;
+            }
+        }
+        pos++;
+    }
+    tty_set_cursor(x, y);
+    return pos;
 }
 
 void
@@ -93,64 +125,25 @@ tty_set_cursor(uint8_t x, uint8_t y)
 }
 
 void
-tty_put_str(char* str)
-{
-    while (*str != '\0') {
-        tty_put_char(*str);
-        str++;
-    }
-    // FIXME: This does not work in user mode.
-    // Work around:
-    //  1. (Easy) Define an IO Permission bitmap in TSS
-    //  2. (More effort) Mount onto file system. (/dev/tty)
-    // tty_sync_cursor();
-}
-
-void
-tty_scroll_up()
+tty_clear_line(int line_num)
 {
-    size_t last_line = TTY_WIDTH * (TTY_HEIGHT - 1);
-    memcpy(tty_vga_buffer, tty_vga_buffer + TTY_WIDTH, last_line * 2);
-    for (size_t i = 0; i < TTY_WIDTH; i++) {
-        *(tty_vga_buffer + i + last_line) = tty_theme_color;
-    }
-    tty_y = tty_y == 0 ? 0 : TTY_HEIGHT - 1;
+    asm volatile("rep stosw" ::"D"(tty_vga_buffer + line_num * TTY_WIDTH),
+                 "c"(TTY_WIDTH),
+                 "a"(tty_theme_color)
+                 : "memory");
 }
 
 void
-tty_clear()
+tty_put_str_at(char* str, int x, int y)
 {
-    for (uint32_t i = 0; i < TTY_WIDTH * TTY_HEIGHT; i++) {
-        *(tty_vga_buffer + i) = tty_theme_color;
-    }
-    tty_x = 0;
-    tty_y = 0;
-}
-
-void
-tty_clear_line(unsigned int y)
-{
-    for (size_t i = 0; i < TTY_WIDTH; i++) {
-        *(tty_vga_buffer + i + y * TTY_WIDTH) = tty_theme_color;
+    char c;
+    while ((c = (*str)) && y < TTY_HEIGHT) {
+        *(tty_vga_buffer + x + y * TTY_WIDTH) = c | tty_theme_color;
+        x++;
+        if (x >= TTY_WIDTH) {
+            y++;
+            x = 0;
+        }
+        str++;
     }
-}
-
-void
-tty_set_cpos(unsigned int x, unsigned int y)
-{
-    tty_x = x % TTY_WIDTH;
-    tty_y = y % TTY_HEIGHT;
-}
-
-void
-tty_get_cpos(unsigned int* x, unsigned int* y)
-{
-    *x = tty_x;
-    *y = tty_y;
-}
-
-vga_attribute
-tty_get_theme()
-{
-    return tty_theme_color;
 }
\ No newline at end of file