"${workspaceFolder}/includes/**"
],
"compilerArgs": [
- "-ffreestanding"
+ "-ffreestanding",
+ "-D__ARCH_IA32"
],
"defines": [],
"compilerPath": "${HOME}/opt/cross-compiler/bin/i686-elf-gcc",
-#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
--- /dev/null
+#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
+++ /dev/null
-#define MB_MAGIC 0x1BADB002
-#define MB_ALIGNED_4K_MEM_MAP 0x03
-#define CHECKSUM(flags) -(MB_MAGIC+flags)
\ No newline at end of file
ata0-master: type=cdrom, path="build/lunaix.iso", status=inserted
+memory: guest=1024, host=1024
+
boot: cdrom
\ No newline at end of file
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
--- /dev/null
+#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)
+ );
+}
+
+
--- /dev/null
+#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
+#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)
void
-_init_gdt();
\ No newline at end of file
+_init_gdt();
+
+#endif
+#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
--- /dev/null
+#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 */
// 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
#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
+++ /dev/null
-#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
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
+#ifndef __LUNAIX_TTY_H
+#define __LUNAIX_TTY_H
typedef unsigned short vga_attribute;
#define VGA_COLOR_BLACK 0
#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);
tty_scroll_up();
void
-tty_clear();
\ No newline at end of file
+tty_clear();
+
+
+#endif /* __LUNAIX_TTY_H */
-#include <lunaix/arch/gdt.h>
+#include <arch/x86/gdt.h>
#include <stdint.h>
#define GDT_ENTRY 5
-#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
-#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
--- /dev/null
+/* 高半核入口点 - 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
--- /dev/null
+#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
+++ /dev/null
-#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
--- /dev/null
+#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
--- /dev/null
+#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
#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
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;
}
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;
}
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;
}
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 '%': {
#define __LUNAIX_LIBC
+#include <stddef.h>
#include <libc/stdlib.h>
char base_char[] = "0123456789abcdefghijklmnopqrstuvwxyz";
__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);
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
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
$(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
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)
@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"