Virtual memory & paging
authorMinep <zelong56@gmail.com>
Fri, 25 Feb 2022 19:28:39 +0000 (19:28 +0000)
committerMinep <zelong56@gmail.com>
Fri, 25 Feb 2022 19:28:39 +0000 (19:28 +0000)
 vm & pm management
 higher half kernel!
 a LOT of memory remapping
 CPUID support
 start working on HAL.

34 files changed:
lunaix-os/.vscode/c_cpp_properties.json
lunaix-os/arch/x86/boot.S
lunaix-os/arch/x86/hhk.c [new file with mode: 0644]
lunaix-os/arch/x86/multiboot.h [deleted file]
lunaix-os/bochs.cfg
lunaix-os/config/make-cc
lunaix-os/hal/cpu.c [new file with mode: 0644]
lunaix-os/includes/arch/x86/boot/multiboot.h [new file with mode: 0644]
lunaix-os/includes/arch/x86/gdt.h [moved from lunaix-os/includes/lunaix/arch/gdt.h with 97% similarity]
lunaix-os/includes/arch/x86/idt.h [moved from lunaix-os/includes/lunaix/arch/idt.h with 56% similarity]
lunaix-os/includes/arch/x86/interrupts.h [new file with mode: 0644]
lunaix-os/includes/arch/x86/types.h [moved from lunaix-os/includes/lunaix/interrupts/types.h with 88% similarity]
lunaix-os/includes/hal/cpu.h [new file with mode: 0644]
lunaix-os/includes/hal/io.h [new file with mode: 0644]
lunaix-os/includes/lunaix/constants.h [new file with mode: 0644]
lunaix-os/includes/lunaix/interrupts/interrupts.h [deleted file]
lunaix-os/includes/lunaix/mm/page.h [new file with mode: 0644]
lunaix-os/includes/lunaix/mm/pmm.h [new file with mode: 0644]
lunaix-os/includes/lunaix/mm/vmm.h [new file with mode: 0644]
lunaix-os/includes/lunaix/tty/tty.h
lunaix-os/kernel/asm/x86/gdt.c [moved from lunaix-os/arch/x86/gdt.c with 95% similarity]
lunaix-os/kernel/asm/x86/idt.c [moved from lunaix-os/arch/x86/idt.c with 81% similarity]
lunaix-os/kernel/asm/x86/interrupt.S [moved from lunaix-os/arch/x86/interrupt.S with 100% similarity]
lunaix-os/kernel/asm/x86/interrupts.c [moved from lunaix-os/kernel/interrupts/interrupts.c with 56% similarity]
lunaix-os/kernel/asm/x86/prologue.S [new file with mode: 0644]
lunaix-os/kernel/k_main.c [new file with mode: 0644]
lunaix-os/kernel/kernel.c [deleted file]
lunaix-os/kernel/mm/pmm.c [new file with mode: 0644]
lunaix-os/kernel/mm/vmm.c [new file with mode: 0644]
lunaix-os/kernel/tty/tty.c
lunaix-os/libs/libc/stdio/sprintf.c
lunaix-os/libs/libc/stdlib/itoa.c
lunaix-os/linker.ld
lunaix-os/makefile

index 10acdd8538f3f7df731520218f0314c8b35480d3..0840db114b3f75d58586c634ff195f27ac550b52 100644 (file)
@@ -6,7 +6,8 @@
                 "${workspaceFolder}/includes/**"
             ],
             "compilerArgs": [
-                "-ffreestanding"
+                "-ffreestanding",
+                "-D__ARCH_IA32"
             ],
             "defines": [],
             "compilerPath": "${HOME}/opt/cross-compiler/bin/i686-elf-gcc",
index b41d24bba5cd81b887032dbfc4272ea201223ae1..bc1eec2758345b99b985c6a86f138480a72d9dbc 100644 (file)
@@ -1,62 +1,88 @@
-#include "multiboot.h"
+#define __ASM__ 1
+#include <arch/x86/boot/multiboot.h>
+
+#define MB_FLAGS    MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN
+#define KPG_SIZE    24*1024
 
 .section .multiboot
-    .long MB_MAGIC
-    .long MB_ALIGNED_4K_MEM_MAP
-    .long CHECKSUM(MB_ALIGNED_4K_MEM_MAP)
+    .long MULTIBOOT_MAGIC
+    .long MB_FLAGS
+    .long CHECKSUM(MB_FLAGS)
 
 .section .bss
-    /* According to System V ABI, the stack must be aligned at 16 bytes boundary */
+    .global mb_info
     .align 16
+    /* 为Multiboot info struct 预留空间 */
+    mb_info:
+        .skip 4096
+    /* 根据System V ABI,栈地址必须16字节对齐 */
+    /* 这里只是一个临时栈,在_hhk_init里面我们会初始化内核专用栈 */
     stack_bottom:
         .skip 16318, 0
     stack_top:
 
-.section .text
+
+/* 
+    1 page directory, 
+    5 page tables:
+        1. Mapping reserved area and hhk_init
+        2-5. Remapping the kernels
+*/
+
+.section .kpg
+    .global _k_ptd
+    _k_ptd:
+        .skip KPG_SIZE, 0
+
+
+.section .hhk_init
     .global start_
     .type start_, @function     /* Optional, this just give the 
                                  * linker more knowledge about the label 
                                  */
-    start_:
+    start_: 
         movl $stack_top, %esp
+
+        subl $16, %esp
+
         /* 
-            TODO: kernel init
-                1. Load GDT
-                2. Load IDT
-                3. Enable paging
+            将咱们的 multiboot_info 挪个地儿,就是上述预留的空间里
+            而后在_hhk_init里,我们会对所有的高半核初始化代码(arch/x86下的所有)进行Identity map
+            这样,我们能够保证当分页与虚拟地址开启后,我们的内核能够访问到multiboot info table
+         */
+
+        movl $mb_info, 4(%esp)
+        movl %ebx, (%esp)
+        call _save_multiboot_info
+
+        /*
+            _hhk_init用来初始化我们高半核:
+                    1. 设置GDT表
+                    2. 设置IDT表(暂时,以后会拿到 kernel_init 里面)
+                    3. 初始化最简单的PTD与PT(重新映射我们的内核至3GiB处,以及对相应的地方进行Identity Map)
+        */
+
+        movl $(KPG_SIZE), 4(%esp)
+        movl $(_k_ptd - 0xC0000000), (%esp)    /* PTD物理地址 */
+        call _hhk_init
+
+        /*
+            基本的映射定义好了,我们可以放心的打开分页了
+            我们只需要把PTD的基地址加载进CR3就好了。
         */
