From cd09c4b222e4ddf45a42522563ae2471a829d1c8 Mon Sep 17 00:00:00 2001 From: Minep Date: Fri, 25 Feb 2022 19:28:39 +0000 Subject: [PATCH 1/1] Virtual memory & paging vm & pm management higher half kernel! a LOT of memory remapping CPUID support start working on HAL. --- lunaix-os/.vscode/c_cpp_properties.json | 3 +- lunaix-os/arch/x86/boot.S | 118 +++++---- lunaix-os/arch/x86/hhk.c | 134 ++++++++++ lunaix-os/arch/x86/multiboot.h | 3 - lunaix-os/bochs.cfg | 2 + lunaix-os/config/make-cc | 4 +- lunaix-os/hal/cpu.c | 76 ++++++ lunaix-os/includes/arch/x86/boot/multiboot.h | 229 ++++++++++++++++++ .../includes/{lunaix/arch => arch/x86}/gdt.h | 7 +- .../includes/{lunaix/arch => arch/x86}/idt.h | 5 +- lunaix-os/includes/arch/x86/interrupts.h | 19 ++ .../{lunaix/interrupts => arch/x86}/types.h | 9 +- lunaix-os/includes/hal/cpu.h | 36 +++ lunaix-os/includes/hal/io.h | 41 ++++ lunaix-os/includes/lunaix/constants.h | 13 + .../includes/lunaix/interrupts/interrupts.h | 15 -- lunaix-os/includes/lunaix/mm/page.h | 62 +++++ lunaix-os/includes/lunaix/mm/pmm.h | 65 +++++ lunaix-os/includes/lunaix/mm/vmm.h | 60 +++++ lunaix-os/includes/lunaix/tty/tty.h | 13 +- lunaix-os/{arch => kernel/asm}/x86/gdt.c | 2 +- lunaix-os/{arch => kernel/asm}/x86/idt.c | 6 +- .../{arch => kernel/asm}/x86/interrupt.S | 0 .../{interrupts => asm/x86}/interrupts.c | 6 +- lunaix-os/kernel/asm/x86/prologue.S | 63 +++++ lunaix-os/kernel/k_main.c | 121 +++++++++ lunaix-os/kernel/kernel.c | 21 -- lunaix-os/kernel/mm/pmm.c | 137 +++++++++++ lunaix-os/kernel/mm/vmm.c | 143 +++++++++++ lunaix-os/kernel/tty/tty.c | 25 +- lunaix-os/libs/libc/stdio/sprintf.c | 5 +- lunaix-os/libs/libc/stdlib/itoa.c | 7 +- lunaix-os/linker.ld | 56 ++++- lunaix-os/makefile | 21 +- 34 files changed, 1399 insertions(+), 128 deletions(-) create mode 100644 lunaix-os/arch/x86/hhk.c delete mode 100644 lunaix-os/arch/x86/multiboot.h create mode 100644 lunaix-os/hal/cpu.c create mode 100644 lunaix-os/includes/arch/x86/boot/multiboot.h rename lunaix-os/includes/{lunaix/arch => arch/x86}/gdt.h (97%) rename lunaix-os/includes/{lunaix/arch => arch/x86}/idt.h (56%) create mode 100644 lunaix-os/includes/arch/x86/interrupts.h rename lunaix-os/includes/{lunaix/interrupts => arch/x86}/types.h (88%) create mode 100644 lunaix-os/includes/hal/cpu.h create mode 100644 lunaix-os/includes/hal/io.h create mode 100644 lunaix-os/includes/lunaix/constants.h delete mode 100644 lunaix-os/includes/lunaix/interrupts/interrupts.h create mode 100644 lunaix-os/includes/lunaix/mm/page.h create mode 100644 lunaix-os/includes/lunaix/mm/pmm.h create mode 100644 lunaix-os/includes/lunaix/mm/vmm.h rename lunaix-os/{arch => kernel/asm}/x86/gdt.c (95%) rename lunaix-os/{arch => kernel/asm}/x86/idt.c (81%) rename lunaix-os/{arch => kernel/asm}/x86/interrupt.S (100%) rename lunaix-os/kernel/{interrupts => asm/x86}/interrupts.c (56%) create mode 100644 lunaix-os/kernel/asm/x86/prologue.S create mode 100644 lunaix-os/kernel/k_main.c delete mode 100644 lunaix-os/kernel/kernel.c create mode 100644 lunaix-os/kernel/mm/pmm.c create mode 100644 lunaix-os/kernel/mm/vmm.c diff --git a/lunaix-os/.vscode/c_cpp_properties.json b/lunaix-os/.vscode/c_cpp_properties.json index 10acdd8..0840db1 100644 --- a/lunaix-os/.vscode/c_cpp_properties.json +++ b/lunaix-os/.vscode/c_cpp_properties.json @@ -6,7 +6,8 @@ "${workspaceFolder}/includes/**" ], "compilerArgs": [ - "-ffreestanding" + "-ffreestanding", + "-D__ARCH_IA32" ], "defines": [], "compilerPath": "${HOME}/opt/cross-compiler/bin/i686-elf-gcc", diff --git a/lunaix-os/arch/x86/boot.S b/lunaix-os/arch/x86/boot.S index b41d24b..bc1eec2 100644 --- a/lunaix-os/arch/x86/boot.S +++ b/lunaix-os/arch/x86/boot.S @@ -1,62 +1,88 @@ -#include "multiboot.h" +#define __ASM__ 1 +#include + +#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 index 0000000..c0e5f9a --- /dev/null +++ b/lunaix-os/arch/x86/hhk.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +#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 index 4aa587a..0000000 --- a/lunaix-os/arch/x86/multiboot.h +++ /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 diff --git a/lunaix-os/bochs.cfg b/lunaix-os/bochs.cfg index 8114f97..216cad6 100644 --- a/lunaix-os/bochs.cfg +++ b/lunaix-os/bochs.cfg @@ -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 diff --git a/lunaix-os/config/make-cc b/lunaix-os/config/make-cc index 416ae68..f3ce340 100644 --- a/lunaix-os/config/make-cc +++ b/lunaix-os/config/make-cc @@ -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 index 0000000..b2ef657 --- /dev/null +++ b/lunaix-os/hal/cpu.c @@ -0,0 +1,76 @@ +#include +#include +#include + +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 index 0000000..a019686 --- /dev/null +++ b/lunaix-os/includes/arch/x86/boot/multiboot.h @@ -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 diff --git a/lunaix-os/includes/lunaix/arch/gdt.h b/lunaix-os/includes/arch/x86/gdt.h similarity index 97% rename from lunaix-os/includes/lunaix/arch/gdt.h rename to lunaix-os/includes/arch/x86/gdt.h index b680f6f..bb2fa27 100644 --- a/lunaix-os/includes/lunaix/arch/gdt.h +++ b/lunaix-os/includes/arch/x86/gdt.h @@ -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 diff --git a/lunaix-os/includes/lunaix/arch/idt.h b/lunaix-os/includes/arch/x86/idt.h similarity index 56% rename from lunaix-os/includes/lunaix/arch/idt.h rename to lunaix-os/includes/arch/x86/idt.h index 4a0d28d..af0ae7d 100644 --- a/lunaix-os/includes/lunaix/arch/idt.h +++ b/lunaix-os/includes/arch/x86/idt.h @@ -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 index 0000000..fb4eb79 --- /dev/null +++ b/lunaix-os/includes/arch/x86/interrupts.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/interrupts/types.h b/lunaix-os/includes/arch/x86/types.h similarity index 88% rename from lunaix-os/includes/lunaix/interrupts/types.h rename to lunaix-os/includes/arch/x86/types.h index 888ca1f..ba2839a 100644 --- a/lunaix-os/includes/lunaix/interrupts/types.h +++ b/lunaix-os/includes/arch/x86/types.h @@ -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 index 0000000..2a06f29 --- /dev/null +++ b/lunaix-os/includes/hal/cpu.h @@ -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 index 0000000..0f5e9d6 --- /dev/null +++ b/lunaix-os/includes/hal/io.h @@ -0,0 +1,41 @@ +#ifndef __LUNAIX_IO_H +#define __LUNAIX_IO_H + +#include + +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 index 0000000..66a6f0c --- /dev/null +++ b/lunaix-os/includes/lunaix/constants.h @@ -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 index 723ba67..0000000 --- a/lunaix-os/includes/lunaix/interrupts/interrupts.h +++ /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 index 0000000..c981839 --- /dev/null +++ b/lunaix-os/includes/lunaix/mm/page.h @@ -0,0 +1,62 @@ +#ifndef __LUNAIX_PAGE_H +#define __LUNAIX_PAGE_H +#include +#include + +#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 index 0000000..36396df --- /dev/null +++ b/lunaix-os/includes/lunaix/mm/pmm.h @@ -0,0 +1,65 @@ +#ifndef __LUNAIX_PMM_H +#define __LUNAIX_PMM_H +// Physical memory manager + +#include +#include + +#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 index 0000000..14b3a7f --- /dev/null +++ b/lunaix-os/includes/lunaix/mm/vmm.h @@ -0,0 +1,60 @@ +#ifndef __LUNAIX_VMM_H +#define __LUNAIX_VMM_H +#include +#include +#include +// 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 */ diff --git a/lunaix-os/includes/lunaix/tty/tty.h b/lunaix-os/includes/lunaix/tty/tty.h index c1a9a92..3d723ca 100644 --- a/lunaix-os/includes/lunaix/tty/tty.h +++ b/lunaix-os/includes/lunaix/tty/tty.h @@ -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 */ diff --git a/lunaix-os/arch/x86/gdt.c b/lunaix-os/kernel/asm/x86/gdt.c similarity index 95% rename from lunaix-os/arch/x86/gdt.c rename to lunaix-os/kernel/asm/x86/gdt.c index c7eec34..41c597e 100644 --- a/lunaix-os/arch/x86/gdt.c +++ b/lunaix-os/kernel/asm/x86/gdt.c @@ -1,4 +1,4 @@ -#include +#include #include #define GDT_ENTRY 5 diff --git a/lunaix-os/arch/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c similarity index 81% rename from lunaix-os/arch/x86/idt.c rename to lunaix-os/kernel/asm/x86/idt.c index 08acda2..9f2bd06 100644 --- a/lunaix-os/arch/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include #define IDT_ENTRY 32 diff --git a/lunaix-os/arch/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S similarity index 100% rename from lunaix-os/arch/x86/interrupt.S rename to lunaix-os/kernel/asm/x86/interrupt.S diff --git a/lunaix-os/kernel/interrupts/interrupts.c b/lunaix-os/kernel/asm/x86/interrupts.c similarity index 56% rename from lunaix-os/kernel/interrupts/interrupts.c rename to lunaix-os/kernel/asm/x86/interrupts.c index ee023de..39682a3 100644 --- a/lunaix-os/kernel/interrupts/interrupts.c +++ b/lunaix-os/kernel/asm/x86/interrupts.c @@ -1,9 +1,9 @@ -#include -#include +#include +#include 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 index 0000000..4e114e9 --- /dev/null +++ b/lunaix-os/kernel/asm/x86/prologue.S @@ -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 index 0000000..8634443 --- /dev/null +++ b/lunaix-os/kernel/k_main.c @@ -0,0 +1,121 @@ +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +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 index 72f2f4e..0000000 --- a/lunaix-os/kernel/kernel.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include - -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 index 0000000..c6b0a25 --- /dev/null +++ b/lunaix-os/kernel/mm/pmm.c @@ -0,0 +1,137 @@ +#include +#include + +#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 index 0000000..aaaf54c --- /dev/null +++ b/lunaix-os/kernel/mm/vmm.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include + +// 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 diff --git a/lunaix-os/kernel/tty/tty.c b/lunaix-os/kernel/tty/tty.c index 2629c74..cb4e13a 100644 --- a/lunaix-os/kernel/tty/tty.c +++ b/lunaix-os/kernel/tty/tty.c @@ -1,21 +1,31 @@ #include #include +#include #include #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; diff --git a/lunaix-os/libs/libc/stdio/sprintf.c b/lunaix-os/libs/libc/stdio/sprintf.c index 15a7fe2..51466cd 100644 --- a/lunaix-os/libs/libc/stdio/sprintf.c +++ b/lunaix-os/libs/libc/stdio/sprintf.c @@ -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 '%': { diff --git a/lunaix-os/libs/libc/stdlib/itoa.c b/lunaix-os/libs/libc/stdlib/itoa.c index 3d0699e..d7920b4 100644 --- a/lunaix-os/libs/libc/stdlib/itoa.c +++ b/lunaix-os/libs/libc/stdlib/itoa.c @@ -1,4 +1,5 @@ #define __LUNAIX_LIBC +#include #include 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 diff --git a/lunaix-os/linker.ld b/lunaix-os/linker.ld index 79dd63a..f0eebd5 100644 --- a/lunaix-os/linker.ld +++ b/lunaix-os/linker.ld @@ -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 diff --git a/lunaix-os/makefile b/lunaix-os/makefile index c25ee5c..625743c 100644 --- a/lunaix-os/makefile +++ b/lunaix-os/makefile @@ -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" -- 2.27.0