The zero stage boot is the XuanTie processor init code before opensbi. Before zero_stage_boot, SoC vendors must prepare ddr_init and CPU reset procedures. All harts would get into zero_stage_boot together, and the first one would duty to relocate GOT & offset variable, and others wait. Every hart would init its CSRs by their CPUID versions separately, allowing different harts to work together, e.g., 4*c908 + 2*c910. You could compile standard opensbi and Linux kernel binaries from open-source repositories, all compatible with XuanTie processors. Here is the simple boot flow:
[Jtag gdbinit] -> [zero_stage_boot] -> [opensbi] -> [Linux] opensbi: https://github.com/riscv-software-src/opensbi Linux: https://kernel.org/
CROSS_COMPILE=riscv64-unknown-linux-gnu- make
The T-HEAD C9xx DTB provided to OpenSBI generic firmware will usually have "riscv,clint0", "thead,c900-plic", compatible strings.
/dts-v1/;
/ {
model = "Test Sample";
compatible = "test,sample";
#address-cells = <2>;
#size-cells = <2>;
memory@60000000 {
device_type = "memory";
reg = <0x0 0x60000000 0x1 0x00000000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <25000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64ima";
mmu-type = "riscv,sv57";
cpu0_intc: interrupt-controller {
#address-cells = <0>;
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@1 {
device_type = "cpu";
reg = <1>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64ima";
mmu-type = "riscv,sv57";
cpu1_intc: interrupt-controller {
#address-cells = <0>;
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@2 {
device_type = "cpu";
reg = <2>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64ima";
mmu-type = "riscv,sv57";
cpu2_intc: interrupt-controller {
#address-cells = <0>;
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@3 {
device_type = "cpu";
reg = <3>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64ima";
mmu-type = "riscv,sv57";
cpu3_intc: interrupt-controller {
#address-cells = <0>;
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
clint0: clint@c000000 {
compatible = "thead,c900-clint";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
&cpu1_intc 3 &cpu1_intc 7
&cpu2_intc 3 &cpu2_intc 7
&cpu3_intc 3 &cpu3_intc 7
>;
reg = <0x0 0x0c000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@8000000 {
#address-cells = <0>;
#interrupt-cells = <1>;
compatible = "thead,c900-plic";
reg = <0x0 0x08000000 0x0 0x04000000>;
riscv,ndev = <80>;
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
&cpu1_intc 0xffffffff &cpu1_intc 9
&cpu2_intc 0xffffffff &cpu2_intc 9
&cpu3_intc 0xffffffff &cpu3_intc 9
>;
};
};
};
# Set gdb environment set confirm off set height 0 monitor set resume-bkpt-exception on # memory layout set $opensbi_addr = 0x60000000 set $vmlinux_addr = $opensbi_addr + 0x00400000 set $rootfs_addr = $opensbi_addr + 0x04000000 set $dtb_addr = $rootfs_addr - 0x00100000 set $zsb_addr = $rootfs_addr - 0x00008000 set $dyninfo_addr = $rootfs_addr - 0x40 set $flag_addr = $rootfs_addr - 0x100 # Load kernel restore zero_stage_boot.bin binary $zsb_addr restore <preceding dts example>.dtb binary $dtb_addr restore fw_dynamic.bin binary $opensbi_addr restore Image binary $vmlinux_addr # Set opensbi dynamic info param set *(unsigned long *)($dyninfo_addr) = 0x4942534f set *(unsigned long *)($dyninfo_addr + 8) = 2 set *(unsigned long *)($dyninfo_addr + 16) = $vmlinux_addr set *(unsigned long *)($dyninfo_addr + 24) = 1 set *(unsigned long *)($dyninfo_addr + 32) = 0 set *(unsigned long *)($dyninfo_addr + 40) = -1 # Set boot flag for CPU functional setting # BIT[0]: Enable RV64XT32 by setting mxstatus.[63]=1 # set *(unsigned int *)$flag_addr = 0x1 set *(unsigned int *)$flag_addr = 0x0 # Set all harts reset address set *0x18030010 = $zsb_addr set *0x18030018 = $zsb_addr set *0x18030020 = $zsb_addr set *0x18030028 = $zsb_addr set *0x18030030 = $zsb_addr set $pc = $zsb_addr # Release all harts from reset set *0x18030000 = 0x7f
Start Jtag Server with local-semihosting mode(opensbi requirements).
DebugServerConsole -prereset -ls
Then use gdb connect the Jtag Server.
riscv64-elf-gdb -ex "tar remote <Jtag Server ip:port>" -x <your soc gdbinit> -x <preceding cpu gdbinit> -ex "c"
Use ctrl+c to get into the gdb shell.
file vmlinux source gdbmarcos.txt dmesg
gdbmacros.txt:
vmlinux: The Linux kernel ELF file