diff --git a/_posts/2023-8-30-arm-smp-demo.markdown b/_posts/2023-8-30-arm-smp-demo.markdown new file mode 100644 index 0000000..fc77f1f --- /dev/null +++ b/_posts/2023-8-30-arm-smp-demo.markdown @@ -0,0 +1,292 @@ +--- +layout: post +title: "ARM架构bare-metal多核程序示例" +categories: Technology +tags: 树莓派 raspberry pi 多核 arm zh smp qemu aarch64 体系结构 en bare-metal 裸金属 +author: Calinyara +description: +--- + +
+ +- ***boot.S*** + +```c +.global _start +.section .text.boot, "ax" + +_start: + mrs x0, mpidr_el1 + and x0, x0, #3 + + mov x6, x0 + mov x1, #0x0 + add x2, x1, #0x400000 + lsl x6, x6, #18 + sub x3, x2, x6 + mov sp, x3 + + bl uart_init + + mrs x0, mpidr_el1 + and x0, x0, #3 + cbz x0, core0 + cmp x0, #1 + b.eq core1 + cmp x0, #2 + b.eq core2 + cmp x0, #3 + b.eq core3 + +core0: + bl print0 + b hang + +core1: + bl print1 + b hang + +core2: + bl print2 + b hang + +core3: + bl print3 + b hang + +hang: + wfi + b hang +``` + +
+ +- ***main.c*** + +```c +extern void delay(unsigned long); +extern void put32(unsigned long, unsigned int); +extern unsigned int get32(unsigned long); +extern int get_el(void); + +#define PBASE 0x3F000000 +#define GPFSEL1 (PBASE + 0x00200004) +#define GPSET0 (PBASE + 0x0020001C) +#define GPCLR0 (PBASE + 0x00200028) +#define GPPUD (PBASE + 0x00200094) +#define GPPUDCLK0 (PBASE + 0x00200098) + +#define AUX_ENABLES (PBASE + 0x00215004) +#define AUX_MU_IO_REG (PBASE + 0x00215040) +#define AUX_MU_IER_REG (PBASE + 0x00215044) +#define AUX_MU_IIR_REG (PBASE + 0x00215048) +#define AUX_MU_LCR_REG (PBASE + 0x0021504C) +#define AUX_MU_MCR_REG (PBASE + 0x00215050) +#define AUX_MU_LSR_REG (PBASE + 0x00215054) +#define AUX_MU_MSR_REG (PBASE + 0x00215058) +#define AUX_MU_SCRATCH (PBASE + 0x0021505C) +#define AUX_MU_CNTL_REG (PBASE + 0x00215060) +#define AUX_MU_STAT_REG (PBASE + 0x00215064) +#define AUX_MU_BAUD_REG (PBASE + 0x00215068) + +void uart_send_char(char c) +{ + while (1) { + if (get32(AUX_MU_LSR_REG) & 0x20) + break; + } + put32(AUX_MU_IO_REG, c); +} + +void uart_init(void) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7 << 12); + selector |= 2 << 12; + selector &= ~(7 << 15); + selector |= 2 << 15; + put32(GPFSEL1, selector); + + put32(GPPUD, 0); + delay(150); + put32(GPPUDCLK0, (1 << 14) | (1 << 15)); + delay(150); + put32(GPPUDCLK0, 0); + + put32(AUX_ENABLES, 1); + put32(AUX_MU_CNTL_REG, 0); + put32(AUX_MU_IER_REG, 0); + put32(AUX_MU_LCR_REG, 3); + put32(AUX_MU_MCR_REG, 0); + put32(AUX_MU_BAUD_REG, 270); + + put32(AUX_MU_CNTL_REG, 3); +} + +void print0() { + for(int j = 0; j <= 3; j++) { + for(int i = 0; i <= 200000000; i++) { + if (i == 1) + uart_send_char('0'); + } + } +} + +void print1() { + for(int j = 0; j <= 3; j++) { + for(int i = 0; i <= 200000000; i++) { + if (i == 10000000) + uart_send_char('1'); + } + } +} + +void print2() { + for(int j = 0; j <= 3; j++) { + for(int i = 0; i <= 200000000; i++) { + if (i == 90000000) + uart_send_char('2'); + } + } +} + +void print3() { + for(int j = 0; j <= 3; j++) { + for(int i = 0; i <= 200000000; i++) { + if (i == 80000000) + uart_send_char('3'); + } + } +} +``` + +
+ +- ***utils.S*** + +```c +.globl get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret + +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret +``` + +
+ +- ***Makefile*** + +```makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = . + +all : arm_smp + +run : arm_smp + qemu-system-aarch64 -M raspi3b -nographic -serial null -serial mon:stdio -kernel kernel8.elf + +clean : + rm -rf $(BUILD_DIR) *.img *.bin *.elf + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +arm_smp: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o kernel8.elf $(OBJ_FILES) +``` + +
+ +- ***linker.ld*** + +```c +ENTRY(_start) + +SECTIONS { + . = 0x80000; + + .text : { + *(.text.boot) + *(.text) + } + + .data : { + *(.data) + } +} +``` + +
+ +```shell +$ make run +0132013201320132 +``` + +
+ + + + + + + + + + + + + + + + \ No newline at end of file