diff --git a/.gitignore b/.gitignore index 99110024b..68149e260 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ !.cargo/* **/target -*.bin *.img /ignored diff --git a/Makefile b/Makefile index 80018258f..1bac0efc8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ # Makefile for top level of zCore ARCH ?= x86_64 +XTASK ?= 1 STRIP := $(ARCH)-linux-musl-strip export PATH=$(shell printenv PATH):$(CURDIR)/ignored/target/$(ARCH)/$(ARCH)-linux-musl-cross/bin/ @@ -21,7 +22,13 @@ update: # put rootfs for linux mode rootfs: +ifeq ($(XTASK), 1) cargo rootfs --arch $(ARCH) +else ifeq ($(ARCH), riscv64) + @rm -rf rootfs/riscv && mkdir -p rootfs/riscv/bin + @wget https://github.com/rcore-os/busybox-prebuilts/raw/master/busybox-1.30.1-riscv64/busybox -O rootfs/riscv/bin/busybox + @ln -s busybox rootfs/riscv/bin/ls +endif # put libc tests into rootfs libc-test: @@ -35,22 +42,18 @@ other-test: # build image from rootfs image: +ifeq ($(XTASK), 1) cargo image --arch $(ARCH) +else ifeq ($(ARCH), riscv64) + @echo building riscv.img + @rcore-fs-fuse zCore/riscv64.img rootfs/riscv zip + @qemu-img resize -f raw zCore/riscv64.img +5M +endif # check code style check: cargo check-style -riscv-rootfs: - @rm -rf rootfs/riscv && mkdir -p rootfs/riscv/bin - @wget https://github.com/rcore-os/busybox-prebuilts/raw/master/busybox-1.30.1-riscv64/busybox -O rootfs/riscv/bin/busybox - @ln -s busybox rootfs/riscv/bin/ls - -riscv-image: riscv-rootfs - @echo building riscv.img - @rcore-fs-fuse zCore/riscv64.img rootfs/riscv zip - @qemu-img resize -f raw zCore/riscv64.img +5M - # build and open project document doc: cargo doc --open diff --git a/docs/README-C910.md b/docs/README-C910.md new file mode 100644 index 000000000..2f2251a15 --- /dev/null +++ b/docs/README-C910.md @@ -0,0 +1,277 @@ +# zCore on riscv64 + +## T-HEAD C910 Light val board 操作说明 +### 编译zCore内核镜像 +编译zCore内核: +``` +cd zCore/zCore +make build LINUX=1 MODE=release ARCH=riscv64 PLATFORM=c910light +``` + +制作u-boot系统镜像: +``` +mkimage -A riscv -O linux -C none -T kernel -a 0x200000 -e 0x200000 -n "zCore for c910" -d ../target/riscv64/release/zcore.bin uImageC910 +``` + +### 编译opensbi镜像 +``` +git clone https://github.com/elliott10/opensbi.git -b thead_light-c910 + +cd opensbi + +make PLATFORM=generic CROSS_COMPILE=/path/to/toolchain/bin/riscv64-unknown-linux-gnu- +# 生成所需的fw_dynamic.bin +``` +注:原编译工具链基于官方仓库https://gitee.com/thead-yocto/xuantie-yocto.git 编译生成出来的。理论上可以使用其他工具链替代之 + +### 基于u-boot运行 + +在搭建好tftp服务的服务器目录中,放入编译好的opensbi镜像`fw_dynamic.bin`和系统镜像`uImageC910`。
+进入配置好网络的C910 Light板子的u-boot命令行上,运行: +``` +ext4load mmc 0:2 $aon_ram_addr light_aon_fpga.bin; ext4load mmc 0:2 $dtb_addr ${fdt_file}; + +tftp $opensbi_addr fw_dynamic.bin; +tftp $kernel_addr uImageC910; + +bootslave; run finduuid; run set_bootargs; bootm $kernel_addr - $dtb_addr; + +``` + +## T-HEAD C910 Light val board 移植说明 +### 1. 系统初步分析并制作系统镜像 + +c910-light + +C910 Light开发板如上图,在取得C910 Light开发板后,先按照官方的用户手册了解基本的硬件组件,以及电源和串口等接口的接线。
+用户手册:https://gitee.com/thead-yocto/documents/blob/master/en/user_guide/T-Head%20Yeying1520%20Yocto%20User%20Guide.pdf
+ +电源接上,以及串口连接到host机后,可以看到有四个串口`/dev/ttyUSBX`,调试用串口是,host机连上该串口,并在启动u-boot时按任意键可进入命令行模式
+u-boot命令行模式上,可以连接通有线网络,并通过tftp协议加载待启动的操作系统镜像。
+ +``` +# minicom -b 115200 -D /dev/ttyUSB2 + +U-Boot 2020.01-ge0ddd4721a (Dec 14 2021 - 22:26:59 +0800) + +CPU: rv64imafdcvsu +Model: T-HEAD c910 light +DRAM: 1 GiB +C910 CPU FREQ: 1500MHz +AHB2_CPUSYS_HCLK FREQ: 250MHz +AHB3_CPUSYS_PCLK FREQ: 125MHz +PERISYS_AHB_HCLK FREQ: 250MHz +PERISYS_APB_PCLK FREQ: 62MHz +GMAC PLL POSTDIV FREQ: 1000MHZ +DPU0 PLL POSTDIV FREQ: 1188MHZ +DPU1 PLL POSTDIV FREQ: 1188MHZ +MMC: sdhci@ffe7080000: 0, sd@ffe7090000: 1 +Loading Environment from MMC... OK +In: serial@ffe7014000 +Out: serial@ffe7014000 +Err: serial@ffe7014000 +Net: eth0: ethernet@ffe7070000 +Hit any key to stop autoboot: 0 +C910 Light# + +# setenv ipaddr +# setenv serverip + +``` + +在这里一开始尝试fu740板子的zCore系统镜像制作以及tftp启动模式, 在u-boot命令行中配置开发板IP地址和服务器IP地址,通过tftp协议加载系统镜像,最后通过bootm运行镜像;
+ +其他正常,但这样在引导zCore系统镜像时会出现报错,显示无法识别该系统镜像. +``` +Filename 'uImageC910'. +Load address: 0x200000 +Loading: ################################################################# + ############################################# + 5.1 MiB/s +done +Bytes transferred = 1609651 (188fb3 hex) +Wrong Image Format for bootm command +ERROR: can't get kernel image! +``` +这个问题分析后,发现由于u-boot的版本不同,导致对系统镜像格式的识别不一致。
+在fu740板子上的zCore系统镜像是基于`.its`脚本的新`FIT image`;
+而C910 Light的板子上的u-boot则只支持`old legacy image`,需要这样制作: + +``` +mkimage -A riscv -O linux -C none -T kernel -a 0x200000 -e 0x200000 -n "zCore for c910" -d ../target/riscv64/release/zcore.bin uImageC910 +``` +### 2. zCore系统引导构建 + +根据板子已有的Linux系统镜像,可获知加载地址是`Load Address: 0x200000`, 执行入口地址是`Entry Point: 0x200000`. + +由`0x200000`入口地址,修改zCore的linker.ld链接脚本文件的`BASE_ADDRESS`变量为相应的值,编译出zCore系统镜像在u-boot中,使用`tftp`命令网络加载镜像,`bootm`命令尝试引导镜像,发现在跳转内核后无任何反应。 + +这里分析可能有两种可能,第一可能zCore默认串口输出调用的opensbi print不正确,第二则可能在开始构建虚拟内存并跳转时出错。于是这里先让zCore引导启动时用物理内存的方式,把`zCore/src/platform/riscv/`目录中的引导有关的偏移地址变量暂修改成以`0x200000`为入口地址的相应的值即可,便没有了问题二,剩下了问题一关于opensbi的输出问题。 + +为了验证opensbi的输出是否正常,先尝试最精简的zCore镜像,在启动到rust代码的最早阶段,调用opensbi的`SBI_CONSOLE_PUTCHAR`输出功能。问题依旧无任何反应,这里陷入了问题僵局; + +C910 Light开发板是一块四方形大板,配置接口很丰富,包括了调试CPU的JTAG口。根据平头哥的官方调试文档连接部署好调试环境 https://occ.t-head.cn/document?temp=linux&slug=t-head-debug-server-user-manual + +jtag + +通过gdb连接JTAG DEBUG Server后,便可以单步调试C910 CPU的指令执行了,不过偶尔也会有无法下断点的问题,需要先把zCore系统镜像加载到内存之后,再下函数断点。 + +在JTAG的单步调试过程中,发现在执行指令`ecall SBI_CONSOLE_PUTCHAR`之后,没有任何反应,理论上应该会有字符从串口输出。这里考虑没有有效的opensbi,要么串口驱动有问题。 + +解决print问题,解决串口输出比较直接,于是参照u-boot的串口代码,把串口输出的基本功能使能,代码如下: + +``` +// T-HEAD C910 light +pub fn uart_put(c: u8) { + let ptr = BADDR as *mut u32; + unsafe { + //LSR bit:THRE + while ptr.add(5).read_volatile() & (1 << 5) == 0 {} + + //此时transmitter empty, THR有效位是8 + ptr.add(0).write_volatile(c as u32); + } +} +pub fn uart_get() -> Option { + let ptr = BADDR as *mut u32; + unsafe { + //查看LSR的DR位为1则有数据 + if ptr.add(5).read_volatile() & 0b1 == 0 { + None + } else { + Some((ptr.add(0).read_volatile() & 0xff) as u8) + } + } +} +``` + +于是zCore便可以运行输出了。 + +这里出现device tree解析DTB失败的问题,经研究尝试,发现是由于DTB加载到内存的空间,被zCore内核覆盖了,把DTB地址往高地址再移一段偏移便可以正常解析到DTB。 + +![c910 uart](img/c910-run-uart.png) + +后面与平头哥的技术支持人员沟通,获得了C910 light板子的文档和代码,据此获知更多有效信息,可以自定义编译u-boot、Linux内核、以及文件系统等板子必要组件; + +通过结合分析C910 light板子的文档和源代码,理清楚了C910 light板子的启动链: + +``` +U-Boot 运行于M态 + | + V +OpenSBI 由U-Boot来加载,会从M态跳转至S态 + | + V +Linux 由U-Boot来加载,并运行于S态 +``` + +所有,若直接使用U-Boot单独加载一个zCore Kernel,是没有OpenSBI可print的,效果便是无任何输出,这里定位了问题便着手修复。 + +试验使用u-boot单独运行opensbi,发现并没有常见的“OPENSBI”大LOGO输出,于是尝试修复opensbi的串口,串口驱动缺少了对C910 light板子型号`snps,dw-apb-uart`的解析,于是走的通用串口型号`ns16550`,打上patch:https://github.com/elliott10/opensbi/commit/404951dd5b047873fa023545eafeb1fa2a9c5838 + +编译运行,OpenSBI的输出work! + +### 3. zCore虚拟内存页表问题 + +zCore继续往下运行,便会遇到新的问题,停在切换页表`switch table`之后。 + +这是个很奇怪的问题,正常流程,这里会映射好zCore kernel的所有sections以及其他的内存地址空间,到一个新创建的页表中,映射的参数和过程都是复用的其他板子类型如qemu或D1等的。理论上这里没理由出现BUG,停在的地点如下: + +``` +[ 48.117274 INFO 0 0:0 kernel_hal::imp::arch::vm] initialized kernel page table @ 0x5c18000 +[ 48.128044 DEBUG 0 0:0 kernel_hal::imp::arch::vm] cpu 0 switch table 2ec000 -> 5c18000 +``` + +这个奇怪的问题再次上JTAG调试器,跟踪CPU运行到这里后单步指令的行为。 + +在`switch table`切换页表前下断点,单步跟踪,发现在`csrw satp`之后,程序便跑飞了,触发异常。于是怀疑satp使用的页表有问题。 + +Linux代码是zCore开发中非常好的参照,这里开始对照Linux的切换页表写satp的过程,找到一些参考: + +c910 pagetable + +Linux源码中的riscv架构下,在构建虚拟内存页表项时, + +为内核镜像内存地址空间`PAGE_KERNEL`添加相比普通页表的额外的flags属性:`CACHE`,`SHARE`,`BUF`; + +为设备地址空间`PAGE_IOREMAP`添加额外的属性:`SHARE`,`SO`; + +这些页表项的额外的flags属性位,可以通过查询C910芯片手册获知其定义信息,C910额外页面属性位于`63:59`位,包括了`SO`, `CACHE`, `BUF`, `SHARE`, `SEC` + +更加其他CPU芯片手册,可指导这些平头哥CPU的拓展属性,不单在C910中存在,在C906 CPU中通用存在。 + +![c910 pte flags](img/c910-pte-flags.png) + +zCore中先尝试把内核的`CACHE`,`SHARE`,`BUF`这些位在构建内核页表时置位上,启动发现问题依旧,依然停在切换页表`switch table`之后,原因不详??? + +既然基于RISCV标准进行自定义拓展的位,理论上应该是可以关闭的吧,于是继续在芯片手册中查找,果然在拓展状态寄存器`MXSTATUS`中找到了相应的设置位`MAEE` + +![c910 mxstatus](img/c910-mxstatus.png) + +C910 CPU的MAEE拓展位可以设置是否打开拓展的MMU地址属性,即是否使能`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`。 + +设置`MAEE = 0`时, 不拓展MMU地址属性`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`; + +设置`MAEE = 1`时, 使能拓展MMU中PTE的地址属性`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`,并可以在页表项PTE中设置对应位; + +![c910 mxstatus](img/c910-maee.jpeg) + +于是直接关闭虚拟内存的页表项拓展属性,设置`MAEE = 0`,果然之前停在页表切换处`switch table`的问题通过了。zCore可以继续往下执行开始解析设备树的各node节点,后面接着会遇到设备地址过高,导致在处理解析到的node节点地址时出错... + +### 4. 页表项PTE的拓展属性设置MAEE于CR1825板子的尝试 + +之前一次与DF交流CR1825目前遇到的BUG情况时,一开始有提议说可能内核的`.BSS`段可能未清除干净。 + +因为在去年刚把增加了riscv支持的zCore移植到D1时,也出现过,spin原子指令死锁的问题,这个问题当时请教的JYK童鞋后,给思路原来`.bss`段没clear干净,导致未初始化时的原子变量存在了随机值,持续死锁。 + +c906 clear bsss + + + +不过,这个清除`.bss`段应该是随后就加上了。虽然后来引导启动部分有重构过,DF也确认确有执行`.bss`段清除。 + +我在调试C910的期间,在芯片手册中了解页表属性及其相关的其他寄存器位的同时,也对比C906手册,发现基本两CPU在属性设置方面没有大的区别。 + +在修复好C910 light板子的停在页表切换处`switch table`的问题后,与DF交流并取得cr1825的opensbi, u-boot, Linux等的源代码,主要对比与C910 light板子的启动代码的区别。 + +发现带C906 CPU的cr1825与C910 CPU的light板子的启动代码很相似,包括虚拟内存的构建过程,同样也对内核虚拟内存的页表项配置了拓展位`cache`, `share`, `buf`,而原生zCore从未对这些位进行配置。 + +于是猜想也许页表项PTE的拓展位设置问题,与当前cr1825遇到的原子锁问题有很大的关联,原子操作即是需要对虚拟内存中的某个值进行判断改写。 + +为了验证该猜想,制作了一个cr1825的启动引导镜像`fip.bin`, 方式是直接关闭虚拟内存的页表项拓展属性,设置`MAEE = 0`,代码修改如:https://github.com/elliott10/opensbi/commit/404951dd5b047873fa023545eafeb1fa2a9c5838 + +请DF帮忙远程验证,幸运地原子锁的问题也通过了,的确与平头哥的拓展页表项有关! + +c906 amo 1 + +c906 amo 1 + +之后在群里与YDR等人继续交流关于平头哥拓展位的原理问题,并获得平头哥技术人员的确认: "PTE中cacheable代表该page可以被906 cache缓存,如果为0则不会进入缓存。PTE中bufferable位控制总线传输时的bufferable信号是否拉起,在行为上cpu并不关心";“amo指令需要cache支持,也就是不能在非cache的区域使用amo指令”。 + +cr1825锁卡住的问题通了后,后面进展较顺利了。 + +在打开`maee`的情况下,这里可能需要注意内核镜像和设备地址空间所设置的`PTE`额外属性值不同。 + +根据Linux源码,在构建虚拟内存页表项时, + +为内核镜像内存地址空间`PAGE_KERNEL`添加相比普通页表的额外的flags属性:`CACHE`,`SHARE`,`BUF`; + +为设备地址空间`PAGE_IOREMAP`添加额外的属性:`SHARE`,`SO`; + +### 5. 设备地址过高的问题 + +前面讲到zCore构建好虚拟内存之后,解析设备树的各node节点时,后面接着会遇到设备地址过高的问题,导致在处理解析到的node节点地址时出错。 + +例如从设备树中,取得的串口基地址是`0xffe7014000`,该地址比一般的设备地址大,例如相比Qemu的串口基地址`0x10000000`。C910 light板子的多种设备基地址都类似的这么大。在物理地址空间中这些大的设备地址不会出问题,但在zCore构建好内核虚拟内存后,当统一加上一个`offset`如`0xffffffe000200000`,便溢出了SV39模式的虚拟内存地址空间。 + +对于地址溢出时,对该问题做一个简单的判断处理,把溢出的保留位重新置为`1`即可: + +``` +paddr | (0x1ffffff << 39) +``` + +### 5. C910 light板子运行 + +zCore顺利运行进busybox shell: + +![c910 zcore](img/c910-zcore-run.png) \ No newline at end of file diff --git a/docs/README-D1.md b/docs/README-D1.md index 191dcaf47..c455a8b32 100644 --- a/docs/README-D1.md +++ b/docs/README-D1.md @@ -1,6 +1,7 @@ -# zCore on riscv64 for D1 +# zCore on riscv64 -## 编译 zCore 系统镜像 +## D1开发板 +### 编译 zCore 系统镜像 先在源码根目录下编译 riscv64 的文件系统。 @@ -12,7 +13,7 @@ cd zCore make build LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release ``` -## riscv64 开发板的烧写 +### riscv64 开发板的烧写 以全志 D1 c906 开发板为例。 @@ -59,7 +60,7 @@ make run LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release sudo xfel exec 0x40000000 ``` -## 引导运行 +### 引导运行 zCore 成功引导后, OpenSBI 会将 dtb 加载到高地址 `0x5ff00000`,运行如下所示: diff --git a/docs/img/c906-amo-1.jpg b/docs/img/c906-amo-1.jpg new file mode 100644 index 000000000..a5325d333 Binary files /dev/null and b/docs/img/c906-amo-1.jpg differ diff --git a/docs/img/c906-amo-2.jpg b/docs/img/c906-amo-2.jpg new file mode 100644 index 000000000..622652310 Binary files /dev/null and b/docs/img/c906-amo-2.jpg differ diff --git a/docs/img/c906-clear-bss.jpeg b/docs/img/c906-clear-bss.jpeg new file mode 100644 index 000000000..538444221 Binary files /dev/null and b/docs/img/c906-clear-bss.jpeg differ diff --git a/docs/img/c910-jtag.jpg b/docs/img/c910-jtag.jpg new file mode 100644 index 000000000..0805ed045 Binary files /dev/null and b/docs/img/c910-jtag.jpg differ diff --git a/docs/img/c910-light.jpeg b/docs/img/c910-light.jpeg new file mode 100644 index 000000000..e0fa57152 Binary files /dev/null and b/docs/img/c910-light.jpeg differ diff --git a/docs/img/c910-linux-pg.png b/docs/img/c910-linux-pg.png new file mode 100644 index 000000000..b3225a8e3 Binary files /dev/null and b/docs/img/c910-linux-pg.png differ diff --git a/docs/img/c910-maee.jpeg b/docs/img/c910-maee.jpeg new file mode 100644 index 000000000..4ff3d194e Binary files /dev/null and b/docs/img/c910-maee.jpeg differ diff --git a/docs/img/c910-mxstatus.png b/docs/img/c910-mxstatus.png new file mode 100644 index 000000000..09e10ee51 Binary files /dev/null and b/docs/img/c910-mxstatus.png differ diff --git a/docs/img/c910-pte-flags.png b/docs/img/c910-pte-flags.png new file mode 100644 index 000000000..ffcef9542 Binary files /dev/null and b/docs/img/c910-pte-flags.png differ diff --git a/docs/img/c910-run-uart.png b/docs/img/c910-run-uart.png new file mode 100644 index 000000000..53a80d0e4 Binary files /dev/null and b/docs/img/c910-run-uart.png differ diff --git a/docs/img/c910-zcore-run.png b/docs/img/c910-zcore-run.png new file mode 100644 index 000000000..748e6f5e7 Binary files /dev/null and b/docs/img/c910-zcore-run.png differ diff --git a/kernel-hal/Cargo.toml b/kernel-hal/Cargo.toml index bea489443..e48c087cf 100644 --- a/kernel-hal/Cargo.toml +++ b/kernel-hal/Cargo.toml @@ -24,6 +24,8 @@ loopback = ["zcore-drivers/loopback", "no-pci"] # Enable graphical output graphic = ["zcore-drivers/graphic"] +board-c910light = [] +link-user-img = [] # Enable extra page table falgs for T-Head CPU with MAEE on thead-maee = [] # Disable PCI diff --git a/kernel-hal/src/bare/arch/riscv/drivers.rs b/kernel-hal/src/bare/arch/riscv/drivers.rs index 58805d07c..de804d500 100644 --- a/kernel-hal/src/bare/arch/riscv/drivers.rs +++ b/kernel-hal/src/bare/arch/riscv/drivers.rs @@ -13,7 +13,12 @@ struct IoMapperImpl; impl IoMapper for IoMapperImpl { fn query_or_map(&self, paddr: PhysAddr, size: usize) -> Option { - let vaddr = phys_to_virt(paddr); + let vaddr = if paddr > (1 << 39) { + // To retrieve avaliable sv39 vaddr + paddr | (0x1ffffff << 39) + } else { + phys_to_virt(paddr) + }; let mut pt = super::vm::kernel_page_table().lock(); if let Ok((paddr_mapped, _, _)) = pt.query(vaddr) { if paddr_mapped == paddr { diff --git a/kernel-hal/src/bare/arch/riscv/sbi.rs b/kernel-hal/src/bare/arch/riscv/sbi.rs index e378fa2ce..a0e5d9d35 100644 --- a/kernel-hal/src/bare/arch/riscv/sbi.rs +++ b/kernel-hal/src/bare/arch/riscv/sbi.rs @@ -95,6 +95,30 @@ pub fn hart_stop() -> usize { sbi_call(HSM_EID, SBI_HART_STOP_FID, 0, 0, 0) } +// Just for T-HEAD C910 light +pub const BADDR: u64 = 0xffffffffe7014000; +pub fn uart_put(c: u8) { + let ptr = BADDR as *mut u32; + unsafe { + //LSR bit:THRE + while ptr.add(5).read_volatile() & (1 << 5) == 0 {} + + //此时transmitter empty, THR有效位是8 + ptr.add(0).write_volatile(c as u32); + } +} +pub fn uart_get() -> Option { + let ptr = BADDR as *mut u32; + unsafe { + //查看LSR的DR位为1则有数据 + if ptr.add(5).read_volatile() & 0b1 == 0 { + None + } else { + Some((ptr.add(0).read_volatile() & 0xff) as u8) + } + } +} + hal_fn_impl! { impl mod crate::hal_fn::console { fn console_write_early(s: &str) { diff --git a/kernel-hal/src/bare/arch/riscv/vm.rs b/kernel-hal/src/bare/arch/riscv/vm.rs index 97dd586af..3bb1f0d47 100644 --- a/kernel-hal/src/bare/arch/riscv/vm.rs +++ b/kernel-hal/src/bare/arch/riscv/vm.rs @@ -70,6 +70,18 @@ fn init_kernel_page_table() -> PagingResult { MMUFlags::READ | MMUFlags::WRITE, )?; } + cfg_if! { + if #[cfg(any(feature = "board-fu740", feature = "board-c910light"))] { + extern "C" { + fn boot_stack(); + fn boot_stack_top(); + } + map_range( + boot_stack as usize, + boot_stack_top as usize, + MMUFlags::READ | MMUFlags::WRITE, + )?; + }} // device tree map_range( phys_to_virt(align_down(KCONFIG.dtb_paddr)), @@ -78,6 +90,7 @@ fn init_kernel_page_table() -> PagingResult { )?; // physical frames for r in crate::mem::free_pmem_regions() { + info!("FREE PHY MEM: {:x?}", r); map_range( phys_to_virt(r.start), phys_to_virt(r.end), diff --git a/prebuilt/firmware/riscv/c910_fw_dynamic.bin b/prebuilt/firmware/riscv/c910_fw_dynamic.bin new file mode 100755 index 000000000..b6b55a215 Binary files /dev/null and b/prebuilt/firmware/riscv/c910_fw_dynamic.bin differ diff --git a/zCore/Cargo.toml b/zCore/Cargo.toml index 79647cd60..ea39f7c89 100644 --- a/zCore/Cargo.toml +++ b/zCore/Cargo.toml @@ -53,6 +53,8 @@ libos = [ # Run on Allwinner d1 board-d1 = ["link-user-img", "no-pci", "kernel-hal/allwinner-drivers"] +# T-HEAD C910 Light val board +board-c910light = ["link-user-img", "kernel-hal/board-c910light", "no-pci"] # Run on u740 board-fu740 = ["link-user-img", "kernel-hal/fu740-drivers"] diff --git a/zCore/Makefile b/zCore/Makefile index 25875ce33..456c66ac7 100644 --- a/zCore/Makefile +++ b/zCore/Makefile @@ -102,6 +102,8 @@ else else ifeq ($(PLATFORM), fu740) SMP := 5 features += board-fu740 + else ifeq ($(PLATFORM), c910light) + features += board-c910light link-user-img endif else ifeq ($(ARCH), aarch64) ifeq ($(PLATFORM), raspi4b) @@ -247,6 +249,10 @@ ifeq ($(PLATFORM), fu740) gzip -9 -cvf $(build_path)/zcore.bin > ./zcore.bin.gz mkimage -f ../prebuilt/firmware/riscv/fu740_fdt.its ./zcore-fu740.itb @echo 'Build zcore-fu740.itb FIT-uImage done' +else ifeq ($(PLATFORM), c910light) + mkimage -A riscv -O linux -C none -T kernel -a 0x200000 -e 0x200000 \ + -n "zCore for c910" \ + -d $(build_path)/zcore.bin uImageC910 endif run: build justrun debug: build debugrun diff --git a/zCore/build.rs b/zCore/build.rs new file mode 100644 index 000000000..c07f8f235 --- /dev/null +++ b/zCore/build.rs @@ -0,0 +1,28 @@ +use std::io::Write; + +fn main() { + if std::env::var("TARGET").unwrap().contains("riscv64") { + let board = std::env::var("PLATFORM"); + let kernel_base_addr: u64 = if board.map_or(false, |x| x.contains("c910light")) { + 0xffffffe000200000 + } else { + 0xffffffc080200000 + }; + + let mut fout = std::fs::File::create("src/platform/riscv/kernel-vars.ld").unwrap(); + writeln!(fout, "/* Generated by build.rs. DO NOT EDIT. */").unwrap(); + writeln!( + fout, + "PROVIDE_HIDDEN(BASE_ADDRESS = {:#x});", + kernel_base_addr + ) + .unwrap(); + } + + // 如果需要链接 rootfs 镜像,将镜像路径设置到环境变量 + #[cfg(feature = "link-user-img")] + println!( + "cargo:rustc-env=USER_IMG=zCore/{}.img", + std::env::var("TARGET").unwrap() + ); +} diff --git a/zCore/src/memory.rs b/zCore/src/memory.rs index 83759eaa5..d0de3fd3f 100644 --- a/zCore/src/memory.rs +++ b/zCore/src/memory.rs @@ -32,7 +32,7 @@ const PAGE_BITS: usize = 12; /// | qemu,virt SMP 1 | 16 KiB /// | qemu,virt SMP 4 | 32 KiB /// | allwinner,nezha | 256 KiB -static mut MEMORY: [u8; 256 << 10] = [0u8; 256 << 10]; +static mut MEMORY: [u8; 2 * 1024 * 1024] = [0u8; 2 * 1024 * 1024]; unsafe impl GlobalAlloc for LockedHeap { #[inline] diff --git a/zCore/src/platform/riscv/boot.asm b/zCore/src/platform/riscv/boot.asm new file mode 100644 index 000000000..6519eb556 --- /dev/null +++ b/zCore/src/platform/riscv/boot.asm @@ -0,0 +1,99 @@ +.equ STACK_MAX, 4096 * 16 +.equ STACK_MAX_HARTS, 8 + + .section .text.entry + .globl _start +_start: + #关中断 + csrw sie, zero + csrw sip, zero + + #关闭mmu + #csrw satp, zero + + #BSS节清零 + la t0, sbss + la t1, ebss + bgeu t0, t1, primary_hart + +clear_bss_loop: + # sd: store double word (64 bits) + sd zero, (t0) + addi t0, t0, 8 + bltu t0, t1, clear_bss_loop + +primary_hart: + call init_vm + la t0, primary_rust_main + la t1, PHY_MEM_OFS + ld t1, (t1) + add t0, t0, t1 + jr t0 + +.globl secondary_hart_start +secondary_hart_start: + csrw sie, zero + csrw sip, zero + call init_vm + la t0, secondary_rust_main + la t1, PHY_MEM_OFS + ld t1, (t1) + add t0, t0, t1 + jr t0 + +init_vm: + #获取页表的物理地址 + la t0, boot_page_table_sv39 + + #右移12位,变为satp的PPN + srli t0, t0, 12 + + #satp的MODE设为Sv39 + li t1, 8 << 60 + + #写satp + or t0, t0, t1 + + #刷新TLB + sfence.vma + + csrw satp, t0 + + #此时在虚拟内存空间,设置sp为虚拟地址 + li t0, STACK_MAX + mul t0, t0, a0 + + la t1, boot_stack_top + la t2, PHY_MEM_OFS + ld t2, (t2) + add sp, t1, t2 + + #计算多个核的sp偏移 + sub sp, sp, t0 + ret + + .section .data + .align 12 #12位对齐 +boot_page_table_sv39: + #1G的一个大页: 0x00000000_00000000 --> 0x00000000 + #1G的一个大页: 0x00000000_80000000 --> 0x80000000 + #1G的一个大页: 0xffffffe0_00000000 --> 0x00000000 + #1G的一个大页: 0xffffffe0_80000000 --> 0x80000000 + + .quad (0 << 10) | 0xef + .zero 8 + .quad (0x80000 << 10) | 0xef + + .zero 8 * 381 + .quad (0 << 10) | 0xef + .zero 8 + .quad (0x80000 << 10) | 0xef + .zero 8 * 125 + + .section .bss.stack + .align 12 + .global boot_stack +boot_stack: + .space STACK_MAX * STACK_MAX_HARTS + .global boot_stack_top +boot_stack_top: diff --git a/zCore/src/platform/riscv/entry64.rs b/zCore/src/platform/riscv/entry64.rs new file mode 100644 index 000000000..b05b5e83c --- /dev/null +++ b/zCore/src/platform/riscv/entry64.rs @@ -0,0 +1,106 @@ +global_asm!(include_str!("boot.asm")); + +use core::arch::{asm, global_asm}; +use core::str::FromStr; +use kernel_hal::arch::sbi::{hart_start, send_ipi, SBI_SUCCESS}; +use kernel_hal::KernelConfig; + +#[no_mangle] +pub static PHY_MEM_OFS: usize = consts::KERNEL_BASE - consts::PHYS_MEMORY_BASE; + +pub mod consts { + cfg_if! { + if #[cfg(feature = "board-fu740")] { + pub const KERNEL_BASE: usize = 0xFFFF_FFE0_8000_0000; + pub const PHYS_MEMORY_BASE: usize = 0x8000_0000; + } else if #[cfg(feature = "board-c910light")] { + pub const KERNEL_BASE: usize = 0xffffffe0_00200000; + pub const PHYS_MEMORY_BASE: usize = 0x200000; + } + } + #[allow(dead_code)] + pub const KERNEL_HEAP_SIZE: usize = 80 * 1024 * 1024; + /// Get HART number from the environment variable + pub const SMP: &str = core::env!("SMP"); + + #[inline] + pub fn phys_to_virt_offset() -> usize { + KERNEL_BASE - PHYS_MEMORY_BASE + } +} + +extern "C" { + fn secondary_hart_start(); +} + +#[no_mangle] +pub extern "C" fn primary_rust_main(hartid: usize, device_tree_paddr: usize) -> ! { + unsafe { + asm!("mv tp, {0}", in(reg) hartid); + + let mut sstatus: usize; + asm!("csrr {0}, sstatus", out(reg) sstatus); + sstatus |= 1 << 18; + asm!("csrw sstatus, {0}", in(reg) sstatus); + + println!( + "\nzCore rust_main(hartid: {}, device_tree_paddr: {:#x}) sstatus={:#x}\n", + hartid, device_tree_paddr, sstatus + ); + }; + + println!(" ____"); + println!(" ____/ ___|___ _ __ ___"); + println!("|_ / | / _ \\| '__/ _ \\"); + println!(" / /| |__| (_) | | | __/"); + println!("/___|\\____\\___/|_| \\___|"); + println!(); + + for id in 0..usize::from_str(consts::SMP).expect("can't parse SMP as usize.") { + #[cfg(feature = "board-fu740")] + if id == 0 { + continue; + } + + if id != hartid { + println!("hart{id} is booting"); + let err_code = hart_start( + id, + secondary_hart_start as usize - PHY_MEM_OFS, // cal physical address + 0, + ); + if err_code != SBI_SUCCESS { + panic!("start hart{} failed. error code={}", id, err_code); + } + + let hart_mask: usize = 1 << id; + let err_code = send_ipi(&hart_mask as *const _ as usize); + if err_code != SBI_SUCCESS { + panic!("send ipi to hart{} failed. error code={}", id, err_code); + } + } else { + println!("hart{id} is the primary hart"); + } + } + + let config = KernelConfig { + phys_to_virt_offset: PHY_MEM_OFS, + dtb_paddr: device_tree_paddr, + dtb_size: 2 * 1024 * 1024, + }; + crate::primary_main(config); + unreachable!() +} + +// Don't print in this function and use console_write_early if necessary +#[no_mangle] +pub extern "C" fn secondary_rust_main(hartid: usize) -> ! { + unsafe { + asm!("mv tp, {0}", in(reg) hartid); + let mut sstatus: usize; + asm!("csrr {0}, sstatus", out(reg) sstatus); + sstatus |= 1 << 18; // set SUM=1 + asm!("csrw sstatus, {0}", in(reg) sstatus); + }; + crate::secondary_main(); +} diff --git a/zCore/src/platform/riscv/linker.ld b/zCore/src/platform/riscv/linker.ld index 26bf1dd56..c7ee8b642 100644 --- a/zCore/src/platform/riscv/linker.ld +++ b/zCore/src/platform/riscv/linker.ld @@ -1,8 +1,9 @@ OUTPUT_ARCH(riscv) ENTRY(_start) +INCLUDE zCore/src/platform/riscv/kernel-vars.ld SECTIONS { - . = 0xffffffc080200000; + . = BASE_ADDRESS; start = .; .text : { diff --git a/zCore/src/platform/riscv/mod.rs b/zCore/src/platform/riscv/mod.rs index b4560191b..874879cf5 100644 --- a/zCore/src/platform/riscv/mod.rs +++ b/zCore/src/platform/riscv/mod.rs @@ -1,3 +1,9 @@ +cfg_if! { + if #[cfg(feature = "board-c910light")] { +mod entry64; +pub use entry64::consts; + } else { mod boot_page_table; pub mod consts; mod entry; + }} diff --git a/zCore/zcore-fu740.itb b/zCore/zcore-fu740.itb deleted file mode 100644 index 614139c00..000000000 Binary files a/zCore/zcore-fu740.itb and /dev/null differ diff --git a/zCore/zcore.bin.gz b/zCore/zcore.bin.gz deleted file mode 100644 index d2ee5a04f..000000000 Binary files a/zCore/zcore.bin.gz and /dev/null differ