1.添加flash
这里加的是pflash意为并行flash。
include/quard_star.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 struct QuardStarState { MachineState parent; RISCVHartArrayState soc[QUARD_STAR_SOCKETS_MAX]; PFlashCFI01 *flash; }; enum { QUARD_STAR_MROM, QUARD_STAR_SRAM, QUARD_STAR_UART0, QUARD_STAR_FLASH, QUARD_STAR_DRAM, };
quard_star.c
定义flash的起始地址和大小 32M
1 2 3 4 5 6 7 static const MemMapEntry quard_star_memmap[] = { [QUARD_STAR_MROM] = { 0x0 , 0x8000 }, [QUARD_STAR_SRAM] = { 0x8000 , 0x8000 }, [QUARD_STAR_UART0] = { 0x10000000 , 0x100 }, [QUARD_STAR_FLASH] = { 0x20000000 , 0x2000000 }, [QUARD_STAR_DRAM] = { 0x80000000 , 0x80 }, };
创建pflash,并且映射到系统总线对应的地址上,最后将其关联 到qemu参数 -drive if=pflash, bus = 0, uint = 0
这样启动的时候就可以将固件文件加载到这 这篇flash上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static void quard_star_flash_create (MchineState *machine) { #define QUARD_STAR_FLASH_SECTOR_SIZE (256 * KiB) QuardStarState *s = RISCV_VIRT_MACHINE (machine); MemoryRegion *system_memory = get_system_memory (); DeviceState *dev = qdev_new (TYPE_PFLASH_CFI01); qdev_prop_set_uint64 (dev, "sector-length" , QUARD_STAR_FLASH_SECTOR_SIZE); qdev_prop_set_uint8 (dev, "width" , 4 ); qdev_prop_set_uint8 (dev, "device-width" , 2 ); qdev_prop_set_bit (dev, "big-endian" , false ); qdev_prop_set_uint16 (dev, "id0" , 0x89 ); qdev_prop_set_uint16 (dev, "id1" , 0x18 ); qdev_prop_set_uint16 (dev, "id2" , 0x00 ); qdev_prop_set_uint16 (dev, "id3" , 0x00 ); qdev_prop_set_string (dev, "name" ,"quard-star.flash0" ); object_property_add_child (OBJECT (s), "quard-star.flash0" , OBJECT (dev)); object_property_add_alias (OBJECT (s), "pflash0" , OBJECT (dev), "drive" ); s->flash = PFLASH_CFI01 (dev); pflash_cfi01_legacy_drive (s->flash,drive_get (IF_PFLASH, 0 , 0 )); hwaddr flashsize = quard_star_memmap[QUARD_STAR_FLASH].size; hwaddr flashbase = quard_star_memmap[QUARD_STAR_FLASH].base; assert (QEMU_IS_ALIGNED (flashsize, QUARD_STAR_FLASH_SECTOR_SIZE)); assert (flashsize / QUARD_STAR_FLASH_SECTOR_SIZE <= UINT32_MAX); qdev_prop_set_uint32 (dev, "num-blocks" , flashsize / QUARD_STAR_FLASH_SECTOR_SIZE); sysbus_realize_and_unref (SYS_BUS_DEVICE (dev), &error_fatal); memory_region_add_subregion (system_memory, flashbase, sysbus_mmio_get_region (SYS_BUS_DEVICE (dev), 0 )); }
1 2 3 4 5 6 7 8 9 static void quard_star_machine_init (MachineState *machine) { quard_star_cpu_create(machine); quard_star_memory_create(machine); quard_star_flash_create(machine); }
修改quard_star_setup_rom_reset_vec函数中bootrom的跳转地址为pflash上的地址。
1 2 3 4 5 riscv_setup_rom_reset_vec(machine, &s->soc[0 ], quard_star_memmap[QUARD_STAR_FLASH].base, quard_star_memmap[QUARD_STAR_MROM].base, quard_star_memmap[QUARD_STAR_MROM].size, 0x0 , 0x0 );
Kconfig 新增flash 设备
1 2 3 4 config QUARD_STAR bool select SERIAL select PFLASH_CFI01
测试
2.中断控制器 串口使用需要使用到中断,后续的一些外设也有需求 这里使用 sifive
quard_star.c 增加基址
riscv的中断分为两个部分,为内核中断CLINT(Core Local Interrupt)和外设中断控制器Platform-Level Interrupt Controller(PLIC)
plic 和 clint 基址的增加 以及相应发分配大小
1 2 3 4 5 6 7 8 9 static const MemMapEntry quard_star_memmap[] = { [QUARD_STAR_MROM] = { 0x0 , 0x8000 }, [QUARD_STAR_SRAM] = { 0x8000 , 0x8000 }, [QUARD_STAR_CLINT] = { 0x02000000 , 0x10000 }, [QUARD_STAR_PLIC] = { 0x0C000000 , 0x4000000 }, [QUARD_STAR_UART0] = { 0x10000000 , 0x100 }, [QUARD_STAR_FLASH] = { 0x20000000 , 0x2000000 }, [QUARD_STAR_DRAM] = { 0x80000000 , 0x80 }, };
分别新建CLINT 和 PLIC 创建函数, plic 在循环中遍历所有的socket , 每个socket需要配置独立的PLIC来管理中断请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 static void quard_star_plic_create (MachineState *machine) { int socket_count = riscv_socket_count(machine); QuardStarState *s = RISCV_VIRT_MACHINE(machine); int i,hart_count,base_hartid; for ( i = 0 ; i < socket_count; i++) { hart_count = riscv_socket_hart_count(machine, i); base_hartid = riscv_socket_first_hartid(machine, i); char *plic_hart_config; plic_hart_config = riscv_plic_hart_config_string(machine->smp.cpus); s->plic[i] = sifive_plic_create( quard_star_memmap[QUARD_STAR_PLIC].base + i *quard_star_memmap[QUARD_STAR_PLIC].size , plic_hart_config, hart_count , base_hartid, QUARD_STAR_PLIC_NUM_SOURCES, QUARD_STAR_PLIC_NUM_PRIORITIES, QUARD_STAR_PLIC_PRIORITY_BASE, QUARD_STAR_PLIC_PENDING_BASE, QUARD_STAR_PLIC_ENABLE_BASE, QUARD_STAR_PLIC_ENABLE_STRIDE, QUARD_STAR_PLIC_CONTEXT_BASE, QUARD_STAR_PLIC_CONTEXT_STRIDE, quard_star_memmap[QUARD_STAR_PLIC].size); g_free(plic_hart_config); } }
这也同理 每个CPU 都需要独立的clint来处理中断请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static void quard_star_aclint_create (MachineState *machine) { int i , hart_count,base_hartid; int socket_count = riscv_socket_count(machine); for ( i = 0 ; i < socket_count; i++) { base_hartid = riscv_socket_first_hartid(machine, i); hart_count = riscv_socket_hart_count(machine, i); riscv_aclint_swi_create( quard_star_memmap[QUARD_STAR_CLINT].base + i *quard_star_memmap[QUARD_STAR_CLINT].size, base_hartid, hart_count, false ); riscv_aclint_mtimer_create(quard_star_memmap[QUARD_STAR_CLINT].base + + i *quard_star_memmap[QUARD_STAR_CLINT].size+ RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 static void quard_star_machine_init (MachineState *machine) { quard_star_cpu_create(machine); quard_star_memory_create(machine); quard_star_flash_create(machine); quard_star_plic_create(machine); quard_star_aclint_create(machine); }
include/quard_star.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 struct QuardStarState { MachineState parent; RISCVHartArrayState soc[QUARD_STAR_SOCKETS_MAX]; PFlashCFI01 *flash; DeviceState *plic[QUARD_STAR_SOCKETS_MAX]; }; enum { QUARD_STAR_MROM, QUARD_STAR_SRAM, QUARD_STAR_CLINT, QUARD_STAR_PLIC, QUARD_STAR_UART0, QUARD_STAR_FLASH, QUARD_STAR_DRAM, }; #define QUARD_STAR_PLIC_NUM_SOURCES 127 #define QUARD_STAR_PLIC_NUM_PRIORITIES 7 #define QUARD_STAR_PLIC_PRIORITY_BASE 0x04 #define QUARD_STAR_PLIC_PENDING_BASE 0x1000 #define QUARD_STAR_PLIC_ENABLE_BASE 0x2000 #define QUARD_STAR_PLIC_ENABLE_STRIDE 0x80 #define QUARD_STAR_PLIC_CONTEXT_BASE 0x200000 #define QUARD_STAR_PLIC_CONTEXT_STRIDE 0x1000
Kconfig
select RISCV_APLIC
RISCV_APLIC :通常表示支持 RISC-V 规范中定义的高级平台级中断控制器(Advanced Platform-Level Interrupt Controller)。APLIC 是 RISC-V 的一种更通用或高级的中断控制器实现,可能包含一些标准功能,用于在多个 RISC-V 实现中使用。
select SIFIVE_PLIC
SIFIVE_PLIC :特指 SiFive 公司的 PLIC 实现。SiFive 是一家专注于 RISC-V 处理器设计的公司,他们的 PLIC 可能有一些特定于他们硬件的功能或优化。选择这个配置选项表示启用 SiFive PLIC 的支持。
1 2 3 4 5 6 7 config QUARD_STAR bool select SERIAL select PFLASH_CFI01 select RISCV_ACLINT select RISCV_APLIC select SIFIVE_PLIC
./build.sh
./run.sh
3.添加串口支持 需要一些串口打印 进行调试
include/quard_star.h
枚举类型加上 串口信息 和 RTC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 enum { QUARD_STAR_MROM, QUARD_STAR_SRAM, QUARD_STAR_CLINT, QUARD_STAR_PLIC, QUARD_STAR_UART0, QUARD_STAR_UART1, QUARD_STAR_UART2, QUARD_STAR_RTC, QUARD_STAR_FLASH, QUARD_STAR_DRAM, }; enum { QUARD_STAR_UART0_IRQ = 10 , QUARD_STAR_UART1_IRQ = 11 , QUARD_STAR_UART2_IRQ = 12 , QUARD_STAR_RTC_IRQ = 13 , };
hw/quard_star.c
配置基址以及大小
1 2 3 4 5 6 7 8 9 10 11 12 13 static const MemMapEntry quard_star_memmap[] = { [QUARD_STAR_MROM] = { 0x0 , 0x8000 }, [QUARD_STAR_SRAM] = { 0x8000 , 0x8000 }, [QUARD_STAR_CLINT] = { 0x02000000 , 0x10000 }, [QUARD_STAR_PLIC] = { 0x0C000000 , 0x4000000 }, [QUARD_STAR_UART0] = { 0x10000000 , 0x100 }, [QUARD_STAR_UART1] = { 0x10001000 , 0x100 }, [QUARD_STAR_UART2] = { 0x10002000 , 0x100 }, [QUARD_STAR_RTC] = { 0x10003000 , 0x1000 }, [QUARD_STAR_FLASH] = { 0x20000000 , 0x2000000 }, [QUARD_STAR_DRAM] = { 0x80000000 , 0x80 }, };
配置RTC 以及 UART
1 2 3 4 5 6 static void quard_star_rtc_create (MachineState *machine) { QuardStarState *s = RISCV_VIRT_MACHINE(machine); sysbus_create_simple("goldfish_rtc" , quard_star_memmap[QUARD_STAR_RTC].base, qdev_get_gpio_in(DEVICE(s->plic[0 ]), QUARD_STAR_RTC_IRQ)); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static void quard_star_serial_create (MachineState *machine) { MemoryRegion *system_memory = get_system_memory(); QuardStarState *s = RISCV_VIRT_MACHINE(machine); serial_mm_init(system_memory, quard_star_memmap[QUARD_STAR_UART0].base, 0 , qdev_get_gpio_in(DEVICE(s->plic[0 ]), QUARD_STAR_UART0_IRQ), 399193 , serial_hd(0 ), DEVICE_LITTLE_ENDIAN); serial_mm_init(system_memory, quard_star_memmap[QUARD_STAR_UART1].base, 0 , qdev_get_gpio_in(DEVICE(s->plic[0 ]), QUARD_STAR_UART1_IRQ), 399193 , serial_hd(1 ), DEVICE_LITTLE_ENDIAN); serial_mm_init(system_memory, quard_star_memmap[QUARD_STAR_UART2].base, 0 , qdev_get_gpio_in(DEVICE(s->plic[0 ]), QUARD_STAR_UART2_IRQ), 399193 , serial_hd(2 ), DEVICE_LITTLE_ENDIAN); }
初始化各种配置 init
1 2 quard_star_rtc_create(machine); quard_star_serial_create(machine);
Kconfig
1 2 3 4 5 6 7 8 config QUARD_STAR bool select SERIAL select PFLASH_CFI01 select RISCV_ACLINT select RISCV_APLIC select SIFIVE_PLIC select GOLDFISH_RTC
测试
修改run.sh 映射monitor到控制台
1 2 3 4 5 6 7 8 9 10 11 12 SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) $ SHELL_FOLDER/output/qemu/bin/qemu-system-riscv64 \ -M quard-star \ -m 1G \ -smp 8 \ -bios none \ -monitor stdio \ ./build.sh ./run.sh