-        call _kernel_init
-        
-        subl $0x6, %esp
-
-        movl $_gdt, 2(%esp)
-        movw _gdt_limit, %ax
-        movw %ax, (%esp)
-        lgdt (%esp)
-
-        movl $_idt, 2(%esp)
-        movw _idt_limit, %ax
-        movw %ax, (%esp)
-        lidt (%esp)
-
-        addl $0x6, %esp
-
-        movw $0x10, %cx
-        movw %cx, %es
-        movw %cx, %ds
-        movw %cx, %fs
-        movw %cx, %gs
-        movw %cx, %ss
-
-        pushw $0x08
-        pushl $_after_gdt
-        retf
-
-    _after_gdt:
-        pushl %ebx
-        call _kernel_main
-
-        cli
-    j_:
-        hlt
-        jmp j_
\ No newline at end of file
+
+        /* 加载PTD基地址(物理地址) */
+        movl (%esp), %eax
+        andl $0xfffff000, %eax      # 有点多余,但写上还算明白一点
+        movl %eax, %cr3
+
+        /* 开启分页与地址转换 (CR0.PG=1) */
+        movl %cr0, %eax
+        orl $0x80000000, %eax
+        movl %eax, %cr0
+
+        addl $16, %esp
+
+        /* 进入高半核! */
+        pushl $hhk_entry_
+        ret
\ No newline at end of file
diff --git a/lunaix-os/arch/x86/hhk.c b/lunaix-os/arch/x86/hhk.c
new file mode 100644 (file)
index 0000000..c0e5f9a
--- /dev/null
@@ -0,0 +1,134 @@
+#include <arch/x86/boot/multiboot.h>
+#include <arch/x86/idt.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/constants.h>
+
+#define PT_ADDR(ptd, pt_index)                       ((ptd_t*)ptd + (pt_index + 1) * 1024)
+#define SET_PDE(ptd, pde_index, pde)                 *((ptd_t*)ptd + pde_index) = pde;
+#define SET_PTE(ptd, pt_index, pte_index, pte)       *(PT_ADDR(ptd, pt_index) + pte_index) = pte;
+#define sym_val(sym)                                 (uintptr_t)(&sym)
+
+#define KERNEL_PAGE_COUNT           ((sym_val(__kernel_end) - sym_val(__kernel_start) + 0x1000 - 1) >> 12);
+#define HHK_PAGE_COUNT              ((sym_val(__init_hhk_end) - 0x100000 + 0x1000 - 1) >> 12)
+
+// use table #1
+#define PG_TABLE_IDENTITY           0
+
+// use table #2-4
+// hence the max size of kernel is 8MiB
+#define PG_TABLE_KERNEL             1
+
+// use table #5
+#define PG_TABLE_STACK              4
+
+// Provided by linker (see linker.ld)
+extern uint8_t __kernel_start;
+extern uint8_t __kernel_end;
+extern uint8_t __init_hhk_end;
+extern uint8_t _k_stack;
+
+void 
+_init_page(ptd_t* ptd) {
+    SET_PDE(ptd, 0, PDE(PG_PRESENT, ptd + PG_MAX_ENTRIES))
+    
+    // 对低1MiB空间进行对等映射(Identity mapping),也包括了我们的VGA,方便内核操作。
+    for (uint32_t i = 0; i < 256; i++)
+    {
+        SET_PTE(ptd, PG_TABLE_IDENTITY, i, PTE(PG_PREM_RW, (i << 12)))
+    }
+
+    // 对等映射我们的hhk_init,这样一来,当分页与地址转换开启后,我们依然能够照常执行最终的 jmp 指令来跳转至
+    //  内核的入口点
+    for (uint32_t i = 0; i < HHK_PAGE_COUNT; i++)
+    {
+        SET_PTE(ptd, PG_TABLE_IDENTITY, 256 + i, PTE(PG_PREM_RW, 0x100000 + (i << 12)))
+    }
+    
+    // --- 将内核重映射至高半区 ---
+    
+    // 这里是一些计算,主要是计算应当映射进的 页目录 与 页表 的条目索引(Entry Index)
+    uint32_t kernel_pde_index = PD_INDEX(sym_val(__kernel_start));
+    uint32_t kernel_pte_index = PT_INDEX(sym_val(__kernel_start));
+    uint32_t kernel_pg_counts = KERNEL_PAGE_COUNT;
+    
+    // 将内核所需要的页表注册进页目录
+    //  当然,就现在而言,我们的内核只占用不到50个页(每个页表包含1024个页)
+    //  这里分配了3个页表(12MiB),未雨绸缪。
+    for (uint32_t i = 0; i < PG_TABLE_STACK - PG_TABLE_KERNEL; i++)
+    {
+        SET_PDE(
+            ptd, 
+            kernel_pde_index + i,   
+            PDE(PG_PREM_RW, PT_ADDR(ptd, PG_TABLE_KERNEL + i))
+        )
+    }
+    
+    // 首先,检查内核的大小是否可以fit进我们这几个表(12MiB)
+    if (kernel_pg_counts > (PG_TABLE_STACK - PG_TABLE_KERNEL) * 1024) {
+        // ERROR: require more pages
+        //  here should do something else other than head into blocking
+        while (1);
+    }
+    
+    // 计算内核.text段的物理地址
+    uintptr_t kernel_pm = V2P(&__kernel_start);
+    
+    // 重映射内核至高半区地址(>=0xC0000000)
+    for (uint32_t i = 0; i < kernel_pg_counts; i++)
+    {
+        SET_PTE(
+            ptd, 
+            PG_TABLE_KERNEL, 
+            kernel_pte_index + i, 
+            PTE(PG_PREM_RW, kernel_pm + (i << 12))
+        )
+    }
+
+    // 最后一个entry用于循环映射
+    SET_PDE(
+        ptd,
+        1023,
+        PDE(T_SELF_REF_PERM, ptd)
+    );
+}
+
+uint32_t __save_subset(uint8_t* destination, uint8_t* base, unsigned int size) {
+    unsigned int i = 0;
+    for (; i < size; i++)
+    {
+        *(destination + i) = *(base + i);
+    }
+    return i;
+}
+
+void 
+_save_multiboot_info(multiboot_info_t* info, uint8_t* destination) {
+    uint32_t current = 0;
+    uint8_t* info_b = (uint8_t*) info;
+    for (; current < sizeof(multiboot_info_t); current++)
+    {
+        *(destination + current) = *(info_b + current);
+    }
+
+    ((multiboot_info_t*) destination)->mmap_addr = (uintptr_t)destination + current;
+    current += __save_subset(destination + current, (uint8_t*)info->mmap_addr, info->mmap_length);
+
+    if (present(info->flags, MULTIBOOT_INFO_DRIVE_INFO)) {
+        ((multiboot_info_t*) destination)->drives_addr = (uintptr_t)destination + current;
+        current += __save_subset(destination + current, (uint8_t*)info->drives_addr, info->drives_length);
+    }
+}
+
+void 
+_hhk_init(ptd_t* ptd, uint32_t kpg_size) {
+
+    // 初始化 kpg 全为0
+    //      P.s. 真没想到GRUB会在这里留下一堆垃圾! 老子的页表全乱套了!
+    uint8_t* kpg = (uint8_t*) ptd;
+    for (uint32_t i = 0; i < kpg_size; i++)
+    {
+        *(kpg + i) = 0;
+    }
+    
+    _init_page(ptd);
+}
\ No newline at end of file
diff --git a/lunaix-os/arch/x86/multiboot.h b/lunaix-os/arch/x86/multiboot.h
deleted file mode 100644 (file)
index 4aa587a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MB_MAGIC                0x1BADB002
-#define MB_ALIGNED_4K_MEM_MAP   0x03
-#define CHECKSUM(flags)         -(MB_MAGIC+flags)
\ No newline at end of file
index 8114f972fbd31df9478aca10d9a546f002177e6d..216cad634d4c5f7fb25d972cb028c26284b60225 100644 (file)
@@ -1,3 +1,5 @@
 ata0-master: type=cdrom, path="build/lunaix.iso", status=inserted
 
+memory: guest=1024, host=1024
+
 boot: cdrom
\ No newline at end of file
index 416ae68828fa23ea3f86e5b9735846b462134acf..f3ce340ae14c890a64eba149cdacbe270965f6fe 100644 (file)
@@ -1,7 +1,9 @@
 CC := i686-elf-gcc
 AS := i686-elf-as
 
+
+ARCH_OPT := -D__ARCH_IA32
 O := -O2
 W := -Wall -Wextra
-CFLAGS := -std=gnu99 -ffreestanding $(O) $(W)
+CFLAGS := -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT)
 LDFLAGS := -ffreestanding $(O) -nostdlib -lgcc
