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 {
/*< private >*/
MachineState parent;

/*< public >*/
RISCVHartArrayState soc[QUARD_STAR_SOCKETS_MAX];
PFlashCFI01 *flash; // FLASH
};

enum {
QUARD_STAR_MROM,
QUARD_STAR_SRAM,
QUARD_STAR_UART0,
QUARD_STAR_FLASH, // 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 }, // 定义flash的起始地址和大小 32M
[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)
{
//创建CPU
quard_star_cpu_create(machine);
// 创建主存
quard_star_memory_create(machine);
// flash
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 // flash

测试

1
2
./build.sh
./run.sh

image-20240602224916448

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
// plic
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;
/* Per-socket PLIC hart topology configuration string */
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);
//每个CPU都需要创建 aclint
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)
{
//创建CPU
quard_star_cpu_create(machine);
// 创建主存
quard_star_memory_create(machine);
// flash
quard_star_flash_create(machine);
// PLIC
quard_star_plic_create(machine);
// clint
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 {
/*< private >*/
MachineState parent;

/*< public >*/
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

image-20240603204507210

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, //定义了串口中断号为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
// BASE SIZE
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
/*UART*/
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 \ #映射monitor


./build.sh
./run.sh

image-20240603224800293