├── 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 | [![CC BY-SA 4.0](https://licensebuttons.net/l/by-sa/4.0/88x31.png)](https://creativecommons.org/licenses/by-sa/4.0/) 10 | [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](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 | ![](./attachments/20250215_19h25m26s_grim.png) 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 | ![](./attachments/Pasted%20image%2020250215230008.png) 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 | ![20250215_19h10m54s_grim.png](./attachments/20250215_19h10m54s_grim.png) 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 | --------------------------------------------------------------------------------