\ No newline at end of file
diff --git a/lunaix-os/hal/cpu.c b/lunaix-os/hal/cpu.c
new file mode 100644 (file)
index 0000000..b2ef657
--- /dev/null
@@ -0,0 +1,76 @@
+#include <hal/cpu.h>
+#include <stdint.h>
+#include <cpuid.h>
+
+void cpu_get_model(char* model_out) {
+    uint32_t* out = (uint32_t*)model_out;
+    reg32 eax, ebx, edx, ecx;
+    
+    __get_cpuid(0, &eax, &ebx, &ecx, &edx);
+
+    out[0] = ebx;
+    out[1] = edx;
+    out[2] = ecx;
+    model_out[12] = '\0';
+}
+
+#define BRAND_LEAF 0x80000000UL
+
+int cpu_brand_string_supported() {
+    reg32 supported = __get_cpuid_max(BRAND_LEAF, 0);
+    return (supported >= 0x80000004UL);
+}
+
+void cpu_get_brand(char* brand_out) {
+    if(!cpu_brand_string_supported()) {
+        brand_out[0] = '?';
+        brand_out[1] = '\0';
+    }
+    uint32_t* out = (uint32_t*) brand_out;
+    reg32 eax, ebx, edx, ecx;
+    for (uint32_t i = 2, j = 0; i < 5; i++)
+    {
+        __get_cpuid(BRAND_LEAF + i, &eax, &ebx, &ecx, &edx);
+        out[j] = eax;
+        out[j + 1] = ebx;
+        out[j + 2] = ecx;
+        out[j + 3] = edx;
+        j+=4;
+    }
+    brand_out[48] = '\0';
+}
+
+reg32 cpu_r_cr0() {
+    asm volatile ("mov %cr0, %eax");
+}
+
+reg32 cpu_r_cr2() {
+    asm volatile ("mov %cr2, %eax");
+}
+
+reg32 cpu_r_cr3() {
+    asm volatile ("mov %cr3, %eax");
+}
+
+void cpu_w_cr0(reg32 v) {
+    asm volatile (
+        "mov %0, %%cr0"
+        :: "r"(v)
+    );
+}
+
+void cpu_w_cr2(reg32 v) {
+    asm volatile (
+        "mov %0, %%cr2"
+        :: "r"(v)
+    );
+}
+
+void cpu_w_cr3(reg32 v) {
+    asm volatile (
+        "mov %0, %%cr3"
+        :: "r"(v)
+    );
+}
+
+
diff --git a/lunaix-os/includes/arch/x86/boot/multiboot.h b/lunaix-os/includes/arch/x86/boot/multiboot.h
new file mode 100644 (file)
index 0000000..a019686
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef MULTIBOOT_HEADER
+#define MULTIBOOT_HEADER 1
+
+// References https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
+
+#define MULTIBOOT_MAGIC 0x1BADB002
+#define CHECKSUM(flags) -(MULTIBOOT_MAGIC + flags)
+
+/* This should be in %eax. */
+#define MULTIBOOT_BOOTLOADER_MAGIC              0x2BADB002
+
+/* Alignment of multiboot modules. */
+#define MULTIBOOT_MOD_ALIGN                     0x00001000
+
+/* Alignment of the multiboot info structure. */
+#define MULTIBOOT_INFO_ALIGN                    0x00000004
+
+/* Flags set in the ’flags’ member of the multiboot header. */
+
+/* Align all boot modules on i386 page (4KB) boundaries. */
+#define MULTIBOOT_PAGE_ALIGN                    0x00000001
+
+/* Must pass memory information to OS. */
+#define MULTIBOOT_MEMORY_INFO                   0x00000002
+
+/* Must pass video information to OS. */
+#define MULTIBOOT_VIDEO_MODE                    0x00000004
+
+/* This flag indicates the use of the address fields in the header. */
+#define MULTIBOOT_AOUT_KLUDGE                   0x00010000
+
+/* Flags to be set in the ’flags’ member of the multiboot info structure. */
+
+/* is there basic lower/upper memory information? */
+#define MULTIBOOT_INFO_MEMORY                   0x00000001
+/* is there a boot device set? */
+#define MULTIBOOT_INFO_BOOTDEV                  0x00000002
+/* is the command-line defined? */
+#define MULTIBOOT_INFO_CMDLINE                  0x00000004
+/* are there modules to do something with? */
+#define MULTIBOOT_INFO_MODS                     0x00000008
+
+/* These next two are mutually exclusive */
+
+/* is there a symbol table loaded? */
+#define MULTIBOOT_INFO_AOUT_SYMS                0x00000010
+/* is there an ELF section header table? */
+#define MULTIBOOT_INFO_ELF_SHDR                 0X00000020
+
+/* is there a full memory map? */
+#define MULTIBOOT_INFO_MEM_MAP                  0x00000040
+
+/* Is there drive info? */
+#define MULTIBOOT_INFO_DRIVE_INFO               0x00000080
+
+/* Is there a config table? */
+#define MULTIBOOT_INFO_CONFIG_TABLE             0x00000100
+
+/* Is there a boot loader name? */
+#define MULTIBOOT_INFO_BOOT_LOADER_NAME         0x00000200
+
+/* Is there a APM table? */
+#define MULTIBOOT_INFO_APM_TABLE                0x00000400
+
+/* Is there video information? */
+#define MULTIBOOT_INFO_VBE_INFO                 0x00000800
+#define MULTIBOOT_INFO_FRAMEBUFFER_INFO         0x00001000
+
+#define present(flags, info)      ((flags) & (info))
+
+#ifndef __ASM__
+
+typedef unsigned char multiboot_uint8_t;
+typedef unsigned short multiboot_uint16_t;
+typedef unsigned int multiboot_uint32_t;
+typedef unsigned long long multiboot_uint64_t;
+
+struct multiboot_symbol_table
+{
+    multiboot_uint32_t tabsize;
+    multiboot_uint32_t strsize;
+    multiboot_uint32_t addr;
+    multiboot_uint32_t reserved;
+};
+typedef struct multiboot_symbol_table multiboot_symbol_table_t;
+
+/* The section header table for ELF. */
+struct multiboot_elf_section_header_table
+{
+    multiboot_uint32_t num;
+    multiboot_uint32_t size;
+    multiboot_uint32_t addr;
+    multiboot_uint32_t shndx;
+};
+typedef struct multiboot_elf_section_header_table
+  multiboot_elf_section_header_table_t;
+
+struct multiboot_info
+{
+    /* Multiboot info version number */
+    multiboot_uint32_t flags;
+
+    /* Available memory from BIOS */
+    multiboot_uint32_t mem_lower;
+    multiboot_uint32_t mem_upper;
+
+    /* "root" partition */
+    multiboot_uint32_t boot_device;
+
+    /* Kernel command line */
+    multiboot_uint32_t cmdline;
+
+    /* Boot-Module list */
+    multiboot_uint32_t mods_count;
+    multiboot_uint32_t mods_addr;
+
+    union
+    {
+        multiboot_symbol_table_t aout_sym;
+        multiboot_elf_section_header_table_t elf_sec;
+    } u;
+
+    /* Memory Mapping buffer */
+    multiboot_uint32_t mmap_length;
+    multiboot_uint32_t mmap_addr;
+
+    /* Drive Info buffer */
+    multiboot_uint32_t drives_length;
+    multiboot_uint32_t drives_addr;
+
+    /* ROM configuration table */
+    multiboot_uint32_t config_table;
+
+    /* Boot Loader Name */
+    multiboot_uint32_t boot_loader_name;
+
+    /* APM table */
+    multiboot_uint32_t apm_table;
+
+    /* Video */
+    multiboot_uint32_t vbe_control_info;
+    multiboot_uint32_t vbe_mode_info;
+    multiboot_uint16_t vbe_mode;
+    multiboot_uint16_t vbe_interface_seg;
+    multiboot_uint16_t vbe_interface_off;
+    multiboot_uint16_t vbe_interface_len;
+
+    multiboot_uint64_t framebuffer_addr;
+    multiboot_uint32_t framebuffer_pitch;
+    multiboot_uint32_t framebuffer_width;
+    multiboot_uint32_t framebuffer_height;
+    multiboot_uint8_t framebuffer_bpp;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
+    multiboot_uint8_t framebuffer_type;
+    union
+    {
+        struct
+        {
+            multiboot_uint32_t framebuffer_palette_addr;
+            multiboot_uint16_t framebuffer_palette_num_colors;
+        };
+        struct
+        {
+            multiboot_uint8_t framebuffer_red_field_position;
+            multiboot_uint8_t framebuffer_red_mask_size;
+            multiboot_uint8_t framebuffer_green_field_position;
+            multiboot_uint8_t framebuffer_green_mask_size;
+            multiboot_uint8_t framebuffer_blue_field_position;
+            multiboot_uint8_t framebuffer_blue_mask_size;
+        };
+    };
+};
+typedef struct multiboot_info multiboot_info_t;
+
+struct multiboot_color
+{
+    multiboot_uint8_t red;
+    multiboot_uint8_t green;
+    multiboot_uint8_t blue;
+};
+
+struct multiboot_mmap_entry
+{
+    multiboot_uint32_t size;
+    multiboot_uint32_t addr_low;
+    multiboot_uint32_t addr_high;
+    multiboot_uint32_t len_low;
+    multiboot_uint32_t len_high;
+#define MULTIBOOT_MEMORY_AVAILABLE 1
+#define MULTIBOOT_MEMORY_RESERVED 2
+#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
+#define MULTIBOOT_MEMORY_NVS 4
+#define MULTIBOOT_MEMORY_BADRAM 5
+    multiboot_uint32_t type;
+} __attribute__((packed));
+
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
+
+struct multiboot_mod_list
+{
+    /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */
+    multiboot_uint32_t mod_start;
+    multiboot_uint32_t mod_end;
+
+    /* Module command line */
+    multiboot_uint32_t cmdline;
+
+    /* padding to take it to 16 bytes (must be zero) */
+    multiboot_uint32_t pad;
+};
+typedef struct multiboot_mod_list multiboot_module_t;
+
+/* APM BIOS info. */
+struct multiboot_apm_info
+{
+    multiboot_uint16_t version;
+    multiboot_uint16_t cseg;
+    multiboot_uint32_t offset;
+    multiboot_uint16_t cseg_16;
+    multiboot_uint16_t dseg;
+    multiboot_uint16_t flags;
+    multiboot_uint16_t cseg_len;
+    multiboot_uint16_t cseg_16_len;
+    multiboot_uint16_t dseg_len;
+};
+#endif
+#endif
\ No newline at end of file
similarity index 97%
rename from lunaix-os/includes/lunaix/arch/gdt.h
rename to lunaix-os/includes/arch/x86/gdt.h
index b680f6faa1bbc4d0b04063110213ed7bb60b9f3c..bb2fa27cca915440b7f256520888844c67c51235 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __LUNAIX_GDT_H 
+#define __LUNAIX_GDT_H 1
+
 #define SD_TYPE(x)              (x << 8)
 #define SD_CODE_DATA(x)         (x << 12)
 #define SD_DPL(x)               (x << 13)
@@ -48,4 +51,6 @@
                             
 
 void
