diff --git a/env.mk b/env.mk index 16680119..f18ab138 100644 --- a/env.mk +++ b/env.mk @@ -1,6 +1,6 @@ ifeq ($(ARCH), ) -# !!!!在这里设置ARCH,可选x86_64和riscv64 +# !!!!在这里设置ARCH,可选 x86_64 和 riscv64 # !!!!!!!如果不同时调整这里以及vscode的settings.json,那么自动补全和检查将会失效 export ARCH?=x86_64 endif diff --git a/kernel/src/arch/riscv64/asm/head.S b/kernel/src/arch/riscv64/asm/head.S index 01ae7ad9..e70ac0ba 100644 --- a/kernel/src/arch/riscv64/asm/head.S +++ b/kernel/src/arch/riscv64/asm/head.S @@ -2,12 +2,30 @@ .section .bootstrap +#define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 +#define CSR_STVEC 0x105 #define CSR_SIP 0x144 +# define CSR_TVEC CSR_STVEC + +# define CSR_STATUS CSR_SSTATUS #define CSR_IE CSR_SIE #define CSR_IP CSR_SIP +#define SR_FS 0x00006000 +#define SR_VS 0x00000600 +#define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */ + +#define SATP_MODE_39 0x8000000000000000UL +#define SATP_MODE_48 0x9000000000000000UL +#define SATP_MODE_57 0xa000000000000000UL + +#define PAGE_OFFSET 0xffffffc000000000 +#define KERNEL_LINK_OFFSET 0x1000000 +#define KERNEL_VIRT_START (PAGE_OFFSET + KERNEL_LINK_OFFSET) + + // 内核入口(从DragonStub跳转到这里) // 参数: // a0: hartid (核心ID) @@ -18,17 +36,317 @@ ENTRY(_start) /* Mask all interrupts */ csrw CSR_IE, zero csrw CSR_IP, zero - /* Load the global pointer */ + + + // 暂存hartid + la t0, __initial_hartid_ptr + sd a0, 0(t0) + // 暂存平坦设备树地址 + la t0, __initial_fdt_ptr + sd a1, 0(t0) + + + // 暂存_start标签被DragonStub加载到的物理地址 + auipc t0, 0 + li t1, -4095 + and t0, t0, t1 + la t1, __initial_start_load_paddr + sd t0, 0(t1) + + // 清空页表的空间 + la a0, __initial_pgtable + call __initial_clear_pgtable + la a0, __initial_l1_pgtable + call __initial_clear_pgtable + la a0, __initial_l1_pgtable + li a1, 4096 + add a0, a0, a1 + call __initial_clear_pgtable + + + + // 设置页表,把内核当前所在的物理地址映射到链接时的内核虚拟空间 + la a0, __initial_start_load_paddr + ld a0, 0(a0) + + // 偏移量0xffffffc000000000,计算起始的L0页表项 + // 因为内核链接地址还有16M的空间,所以这里加上0x1000000 + li a1, KERNEL_VIRT_START + + // 映射物理地址到虚拟地址 + call initial_map_256M_phys_addr + + // 增加恒等映射 + la a0, __initial_start_load_paddr + ld a0, 0(a0) + + mv a1, a0 + call initial_map_1g_identical + +__init_set_pgtable_loop_end: + + call __initial_reloacate_enable_mmu + .option push .option norelax - la sp, BSP_IDLE_STACK_SPACE + + la a0, BSP_IDLE_STACK_SPACE + mv sp, a0 li t0, 32768 add sp, sp, t0 .option pop + /* + * Disable FPU & VECTOR to detect illegal usage of + * floating point or vector in kernel space + */ + li t0, SR_FS_VS + csrc CSR_STATUS, t0 + /* Call the kernel */ + la a0, __initial_hartid_ptr + ld a0, 0(a0) + la a1, __initial_fdt_ptr + ld a1, 0(a1) + + + // 跳转到kernel_main call kernel_main nop -_loop: - j _loop + wfi +__initial_reloacate_enable_mmu: + // 计算起始物理地址与内核高虚拟地址的偏移量 + la t0, __initial_start_load_paddr + ld t0, 0(t0) + + li t1, KERNEL_VIRT_START + sub t1, t1, t0 + + // 重定位返回地址 + add ra, ra, t1 + + /* Point stvec to virtual address of intruction after satp write */ + /* Set trap vector to spin forever to help debug */ + la a2, __initial_Lsecondary_park + add a2, a2, t1 + csrw CSR_TVEC, a2 + + // enable MMU + la a2, __initial_pgtable + srli a2, a2, 12 + la a0, __initial_satp_mode + ld a0, 0(a0) + or a2, a2, a0 + sfence.vma + csrw satp, a2 + + ret + +// 映射物理地址到虚拟地址(2M页,1G大小) +// 参数: +// a0: 物理地址 +// a1: 虚拟地址 +initial_map_256M_phys_addr: + // 检查物理地址是否对齐到2M + li t0, 0x1fffff + and t0, t0, a0 + bnez t0, __initial_map_1g_phys_failed + + // 检查虚拟地址是否对齐到2M + li t0, 0x1fffff + and t0, t0, a1 + bnez t0, __initial_map_1g_phys_failed + + // 把起始虚拟地址存储到t2中 + mv t2, a1 + // 按照2M对齐 + li t1, -0x200000 + and t2, t2, t1 + + // 计算L0页表项的索引 + srl t2, t2, 30 + andi t2, t2, 511 + + + // 填写第一个L0页表项 + la t4, __initial_pgtable + slli t5, t2, 3 // t5 = t2 * 8 + add t4, t4, t5 // t4 = t4 + t5, t4指向L0页表项 + + // 提取L1页表的地址 + la t5, __initial_l1_pgtable + srli t5, t5, 12 + slli t5, t5, 10 + ori t5, t5, 0x1 // 设置L1页表项属性,V = 1 + // 设置L0页表项的值 + sd t5, 0(t4) + + // 计算是否需要填写第二个L1页表项(判断是否超过第一个L1页表的范围) + addi t3, t2, 128 + li t5, 512 + blt t3, t5, __initial_set_l1_pgtable + // 填写第二个L1页表 + la t3, __initial_l1_pgtable + li t5, 4096 + add t3, t3, t5 + srli t3, t3, 12 + slli t3, t3, 10 + ori t3, t3, 0x1 // 设置L1页表项属性,V = 1 + // 设置L0页表项的值 + sd t3, 8(t4) + +__initial_set_l1_pgtable: // 开始填写L1页表 + + // 获取起始物理地址 + mv t6, a0 + // 获取L1页表的地址 + la t0, __initial_l1_pgtable + + // 计算起始L1页表项的索引 + mv t3, a1 + srli t3, t3, 21 + andi t3, t3, 511 + + slli t3, t3, 3 // t3 = t3 * 8 + add t0, t0, t3 // t0 = t0 + t3 + + // 加载计数器 + li t5, 0 +__initial_set_l1_pgtable_loop: + + mv t3, t6 + srli t3, t3, 12 // t3 = t6 >> 12 (page frame number) + li t1, 0x3FFFFFFFFFFFFF + and t3, t3, t1 // t3 = t3 & 0x3FFFFFFFFFFFFF + slli t3, t3, 10 // t3 = t3 << 10 + ori t3, t3, 0xf // 设置L1页表项属性,R/W/X/V = 1 + // 设置L1页表项的值 + sd t3, 0(t0) + + // 增加 页表项指针 + addi t0, t0, 8 + // 增加 t6 的值(2M) + li t2, 0x200000 + add t6, t6, t2 + + // 增加计数器 + addi t5, t5, 1 + // 判断计数器是否超过128 + li t2, 128 + blt t5, t2, __initial_set_l1_pgtable_loop + + + // 填写完成 + ret + + + + +__initial_map_1g_phys_failed: + // 地址没有对齐到2M + wfi + la a0, __initial_map_1g_phys_failed + // 跳转 + jr a0 + + + +// 映射物理地址到虚拟地址(恒等映射) +// 参数: +// a0: 物理地址 +initial_map_1g_identical: + mv a1, a0 + // 把_start向下对齐到1GB + li t0, -0x40000000 + // 计算起始物理地址,存放在t0中 + and t0, t0, a0 + + + // 把起始虚拟地址存储到t2中 + mv t2, a1 + // 按照1g对齐 + li t1, -0x40000000 + and t2, t2, t1 + + // 右移30位,得到L0页表项的索引 + srl t2, t2, 30 + // 与511进行与运算,得到L0页表项的索引 + andi t2, t2, 511 + + + // 填写页表项 + // li t2, 0xf // 页表项属性, R/W/X/V = 1 + la t4, __initial_pgtable + slli t3, t2, 3 // t3 = t2 * 8 + add t4, t4, t3 // t4 = t4 + t3 + + mv t3, t0 + srli t3, t3, 12 // t3 = t0 >> 12 (page frame number) + slli t3, t3, 10 // t3 = t3 << 10 + ori t3, t3, 0xf // set R/W/X/V = 1 + // 设置t0地址在L0页表中的值 + sd t3, 0(t4) + + // 增加 t4 的值 + addi t4, t4, 8 + // 增加 t3 的值(1G) + li t2, 0x40000000 + add t3, t3, t2 + sd t3, 0(t4) + + ret + +// 用于清空页表的空间 +// 参数: +// a0: page table address +__initial_clear_pgtable: + mv t0, a0 + li t1, 512 + li t2, 0 // 用于存储 0 + +__initial_clear_pgtable_loop: + + sd t2, 0(t0) // 将 0 存储到当前word + addi t0, t0, 8 // 增加 t0 的值 + addi t1, t1, -1 // 减少剩余的word数 + bnez t1, __initial_clear_pgtable_loop + + ret + +.align 2 +__initial_Lsecondary_park: + /* We lack SMP support or have too many harts, so park this hart */ + wfi + j __initial_Lsecondary_park + +// 全局变量,存储平坦设备树的地址和hartid +.global __initial_fdt_ptr +__initial_fdt_ptr: + .quad 0 + +.global __initial_hartid_ptr +__initial_hartid_ptr: + .quad 0 + +// _start标签在启动时被加载到的物理地址 +__initial_start_load_paddr: + .quad 0 + +__initial_kernel_main_vaddr: + .quad 0 + + + +.global __initial_satp_mode +__initial_satp_mode: + .quad SATP_MODE_39 + +// 初始页表的空间(sv39模式的L0页表) +.section .initial_pgtable_section +__initial_pgtable: + .skip 4096 + +__initial_l1_pgtable: + .skip 8192 + diff --git a/kernel/src/arch/riscv64/init/mod.rs b/kernel/src/arch/riscv64/init/mod.rs index b822b3bf..43b3a079 100644 --- a/kernel/src/arch/riscv64/init/mod.rs +++ b/kernel/src/arch/riscv64/init/mod.rs @@ -1,14 +1,16 @@ use core::intrinsics::unreachable; -use crate::{ - driver::tty::serial::serial8250::send_to_default_serial8250_port, init::init_before_mem_init, - kdebug, -}; +use crate::{init::init_before_mem_init, kinfo, mm::PhysAddr}; #[no_mangle] -unsafe extern "C" fn kernel_main(hartid: usize, fdt_addr: usize) -> ! { +unsafe extern "C" fn kernel_main(hartid: usize, fdt_paddr: usize) -> ! { + let fdt_paddr = PhysAddr::new(fdt_paddr); init_before_mem_init(); - send_to_default_serial8250_port(&b"Hello, world! RISC-V!\n"[..]); + kinfo!( + "DragonOS kernel is running on hart {}, fdt address:{:?}", + hartid, + fdt_paddr + ); loop {} unreachable() } diff --git a/kernel/src/arch/riscv64/link.ld b/kernel/src/arch/riscv64/link.ld index 5f98fbd3..99dcffd4 100644 --- a/kernel/src/arch/riscv64/link.ld +++ b/kernel/src/arch/riscv64/link.ld @@ -10,20 +10,23 @@ ENTRY(_start) SECTIONS { - //KERNEL_VMA = 0xffffffc000000000; - KERNEL_VMA = 0; + KERNEL_VMA = 0xffffffc000000000; . = 0x1000000; - - .boot.text : + . += KERNEL_VMA; + . = ALIGN(4096); + boot_text_start_pa = .; + .boot.text : AT(boot_text_start_pa - KERNEL_VMA) { KEEP(*(.bootstrap)) - *(.bootstrap.code64) - *(.bootstrap.data) + *(.bootstrap) + *(.bootstrap.*) + . = ALIGN(4096); + *(.initial_pgtable_section) . = ALIGN(4096); } - . += KERNEL_VMA; - . = ALIGN(32768); + + . = ALIGN(4096); text_start_pa = .; .text (text_start_pa): AT(text_start_pa - KERNEL_VMA) { diff --git a/kernel/src/arch/riscv64/mm/init.rs b/kernel/src/arch/riscv64/mm/init.rs new file mode 100644 index 00000000..3d7b8ace --- /dev/null +++ b/kernel/src/arch/riscv64/mm/init.rs @@ -0,0 +1,3 @@ +use virtio_drivers::PhysAddr; + +pub fn setup_vm(dtb_paddr: PhysAddr) {} diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index 7a251f33..aebe31af 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/kernel/src/arch/riscv64/mm/mod.rs @@ -5,6 +5,7 @@ use crate::mm::{ }; pub mod bump; +pub(super) mod init; pub type PageMapper = crate::mm::page::PageMapper; diff --git a/kernel/submodules/DragonStub b/kernel/submodules/DragonStub index bf26173f..5d9a3c15 160000 --- a/kernel/submodules/DragonStub +++ b/kernel/submodules/DragonStub @@ -1 +1 @@ -Subproject commit bf26173f2b67d188d3c531d8b36e982748b062fc +Subproject commit 5d9a3c158772e628967d96e442c7398fa9da576a diff --git a/user/libs/libc/src/Makefile b/user/libs/libc/src/Makefile index 288ef83f..b3b0b9d0 100644 --- a/user/libs/libc/src/Makefile +++ b/user/libs/libc/src/Makefile @@ -35,4 +35,4 @@ clean: libc: $(libc_objs) $(libc_sub_dirs) libc_rust libc_rust: - cargo +nightly-2023-01-21 build --release --target ./arch/x86_64/x86_64-unknown-none.json + cargo +nightly-2023-08-15 build --release --target ./arch/x86_64/x86_64-unknown-none.json