├── src
├── opensbi
│ └── nemu
│ │ └── nemu
│ │ ├── configs
│ │ └── defconfig
│ │ ├── fdt
│ │ ├── nemu.dtb
│ │ └── nemu.dts
│ │ ├── Kconfig
│ │ ├── objects.mk
│ │ └── platform.c
└── linux
│ ├── nemu-uart.c
│ └── nemu_tinyconf.config
├── attachments
├── 20250215_19h10m54s_grim.png
├── 20250215_19h25m26s_grim.png
└── Pasted image 20250215230008.png
├── README.md
├── .github
└── workflows
│ └── jekyll-gh-pages.yml
└── boot-Linux-on-NEMU.md
/src/opensbi/nemu/nemu/configs/defconfig:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/opensbi/nemu/nemu/fdt/nemu.dtb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Seeker0472/ysyx-linux/HEAD/src/opensbi/nemu/nemu/fdt/nemu.dtb
--------------------------------------------------------------------------------
/attachments/20250215_19h10m54s_grim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Seeker0472/ysyx-linux/HEAD/attachments/20250215_19h10m54s_grim.png
--------------------------------------------------------------------------------
/attachments/20250215_19h25m26s_grim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Seeker0472/ysyx-linux/HEAD/attachments/20250215_19h25m26s_grim.png
--------------------------------------------------------------------------------
/attachments/Pasted image 20250215230008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Seeker0472/ysyx-linux/HEAD/attachments/Pasted image 20250215230008.png
--------------------------------------------------------------------------------
/src/opensbi/nemu/nemu/Kconfig:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: BSD-2-Clause
2 |
3 | #
4 | # All mandatory drivers or libraries for this platform should
5 | # be directly selected by the PLATFORM_xyz kconfig symbol.
6 | #
7 | # All optional drivers or libraries for this platform should
8 | # be enabled via configs/defconfig of this platform.
9 | #
10 | config PLATFORM_TEMPLATE
11 | bool
12 | select FDT
13 | select IPI_MSWI
14 | select IRQCHIP_PLIC
15 | select SERIAL_UART8250
16 | select TIMER_MTIMER
17 | default y
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 在NEMU上启动Linux Kernel
2 |
3 | 详情参考[`Seeker的笔记`](./boot-Linux-on-NEMU.md)(NEMU for rv32ima\_zicsr\_zifencei)
4 |
5 | 网页版[`Github Pages`](https://seeker0472.github.io/ysyx-linux/boot-Linux-on-NEMU.html)
6 |
7 | 双周分享会[`bilibili`](https://www.bilibili.com/video/BV14tASeUEYn/)
8 |
9 | [](https://creativecommons.org/licenses/by-sa/4.0/)
10 | [](https://opensource.org/licenses/MIT)
11 |
12 |
--------------------------------------------------------------------------------
/src/opensbi/nemu/nemu/fdt/nemu.dts:
--------------------------------------------------------------------------------
1 | /dts-v1/;
2 |
3 | / {
4 | #address-cells = <1>;
5 | #size-cells = <1>;
6 |
7 | compatible = "seeker_nemu";
8 | chosen {
9 | bootargs = "earlycon=sbi console=ttyNEMU0 init=/init";
10 | };
11 |
12 | cpus {
13 | #address-cells = <1>;
14 | #size-cells = <0>;
15 | timebase-frequency = <1000000>;
16 | cpu@0 {
17 | clock-frequency = <0>;
18 | compatible = "riscv";
19 | device_type = "cpu";
20 | status = "okay";
21 | reg = <0>;
22 | riscv,isa = "rv32ima";
23 | cpu0_intc: interrupt-controller {
24 | #interrupt-cells = <1>;
25 | compatible = "riscv,cpu-intc";
26 | interrupt-controller;
27 | };
28 | };
29 | };
30 |
31 | plic0: interrupt-controller@C000000 {
32 | #address-cells = <0>;
33 | #interrupt-cells = <1>;
34 | compatible = "riscv,plic0";
35 | interrupt-controller;
36 | interrupts-extended =
37 | <&cpu0_intc 11 &cpu0_intc 9>;
38 | riscv,ndev = <32>; // 支持的最大设备中断号+1(至少覆盖你的UART中断号)
39 |
40 | reg = <0xc000000 0x4000000>;
41 | };
42 |
43 | uart: uart@a00003f8 {
44 | compatible = "seeker,nemu_uart";
45 | reg = <0xa00003f8 0x1>;
46 | interrupts = <1>; // 使用PLIC中断源1(可自定义,但需<=riscv,ndev-1)
47 | interrupt-parent = <&plic0>; // 关联到PLIC
48 | status = "okay";
49 | };
50 |
51 | memory@80000000 {
52 | device_type = "memory";
53 | reg = <0x80000000 0x20000000>;
54 | };
55 |
56 | };
57 |
--------------------------------------------------------------------------------
/.github/workflows/jekyll-gh-pages.yml:
--------------------------------------------------------------------------------
1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages
2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled
3 |
4 | on:
5 | # Runs on pushes targeting the default branch
6 | push:
7 | branches: ["master"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20 | concurrency:
21 | group: "pages"
22 | cancel-in-progress: false
23 |
24 | jobs:
25 | # Build job
26 | build:
27 | runs-on: ubuntu-latest
28 | steps:
29 | - name: Checkout
30 | uses: actions/checkout@v4
31 | - name: Setup Pages
32 | uses: actions/configure-pages@v5
33 | - name: Build with Jekyll
34 | uses: actions/jekyll-build-pages@v1
35 | with:
36 | source: ./
37 | destination: ./_site
38 | - name: Upload artifact
39 | uses: actions/upload-pages-artifact@v3
40 |
41 | # Deployment job
42 | deploy:
43 | environment:
44 | name: github-pages
45 | url: ${{ steps.deployment.outputs.page_url }}
46 | runs-on: ubuntu-latest
47 | needs: build
48 | steps:
49 | - name: Deploy to GitHub Pages
50 | id: deployment
51 | uses: actions/deploy-pages@v4
52 |
--------------------------------------------------------------------------------
/src/opensbi/nemu/nemu/objects.mk:
--------------------------------------------------------------------------------
1 | #
2 | # SPDX-License-Identifier: BSD-2-Clause
3 | #
4 | # Copyright (c) 2019 Western Digital Corporation or its affiliates.
5 | #
6 |
7 | # Compiler pre-processor flags
8 | platform-cppflags-y =
9 |
10 | # C Compiler and assembler flags.
11 | platform-cflags-y =
12 | platform-asflags-y =
13 |
14 | # Linker flags: additional libraries and object files that the platform
15 | # code needs can be added here
16 | platform-ldflags-y =
17 |
18 | #
19 | # Command for platform specific "make run"
20 | # Useful for development and debugging on plaftform simulator (such as QEMU)
21 | #
22 | # platform-runcmd = your_platform_run.sh
23 |
24 | #
25 | # Platform RISC-V XLEN, ABI, ISA and Code Model configuration.
26 | # These are optional parameters but platforms can optionaly provide it.
27 | # Some of these are guessed based on GCC compiler capabilities
28 |
29 | PLATFORM_RISCV_XLEN = 32
30 | PLATFORM_RISCV_ABI = ilp32
31 | PLATFORM_RISCV_ISA = rv32ima_zicsr_zifencei
32 | PLATFORM_RISCV_CODE_MODEL = medany
33 |
34 | # Space separated list of object file names to be compiled for the platform
35 | platform-objs-y += platform.o
36 |
37 | #
38 | # If the platform support requires a builtin device tree file, the name of
39 | # the device tree compiled file should be specified here. The device tree
40 | # source file be in the form
.dts
41 | #
42 | # platform-objs-y += .o
43 |
44 | # Optional parameter for path to external FDT
45 | FW_FDT_PATH=${NEMU_HOME}/../linux/opensbi/platform/nemu/fdt/nemu.dtb
46 |
47 | #
48 | # Dynamic firmware configuration.
49 | # Optional parameters are commented out. Uncomment and define these parameters
50 | # as needed.
51 | #
52 | FW_DYNAMIC=n
53 |
54 | #
55 | # Jump firmware configuration.
56 | # Optional parameters are commented out. Uncomment and define these parameters
57 | # as needed.
58 | #
59 | FW_JUMP=n
60 | FW_TEXT_START=0x80000000
61 | FW_JUMP_ADDR=0x80800000
62 |
63 | #
64 | # Firmware with payload configuration.
65 | # Optional parameters are commented out. Uncomment and define these parameters
66 | # as needed.
67 | #
68 | FW_PAYLOAD=y
69 | # This needs to be 4MB aligned for 32-bit support
70 | # This needs to be 2MB aligned for 64-bit support
71 | FW_PAYLOAD_ALIGN=0x1000
72 | FW_PAYLOAD_OFFSET=0x400000
73 | FW_PAYLOAD_PATH=${NEMU_HOME}/../linux/linux515/arch/riscv/boot/Image
74 | FW_PAYLOAD_FDT_ADDR=0x82200000
75 | FW_PAYLOAD_ALIGN=0x1000
76 | #FW_PAYLOAD_FDT_OFFSET=0x400000
77 | #
78 | # You can use fixed address for payload firmware as an alternative option.
79 | # SBI will prefer "FW_PAYLOAD_FDT_ADDR" if both "FW_PAYLOAD_FDT_OFFSET"
80 | # and "FW_PAYLOAD_FDT_ADDR" are defined.
81 | # FW_PAYLOAD_FDT_ADDR=0x80200000
82 |
--------------------------------------------------------------------------------
/src/opensbi/nemu/nemu/platform.c:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: BSD-2-Clause
3 | *
4 | * Copyright (c) 2019 Western Digital Corporation or its affiliates.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 |
17 | /*
18 | * Include these files as needed.
19 | * See objects.mk PLATFORM_xxx configuration parameters.
20 | */
21 | /*
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #define PLATFORM_PLIC_ADDR 0xc000000
28 | #define PLATFORM_PLIC_SIZE (0x200000 + \
29 | (PLATFORM_HART_COUNT * 0x1000))
30 | #define PLATFORM_PLIC_NUM_SOURCES 128
31 | #define PLATFORM_HART_COUNT 4
32 | #define PLATFORM_CLINT_ADDR 0x2000000
33 | #define PLATFORM_ACLINT_MTIMER_FREQ 10000000
34 | #define PLATFORM_ACLINT_MSWI_ADDR (PLATFORM_CLINT_ADDR + \
35 | CLINT_MSWI_OFFSET)
36 | #define PLATFORM_ACLINT_MTIMER_ADDR (PLATFORM_CLINT_ADDR + \
37 | CLINT_MTIMER_OFFSET)
38 | #define PLATFORM_UART_ADDR 0x09000000
39 | #define PLATFORM_UART_INPUT_FREQ 10000000
40 | #define PLATFORM_UART_BAUDRATE 115200
41 |
42 |
43 | static struct plic_data plic = {
44 | .addr = PLATFORM_PLIC_ADDR,
45 | .size = PLATFORM_PLIC_SIZE,
46 | .num_src = PLATFORM_PLIC_NUM_SOURCES,
47 | .context_map = {
48 | [0] = { 0, 1 },
49 | [1] = { 2, 3 },
50 | [2] = { 4, 5 },
51 | [3] = { 6, 7 },
52 | },
53 | };
54 |
55 | static struct aclint_mswi_data mswi = {
56 | .addr = PLATFORM_ACLINT_MSWI_ADDR,
57 | .size = ACLINT_MSWI_SIZE,
58 | .first_hartid = 0,
59 | .hart_count = PLATFORM_HART_COUNT,
60 | };
61 |
62 | static struct aclint_mtimer_data mtimer = {
63 | .mtime_freq = PLATFORM_ACLINT_MTIMER_FREQ,
64 | .mtime_addr = PLATFORM_ACLINT_MTIMER_ADDR +
65 | ACLINT_DEFAULT_MTIME_OFFSET,
66 | .mtime_size = ACLINT_DEFAULT_MTIME_SIZE,
67 | .mtimecmp_addr = PLATFORM_ACLINT_MTIMER_ADDR +
68 | ACLINT_DEFAULT_MTIMECMP_OFFSET,
69 | .mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE,
70 | .first_hartid = 0,
71 | .hart_count = PLATFORM_HART_COUNT,
72 | .has_64bit_mmio = true,
73 | };
74 | */
75 |
76 | static int uart_getch(void)
77 | {
78 | return -1;
79 | }
80 | static void uart_putch(char ch)
81 | {
82 | char *serial_base = (char *)0xa0000000 + 0x00003f8;
83 | *serial_base = ch;
84 | }
85 |
86 | static struct sbi_console_device my_uart = { .name = "nemu_uart",
87 | .console_putc = uart_putch,
88 | .console_getc = uart_getch };
89 |
90 | /*
91 | * Platform early initialization.
92 | */
93 | static int platform_early_init(bool cold_boot)
94 | {
95 | if (!cold_boot)
96 | return 0;
97 |
98 | sbi_console_set_device(&my_uart);
99 | return sbi_domain_root_add_memrange(0x10000000, PAGE_SIZE, PAGE_SIZE,
100 | (SBI_DOMAIN_MEMREGION_MMIO |
101 | SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
102 | return 0;
103 | }
104 |
105 | /*
106 | * Platform final initialization.
107 | */
108 | static int platform_final_init(bool cold_boot)
109 | {
110 | //void *fdt;
111 |
112 | if (!cold_boot)
113 | return 0;
114 |
115 | //fdt = fdt_get_address_rw();
116 |
117 | //fdt_cpu_fixup(fdt);
118 | //fdt_fixups(fdt);
119 |
120 | return 0;
121 | return 0;
122 | }
123 |
124 | /*
125 | * Initialize the platform interrupt controller during cold boot.
126 | */
127 | static int platform_irqchip_init(void)
128 | {
129 | /* Example if the generic PLIC driver is used */
130 | //return plic_cold_irqchip_init(&plic);
131 | return 0;
132 | }
133 |
134 | /*
135 | * Initialize IPI during cold boot.
136 | */
137 | static int platform_ipi_init(void)
138 | {
139 | /* Example if the generic ACLINT driver is used */
140 | //return aclint_mswi_cold_init(&mswi);
141 | return 0;
142 | }
143 |
144 | /*
145 | * Initialize platform timer during cold boot.
146 | */
147 | static int platform_timer_init(void)
148 | {
149 | /* Example if the generic ACLINT driver is used */
150 | //return aclint_mtimer_cold_init(&mtimer, NULL);
151 | return 0;
152 | }
153 |
154 | /*
155 | * Platform descriptor.
156 | */
157 | const struct sbi_platform_operations platform_ops = {
158 | .early_init = platform_early_init,
159 | .final_init = platform_final_init,
160 | .irqchip_init = platform_irqchip_init,
161 | .ipi_init = platform_ipi_init,
162 | .timer_init = platform_timer_init
163 | };
164 | const struct sbi_platform platform = {
165 | .opensbi_version = OPENSBI_VERSION,
166 | .platform_version = SBI_PLATFORM_VERSION(0x0, 0x00),
167 | .name = "nemu",
168 | .features = SBI_PLATFORM_DEFAULT_FEATURES,
169 | .hart_count = 1,
170 | .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
171 | .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1),
172 | .platform_ops_addr = (unsigned long)&platform_ops
173 | };
174 |
--------------------------------------------------------------------------------
/src/linux/nemu-uart.c:
--------------------------------------------------------------------------------
1 | #include "linux/serial_core.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 |
12 | #define DRIVER_NAME "nemu_uart"
13 | //null functions
14 | static int nemu_uart_startup(struct uart_port *port);
15 |
16 | static void nemu_uart_set_termios(struct uart_port *port, struct ktermios *new,
17 | struct ktermios *old)
18 | {
19 | printk("NEMU_uart_set_termios!");
20 | }
21 | static void nemu_uart_stop_rx(struct uart_port *port)
22 | {
23 | printk("NEMU_uart_stop_rx!");
24 | }
25 | static void nemu_uart_stop_tx(struct uart_port *port)
26 | {
27 | printk("NEMU_uart_stop_tx!");
28 | }
29 | static void nemu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
30 | {
31 | printk("NEMU_uart_set_mctrl");
32 | }
33 |
34 | static const char *nemu_uart_type(struct uart_port *port);
35 | static void nemu_uart_start_tx(struct uart_port *port);
36 | static unsigned int nemu_uart_tx_empty(struct uart_port *port);
37 | static unsigned int nemu_uart_get_mctrl(struct uart_port *port);
38 | static int nemu_uart_probe(struct platform_device *pdev);
39 | static int nemu_uart_remove(struct platform_device *pdev);
40 | static int __init nemu_uart_init(void);
41 | static void __exit nemu_uart_exit(void);
42 |
43 | static void nemu_uart_console_write(struct console *co, const char *s,
44 | unsigned int count);
45 | static int nemu_uart_console_setup(struct console *co, char *options);
46 |
47 | static irqreturn_t nemu_uart_irq(int irq, void *dev_id);
48 |
49 | static struct uart_driver nemu_uart_driver;
50 |
51 | // for console
52 | static struct console nemu_uart_console = {
53 | .name = "ttyNEMU",
54 | .write = nemu_uart_console_write,
55 | .device = uart_console_device,
56 | .setup = nemu_uart_console_setup,
57 | .flags = CON_PRINTBUFFER, // 允许输出内核启动日志
58 | .index = -1, // auto delegate
59 | .data = &nemu_uart_driver,
60 | };
61 |
62 | static const struct uart_ops nemu_uart_ops = {
63 | .tx_empty = nemu_uart_tx_empty,
64 | .set_mctrl = nemu_uart_set_mctrl,
65 | .get_mctrl = nemu_uart_get_mctrl,
66 | .start_tx = nemu_uart_start_tx,
67 | .stop_tx = nemu_uart_stop_tx,
68 | .stop_rx = nemu_uart_stop_rx,
69 | .startup = nemu_uart_startup,
70 | .set_termios = nemu_uart_set_termios,
71 | .type = nemu_uart_type,
72 | };
73 |
74 | static struct uart_driver nemu_uart_driver = {
75 | .owner = THIS_MODULE,
76 | .driver_name = DRIVER_NAME,
77 | .dev_name = "ttyNEMU",
78 | .major = 0,
79 | .minor = 64,
80 | .nr = 1,
81 | .cons = &nemu_uart_console,
82 | .state = NULL,
83 | };
84 |
85 | static struct uart_port nemu_uart_port = {
86 | .membase = (void __iomem *)0xa00003f8,
87 | .mapbase = 0xa00003f8,
88 | .irq = 0, // IRQ number
89 | .uartclk = 0, // clock rate
90 | .fifosize = 16, // FIFO size
91 | .iotype = UPIO_MEM,
92 | .line = 0,
93 | .type = 123,
94 | .ops = &nemu_uart_ops,
95 | };
96 |
97 | static const struct of_device_id nemu_uart_of_match[] = {
98 | { .compatible = "seeker,nemu_uart" },
99 | {},
100 | };
101 | MODULE_DEVICE_TABLE(of, nemu_uart_of_match);
102 |
103 | static struct platform_driver nemu_uart_platform_driver = {
104 | .probe = nemu_uart_probe,
105 | .remove = nemu_uart_remove,
106 | .driver = {
107 | .name = DRIVER_NAME,
108 | .of_match_table = nemu_uart_of_match,
109 | },
110 | };
111 | static int nemu_uart_startup(struct uart_port *port)
112 | {
113 | printk("NEMU_uart_startup,registering irq_handlers...");
114 | int ret = request_irq(port->irq, nemu_uart_irq,
115 | IRQF_TRIGGER_RISING, "nemu_uart",
116 | port);
117 | if (ret){
118 | printk("register_irq_ERROR!");
119 | return ret;
120 | }
121 | return 0;
122 | }
123 | static irqreturn_t nemu_uart_irq(int irq, void *dev_id)
124 | {
125 | //TODO:handles the intr
126 | //printk("nemu_uart_irq was called!");
127 | struct uart_port *port = dev_id;
128 | char ch = readb(port->membase);
129 | tty_insert_flip_char(&port->state->port,ch,TTY_NORMAL);
130 | tty_flip_buffer_push(&port->state->port);
131 | return IRQ_HANDLED;
132 | }
133 |
134 | static const char *nemu_uart_type(struct uart_port *port)
135 | {
136 | return DRIVER_NAME;
137 | }
138 |
139 | static void nemu_uart_putchar(struct uart_port *port, int ch)
140 | {
141 | writeb(ch, port->membase);
142 | }
143 |
144 | static void nemu_uart_start_tx(struct uart_port *port)
145 | {
146 | struct circ_buf *xmit = &port->state->xmit;
147 |
148 | while (!uart_circ_empty(xmit)) {
149 | char ch = xmit->buf[xmit->tail];
150 | nemu_uart_putchar(port, ch);
151 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
152 | port->icount.tx++;
153 | }
154 | uart_write_wakeup(port);
155 | }
156 |
157 | static unsigned int nemu_uart_tx_empty(struct uart_port *port)
158 | {
159 | // tx-fifo always empty!
160 | return TIOCSER_TEMT;
161 | }
162 |
163 | static unsigned int nemu_uart_get_mctrl(struct uart_port *port)
164 | {
165 | // according to linux's low-level api,
166 | // If the port does not support CTS, DCD or DSR,
167 | // the driver should indicate that the signal is permanently active.
168 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
169 | }
170 |
171 | static int nemu_uart_probe(struct platform_device *pdev)
172 | {
173 | int ret;
174 | struct resource *res;
175 |
176 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
177 | if (!res) {
178 | dev_err(&pdev->dev, "No memory resource\n");
179 | return -ENODEV;
180 | }
181 |
182 | nemu_uart_port.mapbase = res->start;
183 | nemu_uart_port.membase = devm_ioremap_resource(&pdev->dev, res);
184 | if (IS_ERR(nemu_uart_port.membase)) {
185 | dev_err(&pdev->dev, "Failed to ioremap UART memory\n");
186 | return PTR_ERR(nemu_uart_port.membase);
187 | }
188 |
189 | nemu_uart_port.irq = platform_get_irq(pdev, 0);
190 | if (nemu_uart_port.irq <= 0) {
191 | dev_err(&pdev->dev, "No IRQ resource\n");
192 | return -ENODEV;
193 | }
194 |
195 | if (!nemu_uart_driver.state) {
196 | pr_debug("NEMU_uart: calling uart_register_driver()\n");
197 | ret = uart_register_driver(&nemu_uart_driver);
198 | if (ret < 0) {
199 | pr_err("NEMU_Failed to register UART driver\n");
200 | return ret;
201 | }
202 | }
203 | nemu_uart_port.dev = &pdev->dev;
204 | spin_lock_init(&(nemu_uart_port.lock));
205 |
206 | ret = uart_add_one_port(&nemu_uart_driver, &nemu_uart_port);
207 | if (ret) {
208 | dev_err(&pdev->dev, "Failed to add UART port\n");
209 | return ret;
210 | }
211 |
212 | return 0;
213 | }
214 |
215 | static int nemu_uart_remove(struct platform_device *pdev)
216 | {
217 | struct uart_port *port = platform_get_drvdata(pdev);
218 | uart_remove_one_port(&nemu_uart_driver, port);
219 | return 0;
220 | }
221 |
222 | static int __init nemu_uart_init(void)
223 | {
224 | int ret;
225 |
226 | pr_debug("NEMU_uart: calling platform_driver_register()\n");
227 | ret = platform_driver_register(&nemu_uart_platform_driver);
228 | if (ret) {
229 | pr_err("Failed to register platform driver\n");
230 | }
231 | return 0;
232 | }
233 |
234 | static void __exit nemu_uart_exit(void)
235 | {
236 | platform_driver_unregister(&nemu_uart_platform_driver);
237 | uart_unregister_driver(&nemu_uart_driver);
238 | }
239 | static void nemu_uart_console_write(struct console *co, const char *s,
240 | unsigned int count)
241 | {
242 | struct uart_port *port = &nemu_uart_port;
243 | // the function performs a character by character write, translating newlines to CRLF sequences.
244 | // turnning '\n' -> '\n\r' ?
245 | uart_console_write(port, s, count, nemu_uart_putchar);
246 | uart_write_wakeup(port);
247 | }
248 |
249 | static int nemu_uart_console_setup(struct console *co, char *options)
250 | {
251 | printk("calling nemu_console_setup!");
252 | return 0;
253 | }
254 |
255 | module_init(nemu_uart_init);
256 | module_exit(nemu_uart_exit);
257 |
258 | MODULE_LICENSE("GPL");
259 | MODULE_AUTHOR("Seeker");
260 | MODULE_DESCRIPTION("NEMU UART Driver");
261 |
--------------------------------------------------------------------------------
/src/linux/nemu_tinyconf.config:
--------------------------------------------------------------------------------
1 | #
2 | # Automatically generated file; DO NOT EDIT.
3 | # Linux/riscv 5.15.178 Kernel Configuration
4 | #
5 | CONFIG_CC_VERSION_TEXT="riscv64-unknown-linux-gnu-gcc (GCC) 13.2.0"
6 | CONFIG_CC_IS_GCC=y
7 | CONFIG_GCC_VERSION=130200
8 | CONFIG_CLANG_VERSION=0
9 | CONFIG_AS_IS_GNU=y
10 | CONFIG_AS_VERSION=24100
11 | CONFIG_LD_IS_BFD=y
12 | CONFIG_LD_VERSION=24100
13 | CONFIG_LLD_VERSION=0
14 | CONFIG_CC_CAN_LINK=y
15 | CONFIG_CC_HAS_ASM_GOTO=y
16 | CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
17 | CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
18 | CONFIG_CC_HAS_ASM_INLINE=y
19 | CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
20 | CONFIG_PAHOLE_VERSION=0
21 | CONFIG_IRQ_WORK=y
22 | CONFIG_BUILDTIME_TABLE_SORT=y
23 | CONFIG_THREAD_INFO_IN_TASK=y
24 |
25 | #
26 | # General setup
27 | #
28 | CONFIG_BROKEN_ON_SMP=y
29 | CONFIG_INIT_ENV_ARG_LIMIT=32
30 | # CONFIG_COMPILE_TEST is not set
31 | # CONFIG_WERROR is not set
32 | CONFIG_LOCALVERSION=""
33 | # CONFIG_LOCALVERSION_AUTO is not set
34 | CONFIG_BUILD_SALT=""
35 | CONFIG_DEFAULT_INIT=""
36 | CONFIG_DEFAULT_HOSTNAME="(none)"
37 | # CONFIG_SYSVIPC is not set
38 | # CONFIG_WATCH_QUEUE is not set
39 | CONFIG_CROSS_MEMORY_ATTACH=y
40 | # CONFIG_USELIB is not set
41 | CONFIG_HAVE_ARCH_AUDITSYSCALL=y
42 |
43 | #
44 | # IRQ subsystem
45 | #
46 | CONFIG_GENERIC_IRQ_SHOW=y
47 | CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
48 | CONFIG_IRQ_DOMAIN=y
49 | CONFIG_IRQ_DOMAIN_HIERARCHY=y
50 | CONFIG_HANDLE_DOMAIN_IRQ=y
51 | CONFIG_IRQ_FORCED_THREADING=y
52 | CONFIG_SPARSE_IRQ=y
53 | # end of IRQ subsystem
54 |
55 | CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
56 | CONFIG_ARCH_CLOCKSOURCE_INIT=y
57 | CONFIG_GENERIC_CLOCKEVENTS=y
58 |
59 | #
60 | # Timers subsystem
61 | #
62 | CONFIG_HZ_PERIODIC=y
63 | # CONFIG_NO_HZ_IDLE is not set
64 | # CONFIG_NO_HZ is not set
65 | # CONFIG_HIGH_RES_TIMERS is not set
66 | # end of Timers subsystem
67 |
68 | CONFIG_HAVE_EBPF_JIT=y
69 |
70 | #
71 | # BPF subsystem
72 | #
73 | # CONFIG_BPF_SYSCALL is not set
74 | # end of BPF subsystem
75 |
76 | CONFIG_PREEMPT_NONE=y
77 | # CONFIG_PREEMPT_VOLUNTARY is not set
78 | # CONFIG_PREEMPT is not set
79 |
80 | #
81 | # CPU/Task time and stats accounting
82 | #
83 | CONFIG_TICK_CPU_ACCOUNTING=y
84 | # CONFIG_IRQ_TIME_ACCOUNTING is not set
85 | # CONFIG_PSI is not set
86 | # end of CPU/Task time and stats accounting
87 |
88 | #
89 | # RCU Subsystem
90 | #
91 | CONFIG_TINY_RCU=y
92 | # CONFIG_RCU_EXPERT is not set
93 | CONFIG_SRCU=y
94 | CONFIG_TINY_SRCU=y
95 | # end of RCU Subsystem
96 |
97 | # CONFIG_IKCONFIG is not set
98 | CONFIG_LOG_BUF_SHIFT=17
99 | CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
100 | CONFIG_GENERIC_SCHED_CLOCK=y
101 |
102 | #
103 | # Scheduler features
104 | #
105 | # end of Scheduler features
106 |
107 | # CONFIG_CGROUPS is not set
108 | # CONFIG_CHECKPOINT_RESTORE is not set
109 | # CONFIG_SCHED_AUTOGROUP is not set
110 | # CONFIG_RELAY is not set
111 | CONFIG_BLK_DEV_INITRD=y
112 | CONFIG_INITRAMFS_SOURCE="/home/seeker/Develop/ysyx-workbench/linux/initramfs.cpio.gz"
113 | CONFIG_INITRAMFS_ROOT_UID=0
114 | CONFIG_INITRAMFS_ROOT_GID=0
115 | CONFIG_RD_GZIP=y
116 | CONFIG_RD_BZIP2=y
117 | CONFIG_RD_LZMA=y
118 | CONFIG_RD_XZ=y
119 | CONFIG_RD_LZO=y
120 | CONFIG_RD_LZ4=y
121 | CONFIG_RD_ZSTD=y
122 | CONFIG_INITRAMFS_COMPRESSION_GZIP=y
123 | # CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
124 | # CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
125 | # CONFIG_INITRAMFS_COMPRESSION_XZ is not set
126 | # CONFIG_INITRAMFS_COMPRESSION_LZO is not set
127 | # CONFIG_INITRAMFS_COMPRESSION_LZ4 is not set
128 | # CONFIG_INITRAMFS_COMPRESSION_ZSTD is not set
129 | # CONFIG_INITRAMFS_COMPRESSION_NONE is not set
130 | # CONFIG_BOOT_CONFIG is not set
131 | # CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
132 | CONFIG_CC_OPTIMIZE_FOR_SIZE=y
133 | CONFIG_SYSCTL_EXCEPTION_TRACE=y
134 | CONFIG_EXPERT=y
135 | # CONFIG_MULTIUSER is not set
136 | # CONFIG_SGETMASK_SYSCALL is not set
137 | # CONFIG_SYSFS_SYSCALL is not set
138 | # CONFIG_FHANDLE is not set
139 | # CONFIG_POSIX_TIMERS is not set
140 | CONFIG_PRINTK=y
141 | # CONFIG_BUG is not set
142 | # CONFIG_BASE_FULL is not set
143 | # CONFIG_FUTEX is not set
144 | # CONFIG_EPOLL is not set
145 | # CONFIG_SIGNALFD is not set
146 | # CONFIG_TIMERFD is not set
147 | # CONFIG_EVENTFD is not set
148 | CONFIG_SHMEM=y
149 | # CONFIG_AIO is not set
150 | # CONFIG_IO_URING is not set
151 | # CONFIG_ADVISE_SYSCALLS is not set
152 | # CONFIG_MEMBARRIER is not set
153 | # CONFIG_KALLSYMS is not set
154 | # CONFIG_USERFAULTFD is not set
155 | # CONFIG_KCMP is not set
156 | CONFIG_EMBEDDED=y
157 | CONFIG_HAVE_PERF_EVENTS=y
158 | # CONFIG_PC104 is not set
159 |
160 | #
161 | # Kernel Performance Events And Counters
162 | #
163 | # CONFIG_PERF_EVENTS is not set
164 | # end of Kernel Performance Events And Counters
165 |
166 | # CONFIG_VM_EVENT_COUNTERS is not set
167 | # CONFIG_COMPAT_BRK is not set
168 | # CONFIG_SLAB is not set
169 | # CONFIG_SLUB is not set
170 | CONFIG_SLOB=y
171 | # CONFIG_SLAB_MERGE_DEFAULT is not set
172 | # CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
173 | # CONFIG_PROFILING is not set
174 | # end of General setup
175 |
176 | CONFIG_32BIT=y
177 | CONFIG_RISCV=y
178 | CONFIG_ARCH_MMAP_RND_BITS_MIN=8
179 | CONFIG_ARCH_MMAP_RND_BITS_MAX=17
180 | CONFIG_RISCV_SBI=y
181 | CONFIG_MMU=y
182 | CONFIG_VA_BITS=32
183 | CONFIG_PA_BITS=34
184 | CONFIG_PAGE_OFFSET=0xC0000000
185 | CONFIG_ARCH_FLATMEM_ENABLE=y
186 | CONFIG_ARCH_SPARSEMEM_ENABLE=y
187 | CONFIG_ARCH_SELECT_MEMORY_MODEL=y
188 | CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
189 | CONFIG_ARCH_SUPPORTS_UPROBES=y
190 | CONFIG_STACKTRACE_SUPPORT=y
191 | CONFIG_GENERIC_CALIBRATE_DELAY=y
192 | CONFIG_GENERIC_CSUM=y
193 | CONFIG_GENERIC_HWEIGHT=y
194 | CONFIG_FIX_EARLYCON_MEM=y
195 | CONFIG_ILLEGAL_POINTER_VALUE=0
196 | CONFIG_PGTABLE_LEVELS=2
197 | CONFIG_LOCKDEP_SUPPORT=y
198 |
199 | #
200 | # SoC selection
201 | #
202 | # CONFIG_SOC_MICROCHIP_POLARFIRE is not set
203 | # CONFIG_SOC_SIFIVE is not set
204 | # CONFIG_SOC_VIRT is not set
205 | # end of SoC selection
206 |
207 | #
208 | # CPU errata selection
209 | #
210 | # CONFIG_RISCV_ERRATA_ALTERNATIVE is not set
211 | # end of CPU errata selection
212 |
213 | #
214 | # Platform type
215 | #
216 | CONFIG_ARCH_RV32I=y
217 | # CONFIG_ARCH_RV64I is not set
218 | # CONFIG_CMODEL_MEDLOW is not set
219 | CONFIG_CMODEL_MEDANY=y
220 | # CONFIG_SMP is not set
221 | CONFIG_TUNE_GENERIC=y
222 | # CONFIG_RISCV_ISA_C is not set
223 | CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y
224 | # CONFIG_FPU is not set
225 | # end of Platform type
226 |
227 | #
228 | # Kernel features
229 | #
230 | # CONFIG_HZ_100 is not set
231 | CONFIG_HZ_250=y
232 | # CONFIG_HZ_300 is not set
233 | # CONFIG_HZ_1000 is not set
234 | CONFIG_HZ=250
235 | CONFIG_RISCV_SBI_V01=y
236 | # CONFIG_KEXEC is not set
237 | # CONFIG_CRASH_DUMP is not set
238 | # end of Kernel features
239 |
240 | #
241 | # Boot options
242 | #
243 | CONFIG_CMDLINE=""
244 | # CONFIG_EFI is not set
245 | CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y
246 | # CONFIG_PHYS_RAM_BASE_FIXED is not set
247 | # end of Boot options
248 |
249 | #
250 | # Power management options
251 | #
252 | # CONFIG_PM is not set
253 | # end of Power management options
254 |
255 | CONFIG_CPU_MITIGATIONS=y
256 |
257 | #
258 | # General architecture-dependent options
259 | #
260 | # CONFIG_JUMP_LABEL is not set
261 | CONFIG_HAVE_KPROBES=y
262 | CONFIG_HAVE_KRETPROBES=y
263 | CONFIG_HAVE_KPROBES_ON_FTRACE=y
264 | CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
265 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y
266 | CONFIG_HAVE_ARCH_TRACEHOOK=y
267 | CONFIG_HAVE_DMA_CONTIGUOUS=y
268 | CONFIG_GENERIC_SMP_IDLE_THREAD=y
269 | CONFIG_GENERIC_IDLE_POLL_SETUP=y
270 | CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
271 | CONFIG_ARCH_HAS_SET_MEMORY=y
272 | CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
273 | CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
274 | CONFIG_HAVE_ASM_MODVERSIONS=y
275 | CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
276 | CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
277 | CONFIG_HAVE_PERF_REGS=y
278 | CONFIG_HAVE_PERF_USER_STACK_DUMP=y
279 | CONFIG_HAVE_ARCH_JUMP_LABEL=y
280 | CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
281 | CONFIG_HAVE_ARCH_SECCOMP=y
282 | CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
283 | # CONFIG_SECCOMP is not set
284 | CONFIG_HAVE_STACKPROTECTOR=y
285 | # CONFIG_STACKPROTECTOR is not set
286 | CONFIG_LTO_NONE=y
287 | CONFIG_HAVE_CONTEXT_TRACKING=y
288 | CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
289 | CONFIG_HAVE_MOVE_PUD=y
290 | CONFIG_HAVE_MOVE_PMD=y
291 | CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
292 | CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
293 | CONFIG_ARCH_MMAP_RND_BITS=8
294 | CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
295 | CONFIG_CLONE_BACKWARDS=y
296 | # CONFIG_COMPAT_32BIT_TIME is not set
297 | CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
298 | CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
299 | CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
300 | CONFIG_STRICT_KERNEL_RWX=y
301 | CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
302 | CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
303 |
304 | #
305 | # GCOV-based kernel profiling
306 | #
307 | CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
308 | # end of GCOV-based kernel profiling
309 |
310 | CONFIG_HAVE_GCC_PLUGINS=y
311 | # CONFIG_GCC_PLUGINS is not set
312 | CONFIG_FUNCTION_ALIGNMENT=0
313 | # end of General architecture-dependent options
314 |
315 | CONFIG_BASE_SMALL=1
316 | # CONFIG_MODULES is not set
317 | # CONFIG_BLOCK is not set
318 | CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
319 | CONFIG_INLINE_READ_UNLOCK=y
320 | CONFIG_INLINE_READ_UNLOCK_IRQ=y
321 | CONFIG_INLINE_WRITE_UNLOCK=y
322 | CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
323 | CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
324 | CONFIG_ARCH_HAS_MMIOWB=y
325 | CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
326 |
327 | #
328 | # Executable file formats
329 | #
330 | CONFIG_BINFMT_ELF=y
331 | CONFIG_ELFCORE=y
332 | CONFIG_BINFMT_SCRIPT=y
333 | CONFIG_ARCH_HAS_BINFMT_FLAT=y
334 | # CONFIG_BINFMT_FLAT is not set
335 | # CONFIG_BINFMT_MISC is not set
336 | # CONFIG_COREDUMP is not set
337 | # end of Executable file formats
338 |
339 | #
340 | # Memory Management options
341 | #
342 | CONFIG_SELECT_MEMORY_MODEL=y
343 | CONFIG_FLATMEM_MANUAL=y
344 | # CONFIG_SPARSEMEM_MANUAL is not set
345 | CONFIG_FLATMEM=y
346 | CONFIG_SPLIT_PTLOCK_CPUS=4
347 | CONFIG_COMPACTION=y
348 | # CONFIG_PAGE_REPORTING is not set
349 | CONFIG_MIGRATION=y
350 | # CONFIG_KSM is not set
351 | CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
352 | CONFIG_NEED_PER_CPU_KM=y
353 | # CONFIG_CLEANCACHE is not set
354 | # CONFIG_CMA is not set
355 | # CONFIG_ZPOOL is not set
356 | # CONFIG_ZSMALLOC is not set
357 | CONFIG_GENERIC_EARLY_IOREMAP=y
358 | # CONFIG_PERCPU_STATS is not set
359 |
360 | #
361 | # GUP_TEST needs to have DEBUG_FS enabled
362 | #
363 | CONFIG_ARCH_HAS_PTE_SPECIAL=y
364 |
365 | #
366 | # Data Access Monitoring
367 | #
368 | # CONFIG_DAMON is not set
369 | # end of Data Access Monitoring
370 | # end of Memory Management options
371 |
372 | # CONFIG_NET is not set
373 |
374 | #
375 | # Device Drivers
376 | #
377 | CONFIG_HAVE_PCI=y
378 | # CONFIG_PCI is not set
379 | # CONFIG_PCCARD is not set
380 |
381 | #
382 | # Generic Driver Options
383 | #
384 | # CONFIG_UEVENT_HELPER is not set
385 | # CONFIG_DEVTMPFS is not set
386 | # CONFIG_STANDALONE is not set
387 | # CONFIG_PREVENT_FIRMWARE_BUILD is not set
388 |
389 | #
390 | # Firmware loader
391 | #
392 | # CONFIG_FW_LOADER is not set
393 | # end of Firmware loader
394 |
395 | # CONFIG_ALLOW_DEV_COREDUMP is not set
396 | # CONFIG_DEBUG_DRIVER is not set
397 | # CONFIG_DEBUG_DEVRES is not set
398 | # CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
399 | CONFIG_GENERIC_ARCH_TOPOLOGY=y
400 | # end of Generic Driver Options
401 |
402 | #
403 | # Bus devices
404 | #
405 | # CONFIG_MHI_BUS is not set
406 | # end of Bus devices
407 |
408 | #
409 | # Firmware Drivers
410 | #
411 |
412 | #
413 | # ARM System Control and Management Interface Protocol
414 | #
415 | # end of ARM System Control and Management Interface Protocol
416 |
417 | # CONFIG_FIRMWARE_MEMMAP is not set
418 | # CONFIG_GOOGLE_FIRMWARE is not set
419 |
420 | #
421 | # Tegra firmware driver
422 | #
423 | # end of Tegra firmware driver
424 | # end of Firmware Drivers
425 |
426 | # CONFIG_GNSS is not set
427 | # CONFIG_MTD is not set
428 | CONFIG_DTC=y
429 | CONFIG_OF=y
430 | # CONFIG_OF_UNITTEST is not set
431 | CONFIG_OF_FLATTREE=y
432 | CONFIG_OF_EARLY_FLATTREE=y
433 | CONFIG_OF_ADDRESS=y
434 | CONFIG_OF_IRQ=y
435 | CONFIG_OF_RESERVED_MEM=y
436 | # CONFIG_OF_OVERLAY is not set
437 | # CONFIG_PARPORT is not set
438 |
439 | #
440 | # NVME Support
441 | #
442 | # end of NVME Support
443 |
444 | #
445 | # Misc devices
446 | #
447 | # CONFIG_DUMMY_IRQ is not set
448 | # CONFIG_ENCLOSURE_SERVICES is not set
449 | # CONFIG_SRAM is not set
450 | # CONFIG_XILINX_SDFEC is not set
451 | # CONFIG_C2PORT is not set
452 |
453 | #
454 | # EEPROM support
455 | #
456 | # CONFIG_EEPROM_93CX6 is not set
457 | # end of EEPROM support
458 |
459 | #
460 | # Texas Instruments shared transport line discipline
461 | #
462 | # end of Texas Instruments shared transport line discipline
463 |
464 | #
465 | # Altera FPGA firmware download module (requires I2C)
466 | #
467 | # CONFIG_ECHO is not set
468 | # CONFIG_PVPANIC is not set
469 | # end of Misc devices
470 |
471 | #
472 | # SCSI device support
473 | #
474 | CONFIG_SCSI_MOD=y
475 | # end of SCSI device support
476 |
477 | #
478 | # Input device support
479 | #
480 | CONFIG_INPUT=y
481 | # CONFIG_INPUT_FF_MEMLESS is not set
482 | # CONFIG_INPUT_SPARSEKMAP is not set
483 | # CONFIG_INPUT_MATRIXKMAP is not set
484 |
485 | #
486 | # Userland interfaces
487 | #
488 | # CONFIG_INPUT_MOUSEDEV is not set
489 | # CONFIG_INPUT_JOYDEV is not set
490 | # CONFIG_INPUT_EVDEV is not set
491 | # CONFIG_INPUT_EVBUG is not set
492 |
493 | #
494 | # Input Device Drivers
495 | #
496 | CONFIG_INPUT_KEYBOARD=y
497 | CONFIG_KEYBOARD_ATKBD=y
498 | # CONFIG_KEYBOARD_LKKBD is not set
499 | # CONFIG_KEYBOARD_NEWTON is not set
500 | # CONFIG_KEYBOARD_OPENCORES is not set
501 | # CONFIG_KEYBOARD_SAMSUNG is not set
502 | # CONFIG_KEYBOARD_STOWAWAY is not set
503 | # CONFIG_KEYBOARD_SUNKBD is not set
504 | # CONFIG_KEYBOARD_OMAP4 is not set
505 | # CONFIG_KEYBOARD_XTKBD is not set
506 | # CONFIG_KEYBOARD_BCM is not set
507 | CONFIG_INPUT_MOUSE=y
508 | CONFIG_MOUSE_PS2=y
509 | CONFIG_MOUSE_PS2_ALPS=y
510 | CONFIG_MOUSE_PS2_BYD=y
511 | CONFIG_MOUSE_PS2_LOGIPS2PP=y
512 | CONFIG_MOUSE_PS2_SYNAPTICS=y
513 | CONFIG_MOUSE_PS2_CYPRESS=y
514 | CONFIG_MOUSE_PS2_TRACKPOINT=y
515 | # CONFIG_MOUSE_PS2_ELANTECH is not set
516 | # CONFIG_MOUSE_PS2_SENTELIC is not set
517 | # CONFIG_MOUSE_PS2_TOUCHKIT is not set
518 | CONFIG_MOUSE_PS2_FOCALTECH=y
519 | # CONFIG_MOUSE_SERIAL is not set
520 | # CONFIG_MOUSE_VSXXXAA is not set
521 | # CONFIG_INPUT_JOYSTICK is not set
522 | # CONFIG_INPUT_TABLET is not set
523 | # CONFIG_INPUT_TOUCHSCREEN is not set
524 | # CONFIG_INPUT_MISC is not set
525 | # CONFIG_RMI4_CORE is not set
526 |
527 | #
528 | # Hardware I/O ports
529 | #
530 | CONFIG_SERIO=y
531 | CONFIG_SERIO_SERPORT=y
532 | CONFIG_SERIO_LIBPS2=y
533 | # CONFIG_SERIO_RAW is not set
534 | # CONFIG_SERIO_ALTERA_PS2 is not set
535 | # CONFIG_SERIO_PS2MULT is not set
536 | # CONFIG_SERIO_ARC_PS2 is not set
537 | # CONFIG_SERIO_APBPS2 is not set
538 | # CONFIG_USERIO is not set
539 | # CONFIG_GAMEPORT is not set
540 | # end of Hardware I/O ports
541 | # end of Input device support
542 |
543 | #
544 | # Character devices
545 | #
546 | CONFIG_TTY=y
547 | CONFIG_VT=y
548 | CONFIG_CONSOLE_TRANSLATIONS=y
549 | CONFIG_VT_CONSOLE=y
550 | CONFIG_HW_CONSOLE=y
551 | # CONFIG_VT_HW_CONSOLE_BINDING is not set
552 | CONFIG_UNIX98_PTYS=y
553 | CONFIG_LEGACY_PTYS=y
554 | CONFIG_LEGACY_PTY_COUNT=256
555 | CONFIG_LDISC_AUTOLOAD=y
556 |
557 | #
558 | # Serial drivers
559 | #
560 | CONFIG_SERIAL_EARLYCON=y
561 | # CONFIG_SERIAL_8250 is not set
562 |
563 | #
564 | # Non-8250 serial port support
565 | #
566 | CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
567 | CONFIG_NEMU_UART=y
568 | # CONFIG_SERIAL_UARTLITE is not set
569 | CONFIG_SERIAL_CORE=y
570 | CONFIG_SERIAL_CORE_CONSOLE=y
571 | # CONFIG_SERIAL_SIFIVE is not set
572 | # CONFIG_SERIAL_SCCNXP is not set
573 | # CONFIG_SERIAL_BCM63XX is not set
574 | # CONFIG_SERIAL_ALTERA_JTAGUART is not set
575 | # CONFIG_SERIAL_ALTERA_UART is not set
576 | # CONFIG_SERIAL_XILINX_PS_UART is not set
577 | # CONFIG_SERIAL_ARC is not set
578 | # CONFIG_SERIAL_FSL_LPUART is not set
579 | # CONFIG_SERIAL_FSL_LINFLEXUART is not set
580 | # CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
581 | # CONFIG_SERIAL_SPRD is not set
582 | # end of Serial drivers
583 |
584 | # CONFIG_SERIAL_NONSTANDARD is not set
585 | # CONFIG_NULL_TTY is not set
586 | # CONFIG_HVC_RISCV_SBI is not set
587 | # CONFIG_SERIAL_DEV_BUS is not set
588 | # CONFIG_TTY_PRINTK is not set
589 | # CONFIG_VIRTIO_CONSOLE is not set
590 | # CONFIG_IPMI_HANDLER is not set
591 | # CONFIG_HW_RANDOM is not set
592 | # CONFIG_DEVMEM is not set
593 | # CONFIG_TCG_TPM is not set
594 | # CONFIG_XILLYBUS is not set
595 | # CONFIG_RANDOM_TRUST_BOOTLOADER is not set
596 | # end of Character devices
597 |
598 | #
599 | # I2C support
600 | #
601 | # CONFIG_I2C is not set
602 | # end of I2C support
603 |
604 | # CONFIG_I3C is not set
605 | # CONFIG_SPI is not set
606 | # CONFIG_SPMI is not set
607 | # CONFIG_HSI is not set
608 | # CONFIG_PPS is not set
609 |
610 | #
611 | # PTP clock support
612 | #
613 | CONFIG_PTP_1588_CLOCK_OPTIONAL=y
614 |
615 | #
616 | # Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
617 | #
618 | # end of PTP clock support
619 |
620 | # CONFIG_PINCTRL is not set
621 | # CONFIG_GPIOLIB is not set
622 | # CONFIG_W1 is not set
623 | # CONFIG_POWER_RESET is not set
624 | # CONFIG_POWER_SUPPLY is not set
625 | # CONFIG_HWMON is not set
626 | # CONFIG_THERMAL is not set
627 | # CONFIG_WATCHDOG is not set
628 | CONFIG_SSB_POSSIBLE=y
629 | # CONFIG_SSB is not set
630 | CONFIG_BCMA_POSSIBLE=y
631 | # CONFIG_BCMA is not set
632 |
633 | #
634 | # Multifunction device drivers
635 | #
636 | # CONFIG_MFD_ATMEL_FLEXCOM is not set
637 | # CONFIG_MFD_ATMEL_HLCDC is not set
638 | # CONFIG_MFD_MADERA is not set
639 | # CONFIG_MFD_HI6421_PMIC is not set
640 | # CONFIG_HTC_PASIC3 is not set
641 | # CONFIG_MFD_KEMPLD is not set
642 | # CONFIG_MFD_MT6397 is not set
643 | # CONFIG_MFD_SM501 is not set
644 | # CONFIG_MFD_SYSCON is not set
645 | # CONFIG_MFD_TQMX86 is not set
646 | # end of Multifunction device drivers
647 |
648 | # CONFIG_REGULATOR is not set
649 | # CONFIG_RC_CORE is not set
650 | # CONFIG_MEDIA_CEC_SUPPORT is not set
651 | # CONFIG_MEDIA_SUPPORT is not set
652 |
653 | #
654 | # Graphics support
655 | #
656 | # CONFIG_DRM is not set
657 |
658 | #
659 | # ARM devices
660 | #
661 | # end of ARM devices
662 |
663 | #
664 | # Frame buffer Devices
665 | #
666 | # CONFIG_FB is not set
667 | # end of Frame buffer Devices
668 |
669 | #
670 | # Backlight & LCD device support
671 | #
672 | # CONFIG_LCD_CLASS_DEVICE is not set
673 | # CONFIG_BACKLIGHT_CLASS_DEVICE is not set
674 | # end of Backlight & LCD device support
675 |
676 | #
677 | # Console display driver support
678 | #
679 | CONFIG_VGA_CONSOLE=y
680 | CONFIG_DUMMY_CONSOLE=y
681 | CONFIG_DUMMY_CONSOLE_COLUMNS=80
682 | CONFIG_DUMMY_CONSOLE_ROWS=25
683 | # end of Console display driver support
684 | # end of Graphics support
685 |
686 | # CONFIG_SOUND is not set
687 |
688 | #
689 | # HID support
690 | #
691 | CONFIG_HID=y
692 | # CONFIG_HID_BATTERY_STRENGTH is not set
693 | # CONFIG_HIDRAW is not set
694 | # CONFIG_UHID is not set
695 | CONFIG_HID_GENERIC=y
696 |
697 | #
698 | # Special HID drivers
699 | #
700 | # CONFIG_HID_A4TECH is not set
701 | # CONFIG_HID_ACRUX is not set
702 | # CONFIG_HID_APPLE is not set
703 | # CONFIG_HID_AUREAL is not set
704 | # CONFIG_HID_BELKIN is not set
705 | # CONFIG_HID_CHERRY is not set
706 | # CONFIG_HID_COUGAR is not set
707 | # CONFIG_HID_MACALLY is not set
708 | # CONFIG_HID_CMEDIA is not set
709 | # CONFIG_HID_CYPRESS is not set
710 | # CONFIG_HID_DRAGONRISE is not set
711 | # CONFIG_HID_EMS_FF is not set
712 | # CONFIG_HID_ELECOM is not set
713 | # CONFIG_HID_EZKEY is not set
714 | # CONFIG_HID_GEMBIRD is not set
715 | # CONFIG_HID_GFRM is not set
716 | # CONFIG_HID_GLORIOUS is not set
717 | # CONFIG_HID_VIVALDI is not set
718 | # CONFIG_HID_KEYTOUCH is not set
719 | # CONFIG_HID_KYE is not set
720 | # CONFIG_HID_WALTOP is not set
721 | # CONFIG_HID_VIEWSONIC is not set
722 | # CONFIG_HID_GYRATION is not set
723 | # CONFIG_HID_ICADE is not set
724 | # CONFIG_HID_ITE is not set
725 | # CONFIG_HID_JABRA is not set
726 | # CONFIG_HID_TWINHAN is not set
727 | # CONFIG_HID_KENSINGTON is not set
728 | # CONFIG_HID_LCPOWER is not set
729 | # CONFIG_HID_LENOVO is not set
730 | # CONFIG_HID_MAGICMOUSE is not set
731 | # CONFIG_HID_MALTRON is not set
732 | # CONFIG_HID_MAYFLASH is not set
733 | # CONFIG_HID_REDRAGON is not set
734 | # CONFIG_HID_MICROSOFT is not set
735 | # CONFIG_HID_MONTEREY is not set
736 | # CONFIG_HID_MULTITOUCH is not set
737 | # CONFIG_HID_NTI is not set
738 | # CONFIG_HID_ORTEK is not set
739 | # CONFIG_HID_PANTHERLORD is not set
740 | # CONFIG_HID_PETALYNX is not set
741 | # CONFIG_HID_PICOLCD is not set
742 | # CONFIG_HID_PLANTRONICS is not set
743 | # CONFIG_HID_PLAYSTATION is not set
744 | # CONFIG_HID_PRIMAX is not set
745 | # CONFIG_HID_SAITEK is not set
746 | # CONFIG_HID_SEMITEK is not set
747 | # CONFIG_HID_SPEEDLINK is not set
748 | # CONFIG_HID_STEAM is not set
749 | # CONFIG_HID_STEELSERIES is not set
750 | # CONFIG_HID_SUNPLUS is not set
751 | # CONFIG_HID_RMI is not set
752 | # CONFIG_HID_GREENASIA is not set
753 | # CONFIG_HID_SMARTJOYPLUS is not set
754 | # CONFIG_HID_TIVO is not set
755 | # CONFIG_HID_TOPSEED is not set
756 | # CONFIG_HID_UDRAW_PS3 is not set
757 | # CONFIG_HID_XINMO is not set
758 | # CONFIG_HID_ZEROPLUS is not set
759 | # CONFIG_HID_ZYDACRON is not set
760 | # CONFIG_HID_SENSOR_HUB is not set
761 | # CONFIG_HID_ALPS is not set
762 | # end of Special HID drivers
763 | # end of HID support
764 |
765 | CONFIG_USB_OHCI_LITTLE_ENDIAN=y
766 | # CONFIG_USB_SUPPORT is not set
767 | # CONFIG_MMC is not set
768 | # CONFIG_MEMSTICK is not set
769 | # CONFIG_NEW_LEDS is not set
770 | # CONFIG_ACCESSIBILITY is not set
771 | CONFIG_EDAC_SUPPORT=y
772 | # CONFIG_RTC_CLASS is not set
773 | # CONFIG_DMADEVICES is not set
774 |
775 | #
776 | # DMABUF options
777 | #
778 | # CONFIG_SYNC_FILE is not set
779 | # CONFIG_DMABUF_HEAPS is not set
780 | # end of DMABUF options
781 |
782 | # CONFIG_AUXDISPLAY is not set
783 | # CONFIG_UIO is not set
784 | # CONFIG_VFIO is not set
785 | # CONFIG_VIRT_DRIVERS is not set
786 | # CONFIG_VIRTIO_MENU is not set
787 | # CONFIG_VHOST_MENU is not set
788 |
789 | #
790 | # Microsoft Hyper-V guest support
791 | #
792 | # end of Microsoft Hyper-V guest support
793 |
794 | # CONFIG_COMEDI is not set
795 | # CONFIG_STAGING is not set
796 | # CONFIG_GOLDFISH is not set
797 | CONFIG_HAVE_CLK=y
798 | CONFIG_HAVE_CLK_PREPARE=y
799 | CONFIG_COMMON_CLK=y
800 |
801 | #
802 | # Clock driver for ARM Reference designs
803 | #
804 | # CONFIG_ICST is not set
805 | # CONFIG_CLK_SP810 is not set
806 | # end of Clock driver for ARM Reference designs
807 |
808 | # CONFIG_COMMON_CLK_AXI_CLKGEN is not set
809 | # CONFIG_COMMON_CLK_FIXED_MMIO is not set
810 | # CONFIG_CLK_SIFIVE is not set
811 | # CONFIG_XILINX_VCU is not set
812 | # CONFIG_HWSPINLOCK is not set
813 |
814 | #
815 | # Clock Source drivers
816 | #
817 | CONFIG_TIMER_OF=y
818 | CONFIG_TIMER_PROBE=y
819 | CONFIG_RISCV_TIMER=y
820 | # CONFIG_MICROCHIP_PIT64B is not set
821 | # end of Clock Source drivers
822 |
823 | # CONFIG_MAILBOX is not set
824 | CONFIG_IOMMU_SUPPORT=y
825 |
826 | #
827 | # Generic IOMMU Pagetable Support
828 | #
829 | # end of Generic IOMMU Pagetable Support
830 |
831 | #
832 | # Remoteproc drivers
833 | #
834 | # CONFIG_REMOTEPROC is not set
835 | # end of Remoteproc drivers
836 |
837 | #
838 | # Rpmsg drivers
839 | #
840 | # CONFIG_RPMSG_VIRTIO is not set
841 | # end of Rpmsg drivers
842 |
843 | # CONFIG_SOUNDWIRE is not set
844 |
845 | #
846 | # SOC (System On Chip) specific Drivers
847 | #
848 |
849 | #
850 | # Amlogic SoC drivers
851 | #
852 | # end of Amlogic SoC drivers
853 |
854 | #
855 | # Broadcom SoC drivers
856 | #
857 | # end of Broadcom SoC drivers
858 |
859 | #
860 | # NXP/Freescale QorIQ SoC drivers
861 | #
862 | # end of NXP/Freescale QorIQ SoC drivers
863 |
864 | #
865 | # i.MX SoC drivers
866 | #
867 | # end of i.MX SoC drivers
868 |
869 | #
870 | # Enable LiteX SoC Builder specific drivers
871 | #
872 | # CONFIG_LITEX_SOC_CONTROLLER is not set
873 | # end of Enable LiteX SoC Builder specific drivers
874 |
875 | #
876 | # Qualcomm SoC drivers
877 | #
878 | # end of Qualcomm SoC drivers
879 |
880 | # CONFIG_SOC_TI is not set
881 |
882 | #
883 | # Xilinx SoC drivers
884 | #
885 | # end of Xilinx SoC drivers
886 | # end of SOC (System On Chip) specific Drivers
887 |
888 | # CONFIG_PM_DEVFREQ is not set
889 | # CONFIG_EXTCON is not set
890 | # CONFIG_MEMORY is not set
891 | # CONFIG_IIO is not set
892 | # CONFIG_PWM is not set
893 |
894 | #
895 | # IRQ chip support
896 | #
897 | CONFIG_IRQCHIP=y
898 | # CONFIG_AL_FIC is not set
899 | CONFIG_RISCV_INTC=y
900 | CONFIG_SIFIVE_PLIC=y
901 | # end of IRQ chip support
902 |
903 | # CONFIG_IPACK_BUS is not set
904 | # CONFIG_RESET_CONTROLLER is not set
905 |
906 | #
907 | # PHY Subsystem
908 | #
909 | # CONFIG_GENERIC_PHY is not set
910 | # CONFIG_PHY_CAN_TRANSCEIVER is not set
911 | # CONFIG_BCM_KONA_USB2_PHY is not set
912 | # CONFIG_PHY_CADENCE_TORRENT is not set
913 | # CONFIG_PHY_CADENCE_DPHY is not set
914 | # CONFIG_PHY_CADENCE_SALVO is not set
915 | # CONFIG_PHY_FSL_IMX8MQ_USB is not set
916 | # CONFIG_PHY_MIXEL_MIPI_DPHY is not set
917 | # CONFIG_PHY_PXA_28NM_HSIC is not set
918 | # CONFIG_PHY_PXA_28NM_USB2 is not set
919 | # end of PHY Subsystem
920 |
921 | # CONFIG_POWERCAP is not set
922 | # CONFIG_MCB is not set
923 | # CONFIG_RAS is not set
924 |
925 | #
926 | # Android
927 | #
928 | # CONFIG_ANDROID is not set
929 | # end of Android
930 |
931 | # CONFIG_DAX is not set
932 | # CONFIG_NVMEM is not set
933 |
934 | #
935 | # HW tracing support
936 | #
937 | # CONFIG_STM is not set
938 | # CONFIG_INTEL_TH is not set
939 | # end of HW tracing support
940 |
941 | # CONFIG_FPGA is not set
942 | # CONFIG_FSI is not set
943 | # CONFIG_SIOX is not set
944 | # CONFIG_SLIMBUS is not set
945 | # CONFIG_INTERCONNECT is not set
946 | # CONFIG_COUNTER is not set
947 | # end of Device Drivers
948 |
949 | #
950 | # File systems
951 | #
952 | # CONFIG_VALIDATE_FS_PARSER is not set
953 | # CONFIG_EXPORTFS_BLOCK_OPS is not set
954 | # CONFIG_FILE_LOCKING is not set
955 | # CONFIG_FS_ENCRYPTION is not set
956 | # CONFIG_FS_VERITY is not set
957 | # CONFIG_DNOTIFY is not set
958 | # CONFIG_INOTIFY_USER is not set
959 | # CONFIG_FANOTIFY is not set
960 | # CONFIG_QUOTA is not set
961 | # CONFIG_AUTOFS4_FS is not set
962 | # CONFIG_AUTOFS_FS is not set
963 | # CONFIG_FUSE_FS is not set
964 | # CONFIG_OVERLAY_FS is not set
965 |
966 | #
967 | # Caches
968 | #
969 | # CONFIG_FSCACHE is not set
970 | # end of Caches
971 |
972 | #
973 | # Pseudo filesystems
974 | #
975 | # CONFIG_PROC_FS is not set
976 | # CONFIG_PROC_CHILDREN is not set
977 | # CONFIG_SYSFS is not set
978 | # CONFIG_TMPFS is not set
979 | CONFIG_ARCH_SUPPORTS_HUGETLBFS=y
980 | # CONFIG_HUGETLBFS is not set
981 | CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
982 | # CONFIG_CONFIGFS_FS is not set
983 | # end of Pseudo filesystems
984 |
985 | # CONFIG_MISC_FILESYSTEMS is not set
986 | # CONFIG_NLS is not set
987 | # CONFIG_UNICODE is not set
988 | # end of File systems
989 |
990 | #
991 | # Security options
992 | #
993 | # CONFIG_KEYS is not set
994 | # CONFIG_SECURITY_DMESG_RESTRICT is not set
995 | CONFIG_PROC_MEM_ALWAYS_FORCE=y
996 | # CONFIG_PROC_MEM_FORCE_PTRACE is not set
997 | # CONFIG_PROC_MEM_NO_FORCE is not set
998 | # CONFIG_SECURITYFS is not set
999 | # CONFIG_FORTIFY_SOURCE is not set
1000 | # CONFIG_STATIC_USERMODEHELPER is not set
1001 | CONFIG_DEFAULT_SECURITY_DAC=y
1002 | CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,bpf"
1003 |
1004 | #
1005 | # Kernel hardening options
1006 | #
1007 |
1008 | #
1009 | # Memory initialization
1010 | #
1011 | CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
1012 | CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
1013 | CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
1014 | # CONFIG_INIT_STACK_NONE is not set
1015 | # CONFIG_INIT_STACK_ALL_PATTERN is not set
1016 | CONFIG_INIT_STACK_ALL_ZERO=y
1017 | # CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
1018 | # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
1019 | CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
1020 | # CONFIG_ZERO_CALL_USED_REGS is not set
1021 | # end of Memory initialization
1022 | # end of Kernel hardening options
1023 | # end of Security options
1024 |
1025 | # CONFIG_CRYPTO is not set
1026 |
1027 | #
1028 | # Library routines
1029 | #
1030 | # CONFIG_PACKING is not set
1031 | CONFIG_BITREVERSE=y
1032 | CONFIG_GENERIC_STRNCPY_FROM_USER=y
1033 | CONFIG_GENERIC_STRNLEN_USER=y
1034 | # CONFIG_CORDIC is not set
1035 | # CONFIG_PRIME_NUMBERS is not set
1036 | CONFIG_RATIONAL=y
1037 | CONFIG_GENERIC_PCI_IOMAP=y
1038 |
1039 | #
1040 | # Crypto library routines
1041 | #
1042 | CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
1043 | # CONFIG_CRYPTO_LIB_CURVE25519 is not set
1044 | CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
1045 | # CONFIG_CRYPTO_LIB_POLY1305 is not set
1046 | # end of Crypto library routines
1047 |
1048 | # CONFIG_CRC_CCITT is not set
1049 | # CONFIG_CRC16 is not set
1050 | # CONFIG_CRC_T10DIF is not set
1051 | # CONFIG_CRC_ITU_T is not set
1052 | CONFIG_CRC32=y
1053 | # CONFIG_CRC32_SELFTEST is not set
1054 | CONFIG_CRC32_SLICEBY8=y
1055 | # CONFIG_CRC32_SLICEBY4 is not set
1056 | # CONFIG_CRC32_SARWATE is not set
1057 | # CONFIG_CRC32_BIT is not set
1058 | # CONFIG_CRC64 is not set
1059 | # CONFIG_CRC4 is not set
1060 | # CONFIG_CRC7 is not set
1061 | # CONFIG_LIBCRC32C is not set
1062 | # CONFIG_CRC8 is not set
1063 | CONFIG_XXHASH=y
1064 | # CONFIG_RANDOM32_SELFTEST is not set
1065 | CONFIG_ZLIB_INFLATE=y
1066 | CONFIG_LZO_DECOMPRESS=y
1067 | CONFIG_LZ4_DECOMPRESS=y
1068 | CONFIG_ZSTD_DECOMPRESS=y
1069 | CONFIG_XZ_DEC=y
1070 | CONFIG_XZ_DEC_X86=y
1071 | CONFIG_XZ_DEC_POWERPC=y
1072 | CONFIG_XZ_DEC_IA64=y
1073 | CONFIG_XZ_DEC_ARM=y
1074 | CONFIG_XZ_DEC_ARMTHUMB=y
1075 | CONFIG_XZ_DEC_SPARC=y
1076 | CONFIG_XZ_DEC_BCJ=y
1077 | # CONFIG_XZ_DEC_TEST is not set
1078 | CONFIG_DECOMPRESS_GZIP=y
1079 | CONFIG_DECOMPRESS_BZIP2=y
1080 | CONFIG_DECOMPRESS_LZMA=y
1081 | CONFIG_DECOMPRESS_XZ=y
1082 | CONFIG_DECOMPRESS_LZO=y
1083 | CONFIG_DECOMPRESS_LZ4=y
1084 | CONFIG_DECOMPRESS_ZSTD=y
1085 | CONFIG_HAS_IOMEM=y
1086 | CONFIG_HAS_IOPORT_MAP=y
1087 | CONFIG_HAS_DMA=y
1088 | CONFIG_DMA_DECLARE_COHERENT=y
1089 | # CONFIG_DMA_API_DEBUG is not set
1090 | CONFIG_GENERIC_ATOMIC64=y
1091 | # CONFIG_IRQ_POLL is not set
1092 | CONFIG_LIBFDT=y
1093 | CONFIG_ARCH_STACKWALK=y
1094 | # end of Library routines
1095 |
1096 | CONFIG_GENERIC_IOREMAP=y
1097 | CONFIG_GENERIC_LIB_ASHLDI3=y
1098 | CONFIG_GENERIC_LIB_ASHRDI3=y
1099 | CONFIG_GENERIC_LIB_LSHRDI3=y
1100 | CONFIG_GENERIC_LIB_UCMPDI2=y
1101 | CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
1102 |
1103 | #
1104 | # Kernel hacking
1105 | #
1106 |
1107 | #
1108 | # printk and dmesg options
1109 | #
1110 | CONFIG_PRINTK_TIME=y
1111 | # CONFIG_PRINTK_CALLER is not set
1112 | # CONFIG_STACKTRACE_BUILD_ID is not set
1113 | CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
1114 | CONFIG_CONSOLE_LOGLEVEL_QUIET=4
1115 | CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
1116 | # CONFIG_BOOT_PRINTK_DELAY is not set
1117 | # CONFIG_SYMBOLIC_ERRNAME is not set
1118 | # end of printk and dmesg options
1119 |
1120 | CONFIG_AS_HAS_NON_CONST_LEB128=y
1121 |
1122 | #
1123 | # Compile-time checks and compiler options
1124 | #
1125 | CONFIG_DEBUG_INFO=y
1126 | # CONFIG_DEBUG_INFO_REDUCED is not set
1127 | # CONFIG_DEBUG_INFO_COMPRESSED is not set
1128 | CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
1129 | # CONFIG_DEBUG_INFO_DWARF4 is not set
1130 | # CONFIG_DEBUG_INFO_DWARF5 is not set
1131 | # CONFIG_DEBUG_INFO_BTF is not set
1132 | # CONFIG_GDB_SCRIPTS is not set
1133 | CONFIG_FRAME_WARN=2048
1134 | # CONFIG_STRIP_ASM_SYMS is not set
1135 | # CONFIG_READABLE_ASM is not set
1136 | # CONFIG_HEADERS_INSTALL is not set
1137 | # CONFIG_DEBUG_SECTION_MISMATCH is not set
1138 | # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
1139 | CONFIG_ARCH_WANT_FRAME_POINTERS=y
1140 | # CONFIG_FRAME_POINTER is not set
1141 | # CONFIG_VMLINUX_MAP is not set
1142 | # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
1143 | # end of Compile-time checks and compiler options
1144 |
1145 | #
1146 | # Generic Kernel Debugging Instruments
1147 | #
1148 | # CONFIG_MAGIC_SYSRQ is not set
1149 | # CONFIG_DEBUG_FS is not set
1150 | CONFIG_HAVE_ARCH_KGDB=y
1151 | CONFIG_HAVE_ARCH_KGDB_QXFER_PKT=y
1152 | # CONFIG_KGDB is not set
1153 | CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
1154 | # CONFIG_UBSAN is not set
1155 | CONFIG_HAVE_KCSAN_COMPILER=y
1156 | # end of Generic Kernel Debugging Instruments
1157 |
1158 | CONFIG_DEBUG_KERNEL=y
1159 | # CONFIG_DEBUG_MISC is not set
1160 |
1161 | #
1162 | # Memory Debugging
1163 | #
1164 | # CONFIG_PAGE_EXTENSION is not set
1165 | # CONFIG_DEBUG_PAGEALLOC is not set
1166 | # CONFIG_PAGE_OWNER is not set
1167 | # CONFIG_PAGE_POISONING is not set
1168 | # CONFIG_DEBUG_RODATA_TEST is not set
1169 | CONFIG_ARCH_HAS_DEBUG_WX=y
1170 | # CONFIG_DEBUG_WX is not set
1171 | CONFIG_GENERIC_PTDUMP=y
1172 | # CONFIG_DEBUG_OBJECTS is not set
1173 | CONFIG_HAVE_DEBUG_KMEMLEAK=y
1174 | # CONFIG_DEBUG_KMEMLEAK is not set
1175 | # CONFIG_DEBUG_STACK_USAGE is not set
1176 | # CONFIG_SCHED_STACK_END_CHECK is not set
1177 | CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
1178 | # CONFIG_DEBUG_VM is not set
1179 | # CONFIG_DEBUG_VM_PGTABLE is not set
1180 | CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
1181 | # CONFIG_DEBUG_VIRTUAL is not set
1182 | # CONFIG_DEBUG_MEMORY_INIT is not set
1183 | CONFIG_CC_HAS_KASAN_GENERIC=y
1184 | CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
1185 | # end of Memory Debugging
1186 |
1187 | # CONFIG_DEBUG_SHIRQ is not set
1188 |
1189 | #
1190 | # Debug Oops, Lockups and Hangs
1191 | #
1192 | # CONFIG_PANIC_ON_OOPS is not set
1193 | CONFIG_PANIC_ON_OOPS_VALUE=0
1194 | CONFIG_PANIC_TIMEOUT=0
1195 | # CONFIG_SOFTLOCKUP_DETECTOR is not set
1196 | # CONFIG_DETECT_HUNG_TASK is not set
1197 | # CONFIG_WQ_WATCHDOG is not set
1198 | # end of Debug Oops, Lockups and Hangs
1199 |
1200 | #
1201 | # Scheduler Debugging
1202 | #
1203 | # end of Scheduler Debugging
1204 |
1205 | # CONFIG_DEBUG_TIMEKEEPING is not set
1206 |
1207 | #
1208 | # Lock Debugging (spinlocks, mutexes, etc...)
1209 | #
1210 | CONFIG_LOCK_DEBUGGING_SUPPORT=y
1211 | # CONFIG_PROVE_LOCKING is not set
1212 | # CONFIG_LOCK_STAT is not set
1213 | # CONFIG_DEBUG_SPINLOCK is not set
1214 | # CONFIG_DEBUG_MUTEXES is not set
1215 | # CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
1216 | # CONFIG_DEBUG_RWSEMS is not set
1217 | # CONFIG_DEBUG_LOCK_ALLOC is not set
1218 | # CONFIG_DEBUG_ATOMIC_SLEEP is not set
1219 | # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
1220 | # CONFIG_LOCK_TORTURE_TEST is not set
1221 | # CONFIG_WW_MUTEX_SELFTEST is not set
1222 | # CONFIG_SCF_TORTURE_TEST is not set
1223 | # end of Lock Debugging (spinlocks, mutexes, etc...)
1224 |
1225 | # CONFIG_DEBUG_IRQFLAGS is not set
1226 | # CONFIG_STACKTRACE is not set
1227 | # CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
1228 | # CONFIG_DEBUG_KOBJECT is not set
1229 |
1230 | #
1231 | # Debug kernel data structures
1232 | #
1233 | # CONFIG_DEBUG_LIST is not set
1234 | # CONFIG_DEBUG_PLIST is not set
1235 | # CONFIG_DEBUG_SG is not set
1236 | # CONFIG_DEBUG_NOTIFIERS is not set
1237 | # CONFIG_BUG_ON_DATA_CORRUPTION is not set
1238 | # end of Debug kernel data structures
1239 |
1240 | # CONFIG_DEBUG_CREDENTIALS is not set
1241 |
1242 | #
1243 | # RCU Debugging
1244 | #
1245 | # CONFIG_RCU_SCALE_TEST is not set
1246 | # CONFIG_RCU_TORTURE_TEST is not set
1247 | # CONFIG_RCU_REF_SCALE_TEST is not set
1248 | # CONFIG_RCU_TRACE is not set
1249 | # CONFIG_RCU_EQS_DEBUG is not set
1250 | # end of RCU Debugging
1251 |
1252 | # CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
1253 | CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
1254 | CONFIG_TRACING_SUPPORT=y
1255 | # CONFIG_FTRACE is not set
1256 | # CONFIG_SAMPLES is not set
1257 |
1258 | #
1259 | # riscv Debugging
1260 | #
1261 |
1262 | #
1263 | # Kernel Testing and Coverage
1264 | #
1265 | # CONFIG_KUNIT is not set
1266 | # CONFIG_NOTIFIER_ERROR_INJECTION is not set
1267 | # CONFIG_FAULT_INJECTION is not set
1268 | CONFIG_ARCH_HAS_KCOV=y
1269 | CONFIG_CC_HAS_SANCOV_TRACE_PC=y
1270 | # CONFIG_KCOV is not set
1271 | # CONFIG_RUNTIME_TESTING_MENU is not set
1272 | CONFIG_ARCH_USE_MEMTEST=y
1273 | # CONFIG_MEMTEST is not set
1274 | # end of Kernel Testing and Coverage
1275 | # end of Kernel hacking
1276 |
--------------------------------------------------------------------------------
/boot-Linux-on-NEMU.md:
--------------------------------------------------------------------------------
1 |
2 | # Port-Linux-on-NEMU
3 |
4 | ## About
5 |
6 | 这篇文章是从笔者的笔记整理而来, 比起“讲义”更像“博客” ,目前有许多东西都还没有完善(特别是linux driver的部分)
7 |
8 | 在笔者尝试给`NEMU`移植`kernel`的时候, 感到完全无从下手(也没发现`CommandBlock`老师的教程),过程中踩了非常多的坑,于是总结了这篇笔记
9 |
10 | 虽然大家更加建议的`roadmap`是`PA3,4->xv6->quardstar->linux-nommu->linux-mmu`,但笔者觉得,如果我们给`NEMU`加上了完备的基础设施(`difftest/trace/gdb`),`NEMU`比`QEMU`更能帮助我们理解`kernel`启动的流程,完全可以`PA3,4->(xv6->)linux-mmu`
11 |
12 | 也可以参考
13 | - [`CommandBlock老师的教程`](https://github.com/CmdBlockZQG/rvcore-mini-linux)
14 | - [`quand_star 进阶`](https://github.com/arch-simulator-sig/quard-star-tutorial-2021)
15 |
16 | ## Proposal: Let's build this Document together!🚀
17 |
18 | 发现问题/有好的建议欢迎提PR!
19 |
20 | PR is always welcome here.
21 |
22 | ### 打开方式
23 |
24 | 建议先完成:
25 | - `NEMU PA` 全部内容
26 | - 阅读`Opensbi`和`RISCV Spec Volume II, ch 1,2,3,10`
27 |
28 | 由于笔者的NEMU的架构是`riscv32`,这篇文章的很多Tips可能只适合与`riscv32`架构,但是从生态的角度来讲,`riscv64gc`的生态会非常好,建议大家优先考虑实现`riscv64gc`
29 |
30 | 如果`NEMU`实现的足够优雅是可以通过`menuconfig`来切换`rv32`/`rv64`,但显然我没有😭
31 |
32 | #### 启动`linux kernel` 和启动`nanos-lite`的区别
33 |
34 | - `Nanos-lite`的实现不是很规范,比如在`M-mod`下启用虚拟内存,也没有实现`S-Mod`
35 | - 从硬件(`NEMU`)的角度来说,Linux的规模更大,如果实现有问题更能体现出来
36 | - `Nanos-lite`是我们自己写硬件+软件,如果硬件有BUG可以在软件上加一个workaround()
37 |
38 | ## 启动 `linux kernel` 的多种方式
39 |
40 | - `fsbl->opensbi->linux`
41 | - `fsbl->opensbi->u-boot->linux`
42 | - `uboot-spl->opensbi->u-boot->linux`
43 |
44 | 在 nemu 上都不用实现 fsbl, 所以可以选择最简单的方法: `opensbi->linux`
45 |
46 | > 可以参考 `Opensbi repo`里面的 `fpga/arine`
47 |
48 | ### About OpenSBI
49 |
50 | > "硅基大陆的宪法仍在,城邦却铸造着各自的货币"
51 |
52 | 提供标准SBI接口、隔离硬件访问
53 |
54 | 1.虽然有统一的标准, 但是不同`RISC-V`硬件实现的差异还是太多了, 比如用多少个 `pmp` 寄存器, 相关硬件的早期初始化都不一样, `opensbi`就是负责启动早期的工作的
55 |
56 | 2.抽象和安全
57 | 当计算机世界一个东西变得足够复杂的时候, 就创建一个抽象层来简化它
58 |
59 | 所以启动带 mmu 的 `kernel` 一定要用 `opensbi`
60 |
61 | 
62 |
63 | 1. A platform-specific firmware running in M-mode and a bootloader, a hypervisor or a general-purpose OS executing in S-mode or HS-mode.
64 | 2. A hypervisor running in HS-mode and a bootloader or a general-purpose OS executing in VS-mode.
65 |
66 | ### 所以 uboot 是干什么的?
67 |
68 | 我的理解:更高级的支持->支持命令行/从 `tftp` 服务器上下载文件, 更复杂的硬件和安全支持.
69 | 但显然目前在 `nemu/npc` 上不需要
70 |
71 | ### Opensbi 的多种模式
72 |
73 | - `FW_PAYLOAD` 把下一个阶段的内容直接打包进 `opensbi` 生成的 `binary` 里面
74 | - `FW_JUMP` 直接跳转到一个固定的地址
75 | - `FW_DYNAMIC` 从上一个 booting-stage 获取信息 (比如上一个 stage 已经把 `opensbi` 和系统准备好了)
76 |
77 | 在 `nemu` 上用 ` FW_PAYLOAD ` 是最省力的
78 |
79 | ## 阅读手册
80 |
81 | 为啥不去看看 rv 手册呢 (Volume II, ch 1,2,3,10)
82 |
83 | - `(Reserved Writes Preserve Values, Reads Ignore Value)WPRI`
84 | - `(Write/Read Only Legal Values)WLRL`
85 | - `(Write Any Values, Reads Legal Values)WARL`
86 |
87 | Opensbi 在启动的过程中就会尝试给很多 csr 寄存器写数值, 然后再读取出来,
88 | - 如果寄存器没有实现, 就会抛出 `illegal instruction fault`, 这时候跳转到 `Opensbi` 自己的异常处理程序里面, 如果这个 csr 是必须的, 那么 opensbi 会抛一个异常停下来, 如果不是必须的, 那么接下来就不使用这个寄存器继续
89 | - 如果硬件某些寄存器的位没有实现, Opensbi 会不使用这个位
90 |
91 | `csr` 寄存器可以通过索引的高四位判断权限/RW 权限等等->硬件实现就简单了
92 |
93 | `mstatus/sstatus` & `sie/mie` 的某些位应该是硬件上的相同 bit, 根据手册定义
94 |
95 | ```
96 | A restricted view of mstatus appears as the sstatus register in the S-level ISA.
97 | ```
98 |
99 | ### 思考: 我们需要实现哪些 `csr`?
100 |
101 | 如果目标仅仅是<我要把 `kernel` 正常跑起来>的话
102 |
103 | - 首先排除所有拓展
104 | - 排除和安全相关的 `csr`
105 | - 其实可以直接启动 `opensbi-FW_JUMP` 模式, 把 `opensbi` 的输出调好, 只要能正常跑到跳转的地方就说明 `csr` 已经实现的差不多了
106 |
107 | ## 更强的基础设施
108 |
109 | ### 实现 `difftest`
110 |
111 | #### 阅读 `Spike` 源码
112 |
113 | 重要的文件
114 | - `processor.h/state_t`:里面包含了 spike 的状态 (全部的寄存器)
115 | - `../difftest.cc/difftest_init`: 里面包含了 spike 的初始化参数->只实例化 16 个 `pmpregions`
116 | - `csrs.cc`:里面有各种 csr 寄存器的行为
117 |
118 | ##### 比较有意思的事情
119 |
120 | - 取指的时候先 fetch->dedode->放进 icache 里面, 利用程序的局部性来实现加速.
121 | - Decode 使用了查找表
122 | - 对于各种异常(非法指令,page fault)等使用了try-catch处理
123 | - 某些寄存器的一些位没有完全实现,对这些寄存器的读写有 MASK (在 `csrrs.cc` 中)
124 | - 指令的实现在 `riscv/insns/*.h` 中
125 |
126 | #### 对访问不存在的csr寄存器的时候
127 |
128 | 回想起之前手册的内容, 访问没有实现的 CSR 寄存器的时候会抛出 Illegal Instruction Fault,
129 |
130 | 我们有很多方法来处理
131 | - 和访问设备的处理方式一样,把nemu的寄存器复制进Spike,但这样不太好
132 | - 让Spike在访问nemu未实现的寄存器的时候同步抛一个`illegal instruction fault`
133 |
134 | 那么我们就需要修改Spike的代码了
135 |
136 | 在spike中,所有 csr 指令都会首先 `get_csr`, 如果 csr 不存在就抛异常, 所以只要在不打算实现的 csr 上抛出一个异常就行了
137 |
138 | ```c
139 | bool difftest_dut_csr_notexist = false;
140 |
141 | // Note that get_csr is sometimes called when read side-effects should not
142 | // be actioned. In other words, Spike cannot currently support CSRs with
143 | // side effects on reads.
144 | reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek)
145 | {
146 | if(difftest_dut_csr_notexist) {
147 | difftest_dut_csr_notexist=false;
148 | printf("spike:stepping DUT(nemu,npc)'s unimplemented csr\n");
149 | throw trap_illegal_instruction(insn.bits());
150 | }
151 | auto search = state.csrmap.find(which);
152 | if (search != state.csrmap.end()) {
153 | if (!peek)
154 | search->second->verify_permissions(insn, write);
155 | return search->second->read();
156 | }
157 | printf("spike:stepping REF(spike)'s unimplemented csr\n");
158 | // If we get here, the CSR doesn't exist. Unimplemented CSRs always throw
159 | // illegal-instruction exceptions, not virtual-instruction exceptions.
160 | throw trap_illegal_instruction(insn.bits());
161 | }
162 | ```
163 |
164 | ##### WARN: 不要使用 `ref_difftest_raise_intr`来实现上述功能
165 |
166 | `ref_difftest_raise_intr`是用来实现中断的,只会设置异常号跳转到异常处理程序
167 |
168 | 但是`illegal instruction fault`存在"副作用",会对多个csr寄存器做修改,所以**不要使用下面的方案**
169 | ```c
170 | //不要使用下面的方案!
171 | void difftest_step_raise(uint64_t NO) {
172 | //step
173 | ref_difftest_exec(1);
174 | //rasie intr
175 | ref_difftest_raise_intr(NO);
176 | //set step
177 | difftest_skip_ref();
178 | ref_difftest_regcpy(&cpu, DIFFTEST_TO_REF);
179 | }
180 | ```
181 |
182 | #### 实现 `difftest_csr`
183 |
184 | - 修改 `difftest_init` 的 api, 传入需要 diff 的 csr 的索引数组
185 | - 每次diff的时候只传输需要diff的csr
186 | - 借助宏定义,就可以实现在nemu实现一个csr的同时自动给这个csr做diff
187 | - 宏真好用 ()
188 |
189 | ### 接入 gdb
190 |
191 | 使用[`mini-gdbstub`](https://github.com/RinHizakura/mini-gdbstub)项目可以很轻松在`nemu`里面接入`gdb-server`
192 |
193 | #### 有待解决的问题
194 |
195 | 如果仔细测试`mini-gdbstub`的实现,你会发现虽然`mini-gdbstub`虽然实现了`stepi`函数,但gdb并不会调用它!gdb的每次step都是在下一条指令的位置打一个断点,然后`continue`,这会导致对`ecall``step`的话有问题,无法step进异常处理程序.
196 |
197 | 猜测是init的时候给gdb传的参数有问题.
198 |
199 | #### 进阶操作
200 |
201 | ##### 给`gdb`传送`target description`文件来实现对csr的读取
202 |
203 | 具体参考往期分享会
204 |
205 | ##### 结合`tmux`实现自动分屏
206 |
207 | `tmux split-window -h -p 65 "riscv64-unknown-linux-gnu-gdb -ex \"target remote localhost:1234\" $(ELF)"`
208 |
209 | ##### 自动读取符号表
210 |
211 | `ELFS :='-ex \"set confirm off\" -ex \"symbol-file ${PWD}/opensbi/build/platform/nemu/firmware/fw_payload.elf\" -ex \"add-symbol-file ${PWD}/linux/vmlinux\" -ex \"set confirm on\"'`
212 |
213 | ##### 使用`socket`加速
214 |
215 | 参考该项目[`github pr#5`](https://github.com/RinHizakura/mini-gdbstub/pull/5)
216 |
217 | ### 添加trace
218 |
219 | 为了更加深入理解`linux kernel`的行为,可以考虑添加:
220 | - 异常/中断的`trace`
221 | - 设备(`PLIC`)的`trace`
222 | - `MMU`的`trace`
223 | - `ecall`的`trace`
224 |
225 | ## 我自己的技术选型
226 |
227 | **非常不建议完全按照我的方法走!**
228 |
229 | 一开始在感觉*给 `NEMU` “移植” ` linux ` 的过程中用`NEMU`来模拟硬件的行为是不是怪怪的*
230 | 所以我选择了不改动 `nemu` 的实现 (比如 ` uart `) ,而是给 `opensbi` / `linux` 写驱动 (但这样会花很多时间)
231 |
232 | ~~然后写 `linux-uart` 驱动的时候发现自己小看了 `linux kernel` 的复杂程度 (:-~~
233 |
234 | 其实 nemu 的 uart 可以轻松修改兼容标准的`UART16550`,具体`RTFSC`.
235 |
236 | ## 移植 `Opensbi`
237 |
238 | 主要参考了 `opensbi/docs/platform_guide.md` ,但是,如果 `nemu` 模拟了 `UART16550` 的话, 其实更推荐使用 Opensbi 官方提供的 [`Generic Platform`](https://github.com/riscv-software-src/opensbi/blob/master/docs/platform/generic.md) ,根据官网介绍可以直接按照设备树来自行加载驱动
239 |
240 | ### 创建一个新的 platform
241 |
242 | 从 `platform/template` 里面复制然后稍作修改
243 |
244 | ### 设置 `Makefile` 的参数
245 |
246 | ```Makefile
247 | PLATFORM_RISCV_XLEN = 32
248 | PLATFORM_RISCV_ABI = ilp32
249 | PLATFORM_RISCV_ISA = rv32ima_zicsr_zifencei
250 | PLATFORM_RISCV_CODE_MODEL = medany
251 |
252 | FW_DYNAMIC=n
253 |
254 | FW_JUMP=y
255 | FW_TEXT_START=0x80000000
256 | FW_JUMP_ADDR=0x0
257 | ```
258 |
259 | 这里可以先使用`JUMP`模式,把 `FW_JUMP_ADDR` 设置成 0, 如果执行 `mret` 之后跳转到了 0 就说明 ` opensbi ` 执行完了,后续我们跑linux的时候再使用`PAYLOAD`模式。
260 |
261 | 你接下来需要在开启difftest的情况下正常跑到`mret`的地方.
262 |
263 | 编译:
264 |
265 | ```
266 | make CROSS_COMPILE=riscv64-unknown-linux-gnu- PLATFORM=nemu
267 | ```
268 |
269 | 生成的二进制文件: `./build/platform/nemu/firmware/fw_jump.bin`
270 |
271 | >后续开启PAYLOAD以后二进制文件就是`fw_payload.bin`了
272 |
273 | ### 让 `opensbi` 正常输出字符 (适配 `nemu-uart` )
274 |
275 | 主要参考 `int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,u32 reg_width, u32 reg_offset)` 这个函数的代码, 主要要调用 `sbi_console_set_device` `sbi_domain_root_add_memrange` 这两个函数, 然后自己实现一个 `nemu-uart` 的驱动, 这样就能看到字符的正常输出了
276 |
277 | ```c
278 | static int uart_getch(void)
279 | {
280 | return -1;
281 | }
282 | static void uart_putch(char ch)
283 | {
284 | char *serial_base = (char *)0xa0000000 + 0x00003f8;
285 | *serial_base = ch;
286 | }
287 |
288 | static struct sbi_console_device my_uart = { .name = "nemu_uart",
289 | .console_putc = uart_putch,
290 | .console_getc = uart_getch };
291 |
292 | /*
293 | * Platform early initialization.
294 | */
295 | static int platform_early_init(bool cold_boot)
296 | {
297 | if (!cold_boot)
298 | return 0;
299 |
300 | sbi_console_set_device(&my_uart);
301 | return sbi_domain_root_add_memrange(0x10000000, PAGE_SIZE, PAGE_SIZE,
302 | (SBI_DOMAIN_MEMREGION_MMIO |
303 | SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
304 | return 0;
305 | }
306 | ```
307 |
308 | 如果实现比较正常, 那么你应该能看见输出信息 (要么是 `Opensbi` 的欢迎界面, 要么是 `Opensbi` 报错某个寄存器没有实现)
309 |
310 | ```
311 | system_opcode_insn: Failed to access CSR 0x104 from M-mode
312 | sbi_trap_error: hart0: trap0: illegal instruction handler failed (error -1)
313 | ```
314 |
315 | ### 阅读 `Opensbi` 的源码
316 |
317 | 如果提前看了 opensbi 的汇编代码, 会发现 `csr_read_num` 等函数里面有很多 `csr` 寄存器, 但其实不一定都要实现
318 |
319 | 这是因为:在启动过程中,Opensbi会先注册一个特殊的中断处理程序,然后对很多个寄存器尝试写入,如果这个寄存器硬件没有实现,那么就会跳转到它的中断处理程序里面,如果这个寄存器是必须的,那Opensbi就会抛出一个异常,如果是可选实现,那么就会继续执行,并在之后不使用这个寄存器
320 |
321 | 可以参考下面的代码:
322 | - `sbi_csr_detect.h/csr_read_allowed//csr_write_allowed` 检测寄存器是否支持读写!
323 | - `sbi_hart` 里面 `hart_detect_features` 会检测平台支持的寄存器是否存在等, 它包括异常处理, 允许后续恢复现场
324 |
325 | ### 向 `nemu` 添加更多的寄存器
326 |
327 | 我不选择"一口气把所有手册中定义的 csr 全部实现"因为感觉会陷入名为<细节>的黑洞:要实现很多非必须的csr的功能
328 |
329 | 听北京基地的某位大佬说香山的 `nemu` 的 `csr` 实现的非常巧妙, 感兴趣可以参考, 但我没看 (:-
330 |
331 | #### 宏魔法
332 |
333 | 在实现过程中可能要频繁修改 `csr` 寄存器的列表, 我希望通过宏定义实现相对统一的寄存器管理: 在头文件中添加了一个寄存器之后:
334 | - 自动为寄存器的索引生成一个常量
335 | - `Difftest` 的时候会自动比较这个寄存器
336 | - `gdb/sdb` 能读取/显示/打断点这个寄存器
337 | 所以我使用了 `define` 和 `undef` 组合, 让一个宏有多种展开方式
338 |
339 | ```c
340 | #define CSR_LIST \
341 | GenCSR(MHARTID, 0xf14) \
342 | GenCSR(MSTATUS, 0x300) \
343 | ...
344 |
345 | #define GenCSR(name, paddr) \
346 | static const uint32_t NEMU_CSR_V_##name = paddr; \
347 | static const uint32_t NEMU_CSR_##name = paddr;
348 | CSR_LIST
349 | #undef GenCSR
350 | ...
351 | static const char *difftest_csr_name[] = {
352 | #define GenCSR(NAME,IDX) #NAME,
353 | CSR_DIFF_LIST
354 | #undef GenCSR
355 | };
356 | ...
357 |
358 | #define GenCSR(name, paddr) \
359 | "\n"
360 | ...
361 |
362 | ```
363 |
364 | #### 位域
365 |
366 | ```c
367 | typedef union {
368 | struct {
369 | unsigned int : 1;
370 | unsigned int SSIE : 1;
371 | unsigned int : 1;
372 | unsigned int MSIE : 1;
373 | unsigned int : 1;
374 | unsigned int STIE : 1;
375 | unsigned int : 1;
376 | unsigned int MTIE : 1;
377 | unsigned int : 1;
378 | unsigned int SEIE : 1;
379 | unsigned int : 1;
380 | unsigned int MEIE : 1;
381 | unsigned int : 1;
382 | unsigned int LCOFIE: 1;
383 | unsigned int : 18;
384 | } bits;
385 | uint32_t value;
386 | } mie_t;
387 | #define NEMU_mie ((mie_t *)(&cpu.csr[NEMU_CSR_MIE]))
388 |
389 | //使用
390 | NEMU_mie->bits.STIE = xxx;
391 | NEMU_mie->value = xxx;
392 | ```
393 |
394 | 当然这种写法有问题(Unspecified behavior(参考标准附录J)),根据标准定义,struct中的bit-filed必须被打包进同一可寻址单元的相邻域中(如果大小合适)但是,
395 | - 同一单元之中的位域分配顺序(从高到低还是从低到高,由实现来决定)
396 | - 跨单元的行为由实现来决定
397 |
398 | > (From `ISO/IEC 9899:2024 6.7.3.2.13`)
399 | > An implementation may allocate any addressable storage unit large enough to hold a bit-field. If
400 | enough space remains, a bit-field that immediately follows another bit-field in a structure shall be
401 | packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that
402 | does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The
403 | order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is
404 | implementation-defined. The alignment of the addressable storage unit is unspecified.
405 |
406 | #### 寄存器的细节
407 |
408 | 指令运行执行过程中**当前正在执行的指令直接触发**的异常一般是**同步异常(Synchronous Exception)**, 要立刻阻塞当前的指令执行流, 并且指令本身不应该产生其他的副作用。
409 |
410 | 所以`word_t isa_raise_intr(word_t NO, vaddr_t epc)` didn't work!
411 | 当然我们可以用一个参数来表示是否成功, 但是,考虑这一个指令
412 | `INSTPAT("??????? ????? ????? 001 ????? 11100 11", csrrw , I, R(rd)=CSRR(imm&0xfff,s);CSRW(imm&0xfff,s)=src1);`
413 |
414 | 可能会发生什么呢?
415 | - 访问的 csr 不存在, 抛出 illegal instruction fault
416 | - 没有权限访问 csr, 抛出 illegal instruction fault
417 | - 取指过程中出现 page fault, 抛出Instruction page fault
418 | 对于 L/S, 还可能会抛出 `Load page fault` / `Store/AMO page fault`
419 |
420 | 这么多不同的地方会抛出这么多不同的错误, 这也太不"优雅"了!
421 | 所以 Spike 选择用 try-catch, 但是我们的 c 没有😭
422 |
423 | 回忆 15-213 ,老师似乎讲过一个 none-local-jump 的东西, 允许程序直接从一个很深的调用栈里面直接跳出跳转到某个位置, 查询资料, 找到了 `set-jump` 函数, 虽然有性能的损失,但也能满足我们的需求。
424 |
425 | ```c
426 | int isa_exec_once(Decode *s) {
427 | int jump_value = setjmp(memerr_jump_buffer);
428 | if(jump_value!=0){
429 | return exception_exec(jump_value,s);
430 | }
431 | ...
432 | }
433 | ```
434 |
435 | ## 向LinuxKernel进发!
436 |
437 | 在[`kernel.org`](https://www.kernel.org/)下载linux内核源码
438 |
439 | 可以大致读一下[`Linux的启动流程`](https://en.wikipedia.org/wiki/Booting_process_of_Linux)
440 |
441 | > linux 内核 `6.x` 开始 `menuconfig` 默认不显示 `riscv32`的编译选项了,需要勾选(Allow configurations that result in non-portable kernels),我拉取5.15的版本
442 |
443 | ### 配置kernel
444 |
445 | > [!NOTE]
446 | > BTW, 可以按 `/` 键来搜索menuconfig的选项 (虽然很符合直觉但似乎挺多人不知道hh)
447 |
448 | 建议先从 `defconfig` 改动, 而不是 `tinyconfig` 改动, 先把 `kernel` 跑起来再说
449 |
450 | 虽然提供了具体的配置方案,但还是建议大家自己好好看看kernel 有哪些配制
451 | `make ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- (defconfig/menuconfig/tinyconfig)`
452 |
453 | #### 基于`defconfig`的参考配置方案
454 |
455 | ```
456 | //设置initramfs的文件((可以先不填)如果不填kernel会默认拿一个空文件)
457 | → General setup->Initial RAM filesystem and RAM disk (initramfs/initrd) support(填自己的Initramfs source file(s))
458 | → Platform type ->Base ISA (RV32I)
459 | //关闭了这个才能关闭compressed instructions
460 | → Boot options -> UEFI runtime support (n)
461 | → Platform type->Emit compressed instructions when building Linux (n)
462 | → Platform type->FPU support(n)
463 | → Device Drivers → Character devices → Serial drivers -> NEMU uartlite serial port support (y)(自己写的驱动)
464 | //在vmlinux里面加入调试信息,提升调试体验
465 | → Kernel hacking → Compile-time checks and compiler options->Compile the kernel with debug info (y)
466 | ```
467 |
468 | #### 还是想从`tinyconfig`开始修改?
469 |
470 | - 你需要尽量启用完整的debug支持,特别是`earlycon`,`printk`
471 | - 你需要启用`uart`和`plic`的驱动
472 |
473 | ##### 我们最小需要什么?
474 |
475 | - 串口输出支持
476 | - 中断支持(for `uart` 输入)
477 | - 一些debug支持(`printk`,`early-console`等)
478 | - Riscv32IMA架构
479 |
480 | ##### 一个基于`tinyconfig`实现最小化配制的参考方案
481 |
482 | ```
483 | //启用printk的支持(用于打印log)
484 | → General setup → Configure standard kernel features (expert users) -> Enable support for printk(y)
485 | //启用并选择一个initramfs的内核文件
486 | → General setup->Initial RAM filesystem and RAM disk (initramfs/initrd) support(y)(填自己的Initramfs source file(s))
487 | → Platform type ->Base ISA (RV32I)
488 | → Boot options -> UEFI runtime support (n)
489 | → Platform type->Emit compressed instructions when building Linux (n)
490 | → Kernel hacking → printk and dmesg options->Show timing information on printks
491 | → Kernel hacking → Compile-time checks and compiler options -> Compile the kernel with debug info (y)
492 | → Device Drivers → Character devices ->Enable TTY (y)
493 | → Device Drivers → Character devices ->Enable TTY -> Early console using RISC-V SBI (y)
494 | → Device Drivers → Character devices ->Enable TTY -> NEMU uartlite serial port support (y)
495 | → Executable file formats->Kernel support for scripts starting with #! (y)
496 | → Device Drivers → IRQ chip support->SiFive Platform-Level Interrupt Controller (y)
497 | ```
498 |
499 | ### `linux kernel`的打开方式
500 |
501 | #### 基础设施
502 |
503 | - 可以配置一个好用的`clangd`,支持代码跳转/宏展开等功能
504 | - NEMU接入gdb,边调试边理解
505 | - 觉得每次传参数太麻烦了?->写一个Makefile!
506 | - 让gdb可以调试Spike的代码->默认情况下,直接使用gdb是无法调试作为difftest-ref的spike的,这是因为在`nemu/tools/spike-diff/Makefile`里面有一个替换指令`sed -i -e 's/-g -O2/-O2/' $@`
507 |
508 | ### 编译`kernel`
509 |
510 | `make ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- -j $(nproc)`
511 |
512 | 会编译出:
513 | - `./vmlinux` `kernel`的elf文件
514 | - `./arch/riscv/boot/Image`二进制文件,作为`Opensbi`的payload
515 |
516 | ### 来自虚拟内存的问候NO.1
517 |
518 | 将软件TLB(Translation Lookaside Buffer)填充设置为可选项->在nemu中为了简化就可以不实现TLB了
519 |
520 | > The initial RISC-V paged virtual-memory architectures have been designed as
521 | straightforward implementations to support existing operating systems. We have
522 | architected page table layouts to support a hardware page-table walker. Software TLB
523 | refills are a performance bottleneck on high-performance systems, and are especially
524 | troublesome with decoupled specialized coprocessors. An implementation can
525 | choose to implement software TLB refills using a machine-mode trap handler as an
526 | extension to M-mode.
527 |
528 | ### 来自虚拟内存的问候NO.1
529 |
530 | 如果你在这时候使用`objdump`尝试反编译`vmlinux`的内容,你会发现`kernel`被链接到了`0xC0000000`的位置,这和我们将要把代码放置的位置不同!
531 | 先别急,这是正常现象,如果你的`riscv`模拟器实现正确,`kernel`完全可以正常运行
532 | 为什么?不妨加一个trace自行探索试试看?
533 |
534 | >hint:linux内核中异常!=错误,只有无法处理的异常==错误
535 |
536 | ### 统计 kernel 需要多少 csr
537 |
538 | 为啥不先看看 `kernel` 访问了那些寄存器呢?
539 |
540 | 但注意:有一个 time (timeh) 寄存器反汇编出来的指令是 rdtime/rdtimeh
541 |
542 |
543 | 首先 Objdump 出 `vmlinux` 的内容, 然后可以写一个简单的 Python 脚本来统计总共访问了哪些 csr 寄存器
544 |
545 | ```python
546 | import re
547 | import sys
548 |
549 | def find_csr_registers(disassembly):
550 | csr_pattern = re.compile(r'.*csr[a-z]{1,2}\t.*')
551 | csrr_pattern = re.compile(r'.*csrr\t.*')
552 | csr_registers = set()
553 |
554 | for line in disassembly.split('\n'):
555 | match = csr_pattern.search(line)
556 | csrr_match = csrr_pattern.search(line)
557 | if csrr_match:
558 | result=re.split(r'[,\t]+',line)[-1]
559 | csr_registers.add(result)
560 | elif match:
561 | result=re.split(r'[,\t]+',line)[-2]
562 | csr_registers.add(result)
563 |
564 | return sorted(csr_registers)
565 |
566 | if __name__ == "__main__":
567 |
568 | with open("./result.txt", 'r') as f:
569 | disassembly = f.read()
570 |
571 | csr_list = find_csr_registers(disassembly)
572 |
573 | print("Used CSR registers:")
574 | for csr in csr_list:
575 | print(f"- {csr}")
576 | ```
577 |
578 | #### 来自真实系统的 tradeoff
579 |
580 | 在真实的系统中, 时钟一般不会设计成一个寄存器/csr 的形式, 因为会有多个 hart 同步/关机/动态调频的问题, 一般设计成 MMIO
581 |
582 | 来自 riscv-spec
583 | > Accurate real-time clocks (RTCs) are relatively expensive to provide (requiring a crystal or
584 | MEMS oscillator) and have to run even when the rest of system is powered down, and so
585 | there is usually only one in a system located in a different frequency/voltage domain from
586 | the processors. Hence, the RTC must be shared by all the harts in a system and accesses to
587 | the RTC will potentially incur the penalty of a voltage-level-shifter and clock-domain
588 | crossing. It is thus more natural to expose mtime as a memory-mapped register than as a
589 | CSR.
590 |
591 | ### 再次提醒:基础设施
592 |
593 | `kernel` 的报错输出依赖关键csr寄存器的实现正确,但是csr实现的细节很繁杂,没有difftest的话很可能会存在某些地方实现错误!
594 |
595 | #### gdb大法好
596 |
597 | gdb可以极大地加强你的调试体验,你不会喜欢一直使用printk调试法/ebreak调试法的
598 |
599 | ~~ebrak调试大法~~(别学)
600 |
601 | ```c
602 | asm volatile (
603 | "mv a0, %0\n\t" // 将 start 的值加载到 a0 寄存器
604 | "mv a1, %1\n\t" // 将 end 的值加载到 a1 寄存器
605 | "ebreak" // 执行 ebreak 指令
606 | :
607 | : "r"(start), "r"(end) // 输入操作数:将 start 和 end 传递给寄存器
608 | : "a0", "a1" // 声明 a0 和 a1 寄存器会被修改
609 | );
610 | ```
611 |
612 | gdb好用的地方之一:可以读取函数调用的`backtrace`和参数,如果你的earlycon输出不正常也可以使用gdb来调试
613 |
614 | ```
615 | #2 0x8091d2d8 in panic (fmt=fmt@entry=0x81410b78 "\0014RISC-V system with no 'timebase-frequency' in DTS\n")
616 | at kernel/panic.c:443
617 | ```
618 |
619 | ##### 检查编译内核的时候是否添加了调试新息
620 |
621 | ```
622 | → Kernel hacking → Compile-time checks and compiler options -> Compile the kernel with debug info
623 | ```
624 |
625 | 打开这个选项以后gdb的调试体验会极大增强(可以读函数参数,可以对着源代码调试)
626 |
627 | #### 来自虚拟内存的问候NO.1
628 |
629 | `kernel`启动早期会开启MMU,MMU的实现会导致gdb远程调试出现bug(无法正确扫描内存导致`info src`出现异常),所以需要特殊处理,有两个方法:
630 | - 在gdb扫描内存的时候执行`page table walk`
631 | - (不推荐,地址有问题可能会触发`kernel`的`BUG_ON`宏或者导致设备树读取失败)修改`linux kernel`的`Makefile`,把`PAGE_OFFSET`设置成和加载地址一样的数值,这样可以保证kernel的虚拟地址和物理地址相等
632 |
633 | #### 测试你的基础设施
634 |
635 | 用gdb远程调试给`kernel`打一个断点,看看是否能够正常停下来,`info src`能不能正常定位到源代码
636 |
637 | ### 输出第一条信息
638 |
639 | 回想我们笔记本的linux启动的时候会有很多调试信息,在linux出现问题的时候能给我们很大的提示,但是,serial驱动的初始化往往在`kernel`初始化的很晚的阶段,那怎么看早期的log呢?
640 |
641 | 当我们想到这个问题的时候,大概率有人想过了,这就是OpenSBI提供的`earlycon`功能,如果启用了这个功能以后,`kernel`的输出会经过一次`ecall`以后跳转到Opensbi后然后由Opensbi输出
642 |
643 | #### 启用`kernel`的printk的支持
644 |
645 | 建议检查一下printk的选项有没有开,如果printk没有开那么不会输出log!
646 |
647 | ```
648 | Kernel hacking-> printk and dmesg options
649 |
650 | → General setup → Configure standard kernel features (expert users) -> Enable support for printk
651 | ```
652 |
653 | #### 启用`kernel`的`earlycon`
654 |
655 | 确保在menuconfig里面勾选了earlycon功能,并且给`kernel`传递了`earlycon=sbi`作为启动参数(可以通过设备树传递,也可以临时在menuconfig里面指定(` → Boot options->Built-in kernel command line `))
656 |
657 | ```
658 | [ 0.000000] Linux version 5.15.178 (seeker@miLaptop) (riscv64-unknown-linux-gnu-gcc (GCC) 13.2.0, GNU ld (GNU Binutils) 2.41) #138 SMP Sat Feb 15 16:19:35 HKT 2025
659 | ```
660 |
661 | #### 来自虚拟内存的问候NO.2
662 |
663 | 遇到了问题正在阅读linux kernel mmu的源代码?
664 |
665 | 但是如果阅读`kernel`源代码,会发现一个奇怪的逻辑
666 |
667 | ```c
668 |
669 | void __init create_pgd_mapping(pgd_t *pgdp,
670 | uintptr_t va, phys_addr_t pa,
671 | phys_addr_t sz, pgprot_t prot)
672 | {
673 | pgd_next_t *nextp;
674 | phys_addr_t next_phys;
675 | uintptr_t pgd_idx = pgd_index(va);
676 |
677 | if (sz == PGDIR_SIZE) {
678 | if (pgd_val(pgdp[pgd_idx]) == 0)
679 | pgdp[pgd_idx] = pfn_pgd(PFN_DOWN(pa), prot);
680 | return;
681 | }
682 | ...
683 | }
684 |
685 | ```
686 |
687 | > 不理解?该去翻一下手册了(10.3.2. Virtual Address Translation Process)
688 |
689 | ### Kernel 跑着跑着 hit good (bad) trap 了?
690 |
691 | 如果查看`kernel`的汇编发现指令中混入了一个 `ebreak`!
692 |
693 | 为什么会 `call ebreak`: 因为有 `BUG_ON` 等等宏触发了, 通常是 `Kconfig/Makefile` 有问题
694 |
695 | ```c
696 | BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
697 |
698 | BUG_ON()
699 | #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
700 | #define __BUG_FLAGS(flags) do { \
701 | __asm__ __volatile__ ("ebreak\n"); \
702 | } while (0)
703 |
704 | #define BUG() do { \
705 | __BUG_FLAGS(0); \
706 | unreachable(); \
707 | } while (0)
708 | ```
709 |
710 | ```c
711 | asmlinkage void __init setup_vm(uintptr_t dtb_pa)
712 | {
713 | ...
714 | /* Sanity check alignment and size */
715 | BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
716 | BUG_ON((kernel_map.phys_addr % PMD_SIZE) != 0);
717 | ...
718 | }
719 | ```
720 |
721 | ### 设备树
722 |
723 | [`设备树`](https://en.wikipedia.org/wiki/Devicetree)主要是描述硬件平台设备组成和配置的数据结构,它的核心作用是将硬件信息从内核代码中分离,实现硬件描述与系统软件的解耦,从而提升系统的可移植性、可维护性和灵活性,一般由bootloader加载进内存并传递给kernel,也可以直接打包进kernel.
724 |
725 | > x86架构并没有设备树,x86架构通过ACPI等协议自动探测硬件连接(当然也有[`riscv-ACPI`](https://github.com/riscv-non-isa/riscv-acpi-rimt))
726 |
727 | 第一次学设备树会觉得很抽象, 其实可以直接额参考文档/其他设备的 example
728 | 设备"树"有很多种写法, 感觉 `json` 很像, 但也有区别
729 |
730 | 可以参考
731 | - [`elinux.org/device_tree_usage`](https://elinux.org/Device_Tree_Usage)
732 | - [`k210 的 devicetree`](https://github.com/riscv-software-src/opensbi/blob/555055d14534e436073c818e04f4a5f0d3c141dc/platform/kendryte/k210/k210.dts)
733 | - [`野火的文档`](https://doc.embedfire.com/linux/imx6/driver/zh/latest/linux_driver/driver_tree.html)
734 | - [`sifive-hifive的 devicetree(for PLIC)`](https://github.com/riscv-non-isa/riscv-device-tree-doc/blob/master/examples/sifive-hifive_unleashed-microsemi.dts)
735 | - [`linux & DT`](https://docs.kernel.org/devicetree/usage-model.html)
736 |
737 | 大概需要有什么:
738 |
739 | ```
740 | ┌─────────────────────────────┐
741 | │ Root Node │ / {
742 | ├─────────────────────────────┤
743 | │ #address-cells = <1> │
744 | │ #size-cells = <1> │
745 | │ compatible = "seeker_nemu" │
746 | └─────────────┬───────────────┘
747 | │
748 | ┌────────────────┬─────┴───────────────────┬───────────────────┬──────────────────┐
749 | │ │ │ │ │
750 | ┌───▼──────┐ ┌──────▼───────────┐ ┌────────▼──────────┐ ┌──────▼─────────┐ ┌─────▼───────────┐
751 | │ choosen │ │ cpus │ │ plic0@0xC000000 │ │ uart@a00003f8 │ │ memory@80000000 │
752 | ├──────────┤ ├──────────────────┤ ├───────────────────┤ ├────────────────┤ ├─────────────────┤
753 | │ bootargs │ │timebase-frequency│ │ compatible │ │ reg=0xA00003F8 │ │ reg=0x80000000 │
754 | │ │ │ │ │ riscv,ndev │ │ status=okay │ │ -0x87FFFFFF │
755 | └──────────┘ └──────┬───────────┘ │ reg │ └────────────────┘ └─────────────────┘
756 | │ │interrupts-extended│
757 | ┌──────▼────────┐ └────────────┬──────┘
758 | │ / cpu@0 │ │
759 | ├───────────────┤ │
760 | │ compatible │ │
761 | │ device_type │ │
762 | │ status │ │
763 | │ riscv,isa │ │
764 | └─────────┬─────┘ │
765 | │ │
766 | ┌──▼──────────────────┐ │
767 | │ cpu0_intc │ │
768 | ├─────────────────────┤ │
769 | │ #interrupt-cells │ │
770 | │ compatible │ │
771 | │interrupt-controller ◄───────┘
772 | │ │
773 | └─────────────────────┘
774 | ```
775 |
776 | #### 来自虚拟内存的问候NO.3:opensbi 是如何把设备树地址传递给 `kernel` 的
777 |
778 | 如果你尝试调试`kernel`中访问设备树的部分,你会发现:`kernel`访问设备树时候访问的是`0x3e200000`附近的地址
779 |
780 | 这个地址是怎么来的呢?
781 |
782 | 根据手册规定,设备树地址应该放在a1寄存器传递给`kernel`
783 |
784 | >如何确定这块地址是不是设备树->可以扫描内存看看魔数对不对
785 |
786 | ```asm
787 | /* Save hart ID and DTB physical address */
788 | mv s0, a0
789 | mv s1, a1
790 | ...
791 | #ifdef CONFIG_BUILTIN_DTB
792 | la a0, __dtb_start
793 | #else
794 | mv a0, s1
795 | #endif /* CONFIG_BUILTIN_DTB */
796 | /* Set trap vector to spin forever to help debug */
797 | la a3, .Lsecondary_park
798 | csrw CSR_TVEC, a3
799 | call setup_vm
800 | ```
801 |
802 | 之后我们追踪一下这个变量(`head.s`), 发现传递给了 ` setup_vm `,然后会映射这片内存到`0x3e200000`附近
803 |
804 | ##### 检查设备树是否被正常加载
805 |
806 | 你需要给这里打一个断点,来检测设备树是否读取成功
807 |
808 | ```c
809 | status = early_init_dt_verify(params);
810 | if (!status)
811 | return false;
812 | ```
813 |
814 | ###### 一个未解之谜
815 |
816 | **如果你有任何想法,pr/issue is always welcomed!**
817 |
818 | 如果你的设备树传递的地址没有对齐,可能会在这里设置错误的`dtb_early_va`,我没搞清楚为什么不需要显式对齐
819 |
820 | 这里建议按照[`Opensbi官方仓库里面的fpga/ariane`](https://github.com/riscv-software-src/opensbi/blob/master/platform/fpga/ariane/objects.mk)的makefile来配置`FW_PAYLOAD_FDT_ADDR`,`FW_PAYLOAD_OFFSET`,`FW_PAYLOAD_ALIGN`等参数
821 |
822 | `kernel`的代码:
823 | ```c
824 | dtb_early_va = (void *)fix_fdt_va + (dtb_pa & (PMD_SIZE - 1));
825 | ```
826 | 我认为需要显式对齐的代码:
827 | ```c
828 | dtb_early_va = (void *)(fix_fdt_va & ~(PMD_SIZE-1) ) + (dtb_pa & (PMD_SIZE - 1));
829 | ```
830 |
831 | #### 思考: 设备树是如何解析调用驱动的?
832 |
833 | 可以参考 `drivers/of/fdt.c`, 里面的 `early_init_dt_scan_nodes`,在这里面初始化内存,把设备树解析到内存里面,之后的driver_init的时候再根据设备树里面的`compatable`子段匹配驱动,然后调用对应的`probe`函数
834 |
835 | ```c
836 | void __init early_init_dt_scan_nodes(void)
837 | {
838 | int rc = 0;
839 |
840 | /* Initialize {size,address}-cells info */
841 | of_scan_flat_dt(early_init_dt_scan_root, NULL);
842 |
843 | /* Retrieve various information from the /chosen node */
844 | rc = of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
845 | if (!rc)
846 | pr_warn("No chosen node found, continuing without\n");
847 |
848 | /* Setup memory, calling early_init_dt_add_memory_arch */
849 | of_scan_flat_dt(early_init_dt_scan_memory, NULL);
850 |
851 | /* Handle linux,usable-memory-range property */
852 | early_init_dt_check_for_usable_mem_range();
853 | }
854 | ```
855 | > 这里应该只解析了设备树,初始化设备还在后面,但是内存(页表是在这里初始化的)
856 |
857 | ##### 设备树映射虚拟内存的逻辑:
858 |
859 | 虚拟内存的映射也是根据设备树来的,在设备树读取到内存节点的时候, 会调用 `early_init_dt_add_memory_arch` 之后调用 `memblock_add` 存储地址进 `memblock.memory` 以便之后读取
860 |
861 | ### Linux 适配 nemu-uart 驱动!
862 |
863 | > FIXME: 由于kernel的复杂性,这里有非常多的疏漏和没讲清楚的地方
864 |
865 | 主要参考 [`linux 内核 driver-api/serial/driver`](https://docs.kernel.org/driver-api/serial/driver.html#uart-ops)
866 | 同时可以参考 [`linux 内核的 uart-lite 的驱动`](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/tty/serial/uartlite.c?h=v5.15.178),因为从代码行树来看的话,`uart-lite`是代码最少的uart驱动
867 |
868 | 启用`uart`(`nemu-uart/uartlite`)驱动的位置在 `tinyconfig→ Device Drivers → Character devices->tty->xxx`
869 |
870 | #### 添加 nemu-uart 驱动
871 | - 创建 `nemu-uart.c` 文件
872 | - Kconfig 添加项
873 | - Makefile 添加项`obj-$(CONFIG_NEMU_UART) += nemu-uart.o`
874 | - `menuconfig` 里面勾选驱动
875 |
876 | ##### `kernel`驱动的组成
877 |
878 | Linux 驱动主要包含几个结构体:
879 | - `console`控制台设备的接口
880 | - `uart_ops`定义`uart`的函数集合
881 | - `uart_driver`表示一个`uart`的驱动程序
882 | - `uart_port`表示一个具体的`uart`端口
883 | - `platform_driver`实现平台总线上的一个设备驱动
884 |
885 | ###### 注册驱动
886 |
887 | `module_init`宏会注册模块的初始化函数,如果这个驱动被编译进`kernel`(比如我们的`nemu-uart`驱动),就会在`kernel`启动的时候被`do_initcalls()`调用
888 |
889 | ```c
890 | module_init(nemu_uart_init);
891 | ```
892 |
893 | ##### `uart`驱动的基本流程
894 |
895 | - 内核初始化的时候调用`do_initcalls()`
896 | - 调用`do_one_initcall()`调用每个注册的init函数
897 | - 调用nemu-uart注册的`nemu_uart_init`(初始化函数)
898 | - 调用`platform_driver_register`注册驱动(`nemu_uart_platform_driver`结构体)
899 | - 经过一系列调用调用`driver_probe_device()`,尝试把`driver`和某个`device`绑定
900 | - 再经过一系列函数调用进入`nemu_uart_platform_driver`注册的`nemu_uart_probe()`函数
901 | - `probe`函数获取内存资源/获取中断资源/映射内存/注册驱动/初始化端口/添加自旋锁
902 |
903 | ```
904 | static struct uart_driver nemu_uart_driver = {
905 | .owner = THIS_MODULE,
906 | .driver_name = DRIVER_NAME,
907 | .dev_name = "ttyNEMU",
908 | .major = TTY_MAJOR,
909 | .minor = 2472,
910 | .nr = 1,
911 | };
912 | ```
913 | 主要的参考资料
914 | - [`kernel_docs/low_level_serial_api->uart_ops`](https://docs.kernel.org/driver-api/serial/driver.html)
915 | - [`kernel_docs/driver-api/console->console`](https://docs.kernel.org/driver-api/tty/console.html#console)
916 |
917 | Uart-lite
918 | - [`uartlite's dt`](https://www.kernel.org/doc/Documentation/devicetree/bindings/serial/xlnx%2Copb-uartlite.txt)
919 | - [`uartlite's docs`](https://docs.amd.com/v/u/en-US/pg142-axi-uartlite)
920 |
921 | ### 向文件系统进发!我们需要一个 initramfs
922 |
923 | 更多资料可以参考
924 | - [`gentoo wiki1`](https://wiki.gentoo.org/wiki/Initramfs/Guide)
925 | - [`gentoo wiki2`](https://wiki.gentoo.org/wiki/Initramfs_-_make_your_own)
926 | - [`Wikipedia-InitialRAMDisk`](https://en.wikipedia.org/wiki/Initial_ramdisk)
927 |
928 | 之前的内容跑到这里就说明成功了,接下来就需要一个文件系统了,
929 |
930 | ```
931 | #2 0x8091d1f4 in panic (
932 | fmt=fmt@entry=0x81410748 "No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance.") at kernel/panic.c:443
933 |
934 | ```
935 |
936 | [`文件系统`](https://en.wikipedia.org/wiki/File_system)是操作系统给我们提供的又一层抽象.由于NEMU中我们尚未实现磁盘,所以最好的方法是打包一个initramfs
937 |
938 | 参考[`linux文档`](https://docs.kernel.org/filesystems/ramfs-rootfs-initramfs.html#populating-initramfs),如果不指定路径,内核会使用一个空的initramfs
939 |
940 | >真实系统的initramfs:只是启动过程中的一部分,bootloader负责把kernel和initfs加载进内存然后启动kernel,kernel会判断initfs的类型(initrd/initramfs),
941 | 一般initramfs只是作为在真正的根文件系统被挂载之前的一个临时文件系统,里面存放一些被编译成"可加载的内核模块"的驱动,
942 | 这样也可以简化kernel的实现,因为磁盘的实现有多种多样(可能是软件RAID, LVM, NFS...这些都需要特殊的步骤去挂载, ),但内存是简单统一的.
943 | 再之后会调用`pivot_root()`来卸载`initramfs`并切换到真正的根文件系统
944 |
945 | 需要修改kernel的menuconfig,打开initramdisk的支持,并把我们之后打包的initramfs添加进来:
946 |
947 | ```
948 | -> General setup -> Initial RAM filesystem and RAM disk (initramfs/initrd) support
949 | ```
950 |
951 | 首先,我们需要创建[`linux的目录结构`](https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard)
952 |
953 | ```bash
954 | mkdir --parents /usr/src/initramfs/{bin,dev,etc,lib,lib64,mnt/root,proc,root,sbin,sys,run}
955 | ```
956 |
957 | 创建控制台设备
958 |
959 | ```bash
960 | sudo mknod rootfs/dev/console c 5 1
961 | ```
962 |
963 | #### init 进程
964 |
965 | 系统启动后由内核创建的第一个用户空间进程(PID 为 1)。它是所有其他进程的父进程或间接父进程,负责初始化系统环境、管理系统服务和守护进程的生命周期。
966 |
967 | 我们的目标是在`nemu`上启动一个简单的`kernel`就行了,所以`init`进程主要的工作就是启动shell
968 |
969 |
970 | #### 测试用户空间程序是否能正常加载
971 |
972 | 由于`init`进程是内核启动加载的第一个进程,我们只要测试一下init能不能正常加载执行就可以了
973 |
974 | 可以先用c写一个死循环程序,用工具链静态编译以后打包进`initramfs`里面,之后给kernel传递`init=xxx`参数,让kernel运行init
975 |
976 | ```bash
977 | riscv32-unknown-linux-gnu-gcc -static -o init init.c
978 | ```
979 |
980 | 诶,page fault了?
981 | >hint:异常!=错误
982 |
983 | #### difftest又报错了?
984 |
985 | 该读文档了!
986 | > The Svade extension: when a virtual page is accessed and the A bit is clear, or is written and the D
987 | bit is clear, a page-fault exception is raised.
988 |
989 | riscv页表的脏位检查是允许硬件维护,同时也使用一个`M-mode`拓展来允许软件维护
990 |
991 | 在nemu中就直接抛异常让软件来实现就行了
992 |
993 | 参考Spike的代码:
994 | ```c
995 | reg_t ad = PTE_A | ((type == STORE) * PTE_D);
996 |
997 | if ((pte & ad) != ad) {
998 | if (hade) {
999 | // set accessed and possibly dirty bits.
1000 | pte_store(pte_paddr, pte | ad, addr, virt, type, vm.ptesize);
1001 | } else {
1002 | // take exception if access or possibly dirty bit is not set.
1003 | break;
1004 | }
1005 | }
1006 | ```
1007 |
1008 | #### 编译交叉工具链
1009 |
1010 | 之前编译Opensbi和kernel的时候其实没有链接`glibc`,现在在编译用户程序的时候就需要一个带`glibc`的工具链支持了,可以自行编译[`riscv-gnu-toolchain`](https://github.com/riscv-collab/riscv-gnu-toolchain)
1011 |
1012 | 因为`--enable-multilib`会默认用rv32gc来编译标准库,如果传递了 `--enable-multilib` 可能会导致编译出的标准库包含 c 拓展的指令,从而导致最后静态链接的elf文件包含压缩指令
1013 |
1014 | 可以先用静态链接的方式编译`init/busybox`
1015 |
1016 | 虽然在大多数情况下可以正常运行,但是静态编译链接glibc是非常不推荐的[`参考StackOverflow`](https://stackoverflow.com/questions/57476533/why-is-statically-linking-glibc-discouraged)
1017 |
1018 | 推荐的编译选项:
1019 |
1020 | ```bash
1021 | ./configure --prefix=/opt/riscv --with-arch=rv32ima --with-abi=ilp32
1022 | make linux
1023 | ```
1024 |
1025 | ##### 有关`newlib`和`musl`库
1026 |
1027 | > [!WARNING]
1028 | > 这一段未经验证,可能有问题
1029 |
1030 | 不建议尝试使用`musl`和`newlib`
1031 |
1032 | 截至目前,`newlib`上游只适配了`x86-linux`
1033 |
1034 | 来自[`newlib官网`](https://sourceware.org/newlib/):
1035 |
1036 | > Now linux is a different animal. It is an OS that has an extensive set of syscalls.
1037 | If you look in the newlib/libc/sys/linux directory, you will find a number of syscalls
1038 | there (e.g. see io.c). There is a set of basic syscall macros that are defined
1039 | for the particular platform. For the x86, you will find these macros defined in
1040 | newlib/libc/sys/linux/machine/i386/syscall.h file. At the moment, linux support
1041 | is only for x86. To add another platform, the syscall.h file would
1042 | have to be supplied for the new platform plus some other
1043 | platform-specific files would need to be ported as well.
1044 |
1045 | > [!IMPORTANT]
1046 | > 根据musl的configure,可能有riscv的支持
1047 | > 感兴趣可以尝试用clang+muslc (TODO:docs here)
1048 |
1049 | 截至目前,`musl` 上游没有支持`riscv-linux`
1050 |
1051 | 来自[`musl官网`](https://www.musl-libc.org/intro.html)
1052 |
1053 | > Use it on Linux x86 (32/64), ARM (32/64), MIPS (32/64), PowerPC (32/64), S390X, SuperH, Microblaze, OpenRISC
1054 |
1055 | 虽然有`riscv-newlib`和`riscv-musl`的分支, 不过也是archieve的状态了,也没必要使用没有官方支持/停止维护的东西
1056 |
1057 |
1058 | ##### 有关工具链的"目标三元组"
1059 |
1060 | [`参考`](https://wiki.osdev.org/Target_Triplet)
1061 |
1062 | 编译生成的工具链的名称有`riscv32-unknown-linux-gnu-xxx`,`riscv32-unknown-elf-xxx`,`musl-xxx`等这些其实包含了`Target Triplet`的东西,可以通过`gcc -dumpmachine`查看
1063 |
1064 | `Target Triplet`的格式是`machine-vendor-operatingsystem`,详细信息可以自行STFW
1065 |
1066 | 其中`riscv32-unknown-elf-xxx`使用Newlib的工具链,不包含`riscv-linux`系统相关的代码(比如linux的ecall)
1067 |
1068 | ### Initramfs 的打包
1069 |
1070 | 可以先写一个死循环来测试, 然后再 initscript
1071 |
1072 | **init要有执行权限!**
1073 |
1074 | ```bash
1075 | (cd initramfs && find . | cpio -o --format=newc | gzip > ../initramfs.cpio.gz)
1076 | ```
1077 |
1078 | ### 编译 `busybox`
1079 |
1080 | ```bash
1081 | make CROSS_COMPILE=riscv32-unknown-linux-gnu- ARCH=riscv CONFIG_PREFIX=/root/initramfs meuconfig
1082 | make CROSS_COMPILE=riscv32-unknown-linux-gnu- ARCH=riscv CONFIG_PREFIX=/root/initramfs install
1083 | ```
1084 |
1085 | #### 编译busybox过程中头文件``未找到?
1086 |
1087 | busybox里面有platform-spec的适配代码,通过检查[`gcc 的 System-specific Predefined Macros`](https://gcc.gnu.org/onlinedocs/cpp/System-specific-Predefined-Macros.html)
1088 |
1089 | 在toolchain的config 里面有参数 `--enable-linux`,如果`make linux`的话会默认选中这个参数,但如果强行传--enable-linux就链接到glibc库里面去了
1090 |
1091 | ```c
1092 |
1093 | /* ---- Endian Detection ------------------------------------ */
1094 |
1095 | #include
1096 | #if defined(__digital__) && defined(__unix__)
1097 | # include
1098 | #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
1099 | || defined(__APPLE__)
1100 | # include /* rlimit */
1101 | # include
1102 | # define bswap_64 __bswap64
1103 | # define bswap_32 __bswap32
1104 | # define bswap_16 __bswap16
1105 | #else
1106 | # include
1107 | # include
1108 | #endif
1109 | ```
1110 |
1111 | #### 创建`init`脚本
1112 |
1113 | 需要先开启kernel的init脚本的支持
1114 |
1115 | ```
1116 | → Executable file formats->Kernel support for scripts starting with #!
1117 | ```
1118 |
1119 | 具体可以参考各路wiki,在这里我们可以简化,直接启动一个sh就行了
1120 |
1121 | ### 实现串口的输出
1122 |
1123 | 如果之前一切顺利,那应该能看见`kernel`运行了`init`脚本的内容,并且最终执行了`/bin/sh`
1124 |
1125 | 之后我们当然想要输入,支持输入的话就要中断的支持了,在riscv中,外部的中断需要一个统一的中断控制器来管理,这个中断控制器可以协调多个外部中断源, 实现分配优先级, 抢占, 屏蔽, 路由, 完成通知,...这就是PLIC(Platform-Level Interrupt Controller)
1126 |
1127 | #### 实现更强的终端支持
1128 |
1129 | 在nemu中,我们直接把输出打印到控制台,但是log也会打印到控制台,输入/输出/Log全部混在一起并不是一个明知的选择,所以我采用了[`伪终端(pseudoterminal)`](https://linux.die.net/man/7/pty),创建一个伪终端,通过screen链接这个伪终端来和nemu交互
1130 |
1131 | 写了一个[`最小化实现的例子`](https://github.com/Seeker0472/tinypty)
1132 |
1133 | ##### 一个未解之谜
1134 |
1135 | 如果没有一个`client`(比如`screen`)连接上这个pyt消费掉`master`(nemu)存进去的数据的话,输出的内容会在下一次读取的时候读取出来,我就让`ptyinit`的时候等待`client`链接(详细参考我的例子)
1136 |
1137 | #### PLIC 的适配
1138 |
1139 | 参考:
1140 | - [`PLIC Spec`](https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc)
1141 | - [`sifive PLIC Spec`](https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf)
1142 |
1143 | PLIC就不写驱动了,还是老老实实实现`sive`的`PLIC`吧
1144 |
1145 | 需要修改uart的设备树,声明中断源和连接`plic`
1146 |
1147 | ```
1148 | uart: uart@a00003f8 {
1149 | compatible = "seeker,nemu_uart";
1150 | reg = <0xa00003f8 0x1>;
1151 | interrupts = <1>; // 使用PLIC中断源1(可随便定义,但需<=riscv,ndev-1)
1152 | interrupt-parent = <&plic0>; // 关联到PLIC
1153 | status = "okay";
1154 | };
1155 | ```
1156 |
1157 | ##### PLIC&CLINT
1158 |
1159 | PLIC&CLINT是两个设备,所以需要另外一根线连到处理器核,所以核内也有一个中断控制器(相信在写设备树的时候也发现了)
1160 |
1161 | 这个核内的中断控制器是必须要实现的, 不然`plic`驱动就加载不起来
1162 | ```c
1163 | hartid = riscv_of_parent_hartid(node);
1164 | if (hartid < 0) {
1165 | pr_warn("unable to find hart id for %pOF\n", node);
1166 | return 0;
1167 | }
1168 | ```
1169 |
1170 | 根据riscv手册,优先中断的优先级如下
1171 |
1172 | ```
1173 | Multiple simultaneous interrupts destined for M-mode are handled in the following decreasing
1174 | priority order: MEI, MSI, MTI, SEI, SSI, STI, LCOFI.
1175 | ```
1176 |
1177 | 这里的缩写分别代表:
1178 | - `MEI (Machine External Interrupt)`
1179 | - `MSI (Machine Software Interrupt)`
1180 | - `MTI (Machine Timer Interrupt)`
1181 | - `SEI (Supervisor External Interrupt)`
1182 | - `SSI (Supervisor Software Interrupt)`
1183 | - `STI (Supervisor Timer Interrupt)`
1184 | - `LCOFI (Local Custom Offload Interrupt)`
1185 |
1186 | 这里的主要设计原则:
1187 | - 更高特权级的中断需要先处理
1188 | - 外部中断优先于内部中断(外部设备(比如网络I/O可能有更加严格的时间要求))
1189 | - 软件中断优先于内部定时器中断(定时器中断一般用于时间片流转,而软件中断用于处理器间通讯,可能需要更快的响应),但软件中断在`mip`的低四位,允许单条csr指令(`csrrwi`等)直接修改
1190 |
1191 | ##### 注册中断
1192 |
1193 | 要让kernel知道中断发起的时候应该调用哪个处理函数,就需要我们自己注册中断了
1194 |
1195 | > 其实kernel文档提醒了: Probe 的时候获取中断号 (这里要判断一下是否正常, 否则等到 `platform_get_irq` 的时候会 fail)
1196 |
1197 | ```
1198 | nemu_uart_port.irq = platform_get_irq(pdev, 0);
1199 | ```
1200 |
1201 | 然后 startup 的时候注册中断
1202 |
1203 | ```
1204 | int ret = request_irq(port->irq, nemu_uart_irq,
1205 | IRQF_TRIGGER_RISING, "nemu_uart",
1206 | port);
1207 | ```
1208 |
1209 | 这样当中断到来的时候`kernel`就会调用`nemu_uart_irq`这个函数了
1210 |
1211 | 具体参考[`文档`](https://docs.kernel.org/core-api/genericirq.html#c.request_irq)
1212 |
1213 | ##### PLIC设备的实现
1214 |
1215 | 给 plic 加一个 trace, 发现读写的地址有:
1216 |
1217 | ```
1218 | 0xc002080->Hart 1 M-mode enables
1219 | 0xc002084->same area
1220 | 0xc201000->Hart 1 M-mode priority threshold
1221 | 0xc000004-> source 1 pirority
1222 | ```
1223 |
1224 | 阅读手册, 可以知道大概的流程是
1225 | - Uart中断传送到PLIC
1226 | - PLIC设置pendingbit
1227 | - 等待时机抛出异常(M/S external interrupt)
1228 | - linux 进行异常处理 (跳转到PLIC驱动)
1229 | - claim 读取`claim/complete reg`(反回0或最高记别的中断)
1230 | - linux进行跳转到对应的回调函数进行处理
1231 | - 结束以后 写 `claim/complete reg`如果成功就清除`pengding bit`
1232 |
1233 | 实现PLIC的行为就很简单了
1234 |
1235 | 
1236 |
1237 | #### 异常处理的细节
1238 |
1239 | 其实没有完全实现正确可能也能跑,因为目前 difftest 的框架没有办法`diff`到中端是否应该被响应->我们`difftest`的`difftest_raise_intr(NO)`只会发起一个intr并立刻响应,并不会检查这个中断是否被屏蔽了;
1240 |
1241 | 所以实现的时候要仔细阅读手册
1242 |
1243 | 中断是交给M-Mode 处理还是S-Mod处理->应该仔细阅读手册有关`medeleg` & `mideleg`的部分
1244 |
1245 | 默认情况下会把所有异常/中断都交给 M-Mod 处理, 然后让 M-mod 的程序来选择是自己处理还是交给S-Mode的操作系统来处理, 但是为了提高性能, 可以把某一些中断/异常委托给 S-Mod (timer/pagefault/plic)
1246 |
1247 | 在mstatus中有全局中断使能,`mie` & `mip`有对细分的中断使能
1248 |
1249 | 
1250 |
1251 | ## 为什么不跑一个发行版呢?
1252 |
1253 | 看看远方的 Riscv64 吧!
1254 | - "32-bit architectures are being killed off one-by-one, not being added." (from debian mail-list)
1255 | - "**What needs to be done**: Get riscv32 running somehow (fails due to bugs in qemu user mode emulation)" (from gentoo wiki)
1256 | - fedora wiki : not even mentioned yet.
1257 |
1258 | 如果发新版支持,可以直接chroot进不同架构的rootfs[`参考`](https://unix.stackexchange.com/questions/292433/chroot-into-a-different-architecture),然后直接执行`apt install` [`大致的步骤`](https://github.com/carlosedp/riscv-bringup/blob/master/Debian-Rootfs-Guide.md)
1259 |
1260 | 当然`rv32`也有社区支持,[`参考`](https://github.com/yuzibo/riscv32)
1261 |
1262 | ## 迈向更安全的大厦
1263 |
1264 | ### PMP
1265 |
1266 | 启动linux的时候不需要实现PMP的功能
1267 |
1268 | `pmpcfg`: `L0A | XWR` L: locked->(addr&entry) O:reserved A: Access Type
1269 |
1270 |
1271 | Permissions-error:
1272 | - Instruction access fault
1273 | - load access-fault
1274 | - Store access-fault
1275 |
1276 | AccessType:
1277 | - 0-关闭
1278 | - 1-TOR (TOP of Range),TOR 模式通过两个相邻的 `pmpaddr` 寄存器定义一个连续的地址范围
1279 | - Matches `pmaddr(i-1)NA4 (Naturally aligned four-byte region),定义一个 **4 字节对齐** 的极小内存区域
1281 | - 3->NAOT (Naturally aligned power-of-two region, ≥8 bytes)NAPOT 模式定义一个 **2 的幂次方大小且自然对齐** 的内存区域->看末尾有多少个 1?
1282 |
--------------------------------------------------------------------------------