-_init_gdt();
\ No newline at end of file
+_init_gdt();
+
+#endif
similarity index 56%
rename from lunaix-os/includes/lunaix/arch/idt.h
rename to lunaix-os/includes/arch/x86/idt.h
index 4a0d28d5ac8c619a29b2b2cd8a3fea9382d5f5a5..af0ae7d57bc457d5cc23fac361efe8389d20c7db 100644 (file)
@@ -1,4 +1,7 @@
+#ifndef __LUNAIX_IDT_H
+#define __LUNAIX_IDT_H 1
 #define IDT_ATTR(dpl)                   ((0x70 << 5) | (dpl & 3) << 13 | 1 << 15)
 
 void
-_init_idt();
\ No newline at end of file
+_init_idt();
+#endif
\ No newline at end of file
diff --git a/lunaix-os/includes/arch/x86/interrupts.h b/lunaix-os/includes/arch/x86/interrupts.h
new file mode 100644 (file)
index 0000000..fb4eb79
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __LUNAIX_INTERRUPTS_H
+#define __LUNAIX_INTERRUPTS_H
+
+typedef struct {
+    unsigned int vector;
+    unsigned int err_code;
+    unsigned int eip;
+    unsigned int cs;
+    unsigned int eflags;
+} __attribute__((packed)) isr_param;
+
+void
+_asm_isr0();
+
+void
+interrupt_handler(isr_param* param);
+
+
+#endif /* __LUNAIX_INTERRUPTS_H */
similarity index 88%
rename from lunaix-os/includes/lunaix/interrupts/types.h
rename to lunaix-os/includes/arch/x86/types.h
index 888ca1f33610b1ce0b03f9b4cf2ebabad746dd10..ba2839a956b56d5545e4fb809561051fab3df778 100644 (file)
@@ -1,4 +1,8 @@
 // Ref: Intel Manuel Vol.3 Figure 6-1
+
+#ifndef __LUNAIX_TYPES_H
+#define __LUNAIX_TYPES_H
+
 #define FAULT_DIVISION_ERROR            0x0
 #define FAULT_TRAP_DEBUG_EXCEPTION      0x1
 #define INT_NMI                         0x2
@@ -20,4 +24,7 @@
 #define ABORT_MACHINE_CHECK             0x12
 #define FAULT_SIMD_FP_EXCEPTION         0x13
 #define FAULT_VIRTUALIZATION_EXCEPTION  0x14
-#define FAULT_CONTROL_PROTECTION        0x15
\ No newline at end of file
+#define FAULT_CONTROL_PROTECTION        0x15
+
+
+#endif /* __LUNAIX_TYPES_H */
diff --git a/lunaix-os/includes/hal/cpu.h b/lunaix-os/includes/hal/cpu.h
new file mode 100644 (file)
index 0000000..2a06f29
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __LUNAIX_CPU_H
+#define __LUNAIX_CPU_H
+
+typedef unsigned long reg32;
+typedef unsigned short reg16;
+
+typedef struct {
+    reg32 edi;
+    reg32 esi;
+    reg32 ebp;
+    reg32 esp;
+    reg32 ebx;
+    reg32 edx;
+    reg32 ecx;
+    reg32 eax;
+} __attribute__((packed)) registers;
+
+reg32 cpu_r_cr0();
+
+reg32 cpu_r_cr2();
+
+reg32 cpu_r_cr3();
+
+void cpu_w_cr0(reg32 v);
+
+void cpu_w_cr2(reg32 v);
+
+void cpu_w_cr3(reg32 v);
+
+void cpu_get_model(char* model_out);
+
+int cpu_brand_string_supported();
+
+void cpu_get_brand(char* brand_out);
+
+#endif /* __LUNAIX_CPU_H */
diff --git a/lunaix-os/includes/hal/io.h b/lunaix-os/includes/hal/io.h
new file mode 100644 (file)
index 0000000..0f5e9d6
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __LUNAIX_IO_H
+#define __LUNAIX_IO_H
+
+#include <stdint.h>
+
+void io_port_wb(uint8_t port, uint8_t value) {
+    asm volatile (
+        "movb %0, %%al\n"
+        "movb %1, %%dx\n"
+        "out %%al, %%dx\n"
+        :: "r"(value) "r"(port)
+    );
+}
+
+void io_port_wl(uint8_t port, uint32_t value) {
+    asm volatile (
+        "movl %0, %%eax\n"
+        "movb %1, %%dx\n"
+        "out %%eax, %%dx\n"
+        :: "r"(value) "r"(port)
+    );
+}
+
+uint8_t io_port_rb(uint8_t port) {
+    asm volatile (
+        "movb $0, %%eax\n"
+        "movb %0, %%dx\n"
+        "in %%dx, %%al\n"
+        :: "r"(port)
+    );
+}
+
+uint32_t io_port_rl(uint8_t port) {
+    asm volatile (
+        "movb %0, %%dx\n"
+        "in %%dx, %%eax\n"
+        :: "r"(port)
+    );
+}
+
+#endif /* __LUNAIX_IO_H */
diff --git a/lunaix-os/includes/lunaix/constants.h b/lunaix-os/includes/lunaix/constants.h
new file mode 100644 (file)
index 0000000..66a6f0c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __LUNAIX_CONSTANTS_H
+#define __LUNAIX_CONSTANTS_H
+
+#define K_STACK_SIZE            0x100000U
+#define K_STACK_START           ((0xFFBFFFFFU - K_STACK_SIZE) + 1)
+#define HIGHER_HLF_BASE         0xC0000000UL
+#define MEM_1MB                 0x100000UL
+
+#define VGA_BUFFER_VADDR        0xB0000000UL
+#define VGA_BUFFER_PADDR        0xB8000UL
+#define VGA_BUFFER_SIZE         4096
+
+#endif /* __LUNAIX_CONSTANTS_H */
diff --git a/lunaix-os/includes/lunaix/interrupts/interrupts.h b/lunaix-os/includes/lunaix/interrupts/interrupts.h
deleted file mode 100644 (file)
index 723ba67..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma pack(push, 1)
-typedef struct {
-    unsigned int vector;
-    unsigned int err_code;
-    unsigned int eip;
-    unsigned short cs;
-    unsigned int eflags;
-} isr_param;
-#pragma pack(pop)
-
-void
-_asm_isr0();
-
-void
-interrupt_handler(isr_param* param);
\ No newline at end of file
diff --git a/lunaix-os/includes/lunaix/mm/page.h b/lunaix-os/includes/lunaix/mm/page.h
new file mode 100644 (file)
index 0000000..c981839
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __LUNAIX_PAGE_H
+#define __LUNAIX_PAGE_H
+#include <stdint.h>
+#include <lunaix/constants.h>
+
+#define PG_MAX_ENTRIES              1024U
+#define PG_LAST_TABLE               PG_MAX_ENTRIES - 1
+#define PG_FIRST_TABLE              0
+
+#define P2V(paddr)          ((uintptr_t)(paddr)  +  HIGHER_HLF_BASE)
+#define V2P(vaddr)          ((uintptr_t)(vaddr)  -  HIGHER_HLF_BASE)
+
+#define PG_ALIGN(addr)      ((uintptr_t)(addr)   & 0xFFFFF000UL)
+
+#define PD_INDEX(vaddr)     (((uintptr_t)(vaddr) & 0xFFC00000UL) >> 22)
+#define PT_INDEX(vaddr)     (((uintptr_t)(vaddr) & 0x003FF000UL) >> 12)
+#define PG_OFFSET(vaddr)    ((uintptr_t)(vaddr)  & 0x00000FFFUL)
+
+#define GET_PT_ADDR(pde)    PG_ALIGN(pde)
+#define GET_PG_ADDR(pte)    PG_ALIGN(pte)
+
+#define PG_DIRTY(pte)           ((pte & (1 << 6)) >> 6)
+#define PG_ACCESSED(pte)        ((pte & (1 << 5)) >> 5)
+
+#define IS_CACHED(entry)    ((entry & 0x1))
+
+#define PG_PRESENT              (0x1)
+#define PG_WRITE                (0x1 << 1)
+#define PG_ALLOW_USER           (0x1 << 2)
+#define PG_WRITE_THROUGHT       (1 << 3)
+#define PG_DISABLE_CACHE        (1 << 4)
+#define PG_PDE_4MB              (1 << 7)
+
+#define PDE(flags, pt_addr)     (PG_ALIGN(pt_addr) | ((flags) & 0xfff))
+#define PTE(flags, pg_addr)     (PG_ALIGN(pg_addr) | ((flags) & 0xfff))
+
+#define V_ADDR(pd, pt, offset)  ((pd) << 22 | (pt) << 12 | (offset))
+#define P_ADDR(ppn, offset)     ((ppn << 12) | (offset))
+
+// 用于对PD进行循环映射,因为我们可能需要对PD进行频繁操作,我们在这里禁用TLB缓存
+#define PG_PREM_R              PG_PRESENT
+#define PG_PREM_RW             PG_PRESENT | PG_WRITE
+#define PG_PREM_UR             PG_PRESENT | PG_ALLOW_USER
+#define PG_PREM_URW            PG_PRESENT | PG_WRITE | PG_ALLOW_USER
+#define T_SELF_REF_PERM        PG_PREM_RW | PG_DISABLE_CACHE
+
+
+// 页目录的虚拟基地址,可以用来访问到各个PDE
+#define PTD_BASE_VADDR                0xFFFFF000U
+
+// 页表的虚拟基地址,可以用来访问到各个PTE
+#define PT_BASE_VADDR                 0xFFC00000U
+
+// 用来获取特定的页表的虚拟地址
+#define PT_VADDR(pd_offset)           (PT_BASE_VADDR | (pd_offset << 12))
+
+typedef unsigned int ptd_t;
+typedef unsigned int pt_t;
+typedef unsigned int pt_attr;
+
+
+#endif /* __LUNAIX_PAGE_H */
diff --git a/lunaix-os/includes/lunaix/mm/pmm.h b/lunaix-os/includes/lunaix/mm/pmm.h
new file mode 100644 (file)
index 0000000..36396df
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef __LUNAIX_PMM_H
+#define __LUNAIX_PMM_H
+// Physical memory manager
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define PM_PAGE_SIZE            4096
+#define PM_BMP_MAX_SIZE        (128 * 1024)
+
+/**
+ * @brief 标注物理页为可使用
+ * 
+ * @param ppn page number
+ */
+void pmm_mark_page_free(uintptr_t ppn);
+
+/**
+ * @brief 标注物理页为已占用
+ * 
+ * @param ppn 
+ */
+void pmm_mark_page_occupied(uintptr_t ppn);
+
+/**
+ * @brief 标注多个连续的物理页为可用
+ * 
+ * @param start_ppn 起始PPN
+ * @param 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(uintptr_t start_ppn, size_t page_count);
+
+/**
+ * @brief 分配一个可用的物理页
+ * 
+ * @return void* 可用的页地址,否则为 NULL
+ */
+void* pmm_alloc_page();
+
+/**
+ * @brief 初始化物理内存管理器
+ * 
+ * @param mem_upper_lim 最大可用内存地址
+ */
+void pmm_init(uintptr_t mem_upper_lim);
+
+
+/**
+ * @brief 释放一个已分配的物理页,假若页地址不存在,则无操作。
+ * 
+ * @param page 页地址
+ * @return 是否成功
+ */
+int pmm_free_page(void* page);
+
+
+#endif /* __LUNAIX_PMM_H */
diff --git a/lunaix-os/includes/lunaix/mm/vmm.h b/lunaix-os/includes/lunaix/mm/vmm.h
new file mode 100644 (file)
index 0000000..14b3a7f
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __LUNAIX_VMM_H
+#define __LUNAIX_VMM_H
+#include <stdint.h>
+#include <stddef.h>
+#include <lunaix/mm/page.h>
+// Virtual memory manager
+
+/**
+ * @brief 初始化虚拟内存管理器
+ * 
+ */
+void vmm_init();
+
+/**
+ * @brief 创建一个页目录
+ * 
+ * @return ptd_entry* 页目录的物理地址,随时可以加载进CR3
+ */
+ptd_t* vmm_init_pd();
+
+/**
+ * @brief 
+ * 尝试建立一个映射关系。映射指定的物理页地址至虚拟页地址,如果指定的虚拟页地址已被占用
+ * 则尝试寻找新的可用地址(改地址总是大于指定的地址)。
+ * 
+ * @param vpn 虚拟页地址
+ * @param ppn 物理页地址
+ * @param dattr PDE 的属性
+ * @param tattr PTE 的属性
+ * @return 虚拟页地址,如不成功,则为 NULL
+ */
+void* vmm_map_page(void* vpn, void* ppn, pt_attr dattr, pt_attr tattr);
+
+/**
+ * @brief 尝试为一个虚拟页地址创建一个可用的物理页映射
+ * 
+ * @param vpn 虚拟页地址
+ * @return 物理页地址,如不成功,则为 NULL
+ */
+void* vmm_alloc_page(void* vpn, pt_attr dattr, pt_attr tattr);
+
+/**
+ * @brief 删除一个映射
+ * 
+ * @param vpn 
+ */
+void vmm_unmap_page(void* vpn);
+
+ptd_t* get_pd();
+void set_pd(ptd_t* pd);
+
+/**
+ * @brief 将虚拟地址翻译为其对应的物理映射
+ * 
+ * @param va 虚拟地址
+ * @return void* 物理地址,如映射不存在,则为NULL
+ */
+void* vmm_v2p(void* va);
+
+#endif /* __LUNAIX_VMM_H */
index c1a9a92a258fe9f11aa12db353532ff84f68f26e..3d723ca169a08853636145ba7c1f5f79c582a2cb 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef __LUNAIX_TTY_H
+#define __LUNAIX_TTY_H
 typedef unsigned short vga_attribute;
 
 #define VGA_COLOR_BLACK 0
@@ -17,6 +19,12 @@ typedef unsigned short vga_attribute;
 #define VGA_COLOR_LIGHT_BROWN 14
 #define VGA_COLOR_WHITE 15
 
+void 
+tty_init(void* vga_buf);
+
+void
+tty_set_buffer(void* vga_buf);
+
 void
 tty_set_theme(vga_attribute fg, vga_attribute bg);
 
@@ -30,4 +38,7 @@ void
 tty_scroll_up();
 
 void
-tty_clear();
\ No newline at end of file
+tty_clear();
+
+
+#endif /* __LUNAIX_TTY_H */
similarity index 95%
rename from lunaix-os/arch/x86/gdt.c
rename to lunaix-os/kernel/asm/x86/gdt.c
index c7eec3470a7be048ca41bc4c8f9838e9c2a07901..41c597e962e7b9dc02e8e37739d923bac04f3f3f 100644 (file)
@@ -1,4 +1,4 @@
-#include <lunaix/arch/gdt.h>
+#include <arch/x86/gdt.h>
 #include <stdint.h>
 
 #define GDT_ENTRY 5
similarity index 81%
rename from lunaix-os/arch/x86/idt.c
rename to lunaix-os/kernel/asm/x86/idt.c
index 08acda2a85ec3f6bf92fa54ce8d2a5afd49b2bef..9f2bd069180f0ea5c26ab3439f39f44ea0563f6e 100644 (file)
@@ -1,6 +1,6 @@
-#include <lunaix/arch/idt.h>
-#include <lunaix/interrupts/interrupts.h>
-#include <lunaix/interrupts/types.h>
+#include <arch/x86/idt.h>
+#include <arch/x86/interrupts.h>
+#include <arch/x86/types.h>
 #include <stdint.h>
 
 #define IDT_ENTRY 32
similarity index 56%
rename from lunaix-os/kernel/interrupts/interrupts.c
rename to lunaix-os/kernel/asm/x86/interrupts.c
index ee023de494f649c6e4a9f84e20e6e6ae21b1d0df..39682a38a2c850e8df3b1e4a7dee6da55eec347c 100644 (file)
@@ -1,9 +1,9 @@
-#include <lunaix/interrupts/interrupts.h>
-#include <lunaix/tty/tty.h>
+#include <arch/x86/interrupts.h>
+#include <libc/stdio.h>
 
 void isr0 (isr_param* param) {
     tty_clear();
-    tty_put_str("!!PANIC!!");
+    printf("[PANIC] Exception (%d) CS=0x%X, EIP=0x%X", param->vector, param->cs, param->eip);
 }
 
 void 
diff --git a/lunaix-os/kernel/asm/x86/prologue.S b/lunaix-os/kernel/asm/x86/prologue.S
new file mode 100644 (file)
index 0000000..4e114e9
--- /dev/null
@@ -0,0 +1,63 @@
+/* 高半核入口点 - 0xC0000000 */
+
+.section .text
+    .global hhk_entry_
+    hhk_entry_:
+        /*
+            欢迎来到虚拟内存的世界! :D
+         */
+
+        subl $16, %esp
+        /* 
+            最终还是决定将IDT&GDT的初始化和安装放在这里
+            注意:由于已开启分页,GDTR与IDTR里面放的不是物理地址,是线性地址! 
+        */
+        /* 
+            加载 GDT 
+            P.s. 虽然GDT在分页后已变得不重要,甚至可以忽略不作。但为了保持完整性,还是选择加载他
+                    这主要是为了保险起见,让GDTR有一个合法的值,否则多咱的粗心大意,容易出#GP
+        */
+        call _init_gdt
+        movl $_gdt, 2(%esp)
+        movw _gdt_limit, %ax
+        movw %ax, (%esp)
+        lgdt (%esp)
+
+        /* 更新段寄存器 */
+        movw $0x10, %cx
+        movw %cx, %es
+        movw %cx, %ds
+        movw %cx, %fs
+        movw %cx, %gs
+        movw %cx, %ss
+
+        /* 更新 CS:EIP */
+        pushw $0x08
+        pushl $_after_gdt
+        retf
+
+    _after_gdt:
+
+        movl $mb_info, (%esp)
+        call _kernel_init
+
+        # 加载 IDT
+        movl $_idt, 2(%esp)
+        movw _idt_limit, %ax
+        movw %ax, (%esp)
+        lidt (%esp)
+
+        /* 
+            加载新的栈指针,位于0xffbfffff,但因为16字节对齐的需求,低四位清零。
+            为什么不是0xffffffff? 因为0xffc00000 - 0xffffffff 这4MiB的空间用于
+            对页表与页目录的循环映射。
+        */
+        mov $0xffbffff0, %esp     
+
+        /* 进入内核 */  
+        call _kernel_main
+
+        cli
+    j_:
+        hlt
+        jmp j_
\ No newline at end of file
diff --git a/lunaix-os/kernel/k_main.c b/lunaix-os/kernel/k_main.c
new file mode 100644 (file)
index 0000000..8634443
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdint.h>
+
+#include <lunaix/constants.h>
+#include <lunaix/tty/tty.h>
+
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/vmm.h>
+
+#include <hal/cpu.h>
+
+#include <arch/x86/boot/multiboot.h>
+#include <arch/x86/gdt.h>
+#include <arch/x86/idt.h>
+
+#include <libc/stdio.h>
+
+extern void __kernel_start;
+extern void __kernel_end;
+extern void __init_hhk_end;
+
+void
+_kernel_init(multiboot_info_t* mb_info)
+{
+    _init_idt();
+
+    multiboot_memory_map_t* map = (multiboot_memory_map_t*)mb_info->mmap_addr;
+
+    // TODO: 内核初始化
+    //   (v) 根据memory map初始化内存管理器
+    //   (v) 分配新的栈空间
+    //       调整映射:
+    //   ( )    + 映射 memory map (APCI,APIC,IO映射) (以后)
+    //   (v)    + 释放 hhk_init 所占据的空间
+
+    // 初始化物理内存管理器
+    pmm_init(MEM_1MB + mb_info->mem_upper << 10);
+    vmm_init();
+    tty_init(VGA_BUFFER_PADDR);
+
+    tty_set_theme(VGA_COLOR_GREEN, VGA_COLOR_BLACK);
+
+    printf("[KERNEL] Initializing Memory ...\n");
+    unsigned int map_size =
+      mb_info->mmap_length / sizeof(multiboot_memory_map_t);
+    printf("[MM] Mem: %d KiB, Extended Mem: %d KiB\n",
+           mb_info->mem_lower,
+           mb_info->mem_upper);
+
+    // 按照 Memory map 标识可用的物理页
+    for (unsigned int i = 0; i < map_size; i++) {
+        multiboot_memory_map_t mmap = map[i];
+        printf("[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 >> 12, map[i].len_low >> 12);
+            printf("[MM] Freed %u pages start from 0x%x\n",
+                   map[i].len_low >> 12,
+                   pg & ~0x0fffU);
+        }
+    }
+
+    // 将内核占据的页设为已占用
+    size_t pg_count = (uintptr_t)(&__kernel_end - &__kernel_start) >> 12;
+    pmm_mark_chunk_occupied(V2P(&__kernel_start) >> 12, pg_count);
+    printf("[MM] Allocated %d pages for kernel.\n", pg_count);
+
+
+    size_t hhk_init_pg_count = ((uintptr_t)(&__init_hhk_end)) >> 12;
+    printf("[MM] Releaseing %d pages from 0x0.\n", hhk_init_pg_count);
+
+    // 清除 hhk_init 与前1MiB的映射
+    // 从这里开始,到新的vga缓存地址设置前,不能够进行任何的打印操作
+    for (size_t i = 0; i < hhk_init_pg_count; i++) {
+        vmm_unmap_page((i << 12));
+    }
+
+    size_t vga_buf_pgs = VGA_BUFFER_SIZE >> 12;
+    
+    // 首先,标记VGA部分为已占用
+    pmm_mark_chunk_occupied(VGA_BUFFER_PADDR >> 12, vga_buf_pgs);
+    
+    // 重映射VGA文本缓冲区(以后会变成显存,i.e., framebuffer)
+    for (size_t i = 0; i < vga_buf_pgs; i++)
+    {
+        vmm_map_page(VGA_BUFFER_VADDR + (i << 12), VGA_BUFFER_PADDR + (i << 12), PG_PREM_RW, PG_PREM_RW);
+    }
+    
+    // 更新VGA缓冲区位置至虚拟地址
+    tty_set_buffer(VGA_BUFFER_VADDR);
+
+    printf("[MM] Mapped VGA to %p.\n", VGA_BUFFER_VADDR);
+
+    // 为内核创建一个专属栈空间。
+    for (size_t i = 0; i < (K_STACK_SIZE >> 12); i++) {
+        vmm_alloc_page(K_STACK_START + (i << 12), PG_PREM_RW, PG_PREM_RW);
+    }
+    printf("[MM] Allocated %d pages for stack start at %p\n", K_STACK_SIZE>>12, K_STACK_START);
+
+    printf("[KERNEL] Done!\n\n");
+}
+
+void
+_kernel_main()
+{
+    char* buf[64];
+    
+    printf("Hello higher half kernel world!\nWe are now running in virtual "
+           "address space!\n\n");
+    
+    cpu_get_brand(buf);
+    printf("CPU: %s\n\n", buf);
+
+    uintptr_t k_start = vmm_v2p(&__kernel_start);
+    printf("The kernel's base address mapping: %p->%p\n", &__kernel_start, k_start);
+    // __asm__("int $0\n");
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/kernel.c b/lunaix-os/kernel/kernel.c
deleted file mode 100644 (file)
index 72f2f4e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <lunaix/tty/tty.h>
-#include <lunaix/arch/gdt.h>
-#include <lunaix/arch/idt.h>
-
-void
-_kernel_init()
-{
-    // TODO
-    _init_gdt();
-    _init_idt();
-}
-
-void
-_kernel_main(void* info_table)
-{
-    // remove the warning
-    (void)info_table;
-    // TODO
-    tty_set_theme(VGA_COLOR_GREEN, VGA_COLOR_BLACK);
-    tty_put_str("Hello kernel world!\nThis is second line.");
-}
\ No newline at end of file
diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c
new file mode 100644 (file)
index 0000000..c6b0a25
--- /dev/null
@@ -0,0 +1,137 @@
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/pmm.h>
+
+#define MARK_PG_AUX_VAR(ppn)                                                   \
+    uint32_t group = ppn / 8;                                                  \
+    uint32_t msk = (0x80U >> (ppn % 8));                                       \
+
+#define MARK_CHUNK_AUX_VAR(start_ppn, page_count)                              \
+    uint32_t group = start_ppn / 8;                                            \
+    uint32_t offset = start_ppn % 8;                                           \
+    uint32_t group_count = (page_count + offset) / 8;                          \
+    uint32_t remainder = (page_count + offset) % 8;                            \
+    uint32_t leading_shifts =                                                  \
+      (page_count + offset) < 8 ? page_count : 8 - offset;
+
+uint8_t pm_bitmap[PM_BMP_MAX_SIZE];
+
+uintptr_t max_pg;
+
+void
+pmm_mark_page_free(uintptr_t ppn)
+{
+    MARK_PG_AUX_VAR(ppn)
+    pm_bitmap[group] = pm_bitmap[group] & ~msk;
+}
+
+void
+pmm_mark_page_occupied(uintptr_t ppn)
+{
+    MARK_PG_AUX_VAR(ppn)
+    pm_bitmap[group] = pm_bitmap[group] | msk;
+}
+
+void
+pmm_mark_chunk_free(uintptr_t start_ppn, size_t page_count)
+{
+    MARK_CHUNK_AUX_VAR(start_ppn, page_count)
+
+    // nasty bit level hacks but it reduce # of iterations.
+
+    pm_bitmap[group] &= ~(((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
+
+    group++;
+
+    // prevent unsigned overflow
+    for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
+        pm_bitmap[group] = 0;
+    }
+
+    pm_bitmap[group] &=
+      ~(((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
+}
+
+void
+pmm_mark_chunk_occupied(uint32_t start_ppn, size_t page_count)
+{
+    MARK_CHUNK_AUX_VAR(start_ppn, page_count)
+
+    pm_bitmap[group] |= (((1U << leading_shifts) - 1) << (8 - offset - leading_shifts));
+
+    group++;
+
+    // prevent unsigned overflow
+    for (uint32_t i = 0; group_count !=0 && i < group_count - 1; i++, group++) {
+        pm_bitmap[group] = 0xFFU;
+    }
+
+    pm_bitmap[group] |=
+      (((1U << (page_count > 8 ? remainder : 0)) - 1) << (8 - remainder));
+}
+
+// 我们跳过位于0x0的页。我们不希望空指针是指向一个有效的内存空间。
+#define LOOKUP_START 1
+
+size_t pg_lookup_ptr;
+
+void
+pmm_init(uintptr_t mem_upper_lim)
+{
+    max_pg = (PG_ALIGN(mem_upper_lim) >> 12) + 1;
+
+    pg_lookup_ptr = LOOKUP_START;
+
+    // mark all as occupied
+    for (size_t i = 0; i < PM_BMP_MAX_SIZE; i++) {
+        pm_bitmap[i] = 0xFFU;
+    }
+}
+
+void*
+pmm_alloc_page()
+{
+    // Next fit approach. Maximize the throughput!
+    uintptr_t good_page_found = NULL;
+    size_t old_pg_ptr = pg_lookup_ptr;
+    size_t upper_lim = max_pg;
+    uint8_t chunk = 0;
+    while (!good_page_found && pg_lookup_ptr < upper_lim) {
+        chunk = pm_bitmap[pg_lookup_ptr >> 3];
+
+        // skip the fully occupied chunk, reduce # of iterations
+        if (chunk != 0xFFU) {
+            for (size_t i = pg_lookup_ptr % 8; i < 8; i++, pg_lookup_ptr++) {
+                if (!(chunk & (0x80U >> i))) {
+                    pmm_mark_page_occupied(pg_lookup_ptr);
+                    good_page_found = pg_lookup_ptr << 12;
+                    break;
+                }
+            }
+        } else {
+            pg_lookup_ptr += 8;
+
+            // We've searched the interval [old_pg_ptr, max_pg) but failed
+            //   may be chances in [1, old_pg_ptr) ?
+            // Let's find out!
+            if (pg_lookup_ptr >= upper_lim && old_pg_ptr != LOOKUP_START) {
+                upper_lim = old_pg_ptr;
+                pg_lookup_ptr = LOOKUP_START;
+                old_pg_ptr = LOOKUP_START;
+            }
+        }
+    }
+    return (void*)good_page_found;
+}
+
+int
+pmm_free_page(void* page)
+{
+    // TODO: Add kernel reserved memory page check
+    uint32_t pg = (uintptr_t)page >> 12;
+    if (pg && pg < max_pg)
+    {
+        pmm_mark_page_free(pg);
+        return 1;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/mm/vmm.c b/lunaix-os/kernel/mm/vmm.c
new file mode 100644 (file)
index 0000000..aaaf54c
--- /dev/null
@@ -0,0 +1,143 @@
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/mm/pmm.h>
+#include <libc/string.h>
+
+// TODO: Move these nasty inline asm stuff into hal
+//      These should be arch dependent
+ptd_t* get_pd() {
+    ptd_t* pd;
+    #ifdef __ARCH_IA32
+    __asm__(
+        "movl %%cr3, %0\n"
+        "andl $0xfffff000, %0"
+        : "=r"(pd)
+    );
+    #endif
+    return P2V(pd);
+}
+
+void set_pd(ptd_t* pd) {
+    #ifdef __ARCH_IA32
+    __asm__(
+        "movl %0, %%eax\n"
+        "andl $0xfffff000, %%eax\n"
+        "movl %%eax, %%cr3\n"
+        :
+        : "r" (pd)
+    );
+    #endif
+}
+
+void vmm_init() {
+    // TODO: something here?
+}
+
+ptd_t* vmm_init_pd() {
+    ptd_t* dir = pmm_alloc_page();
+    for (size_t i = 0; i < 1024; i++)
+    {
+        dir[i] = 0;
+    }
+    
+    // 自己映射自己,方便我们在软件层面进行查表地址转换
+    dir[1023] = PDE(T_SELF_REF_PERM, dir);
+
+    return dir;
+}
+
+void* vmm_map_page(void* va, void* pa, pt_attr dattr, pt_attr tattr) {
+    // 显然,对空指针进行映射没有意义。
+    if (!pa || !va) {
+        return NULL;
+    }
+
+    uintptr_t pd_offset = PD_INDEX(va);
+    uintptr_t pt_offset = PT_INDEX(va);
+    ptd_t* ptd = PTD_BASE_VADDR;
+
+    // 在页表与页目录中找到一个可用的空位进行映射(位于va或其附近)
+    ptd_t* pde = ptd[pd_offset];
+    pt_t* pt = (uintptr_t)(PT_BASE_VADDR | (pd_offset << 12));
+    while (pde && pd_offset < 1024) {
+        if (pt_offset == 1024) {
+            pd_offset++;
+            pt_offset = 0;
+            pde = ptd[pd_offset];
+            pt = (pt_t*)PT_VADDR(pd_offset);
+        }
+        // 页表有空位,只需要开辟一个新的 PTE
+        if (pt && !pt[pt_offset]) {
+            pt[pt_offset] = PTE(tattr, pa);
+            return V_ADDR(pd_offset, pt_offset, PG_OFFSET(va));
+        }
+        pt_offset++;
+    }
+    
+    // 页目录与所有页表已满!
+    if (pd_offset > 1024) {
+        return NULL;
+    }
+
+    // 页目录有空位,需要开辟一个新的 PDE
+    uint8_t* new_pt_pa = pmm_alloc_page();
+    
+    // 物理内存已满!
+    if (!new_pt_pa) {
+        return NULL;
+    }
+    
+    ptd[pd_offset] = PDE(dattr, new_pt_pa);
+    memset((void*)PT_VADDR(pd_offset), 0, PM_PAGE_SIZE);
+    
+    pt[pt_offset] = PTE(tattr, pa);
+
+    return V_ADDR(pd_offset, pt_offset, PG_OFFSET(va));
+}
+
+void* vmm_alloc_page(void* vpn, pt_attr dattr, pt_attr tattr) {
+    void* pp = pmm_alloc_page();
+    void* result = vmm_map_page(vpn, pp, dattr, tattr);
+    if (!result) {
+        pmm_free_page(pp);
+    }
+    return result;
+}
+
+void vmm_unmap_page(void* vpn) {
+    uintptr_t pd_offset = PD_INDEX(vpn);
+    uintptr_t pt_offset = PT_INDEX(vpn);
+    ptd_t* self_pde = PTD_BASE_VADDR;
+
+    ptd_t pde = self_pde[pd_offset];
+
+    if (pde) {
+        pt_t* pt = (pt_t*)PT_VADDR(pd_offset);
+        uint32_t pte = pt[pt_offset];
+        if (IS_CACHED(pte) && pmm_free_page(pte)) {
+            // 刷新TLB
+            #ifdef __ARCH_IA32
+            __asm__("invlpg (%0)" :: "r"((uintptr_t)vpn) : "memory");
+            #endif
+        }
+        pt[pt_offset] = 0;
+    }
+}
+
+void* vmm_v2p(void* va) {
+    uintptr_t pd_offset = PD_INDEX(va);
+    uintptr_t pt_offset = PT_INDEX(va);
+    uintptr_t po = PG_OFFSET(va);
+    ptd_t* self_pde = PTD_BASE_VADDR;
+
+    ptd_t pde = self_pde[pd_offset];
+    if (pde) {
+        pt_t pte = ((pt_t*)PT_VADDR(pd_offset))[pt_offset];
+        if (pte) {
+            uintptr_t ppn = pte >> 12;
+            return (void*)P_ADDR(ppn, po);
+        }
+    }
+
+    return NULL;
+}
\ No newline at end of file
index 2629c747f96b1dae44324895d09675ed18a315c4..cb4e13a1d21954182363b280b2ca84c1d6bf6487 100644 (file)
@@ -1,21 +1,31 @@
 #include <libc/string.h>
 #include <lunaix/tty/tty.h>
+#include <lunaix/constants.h>
 #include <stdint.h>
 
 #define TTY_WIDTH 80
 #define TTY_HEIGHT 25
 
-vga_attribute* buffer = (vga_attribute*)0xB8000;
+vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR;
 
-vga_attribute theme_color = VGA_COLOR_BLACK;
+vga_attribute tty_theme_color = VGA_COLOR_BLACK;
 
 uint32_t tty_x = 0;
 uint16_t tty_y = 0;
 
+void tty_init(void* vga_buf) {
+    tty_vga_buffer = (vga_attribute*)vga_buf;
+    tty_clear();
+}
+
+void tty_set_buffer(void* vga_buf) {
+    tty_vga_buffer = (vga_attribute*)vga_buf;
+}
+
 void
 tty_set_theme(vga_attribute fg, vga_attribute bg)
 {
-    theme_color = (bg << 4 | fg) << 8;
+    tty_theme_color = (bg << 4 | fg) << 8;
 }
 
 void
@@ -27,11 +37,12 @@ tty_put_char(char chr)
             break;
         case '\n':
             tty_y++;
+            // fall through
         case '\r':
             tty_x = 0;
             break;
         default:
-            *(buffer + tty_x + tty_y * TTY_WIDTH) = (theme_color | chr);
+            *(tty_vga_buffer + tty_x + tty_y * TTY_WIDTH) = (tty_theme_color | chr);
             tty_x++;
             break;
     }
@@ -58,9 +69,9 @@ void
 tty_scroll_up()
 {
     size_t last_line = TTY_WIDTH * (TTY_HEIGHT - 1);
-    memcpy(buffer, buffer + TTY_WIDTH, last_line);
+    memcpy(tty_vga_buffer, tty_vga_buffer + TTY_WIDTH, last_line);
     for (size_t i = 0; i < TTY_WIDTH; i++) {
-        *(buffer + i + last_line) = theme_color;
+        *(tty_vga_buffer + i + last_line) = tty_theme_color;
     }
     tty_y = tty_y == 0 ? 0 : tty_y - 1;
 }
@@ -69,7 +80,7 @@ void
 tty_clear()
 {
     for (uint32_t i = 0; i < TTY_WIDTH * TTY_HEIGHT; i++) {
-        *(buffer + i) = theme_color;
+        *(tty_vga_buffer + i) = tty_theme_color;
     }
     tty_x = 0;
     tty_y = 0;
index 15a7fe2503fd840eeb00d245a912c98ba02f452a..51466cd59483035be7e76e10f68c5a9b96e13888 100644 (file)
@@ -64,7 +64,10 @@ __sprintf_internal(char* buffer, char* fmt, va_list args)
                 }
                 case 'p': {
                     uintptr_t dptr = va_arg(args, uintptr_t);
-                    __itoa_internal((int)dptr, buffer + ptr, 16, &adv);
+                    buffer[ptr] = '0';
+                    buffer[ptr+1] = 'x';
+                    __itoa_internal((int)dptr, buffer + ptr + 2, 16, &adv);
+                    adv+=2;
                     break;
                 }
                 case '%': {
index 3d0699ef9f51b8ed1187d0e8099a942de7b75234..d7920b4354b7f6023e8426af211e0ee4826675c5 100644 (file)
@@ -1,4 +1,5 @@
 #define __LUNAIX_LIBC
+#include <stddef.h>
 #include <libc/stdlib.h>
 
 char base_char[] = "0123456789abcdefghijklmnopqrstuvwxyz";
@@ -35,10 +36,8 @@ char*
 __itoa_internal(int value, char* str, int base, unsigned int* size)
 {
     if (value < 0 && base == 10) {
-        unsigned int msk = value >> 31;
-        // evil bit level hack for abs()
-        unsigned int _v = (unsigned int)((value + msk) ^ msk);
         str[0] = '-';
+        unsigned int _v = (unsigned int)(-value);
         __uitoa_internal(_v, str + 1, base, size);
     } else {
         __uitoa_internal(value, str, base, size);
@@ -50,5 +49,5 @@ __itoa_internal(int value, char* str, int base, unsigned int* size)
 char*
 itoa(int value, char* str, int base)
 {
-    return __itoa_internal(value, str, base, (void*)0);
+    return __itoa_internal(value, str, base, NULL);
 }
\ No newline at end of file
index 79dd63a0ee4bccaaebd3398bb92abbeb88769fb2..f0eebd51673bd481992abca7caa72b8d44d65edd 100644 (file)
@@ -1,23 +1,61 @@
 ENTRY(start_)
 
+/*
+    FUTURE: Use dynamic linker to separate kernel and boot code
+    A bit of messy here.
+    We will pull our higher half kernel out of this shit
+      and load it separately once we have our dynamic linker ready.
+*/
+
 SECTIONS {
     . = 0x100000;
 
-    .text BLOCK(4K) : {
+    /* 这里是我们的高半核初始化代码段和数据段 */
+
+    .hhk_init_text BLOCK(4K) : {
         * (.multiboot)
-        * (.text)
+        build/obj/arch/x86/*.o (.hhk_init)
+        build/obj/arch/x86/*.o (.text)
+    }
+
+    .hhk_init_bss BLOCK(4K) : {
+        build/obj/arch/x86/*.o (.bss)
+    }
+
+    .hhk_init_data BLOCK(4K) : {
+        build/obj/arch/x86/*.o (.data)
+    }
+
+    .hhk_init_rodata BLOCK(4K) : {
+        build/obj/arch/x86/*.o (.rodata)
+    }
+    __init_hhk_end = .;
+
+    /* Relocation of our higher half kernel */
+    . += 0xC0000000;
+
+    /* 好了,我们的内核…… */
+    .text BLOCK(4K) : AT ( ADDR(.text) - 0xC0000000 ) {
+        __kernel_start = .;
+        build/obj/kernel/*.o (.text)
     }
 
-    .bss BLOCK(4K) : {
-        * (COMMON)
-        * (.bss)
+    .bss BLOCK(4K) : AT ( ADDR(.bss) - 0xC0000000 ) {
+        build/obj/kernel/*.o (.bss)
     }
 
-    .data BLOCK(4k) : {
-        * (.data)
+    .data BLOCK(4k) : AT ( ADDR(.data) - 0xC0000000 ) {
+        build/obj/kernel/*.o (.data)
     }
 
-    .rodata BLOCK(4K) : {
-        * (.rodata)
+    .rodata BLOCK(4K) : AT ( ADDR(.rodata) - 0xC0000000 ) {
+        build/obj/kernel/*.o (.rodata)
     }
+
+    .kpg BLOCK(4K) : AT ( ADDR(.kpg) - 0xC0000000 ) {
+        build/obj/arch/x86/*.o (.kpg)
+    }
+
+    __kernel_end = ALIGN(.);
+    __heap_start = ALIGN(.);    /* 内核结束的地方即堆开始的地方 */
 }
\ No newline at end of file
index c25ee5cee93b9e99fa5765bf9e46caa6f50503e4..625743c9926001bf57b72e5aba57692a3a8b4e22 100644 (file)
@@ -20,14 +20,17 @@ $(ISO_DIR):
 
 $(OBJECT_DIR)/%.S.o: %.S
        @mkdir -p $(@D)
-       $(CC) $(INCLUDES) -c $< -o $@
+       @echo "Compiling: $< -> $@"
+       @$(CC) $(INCLUDES) -c $< -o $@
 
 $(OBJECT_DIR)/%.c.o: %.c 
        @mkdir -p $(@D)
-       $(CC) $(INCLUDES) -c $< -o $@ $(CFLAGS)
+       @echo "Compiling: $< -> $@"
+       @$(CC) $(INCLUDES) -c $< -o $@ $(CFLAGS)
 
 $(BIN_DIR)/$(OS_BIN): $(OBJECT_DIR) $(BIN_DIR) $(SRC)
-       $(CC) -T linker.ld -o $(BIN_DIR)/$(OS_BIN) $(SRC) $(LDFLAGS)
+       @echo "Linking ..."
+       @$(CC) -T linker.ld -o $(BIN_DIR)/$(OS_BIN) $(SRC) $(LDFLAGS)
 
 $(BUILD_DIR)/$(OS_ISO): $(ISO_DIR) $(BIN_DIR)/$(OS_BIN) GRUB_TEMPLATE
        @./config-grub.sh ${OS_NAME} > $(ISO_GRUB_DIR)/grub.cfg
@@ -36,12 +39,12 @@ $(BUILD_DIR)/$(OS_ISO): $(ISO_DIR) $(BIN_DIR)/$(OS_BIN) GRUB_TEMPLATE
 
 all: clean $(BUILD_DIR)/$(OS_ISO)
 
-all-debug: O := -O0
-all-debug: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W)
-all-debug: LDFLAGS := -ffreestanding $(O) -nostdlib -lgcc
+all-debug: O := -Og
+all-debug: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT)
+all-debug: LDFLAGS := -g -ffreestanding $(O) -nostdlib -lgcc
 all-debug: clean $(BUILD_DIR)/$(OS_ISO)
        @echo "Dumping the disassembled kernel code to $(BUILD_DIR)/kdump.txt"
-       @i686-elf-objdump -S $(BIN_DIR)/$(OS_BIN) > $(BUILD_DIR)/kdump.txt
+       @i686-elf-objdump -D $(BIN_DIR)/$(OS_BIN) > $(BUILD_DIR)/kdump.txt
 
 clean:
        @rm -rf $(BUILD_DIR)
@@ -52,8 +55,8 @@ run: $(BUILD_DIR)/$(OS_ISO)
        @telnet 127.0.0.1 $(QEMU_MON_PORT)
 
 debug-qemu: all-debug
-       @objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg
-       @qemu-system-i386 -s -S -kernel $(BIN_DIR)/$(OS_BIN) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
+       @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg
+       @qemu-system-i386 -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait &
        @sleep 1
        @$(QEMU_MON_TERM) -e "telnet 127.0.0.1 $(QEMU_MON_PORT)"
        @gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234"