├── .gitignore ├── bcm43438-doc ├── brcmfmac_sdio_log.txt └── brcmfmac_trace_log.txt ├── qemu-raspi2 ├── framebuffer01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── int01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld └── timer01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── qemu-raspi3 ├── dma01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── framebuffer01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── int01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── int02 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── sdhost01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ ├── linker.ld │ └── sd.img ├── sdhost02 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ ├── linker.ld │ └── sd.img ├── sdio01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ ├── linker.ld │ └── sd.img ├── sdio02 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ ├── linker.ld │ └── sd.img ├── sdio03 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ ├── linker.ld │ └── sd.img ├── task01 │ ├── Makefile │ ├── README.md │ ├── asmfunc.S │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── task02 │ ├── Makefile │ ├── README.md │ ├── asmfunc.S │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── timer01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── kernel.c │ └── linker.ld ├── usb01 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ └── linker.ld ├── usb02 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ └── linker.ld └── usb03 │ ├── Makefile │ ├── README.md │ ├── boot.S │ ├── events │ ├── kernel.c │ └── linker.ld └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.elf 3 | *.list 4 | -------------------------------------------------------------------------------- /qemu-raspi2/framebuffer01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = arm-none-eabi 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a7 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a7 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-arm -M raspi2 -m 128 -serial null -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-arm -M raspi2 -m 128 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 27 | 28 | clean: 29 | rm -f *.o *.elf *.list 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /qemu-raspi2/framebuffer01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example draws framebuffer on QEMU raspi2 model. 3 | This program only supports QEMU raspi2 model, and does not work on real hardware. 4 | QEMU raspi2 model has default parameteor of frame buffer : 640 x 480 / 16 bpp . 5 | 6 | 7 | -------------------------------------------------------------------------------- /qemu-raspi2/framebuffer01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrc p15, #0, r1, c0, c0, #5 13 | and r1, r1, #3 14 | cmp r1, #0 15 | bne io_halt 16 | 17 | // Setup the stack. 18 | mov sp, #0x8000 19 | 20 | // Clear out bss. 21 | ldr r4, =__bss_start 22 | ldr r9, =__bss_end 23 | mov r5, #0 24 | mov r6, #0 25 | mov r7, #0 26 | mov r8, #0 27 | b 2f 28 | 29 | 1: 30 | // store multiple at r4. 31 | stmia r4!, {r5-r8} 32 | 33 | // If we are still below bss_end, loop. 34 | 2: 35 | cmp r4, r9 36 | blo 1b 37 | 38 | // Call kernel_main 39 | ldr r3, =kernel_main 40 | blx r3 41 | 42 | // halt 43 | .globl io_halt 44 | io_halt: 45 | wfe 46 | b io_halt 47 | -------------------------------------------------------------------------------- /qemu-raspi2/framebuffer01/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern void io_halt(void); 5 | 6 | void boxfill8(uint16_t *vram, int xsize, uint16_t c, int x0, int y0, int x1, int y1) 7 | { 8 | int x, y; 9 | for (y = y0; y <= y1; y++) { 10 | for (x = x0; x <= x1; x++) 11 | vram[y * xsize + x] = c; 12 | } 13 | return; 14 | } 15 | 16 | #define COL8_000000 ( ((0x00>>3)<<11) + ((0x00>>3)<<6) + (0x00>>3)) 17 | #define COL8_008484 ( ((0x00>>3)<<11) + ((0x84>>3)<<6) + (0x84>>3)) 18 | #define COL8_848484 ( ((0x84>>3)<<11) + ((0x84>>3)<<6) + (0x84>>3)) 19 | #define COL8_C6C6C6 ( ((0xC6>>3)<<11) + ((0xC6>>3)<<6) + (0xC6>>3)) 20 | #define COL8_FFFFFF ( ((0xFF>>3)<<11) + ((0xFF>>3)<<6) + (0xFF>>3)) 21 | 22 | void kernel_main(void) 23 | { 24 | uint16_t *vram = (uint16_t *) 0x4100000; 25 | int x = 640 ,y = 480; 26 | 27 | boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); 28 | boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); 29 | boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); 30 | boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); 31 | 32 | boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); 33 | boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); 34 | boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); 35 | boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); 36 | boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); 37 | boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); 38 | 39 | boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); 40 | boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); 41 | boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); 42 | boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); 43 | 44 | while (1) 45 | io_halt(); 46 | } 47 | -------------------------------------------------------------------------------- /qemu-raspi2/framebuffer01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x8000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | -------------------------------------------------------------------------------- /qemu-raspi2/int01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = arm-none-eabi 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a7 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a7 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | boot.o: boot.S 14 | ${AS} ${ASM_FLAGS} -c $< -o $@ 15 | 16 | %.o : %.c Makefile 17 | $(CC) ${CFLAGS} -c -o $*.o $*.c 18 | 19 | run : 20 | $(MAKE) kernel.elf 21 | qemu-system-arm -M raspi2 -m 128 -serial mon:stdio -kernel kernel.elf -nographic 22 | 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-arm -M raspi2 -m 128 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 26 | 27 | clean: 28 | rm -f *.o *.elf *.list 29 | 30 | .PHONY: clean 31 | -------------------------------------------------------------------------------- /qemu-raspi2/int01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example uart rx interrupt on QEMU raspi2 model. 3 | This program only supports QEMU raspi2 model, and does not work on real hardware. 4 | 5 | -------------------------------------------------------------------------------- /qemu-raspi2/int01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | reset: 9 | // disable core0,1,2. 10 | mrc p15, #0, r1, c0, c0, #5 11 | and r1, r1, #3 12 | cmp r1, #0 13 | bne io_halt 14 | 15 | // set vector address. 16 | ldr r0, =vector 17 | mcR P15, 0, r0, c12, c0, 0 18 | 19 | // save cpsr. 20 | mrs r0, cpsr 21 | 22 | // setup sp in IRQ mode. 23 | bic r1, r0, #0x1f 24 | orr r1, r1, #0x12 25 | msr cpsr_c,r1 26 | mov sp,#0x4000 27 | 28 | // restore cpsr. 29 | msr cpsr_c, r0 30 | 31 | // setup the stack in SVC mode. 32 | mov sp, #0x8000 33 | 34 | // Clear out bss. 35 | ldr r4, =__bss_start 36 | ldr r9, =__bss_end 37 | mov r5, #0 38 | mov r6, #0 39 | mov r7, #0 40 | mov r8, #0 41 | b 2f 42 | 43 | 1: 44 | // store multiple at r4. 45 | stmia r4!, {r5-r8} 46 | 47 | // If we are still below bss_end, loop. 48 | 2: 49 | cmp r4, r9 50 | blo 1b 51 | 52 | // Call kernel_main 53 | ldr r3, =kernel_main 54 | blx r3 55 | 56 | irq: 57 | push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 58 | bl c_irq_handler 59 | pop {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 60 | subs pc, lr, #4 61 | 62 | .globl io_halt 63 | io_halt: 64 | wfi 65 | b io_halt 66 | 67 | .globl enable_irq 68 | enable_irq: 69 | cpsie i 70 | bx lr 71 | 72 | .globl disable_irq 73 | disable_irq: 74 | cpsid i 75 | bx lr 76 | 77 | .align 5 78 | vector: 79 | ldr pc, reset_handler 80 | ldr pc, undefined_handler 81 | ldr pc, swi_handler 82 | ldr pc, prefetch_handler 83 | ldr pc, data_handler 84 | ldr pc, unused_handler 85 | ldr pc, irq_handler 86 | ldr pc, fiq_handler 87 | 88 | reset_handler: .word reset 89 | undefined_handler: .word io_halt 90 | swi_handler: .word io_halt 91 | prefetch_handler: .word io_halt 92 | data_handler: .word io_halt 93 | unused_handler: .word io_halt 94 | irq_handler: .word irq 95 | fiq_handler: .word io_halt 96 | 97 | 98 | -------------------------------------------------------------------------------- /qemu-raspi2/int01/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern void io_halt(void); 5 | extern void enable_irq(void); 6 | extern void disable_irq(void); 7 | 8 | #define UART0_DR ((volatile uint32_t *)(0x3F201000)) 9 | #define UART0_FR ((volatile uint32_t *)(0x3F201018)) 10 | #define UART0_IMSC ((volatile uint32_t *)(0x3F201038)) 11 | #define UART0_MIS ((volatile uint32_t *)(0x3F201040)) 12 | 13 | void uart_putc(unsigned char c) 14 | { 15 | // Wait for UART to become ready to transmit. 16 | while (*UART0_FR & (1 << 5)) { } 17 | *UART0_DR = c; 18 | } 19 | 20 | void uart_puts(const char* str) 21 | { 22 | for (size_t i = 0; str[i] != '\0'; i ++) 23 | uart_putc((unsigned char)str[i]); 24 | } 25 | 26 | #define IRQ_PEND2 ((volatile uint32_t *)(0x3F00B208)) 27 | #define IRQ_ENABLE2 ((volatile uint32_t *)(0x3F00B214)) 28 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 29 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 30 | 31 | void c_irq_handler(void) 32 | { 33 | char c; 34 | disable_irq(); 35 | // check inteerupt source 36 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 37 | if (*IRQ_PEND2 & (1 << 25)) { 38 | if (*UART0_MIS & (1 << 4)) { 39 | c = (unsigned char) *UART0_DR; // read for clear tx interrupt. 40 | enable_irq(); 41 | uart_putc(c); 42 | uart_puts(" c_irq_handler\n"); 43 | return; 44 | } 45 | } 46 | } 47 | enable_irq(); 48 | return; 49 | } 50 | 51 | 52 | void kernel_main(void) 53 | { 54 | uart_puts("int01 : uart rx interrupt.\n"); 55 | uart_puts("exit : Ctrl-A x ,monitor : Ctrl-A c\n\n"); 56 | 57 | // enable UART RX interrupt. 58 | *UART0_IMSC = 1 << 4; 59 | 60 | // UART interrupt routing. 61 | *IRQ_ENABLE2 = 1 << 25; 62 | 63 | // IRQ routeing to CORE0. 64 | *GPU_INTERRUPTS_ROUTING = 0x00; 65 | 66 | enable_irq(); 67 | 68 | while (1) 69 | io_halt(); 70 | } 71 | -------------------------------------------------------------------------------- /qemu-raspi2/int01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x8000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | -------------------------------------------------------------------------------- /qemu-raspi2/timer01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = arm-none-eabi 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a7 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a7 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-arm -M raspi2 -m 128 -serial mon:stdio -nographic -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-arm -M raspi2 -m 128 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 27 | 28 | clean: 29 | rm -f *.o *.elf *.list 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /qemu-raspi2/timer01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example set generic timer to 1 sec on QEMU raspi2 model. 3 | This program only supports QEMU raspi2 model, and does not work on real hardware. 4 | 5 | -------------------------------------------------------------------------------- /qemu-raspi2/timer01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | reset: 9 | // in QEMU all of 4 ARM CPUs are started simultaniously 10 | // by default. I don't know if this is the real hw behaviour, 11 | // but here I jump to halt if CPU ID (stored in MPIDR 12 | // register, first 2 bits) is not 0 13 | mrc p15, #0, r1, c0, c0, #5 14 | and r1, r1, #3 15 | cmp r1, #0 16 | bne hang 17 | 18 | // set vector address. 19 | ldr r0, =vector 20 | mcr P15, 0, r0, c12, c0, 0 21 | 22 | // save CPSR. 23 | mrs r0, cpsr 24 | 25 | // set sp in irq mode. 26 | bic r1, r0, #0x1F 27 | orr r1, r1, #0x12 28 | msr cpsr_c,r1 29 | mov sp, #0x4000 30 | 31 | // set sp in svc mode. 32 | msr cpsr_c, r0 33 | mov sp, #0x8000 34 | 35 | // Clear bss. 36 | ldr r4, =__bss_start 37 | ldr r9, =__bss_end 38 | mov r5, #0 39 | mov r6, #0 40 | mov r7, #0 41 | mov r8, #0 42 | b 2f 43 | 44 | 1: 45 | // store multiple at r4. 46 | stmia r4!, {r5-r8} 47 | 48 | // If we are still below bss_end, loop. 49 | 2: 50 | cmp r4, r9 51 | blo 1b 52 | 53 | // Call kernel_main 54 | ldr r3, =kernel_main 55 | blx r3 56 | 57 | hang: 58 | wfi 59 | b hang 60 | 61 | .globl io_halt 62 | io_halt: 63 | wfi 64 | bx lr 65 | 66 | .globl enable_irq 67 | enable_irq: 68 | cpsie i 69 | bx lr 70 | 71 | .globl disable_irq 72 | disable_irq: 73 | cpsid i 74 | bx lr 75 | 76 | irq: 77 | push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 78 | bl c_irq_handler 79 | pop {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 80 | subs pc,lr,#4 81 | 82 | .balign 32 83 | vector: 84 | ldr pc, reset_handler 85 | ldr pc, undefined_handler 86 | ldr pc, swi_handler 87 | ldr pc, prefetch_handler 88 | ldr pc, data_handler 89 | ldr pc, unused_handler 90 | ldr pc, irq_handler 91 | ldr pc, fiq_handler 92 | reset_handler: .word reset 93 | undefined_handler: .word hang 94 | swi_handler: .word hang 95 | prefetch_handler: .word hang 96 | data_handler: .word hang 97 | unused_handler: .word hang 98 | irq_handler: .word irq 99 | fiq_handler: .word hang 100 | 101 | 102 | -------------------------------------------------------------------------------- /qemu-raspi2/timer01/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern void enable_irq(void); 5 | extern void disable_irq(void); 6 | extern void io_halt(void); 7 | 8 | // Memory-Mapped I/O output 9 | static inline void mmio_write(uint32_t reg, uint32_t data) 10 | { 11 | *(volatile uint32_t*)reg = data; 12 | } 13 | 14 | // Memory-Mapped I/O input 15 | static inline uint32_t mmio_read(uint32_t reg) 16 | { 17 | return *(volatile uint32_t*)reg; 18 | } 19 | 20 | #define UART0_DR 0x3F201000 21 | #define UART0_FR 0x3F201018 22 | #define UART0_IMSC 0x3F201038 23 | 24 | void uart_putc(unsigned char c) 25 | { 26 | // Wait for UART to become ready to transmit. 27 | while ( mmio_read(UART0_FR) & (1 << 5) ) { } 28 | mmio_write(UART0_DR, c); 29 | } 30 | 31 | void uart_puts(const char* str) 32 | { 33 | for (size_t i = 0; str[i] != '\0'; i ++) 34 | uart_putc((unsigned char)str[i]); 35 | } 36 | 37 | void uart_hex_puts(uint32_t num) 38 | { 39 | int n = 0; 40 | uint32_t base = 16; 41 | uint32_t d = 1; 42 | char buf[16], *bf; 43 | 44 | bf = buf; 45 | *bf++ = '0'; 46 | *bf++ = 'x'; 47 | 48 | while ( num / d >= base) 49 | d *= base; 50 | 51 | while (d != 0) { 52 | int dgt = num / d; 53 | num %= d; 54 | d /= base; 55 | if (n || dgt > 0 || d == 0) { 56 | *bf++ = dgt + (dgt < 10 ? '0' : ('A') - 10); 57 | ++n; 58 | } 59 | } 60 | *bf++ = '\n'; 61 | *bf = 0; 62 | 63 | uart_puts(buf); 64 | } 65 | 66 | #define CORE0_TIMER_IRQCNTL 0x40000040 67 | #define CORE0_IRQ_SOURCE 0x40000060 68 | 69 | void routing_core0cntv_to_core0irq(void) 70 | { 71 | mmio_write(CORE0_TIMER_IRQCNTL, 0x08); 72 | } 73 | 74 | uint32_t read_core0timer_pending(void) 75 | { 76 | uint32_t tmp; 77 | tmp = mmio_read(CORE0_IRQ_SOURCE); 78 | return tmp; 79 | } 80 | 81 | static uint32_t cntfrq = 0; 82 | 83 | void enable_cntv(void) 84 | { 85 | uint32_t cntv_ctl; 86 | cntv_ctl = 1; 87 | asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL 88 | } 89 | 90 | void disable_cntv(void) 91 | { 92 | uint32_t cntv_ctl; 93 | cntv_ctl = 0; 94 | asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL 95 | } 96 | 97 | uint64_t read_cntvct(void) 98 | { 99 | uint64_t val; 100 | asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (val)); 101 | return (val); 102 | } 103 | 104 | uint64_t read_cntvoff(void) 105 | { 106 | uint64_t val; 107 | asm volatile("mrrc p15, 4, %Q0, %R0, c14" : "=r" (val)); 108 | return (val); 109 | } 110 | 111 | uint32_t read_cntv_tval(void) 112 | { 113 | uint32_t val; 114 | asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) ); 115 | return val; 116 | } 117 | 118 | void write_cntv_tval(uint32_t val) 119 | { 120 | asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) ); 121 | return; 122 | } 123 | 124 | uint32_t read_cntfrq(void) 125 | { 126 | uint32_t val; 127 | asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) ); 128 | return val; 129 | } 130 | 131 | void c_irq_handler(void) 132 | { 133 | if (read_core0timer_pending() & 0x08 ) { 134 | write_cntv_tval(cntfrq); // clear cntv interrupt and set next 1sec timer. 135 | 136 | uart_puts("core0timer_pendig : "); 137 | uart_hex_puts(read_core0timer_pending()); 138 | uart_puts("handler CNTV_TVAL : "); 139 | uart_hex_puts(read_cntv_tval()); 140 | uart_puts("handler CNTVCT : "); 141 | uart_hex_puts( (uint32_t) read_cntvct() & 0xFFFFFFFF); 142 | } 143 | return; 144 | } 145 | 146 | void kernel_main(void) 147 | { 148 | uint32_t val; 149 | 150 | uart_puts("timer01 : arm generic timer every 1 sec.\n"); 151 | uart_puts("exit : Ctrl-A x ,monitor : Ctrl-A c\n\n"); 152 | 153 | uart_puts("CNTFRQ : "); 154 | cntfrq = read_cntfrq(); 155 | uart_hex_puts(cntfrq); 156 | 157 | write_cntv_tval(cntfrq); // clear cntv interrupt and set next 1 sec timer. 158 | uart_puts("CNTV_TVAL: "); 159 | val = read_cntv_tval(); 160 | uart_hex_puts(val); 161 | 162 | routing_core0cntv_to_core0irq(); 163 | enable_cntv(); 164 | enable_irq(); 165 | 166 | while (1) { 167 | io_halt(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /qemu-raspi2/timer01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x8000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | -------------------------------------------------------------------------------- /qemu-raspi3/dma01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | boot.o: boot.S 14 | ${AS} ${ASM_FLAGS} -c $< -o $@ 15 | 16 | %.o : %.c Makefile 17 | $(CC) ${CFLAGS} -c -o $*.o $*.c 18 | 19 | run : 20 | $(MAKE) kernel.elf 21 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -kernel kernel.elf 22 | 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 26 | 27 | clean: 28 | rm -f *.o *.elf *.list 29 | 30 | .PHONY: clean 31 | -------------------------------------------------------------------------------- /qemu-raspi3/dma01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example DMA memory copy on QEMU raspi3 model. 3 | 4 | This program only supports QEMU raspi3 model, and does not work on real hardware. 5 | 6 | ``` 7 | $make run 8 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -kernel kernel.elf 9 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 10 | dma01 11 | c_irq_handler 12 | print destination string : hello world 13 | 14 | ``` 15 | -------------------------------------------------------------------------------- /qemu-raspi3/dma01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | 17 | // address for stack pointer 18 | ldr x1, =_start 19 | 20 | // drop to EL2 21 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 22 | msr scr_el3, x2 23 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 24 | msr spsr_el3, x2 25 | adr x2, start_el2 26 | msr elr_el3, x2 27 | eret 28 | 29 | start_el2: 30 | // set sp in EL1 31 | msr sp_el1, x1 32 | // enable AArch64 in EL1 33 | mov x0, #(1 << 31) // AArch64 34 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 35 | msr hcr_el2, x0 36 | mrs x0, hcr_el2 37 | // set vector address in EL1. 38 | ldr x0, =vector 39 | msr vbar_el1, x0 40 | // change execution level to EL1 41 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 42 | msr spsr_el2, x2 43 | adr x2, start_el1 44 | msr elr_el2, x2 45 | eret 46 | 47 | start_el1: 48 | // set sp 49 | mov sp, x1 50 | // Clear bss. 51 | ldr x1, =__bss_start 52 | ldr w2, =__bss_size 53 | 1: cbz w2, 2f 54 | str xzr, [x1], #8 55 | sub w2, w2, #1 56 | cbnz w2, 1b 57 | 58 | 2: bl kernel_main 59 | 60 | hang: 61 | wfi 62 | b hang 63 | 64 | .balign 2048 65 | vector: 66 | .balign 128 67 | b hang 68 | .balign 128 69 | stp x0, x1, [sp, #-16]! 70 | stp x2, x3, [sp, #-16]! 71 | stp x4, x5, [sp, #-16]! 72 | stp x6, x7, [sp, #-16]! 73 | stp x8, x9, [sp, #-16]! 74 | stp x10, x11, [sp, #-16]! 75 | stp x12, x13, [sp, #-16]! 76 | stp x14, x15, [sp, #-16]! 77 | stp x16, x17, [sp, #-16]! 78 | stp x18, x19, [sp, #-16]! 79 | // call c handler. 80 | bl c_irq_handler 81 | 82 | ldp x18, x19, [sp], #16 83 | ldp x16, x17, [sp], #16 84 | ldp x14, x15, [sp], #16 85 | ldp x12, x13, [sp], #16 86 | ldp x10, x11, [sp], #16 87 | ldp x8, x9, [sp], #16 88 | ldp x6, x7, [sp], #16 89 | ldp x4, x5, [sp], #16 90 | ldp x2, x3, [sp], #16 91 | ldp x0, x1, [sp], #16 92 | eret 93 | .balign 128 94 | b hang 95 | .balign 128 96 | b hang 97 | .balign 128 98 | b hang 99 | .balign 128 100 | b hang 101 | .balign 128 102 | b hang 103 | .balign 128 104 | b hang 105 | .balign 128 106 | b hang 107 | .balign 128 108 | b hang 109 | .balign 128 110 | b hang 111 | .balign 128 112 | b hang 113 | .balign 128 114 | b hang 115 | .balign 128 116 | b hang 117 | .balign 128 118 | b hang 119 | .balign 128 120 | b hang 121 | 122 | -------------------------------------------------------------------------------- /qemu-raspi3/dma01/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dma01 3 | * 4 | * BCM2835 ARM Peripherals 5 | * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf 6 | * 4 DMA Controller 7 | * 8 | * BCM2835 datasheet errata 9 | * https://elinux.org/BCM2835_datasheet_errata 10 | * 11 | * BCM2836 QA7 ARM Quad A7 core 12 | * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | static inline void io_halt(void) 19 | { 20 | asm volatile ("wfi"); 21 | } 22 | 23 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 24 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 25 | 26 | void uart_putchar(uint8_t c) 27 | { 28 | /* wait mini uart for tx idle. */ 29 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 30 | *AUX_MU_IO = c; 31 | } 32 | 33 | void uart_puts(const char* str) 34 | { 35 | for (size_t i = 0; str[i] != '\0'; i ++) 36 | uart_putchar((uint8_t)str[i]); 37 | } 38 | 39 | void uart_puthex(uint64_t v) 40 | { 41 | const char *hexdigits = "0123456789ABCDEF"; 42 | for (int i = 60; i >= 0; i -= 4) 43 | uart_putchar(hexdigits[(v >> i) & 0xf]); 44 | } 45 | 46 | typedef struct{ 47 | uint32_t transfer_information; 48 | uint32_t source_addr; 49 | uint32_t dest_addr; 50 | uint32_t transfer_length; 51 | uint32_t stride; 52 | uint32_t next_control_block; 53 | uint32_t dummy0; 54 | uint32_t dummy1; 55 | } DMA_CONTROLBLOCK __attribute__ ((aligned(32))); 56 | 57 | #define DMA_CH0_CTRL ((volatile uint32_t *)(0x3F007000)) 58 | #define DMA_CH0_ADDR ((volatile uint32_t *)(0x3F007004)) 59 | #define DMA_ENABLE ((volatile uint32_t *)(0x3F007FF0)) 60 | #define DMA_INT_STATUS ((volatile uint32_t *)(0x3F007FE0)) 61 | static uint8_t src[256] = "hello world\n"; 62 | static uint8_t dst[256] = { 0 }; 63 | DMA_CONTROLBLOCK dma_control_block; 64 | 65 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 66 | #define IRQ_PEND1 ((volatile uint32_t *)(0x3F00B204)) 67 | #define IRQ_ENABLE1 ((volatile uint32_t *)(0x3F00B210)) 68 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 69 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 70 | 71 | static inline void enable_irq(void) 72 | { 73 | asm volatile ("msr daifclr, #2"); 74 | } 75 | 76 | void c_irq_handler(void) 77 | { 78 | /* check inteerupt source */ 79 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 80 | if (*IRQ_BASIC & (1 << 8)) { 81 | if (*IRQ_PEND1 & (1 << 16)) { 82 | if (*DMA_CH0_CTRL & (1 << 2)) { 83 | *DMA_CH0_CTRL |= 1 << 2; /* clear INT */ 84 | uart_puts(" c_irq_handler\n"); 85 | uart_puts(" print destination string : "); 86 | uart_puts((const char *) dst); 87 | uart_puts("\n"); 88 | return; 89 | } 90 | } 91 | } 92 | } 93 | return; 94 | } 95 | 96 | void kernel_main(void) 97 | { 98 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 99 | uart_puts("dma01\n"); 100 | 101 | *DMA_INT_STATUS = 0; 102 | *DMA_ENABLE |= 1 << 0; /* enable DMA ch 0 */ 103 | 104 | *DMA_CH0_CTRL |= 1 << 31; /* set reset */ 105 | 106 | /* setup dma control block */ 107 | dma_control_block.transfer_information = 0; 108 | dma_control_block.transfer_information |= 1 << 26 | 1<< 8 | 1 << 4; /* no wide bursts, src increment, dest increment */ 109 | dma_control_block.source_addr = (intptr_t) src; 110 | dma_control_block.dest_addr = (intptr_t) dst; 111 | dma_control_block.next_control_block = 0; 112 | dma_control_block.stride = 0; 113 | dma_control_block.transfer_length = 256; /* Multiples of 4 */ 114 | dma_control_block.dummy0 = 0; 115 | dma_control_block.dummy1 = 0; 116 | 117 | /* interrupt */ 118 | *GPU_INTERRUPTS_ROUTING = 0x00; /* core0 */ 119 | *IRQ_ENABLE1 = 1 << 16; /* DMA CH0 */ 120 | enable_irq(); 121 | dma_control_block.transfer_information |= 1 << 0; /* INTEN */ 122 | 123 | /* kick dma */ 124 | *DMA_CH0_ADDR = (intptr_t) &dma_control_block; 125 | *DMA_CH0_CTRL |= 1 << 0; /* Active */ 126 | 127 | while (1) { 128 | io_halt(); 129 | } 130 | } 131 | 132 | -------------------------------------------------------------------------------- /qemu-raspi3/dma01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/framebuffer01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -kernel kernel.elf -d in_asm 27 | 28 | clean: 29 | rm -f *.o *.elf *.list 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /qemu-raspi3/framebuffer01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example draws framebuffer on QEMU raspi3 model. 3 | 4 | This program only supports QEMU raspi3 model, and does not work on real hardware. 5 | 6 | QEMU raspi3 model has default parameteor of frame buffer : 640 x 480 / 16 bpp . 7 | 8 | -------------------------------------------------------------------------------- /qemu-raspi3/framebuffer01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | 17 | // address for stack pointer 18 | ldr x1, =_start 19 | 20 | // drop to EL2 21 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 22 | msr scr_el3, x2 23 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 24 | msr spsr_el3, x2 25 | adr x2, start_el2 26 | msr elr_el3, x2 27 | eret 28 | 29 | start_el2: 30 | // set sp in EL1 31 | msr sp_el1, x1 32 | // enable AArch64 in EL1 33 | mov x0, #(1 << 31) // AArch64 34 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 35 | msr hcr_el2, x0 36 | mrs x0, hcr_el2 37 | // set vector address in EL1. 38 | ldr x0, =vector 39 | msr vbar_el1, x0 40 | // change execution level to EL1 41 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 42 | msr spsr_el2, x2 43 | adr x2, start_el1 44 | msr elr_el2, x2 45 | eret 46 | 47 | start_el1: 48 | // set sp 49 | mov sp, x1 50 | // Clear bss. 51 | ldr x1, =__bss_start 52 | ldr w2, =__bss_size 53 | 1: cbz w2, 2f 54 | str xzr, [x1], #8 55 | sub w2, w2, #1 56 | cbnz w2, 1b 57 | 58 | 2: bl kernel_main 59 | 60 | hang: 61 | wfi 62 | b hang 63 | 64 | .balign 4096 65 | vector: 66 | .balign 128 67 | b hang 68 | .balign 128 69 | b hang 70 | .balign 128 71 | b hang 72 | .balign 128 73 | b hang 74 | .balign 128 75 | b hang 76 | .balign 128 77 | b hang 78 | .balign 128 79 | b hang 80 | .balign 128 81 | b hang 82 | .balign 128 83 | b hang 84 | .balign 128 85 | b hang 86 | .balign 128 87 | b hang 88 | .balign 128 89 | b hang 90 | .balign 128 91 | b hang 92 | .balign 128 93 | b hang 94 | .balign 128 95 | b hang 96 | .balign 128 97 | b hang 98 | 99 | -------------------------------------------------------------------------------- /qemu-raspi3/framebuffer01/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static inline void io_halt(void) 5 | { 6 | asm volatile ("wfi"); 7 | } 8 | 9 | void boxfill8(uint16_t *vram, int xsize, uint16_t c, int x0, int y0, int x1, int y1) 10 | { 11 | int x, y; 12 | for (y = y0; y <= y1; y++) { 13 | for (x = x0; x <= x1; x++) 14 | vram[y * xsize + x] = c; 15 | } 16 | return; 17 | } 18 | 19 | #define COL8_000000 ( ((0x00>>3)<<11) + ((0x00>>3)<<6) + (0x00>>3)) 20 | #define COL8_008484 ( ((0x00>>3)<<11) + ((0x84>>3)<<6) + (0x84>>3)) 21 | #define COL8_848484 ( ((0x84>>3)<<11) + ((0x84>>3)<<6) + (0x84>>3)) 22 | #define COL8_C6C6C6 ( ((0xC6>>3)<<11) + ((0xC6>>3)<<6) + (0xC6>>3)) 23 | #define COL8_FFFFFF ( ((0xFF>>3)<<11) + ((0xFF>>3)<<6) + (0xFF>>3)) 24 | 25 | void kernel_main(void) 26 | { 27 | uint16_t *vram = (uint16_t *) 0x4100000; 28 | int x = 640 ,y = 480; 29 | 30 | boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); 31 | boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); 32 | boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); 33 | boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); 34 | 35 | boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); 36 | boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); 37 | boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); 38 | boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); 39 | boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); 40 | boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); 41 | 42 | boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); 43 | boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); 44 | boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); 45 | boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); 46 | 47 | while (1) 48 | io_halt(); 49 | } 50 | -------------------------------------------------------------------------------- /qemu-raspi3/framebuffer01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/int01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 27 | 28 | clean: 29 | rm -f *.o *.elf *.list 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /qemu-raspi3/int01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example uart rx interrupt on QEMU raspi3 model. 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | ``` 6 | $ make run 7 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 8 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 9 | int01 10 | a c_irq_handler 11 | b c_irq_handler 12 | c c_irq_handler 13 | ``` 14 | -------------------------------------------------------------------------------- /qemu-raspi3/int01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | ldr x1, =_start 18 | // drop to EL2. 19 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 20 | msr scr_el3, x2 21 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 22 | msr spsr_el3, x2 23 | adr x2, start_el2 24 | msr elr_el3, x2 25 | eret 26 | 27 | start_el2: 28 | // set sp in EL1. 29 | msr sp_el1, x1 30 | // enable AArch64 in EL1. 31 | mov x0, #(1 << 31) // AArch64 32 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 33 | msr hcr_el2, x0 34 | mrs x0, hcr_el2 35 | // set vector address in EL1. 36 | ldr x0, =vector 37 | msr vbar_el1, x0 38 | // change execution level to EL1. 39 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 40 | msr spsr_el2, x2 41 | adr x2, start_el1 42 | msr elr_el2, x2 43 | eret 44 | 45 | start_el1: 46 | // set sp 47 | mov sp, x1 48 | // clear bss. 49 | ldr x1, =__bss_start 50 | ldr w2, =__bss_size 51 | 1: cbz w2, 2f 52 | str xzr, [x1], #8 53 | sub w2, w2, #1 54 | cbnz w2, 1b 55 | 56 | 2: bl kernel_main 57 | 58 | hang: 59 | wfi 60 | b hang 61 | 62 | .globl enable_irq 63 | enable_irq: 64 | msr daifclr, #2 65 | ret 66 | 67 | .globl disable_irq 68 | disable_irq: 69 | msr daifset, #2 70 | ret 71 | 72 | .balign 2048 73 | vector: 74 | .balign 128 75 | b hang 76 | .balign 128 77 | stp x0, x1, [sp, #-16]! 78 | stp x2, x3, [sp, #-16]! 79 | stp x4, x5, [sp, #-16]! 80 | stp x6, x7, [sp, #-16]! 81 | stp x8, x9, [sp, #-16]! 82 | stp x10, x11, [sp, #-16]! 83 | stp x12, x13, [sp, #-16]! 84 | stp x14, x15, [sp, #-16]! 85 | stp x16, x17, [sp, #-16]! 86 | stp x18, x19, [sp, #-16]! 87 | // call c handler. 88 | bl c_irq_handler 89 | 90 | ldp x18, x19, [sp], #16 91 | ldp x16, x17, [sp], #16 92 | ldp x14, x15, [sp], #16 93 | ldp x12, x13, [sp], #16 94 | ldp x10, x11, [sp], #16 95 | ldp x8, x9, [sp], #16 96 | ldp x6, x7, [sp], #16 97 | ldp x4, x5, [sp], #16 98 | ldp x2, x3, [sp], #16 99 | ldp x0, x1, [sp], #16 100 | eret 101 | .balign 128 102 | b hang 103 | .balign 128 104 | b hang 105 | .balign 128 106 | b hang 107 | .balign 128 108 | b hang 109 | .balign 128 110 | b hang 111 | .balign 128 112 | b hang 113 | .balign 128 114 | b hang 115 | .balign 128 116 | b hang 117 | .balign 128 118 | b hang 119 | .balign 128 120 | b hang 121 | .balign 128 122 | b hang 123 | .balign 128 124 | b hang 125 | .balign 128 126 | b hang 127 | .balign 128 128 | b hang 129 | 130 | -------------------------------------------------------------------------------- /qemu-raspi3/int01/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * int01 3 | * 4 | * BCM2835 ARM Peripherals 5 | * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf 6 | * 7 | * BCM2835 datasheet errata 8 | * https://elinux.org/BCM2835_datasheet_errata 9 | * 10 | * BCM2836 QA7 ARM Quad A7 core 11 | * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | extern void enable_irq(void); 18 | extern void disable_irq(void); 19 | 20 | static inline void io_halt(void) 21 | { 22 | asm volatile ("wfi"); 23 | } 24 | 25 | #define UART0_DR ((volatile uint32_t *)(0x3F201000)) 26 | #define UART0_FR ((volatile uint32_t *)(0x3F201018)) 27 | #define UART0_IMSC ((volatile uint32_t *)(0x3F201038)) 28 | #define UART0_MIS ((volatile uint32_t *)(0x3F201040)) 29 | 30 | void uart_putc(unsigned char c) 31 | { 32 | // Wait for UART to become ready to transmit. 33 | while (*UART0_FR & (1 << 5)) { } 34 | *UART0_DR = c; 35 | } 36 | 37 | void uart_puts(const char* str) 38 | { 39 | for (size_t i = 0; str[i] != '\0'; i ++) 40 | uart_putc((unsigned char)str[i]); 41 | } 42 | 43 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 44 | #define IRQ_PEND2 ((volatile uint32_t *)(0x3F00B208)) 45 | #define IRQ_ENABLE2 ((volatile uint32_t *)(0x3F00B214)) 46 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 47 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 48 | 49 | void c_irq_handler(void) 50 | { 51 | char c; 52 | // check inteerupt source 53 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 54 | if (*IRQ_BASIC & (1 << 9)) { 55 | if (*IRQ_PEND2 & (1 << 25)) { 56 | if (*UART0_MIS & (1 << 4)) { 57 | c = (unsigned char) *UART0_DR; // read for clear tx interrupt. 58 | uart_putc(c); 59 | uart_puts(" c_irq_handler\n"); 60 | return; 61 | } 62 | } 63 | } 64 | } 65 | return; 66 | } 67 | 68 | void kernel_main(void) 69 | { 70 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 71 | uart_puts("int01\n"); 72 | 73 | // enable UART RX interrupt. 74 | *UART0_IMSC = 1 << 4; 75 | 76 | // UART interrupt routing. 77 | *IRQ_ENABLE2 = 1 << 25; 78 | 79 | // IRQ routeing to CORE0. 80 | *GPU_INTERRUPTS_ROUTING = 0x00; 81 | 82 | enable_irq(); 83 | 84 | while (1) { 85 | io_halt(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /qemu-raspi3/int01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/int02/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 27 | 28 | clean: 29 | rm -f *.o *.elf *.list 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /qemu-raspi3/int02/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example miniuart rx interrupt on QEMU raspi3 model. 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | ``` 6 | $ make run 7 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf 8 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 9 | int02 10 | a c_irq_handler 11 | b c_irq_handler 12 | c c_irq_handler 13 | ``` 14 | -------------------------------------------------------------------------------- /qemu-raspi3/int02/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | ldr x1, =_start 18 | // drop to EL2. 19 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 20 | msr scr_el3, x2 21 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 22 | msr spsr_el3, x2 23 | adr x2, start_el2 24 | msr elr_el3, x2 25 | eret 26 | 27 | start_el2: 28 | // set sp in EL1. 29 | msr sp_el1, x1 30 | // enable AArch64 in EL1. 31 | mov x0, #(1 << 31) // AArch64 32 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 33 | msr hcr_el2, x0 34 | mrs x0, hcr_el2 35 | // set vector address in EL1. 36 | ldr x0, =vector 37 | msr vbar_el1, x0 38 | // change execution level to EL1. 39 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 40 | msr spsr_el2, x2 41 | adr x2, start_el1 42 | msr elr_el2, x2 43 | eret 44 | 45 | start_el1: 46 | // set sp 47 | mov sp, x1 48 | // clear bss. 49 | ldr x1, =__bss_start 50 | ldr w2, =__bss_size 51 | 1: cbz w2, 2f 52 | str xzr, [x1], #8 53 | sub w2, w2, #1 54 | cbnz w2, 1b 55 | 56 | 2: bl kernel_main 57 | 58 | hang: 59 | wfi 60 | b hang 61 | 62 | .globl enable_irq 63 | enable_irq: 64 | msr daifclr, #2 65 | ret 66 | 67 | .globl disable_irq 68 | disable_irq: 69 | msr daifset, #2 70 | ret 71 | 72 | .balign 2048 73 | vector: 74 | .balign 128 75 | b hang 76 | .balign 128 77 | stp x0, x1, [sp, #-16]! 78 | stp x2, x3, [sp, #-16]! 79 | stp x4, x5, [sp, #-16]! 80 | stp x6, x7, [sp, #-16]! 81 | stp x8, x9, [sp, #-16]! 82 | stp x10, x11, [sp, #-16]! 83 | stp x12, x13, [sp, #-16]! 84 | stp x14, x15, [sp, #-16]! 85 | stp x16, x17, [sp, #-16]! 86 | stp x18, x19, [sp, #-16]! 87 | // call c handler. 88 | bl c_irq_handler 89 | 90 | ldp x18, x19, [sp], #16 91 | ldp x16, x17, [sp], #16 92 | ldp x14, x15, [sp], #16 93 | ldp x12, x13, [sp], #16 94 | ldp x10, x11, [sp], #16 95 | ldp x8, x9, [sp], #16 96 | ldp x6, x7, [sp], #16 97 | ldp x4, x5, [sp], #16 98 | ldp x2, x3, [sp], #16 99 | ldp x0, x1, [sp], #16 100 | eret 101 | .balign 128 102 | b hang 103 | .balign 128 104 | b hang 105 | .balign 128 106 | b hang 107 | .balign 128 108 | b hang 109 | .balign 128 110 | b hang 111 | .balign 128 112 | b hang 113 | .balign 128 114 | b hang 115 | .balign 128 116 | b hang 117 | .balign 128 118 | b hang 119 | .balign 128 120 | b hang 121 | .balign 128 122 | b hang 123 | .balign 128 124 | b hang 125 | .balign 128 126 | b hang 127 | .balign 128 128 | b hang 129 | 130 | -------------------------------------------------------------------------------- /qemu-raspi3/int02/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * int02 : mini uart rx interrupt 3 | * 4 | * BCM2835 ARM Peripherals 5 | * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf 6 | * 7 | * BCM2835 datasheet errata 8 | * https://elinux.org/BCM2835_datasheet_errata 9 | * 10 | * BCM2836 QA7 ARM Quad A7 core 11 | * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | extern void enable_irq(void); 18 | extern void disable_irq(void); 19 | 20 | static inline void io_halt(void) 21 | { 22 | asm volatile ("wfi"); 23 | } 24 | 25 | #define AUX_ENABLES ((volatile uint32_t *)(0x3F215004)) 26 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 27 | #define AUX_MU_IER ((volatile uint32_t *)(0x3F215044)) 28 | #define AUX_MU_IIR ((volatile uint32_t *)(0x3F215048)) 29 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 30 | 31 | void uart_putc(unsigned char c) 32 | { 33 | /* Wait for UART to become ready to transmit. */ 34 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 35 | *AUX_MU_IO = c; 36 | } 37 | 38 | void uart_puts(const char* str) 39 | { 40 | for (size_t i = 0; str[i] != '\0'; i ++) 41 | uart_putc((unsigned char)str[i]); 42 | } 43 | 44 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 45 | #define IRQ_PEND1 ((volatile uint32_t *)(0x3F00B204)) 46 | #define IRQ_ENABLE1 ((volatile uint32_t *)(0x3F00B210)) 47 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 48 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 49 | 50 | void c_irq_handler(void) 51 | { 52 | char c; 53 | /* check inteerupt source */ 54 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 55 | if (*IRQ_BASIC & (1 << 8)) { 56 | if (*IRQ_PEND1 & (1 << 29)) { 57 | c = *AUX_MU_IO; /* read for clear tx interrupt. */ 58 | uart_putc(c); 59 | uart_puts(" c_irq_handler\n"); 60 | } 61 | } 62 | } 63 | return; 64 | } 65 | 66 | void kernel_main(void) 67 | { 68 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 69 | uart_puts("int02\n"); 70 | 71 | /* enable UART RX interrupt. */ 72 | *AUX_ENABLES = 1; 73 | //*AUX_MU_IIR = 4; 74 | *AUX_MU_IER = 1; 75 | 76 | /* UART interrupt routing. */ 77 | *IRQ_ENABLE1 = 1 << 29; 78 | 79 | /* IRQ routeing to CORE0. */ 80 | *GPU_INTERRUPTS_ROUTING = 0x00; 81 | 82 | enable_irq(); 83 | 84 | while (1) { 85 | io_halt(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /qemu-raspi3/int02/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img -d in_asm 26 | 27 | clean: 28 | rm -f *.o *.elf *.list 29 | 30 | .PHONY: clean 31 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example sdhost init sdcard on QEMU raspi3 model. 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | ``` 6 | $ make run 7 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img 8 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 9 | sdhost01 10 | cmd 0 arg 0 11 | resp 0 0 0 0 12 | cmd 8 arg 1AA 13 | resp 0 0 0 1AA 14 | cmd 37 arg 0 15 | resp 0 0 0 120 16 | cmd 29 arg 51FF8000 17 | resp 0 0 0 80FFFF00 18 | cmd 2 arg 0 19 | resp AA585951 454D5521 1DEADBE EF006219 20 | ``` 21 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | 17 | // address for stack pointer 18 | ldr x1, =_start 19 | 20 | // drop to EL2 21 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 22 | msr scr_el3, x2 23 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 24 | msr spsr_el3, x2 25 | adr x2, start_el2 26 | msr elr_el3, x2 27 | eret 28 | 29 | start_el2: 30 | // set sp in EL1 31 | msr sp_el1, x1 32 | // enable AArch64 in EL1 33 | mov x0, #(1 << 31) // AArch64 34 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 35 | msr hcr_el2, x0 36 | mrs x0, hcr_el2 37 | // change execution level to EL1 38 | mov x2, #0x3c5 // D=1, A=1, I=1, F=1 M=EL1h 39 | msr spsr_el2, x2 40 | adr x2, start_el1 41 | msr elr_el2, x2 42 | eret 43 | 44 | start_el1: 45 | // set sp 46 | mov sp, x1 47 | // Clear bss. 48 | ldr x1, =__bss_start 49 | ldr w2, =__bss_size 50 | 1: cbz w2, 2f 51 | str xzr, [x1], #8 52 | sub w2, w2, #1 53 | cbnz w2, 1b 54 | 55 | 2: bl kernel_main 56 | 57 | hang: 58 | wfi 59 | b hang 60 | 61 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost01/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sdhost01.c : sdhost init sdcard 3 | */ 4 | #include 5 | #include 6 | 7 | static inline void io_halt(void) 8 | { 9 | asm volatile ("wfi"); 10 | } 11 | 12 | #define UART0_DR ((volatile uint32_t *)(0x3F201000)) 13 | #define UART0_FR ((volatile uint32_t *)(0x3F201018)) 14 | 15 | void uart_putc(uint8_t c) 16 | { 17 | // Wait for UART to become ready to transmit. 18 | while (*UART0_FR & (1 << 5)) { } 19 | *UART0_DR = c; 20 | } 21 | 22 | void uart_puts(const char *str) 23 | { 24 | for (size_t i = 0; str[i] != '\0'; i ++) 25 | uart_putc((uint8_t)str[i]); 26 | } 27 | 28 | void uart_hex(uint64_t num) 29 | { 30 | uint64_t n = 0; 31 | uint64_t base = 16; 32 | uint64_t d = 1; 33 | char buf[32], *bf; 34 | 35 | bf = buf; 36 | 37 | while ( num / d >= base) 38 | d *= base; 39 | 40 | while (d != 0) { 41 | uint64_t dgt = num / d; 42 | num %= d; 43 | d /= base; 44 | if (n || dgt > 0 || d == 0) { 45 | *bf++ = dgt + (dgt < 10 ? '0' : ('A') - 10); 46 | ++n; 47 | } 48 | } 49 | *bf = 0; 50 | 51 | uart_puts(buf); 52 | } 53 | 54 | //GPIO 55 | #define GPFSEL4 ((volatile uint32_t*)(0x3F200010)) 56 | #define GPFSEL5 ((volatile uint32_t*)(0x3F200014)) 57 | #define GPPUD ((volatile uint32_t*)(0x3F200094)) 58 | #define GPPUDCLK1 ((volatile uint32_t*)(0x3F20009C)) 59 | 60 | void wait_cycles(uint32_t n) 61 | { 62 | if(n) while(n--) { asm volatile("nop"); } 63 | } 64 | 65 | void wait_msec(uint32_t num) 66 | { 67 | (void) num; 68 | } 69 | 70 | #define SDCMD ((volatile uint32_t *)(0x3F202000)) 71 | #define SDCMD_NEW (1 << 15) 72 | #define SDCMD_FAIL (1 << 14) 73 | #define SDCMD_NORESP (1 << 10) 74 | #define SDCMD_LONGRESP (1 << 9) 75 | #define SDCMD_CMD_MASK 0x03FF 76 | #define SDARG ((volatile uint32_t *)(0x3F202004)) 77 | #define SDTOUT ((volatile uint32_t *)(0x3F202008)) 78 | #define SDCDIV ((volatile uint32_t *)(0x3F20200C)) 79 | #define SDRSP0 ((volatile uint32_t *)(0x3F202010)) 80 | #define SDRSP1 ((volatile uint32_t *)(0x3F202014)) 81 | #define SDRSP2 ((volatile uint32_t *)(0x3F202018)) 82 | #define SDRSP3 ((volatile uint32_t *)(0x3F20201C)) 83 | #define SDHSTS ((volatile uint32_t *)(0x3F202020)) 84 | #define SDVDD ((volatile uint32_t *)(0x3F202030)) 85 | #define SDEDM ((volatile uint32_t *)(0x3F202034)) 86 | #define SDVDD_POWER_ON 1 87 | #define SDVDD_POWER_OFF 0 88 | #define SDHCFG ((volatile uint32_t *)(0x3F202038)) 89 | #define SDHBCT ((volatile uint32_t *)(0x3F20203C)) 90 | #define HCFG_BUSY_IRPT_EN 0x400 91 | #define SDDATA ((volatile uint32_t *)(0x3F202040)) 92 | #define SDHBLC ((volatile uint32_t *)(0x3F202050)) 93 | 94 | #define CMD0 0x0000 95 | #define CMD2 0x0002 96 | #define CMD8 0x0008 97 | #define CMD55 0x0037 98 | #define ACMD41 0x0029 99 | 100 | #define SD_OK 0 101 | #define SD_ERROR -2 102 | 103 | static int32_t sd_err; 104 | 105 | uint64_t sdhost_cmd(uint16_t opcode, uint32_t arg) 106 | { 107 | uint64_t r; 108 | uint32_t sdcmd; 109 | 110 | uart_puts("cmd "); uart_hex(opcode); uart_puts(" arg "); uart_hex(arg); uart_putc('\n'); 111 | 112 | // wait busy 113 | 114 | // clear error flag 115 | 116 | *SDARG = arg; 117 | sdcmd = opcode & SDCMD_CMD_MASK; 118 | 119 | // set flag 120 | if (opcode == CMD0 ) { sdcmd |= SDCMD_NORESP; } else 121 | if (opcode == CMD2 ) { sdcmd |= SDCMD_LONGRESP; } 122 | 123 | // send command 124 | *SDCMD = sdcmd | SDCMD_NEW; 125 | 126 | // wait resp 127 | 128 | r = ((uint64_t) *SDRSP1 << 32) | *SDRSP0; 129 | uart_puts("resp "); uart_hex(*SDRSP3); uart_putc(' '); uart_hex(*SDRSP2); uart_putc(' '); uart_hex(*SDRSP1); uart_putc(' '); uart_hex(*SDRSP0); uart_putc('\n'); 130 | 131 | if (sdcmd & SDCMD_FAIL) { uart_puts("sdcmd fail\n"); sd_err = SD_ERROR; } 132 | 133 | return r; 134 | } 135 | 136 | void sdhost_init(void) 137 | { 138 | uint32_t r; 139 | 140 | // GPIO_CLK, GPIO_CMD 141 | r=*GPFSEL4; r|=(4<<(8*3))|(4<<(9*3)); *GPFSEL4=r; 142 | *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; 143 | 144 | // GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3 145 | r=*GPFSEL5; r|=(4<<(0*3)) | (4<<(1*3)) | (4<<(2*3)) | (4<<(3*3)); *GPFSEL5=r; 146 | *GPPUD=2; wait_cycles(150); 147 | *GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21); 148 | wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; 149 | 150 | // init hardware 151 | *SDVDD = SDVDD_POWER_OFF; 152 | *SDCMD = 0; 153 | *SDARG = 0; 154 | *SDTOUT = 0xF00000; 155 | *SDCDIV = 0; 156 | *SDHSTS = 0x7F8; 157 | *SDHCFG = 0; 158 | *SDHBCT = 0; 159 | *SDHBLC = 0; 160 | 161 | wait_msec(20); 162 | *SDVDD = SDVDD_POWER_ON; 163 | wait_msec(20); 164 | 165 | *SDHCFG = HCFG_BUSY_IRPT_EN; 166 | 167 | sdhost_cmd(CMD0, 0); 168 | 169 | sdhost_cmd(CMD8, 0x000001AA); 170 | 171 | sdhost_cmd(CMD55, 0); 172 | 173 | sdhost_cmd(ACMD41, 0x51FF8000); 174 | 175 | sdhost_cmd(CMD2, 0); 176 | } 177 | 178 | void kernel_main(void) 179 | { 180 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 181 | uart_puts("sdhost01\n"); 182 | 183 | sdhost_init(); 184 | 185 | while (1) { 186 | io_halt(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost01/sd.img: -------------------------------------------------------------------------------- 1 | SDCARD TEST IMAGE ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 2 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o: %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run: 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img -d in_asm 26 | 27 | trun: 28 | $(MAKE) kernel.elf 29 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img -trace events=events 30 | 31 | clean: 32 | rm -f *.o *.elf *.list 33 | 34 | .PHONY: clean 35 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example sdhost read sector from sdcard on QEMU raspi3 model. 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | 6 | ``` 7 | $ make run 8 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -drive if=sd,id=sd0,format=raw,file=sd.img 9 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 10 | sdhost02 11 | flg 0000000000008400 cmd 0000000000000000 arg 0000000000000000 12 | flg 0000000000008000 cmd 0000000000000008 arg 00000000000001AA 13 | resp 0000000000000000 0000000000000000 0000000000000000 00000000000001AA 14 | state 0000000000000000 APP_CMD 15 | flg 0000000000008000 cmd 0000000000000037 arg 0000000000000000 16 | resp 0000000000000000 0000000000000000 0000000000000000 0000000000000120 17 | state 0000000000000000 APP_CMD 18 | flg 0000000000008000 cmd 0000000000000029 arg 0000000051FF8000 19 | resp 0000000000000000 0000000000000000 0000000000000000 0000000080FFFF00 20 | flg 0000000000008200 cmd 0000000000000002 arg 0000000000000000 21 | resp 00000000AA585951 00000000454D5521 0000000001DEADBE 00000000EF006219 22 | flg 0000000000008000 cmd 0000000000000003 arg 0000000000000000 23 | resp 0000000000000000 0000000000000000 0000000000000000 0000000045670500 24 | state 0000000000000002 25 | flg 0000000000008800 cmd 0000000000000007 arg 0000000045670000 26 | resp 0000000000000000 0000000000000000 0000000000000000 0000000000000700 27 | state 0000000000000003 28 | flg 0000000000008000 cmd 0000000000000037 arg 0000000045670000 29 | resp 0000000000000000 0000000000000000 0000000000000000 0000000000000920 30 | state 0000000000000004 APP_CMD 31 | flg 0000000000008040 cmd 0000000000000033 arg 0000000000000000 32 | resp 0000000000000000 0000000000000000 0000000000000000 0000000000000920 33 | state 0000000000000004 APP_CMD 34 | SCR 0000000000002502 0000000000000000 35 | flg 0000000000008040 cmd 0000000000000011 arg 0000000000000000 36 | resp 0000000000000000 0000000000000000 0000000000000000 0000000000000900 37 | state 0000000000000004 38 | 000000000007FDF0: 53 44 43 41 52 44 20 54 45 53 54 20 49 4D 41 47 SDCARD TEST IMAG 39 | 000000000007FE00: 45 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E E ABCDEFGHIJKLMN 40 | 000000000007FE10: 4F 50 51 52 53 54 55 56 57 58 59 5A 20 41 42 43 OPQRSTUVWXYZ ABC 41 | 000000000007FE20: 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 DEFGHIJKLMNOPQRS 42 | 000000000007FE30: 54 55 56 57 58 59 5A 20 41 42 43 44 45 46 47 48 TUVWXYZ ABCDEFGH 43 | 000000000007FE40: 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 IJKLMNOPQRSTUVWX 44 | 000000000007FE50: 59 5A 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D YZ ABCDEFGHIJKLM 45 | 000000000007FE60: 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 20 41 42 NOPQRSTUVWXYZ AB 46 | 000000000007FE70: 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 CDEFGHIJKLMNOPQR 47 | 000000000007FE80: 53 54 55 56 57 58 59 5A 20 41 42 43 44 45 46 47 STUVWXYZ ABCDEFG 48 | 000000000007FE90: 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 HIJKLMNOPQRSTUVW 49 | 000000000007FEA0: 58 59 5A 20 41 42 43 44 45 46 47 48 49 4A 4B 4C XYZ ABCDEFGHIJKL 50 | 000000000007FEB0: 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 20 41 MNOPQRSTUVWXYZ A 51 | 000000000007FEC0: 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 BCDEFGHIJKLMNOPQ 52 | 000000000007FED0: 52 53 54 55 56 57 58 59 5A 20 41 42 43 44 45 46 RSTUVWXYZ ABCDEF 53 | 000000000007FEE0: 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 GHIJKLMNOPQRSTUV 54 | 000000000007FEF0: 57 58 59 5A 20 41 42 43 44 45 46 47 48 49 4A 4B WXYZ ABCDEFGHIJK 55 | 000000000007FF00: 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 20 LMNOPQRSTUVWXYZ 56 | 000000000007FF10: 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 ABCDEFGHIJKLMNOP 57 | 000000000007FF20: 51 52 53 54 55 56 57 58 59 5A 20 41 42 43 44 45 QRSTUVWXYZ ABCDE 58 | 000000000007FF30: 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 FGHIJKLMNOPQRSTU 59 | 000000000007FF40: 56 57 58 59 5A 20 41 42 43 44 45 46 47 48 49 4A VWXYZ ABCDEFGHIJ 60 | 000000000007FF50: 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A KLMNOPQRSTUVWXYZ 61 | 000000000007FF60: 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F ABCDEFGHIJKLMNO 62 | 000000000007FF70: 50 51 52 53 54 55 56 57 58 59 5A 20 41 42 43 44 PQRSTUVWXYZ ABCD 63 | 000000000007FF80: 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 EFGHIJKLMNOPQRST 64 | 000000000007FF90: 55 56 57 58 59 5A 20 41 42 43 44 45 46 47 48 49 UVWXYZ ABCDEFGHI 65 | 000000000007FFA0: 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 JKLMNOPQRSTUVWXY 66 | 000000000007FFB0: 5A 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E Z ABCDEFGHIJKLMN 67 | 000000000007FFC0: 4F 50 51 52 53 54 55 56 57 58 59 5A 20 41 42 43 OPQRSTUVWXYZ ABC 68 | 000000000007FFD0: 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 DEFGHIJKLMNOPQRS 69 | 000000000007FFE0: 54 55 56 57 58 59 5A 20 41 42 43 44 45 46 47 0A TUVWXYZ ABCDEFG. 70 | ``` 71 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | 17 | // address for stack pointer 18 | ldr x1, =_start 19 | 20 | // drop to EL2 21 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 22 | msr scr_el3, x2 23 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 24 | msr spsr_el3, x2 25 | adr x2, start_el2 26 | msr elr_el3, x2 27 | eret 28 | 29 | start_el2: 30 | // set sp in EL1 31 | msr sp_el1, x1 32 | // enable AArch64 in EL1 33 | mov x0, #(1 << 31) // AArch64 34 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 35 | msr hcr_el2, x0 36 | mrs x0, hcr_el2 37 | // change execution level to EL1 38 | mov x2, #0x3c5 // D=1, A=1, I=1, F=1 M=EL1h 39 | msr spsr_el2, x2 40 | adr x2, start_el1 41 | msr elr_el2, x2 42 | eret 43 | 44 | start_el1: 45 | // set sp 46 | mov sp, x1 47 | // Clear bss. 48 | ldr x1, =__bss_start 49 | ldr w2, =__bss_size 50 | 1: cbz w2, 2f 51 | str xzr, [x1], #8 52 | sub w2, w2, #1 53 | cbnz w2, 1b 54 | 55 | 2: bl kernel_main 56 | 57 | hang: 58 | wfi 59 | b hang 60 | 61 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/events: -------------------------------------------------------------------------------- 1 | sdcard_* 2 | sdbus_* 3 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sdhost02.c : read 1st sector from sdcard 3 | */ 4 | #include 5 | #include 6 | 7 | static inline void io_halt(void) 8 | { 9 | asm volatile ("wfi"); 10 | } 11 | 12 | #define UART0_DR ((volatile uint32_t *)(0x3F201000)) 13 | #define UART0_FR ((volatile uint32_t *)(0x3F201018)) 14 | 15 | void uart_putc(uint8_t c) 16 | { 17 | // Wait for UART to become ready to transmit. 18 | while (*UART0_FR & (1 << 5)) { } 19 | *UART0_DR = c; 20 | } 21 | 22 | void uart_puts(const char *str) 23 | { 24 | for (size_t i = 0; str[i] != '\0'; i ++) 25 | uart_putc((uint8_t)str[i]); 26 | } 27 | 28 | void uart_hex(uint64_t n) 29 | { 30 | const char *hexdigits = "0123456789ABCDEF"; 31 | for (int i = 60; i >= 0; i -= 4) 32 | uart_putc(hexdigits[(n >> i) & 0xf]); 33 | } 34 | 35 | void uart_dump(void *ptr) 36 | { 37 | uint64_t a,b,d; 38 | uint8_t c; 39 | for ( a =(uint64_t) ptr; a < (uint64_t) ptr + 512; a += 16) { 40 | uart_hex(a); uart_puts(": "); 41 | for(b = 0; b < 16; b++) { 42 | c = *((uint8_t *)(a + b)); 43 | d = (uint64_t) c; d >>= 4; d &= 0xF; d += d > 9 ? 0x37: 0x30; uart_putc(d); 44 | d = (uint64_t) c; d &= 0xF; d += d > 9 ? 0x37 : 0x30; uart_putc(d); 45 | uart_putc(' '); 46 | if(b % 4 == 3) 47 | uart_putc(' '); 48 | } 49 | for(b = 0; b < 16; b++) { 50 | c = *((uint8_t *)(a + b)); 51 | uart_putc(c < 32 || c >= 127 ? '.' : c); 52 | } 53 | uart_putc('\n'); 54 | } 55 | } 56 | 57 | // GPIO 58 | #define GPFSEL4 ((volatile uint32_t*)(0x3F200010)) 59 | #define GPFSEL5 ((volatile uint32_t*)(0x3F200014)) 60 | #define GPPUD ((volatile uint32_t*)(0x3F200094)) 61 | #define GPPUDCLK1 ((volatile uint32_t*)(0x3F20009C)) 62 | 63 | // wait 64 | void wait_cycles(uint32_t n) 65 | { 66 | if(n) while(n--) { asm volatile("nop"); } 67 | } 68 | 69 | void wait_msec(uint32_t num) 70 | { 71 | (void) num; 72 | } 73 | 74 | // SD 75 | #define SDCMD ((volatile uint32_t *)(0x3F202000)) 76 | #define SDCMD_NEW (1 << 15) 77 | #define SDCMD_FAIL (1 << 14) 78 | #define SDCMD_BUSYWAIT (1 << 11) 79 | #define SDCMD_NORESP (1 << 10) 80 | #define SDCMD_LONGRESP (1 << 9) 81 | #define SDCMD_WRITE (1 << 7) 82 | #define SDCMD_READ (1 << 6) 83 | #define SDCMD_CMD_MASK 0x03FF 84 | #define SDARG ((volatile uint32_t *)(0x3F202004)) 85 | #define SDTOUT ((volatile uint32_t *)(0x3F202008)) 86 | #define SDCDIV ((volatile uint32_t *)(0x3F20200C)) 87 | #define SDRSP0 ((volatile uint32_t *)(0x3F202010)) 88 | #define SDRSP1 ((volatile uint32_t *)(0x3F202014)) 89 | #define SDRSP2 ((volatile uint32_t *)(0x3F202018)) 90 | #define SDRSP3 ((volatile uint32_t *)(0x3F20201C)) 91 | #define SDHSTS ((volatile uint32_t *)(0x3F202020)) 92 | #define SDVDD ((volatile uint32_t *)(0x3F202030)) 93 | #define SDVDD_POWER_ON 1 94 | #define SDVDD_POWER_OFF 0 95 | #define SDEDM ((volatile uint32_t *)(0x3F202034)) 96 | #define SDHCFG ((volatile uint32_t *)(0x3F202038)) 97 | #define HCFG_BUSY_IRPT_EN (1 << 10) 98 | #define SDHBCT ((volatile uint32_t *)(0x3F20203C)) 99 | #define SDDATA ((volatile uint32_t *)(0x3F202040)) 100 | #define SDHBLC ((volatile uint32_t *)(0x3F202050)) 101 | 102 | #define CMD0 0x0000 103 | #define CMD2 0x0002 104 | #define CMD3 0x0003 105 | #define CMD7 0x0007 106 | #define CMD8 0x0008 107 | #define CMD17 0x0011 108 | #define CMD55 0x0037 109 | #define ACMD41 0x0029 110 | #define ACMD51 0x0033 111 | 112 | #define CMD3_RESP_RCA_MASK 0XFFFF0000 113 | 114 | #define SD_OK 0 115 | #define SD_ERROR -2 116 | 117 | static int32_t sd_err, sd_scr[2]; 118 | static uint64_t sd_rca; 119 | 120 | uint64_t sdhost_cmd(uint16_t opcode, uint32_t arg) 121 | { 122 | uint64_t r; 123 | uint32_t sdcmd; 124 | 125 | sd_err = SD_OK; 126 | 127 | // todo wait busy 128 | 129 | // clear error flag 130 | *SDARG = arg; 131 | 132 | // set opcode 133 | sdcmd = opcode & SDCMD_CMD_MASK; 134 | 135 | // set flag 136 | if (opcode == CMD0 ) { sdcmd |= SDCMD_NORESP; } else 137 | if (opcode == CMD2 ) { sdcmd |= SDCMD_LONGRESP; } else 138 | if (opcode == CMD7 ) { sdcmd |= SDCMD_BUSYWAIT; } else 139 | if (opcode == CMD17) { sdcmd |= SDCMD_READ; } 140 | if (opcode == ACMD51) { sdcmd |= SDCMD_READ; } 141 | 142 | // set byte count and block count 143 | if (opcode == CMD17 ) { *SDHBCT = 512; *SDHBLC = 1;} 144 | if (opcode == ACMD51) { *SDHBCT = 8; *SDHBLC = 1;} 145 | 146 | // send command 147 | sdcmd |= SDCMD_NEW; 148 | uart_puts("flg "); uart_hex(sdcmd & 0xFFC0); 149 | uart_puts(" cmd "); uart_hex(sdcmd & 0x3F); 150 | uart_puts(" arg "); uart_hex(arg); uart_putc('\n'); 151 | *SDCMD = sdcmd; 152 | 153 | // no resp 154 | if (sdcmd & SDCMD_NORESP) {return 0;} 155 | 156 | // todo wait resp 157 | 158 | // resp 159 | r = *SDRSP0; 160 | uart_puts("resp "); uart_hex(*SDRSP3); uart_putc(' '); uart_hex(*SDRSP2); uart_putc(' '); uart_hex(*SDRSP1); uart_putc(' '); uart_hex(*SDRSP0); uart_putc('\n'); 161 | 162 | // status check 163 | if (*SDCMD & SDCMD_FAIL) { uart_puts("sdcmd fail\n"); sd_err = SD_ERROR; return 0;} 164 | 165 | if (!(sdcmd & SDCMD_LONGRESP)) { 166 | if (opcode == CMD3 || 167 | opcode == CMD7 || 168 | opcode == CMD8 || 169 | opcode == CMD17 || 170 | opcode == CMD55 || 171 | opcode == ACMD51 ) { 172 | uart_puts("state "); uart_hex((r & 0x1E00) >> 9); 173 | if (r & 0x0020) { uart_puts(" APP_CMD "); } 174 | uart_putc('\n'); 175 | } 176 | } 177 | 178 | return r; 179 | } 180 | 181 | void sdhost_init(void) 182 | { 183 | uint32_t r; 184 | 185 | // GPIO_CLK, GPIO_CMD 186 | r=*GPFSEL4; r|=(4<<(8*3))|(4<<(9*3)); *GPFSEL4=r; 187 | *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; 188 | 189 | // GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3 190 | r=*GPFSEL5; r|=(4<<(0*3)) | (4<<(1*3)) | (4<<(2*3)) | (4<<(3*3)); *GPFSEL5=r; 191 | *GPPUD=2; wait_cycles(150); 192 | *GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21); 193 | wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; 194 | 195 | // init hardware 196 | *SDVDD = SDVDD_POWER_OFF; 197 | *SDCMD = 0; 198 | *SDARG = 0; 199 | *SDTOUT = 0xF00000; 200 | *SDCDIV = 0; 201 | *SDHSTS = 0x7F9; 202 | *SDHCFG = 0; 203 | *SDHBCT = 0; 204 | *SDHBLC = 0; 205 | 206 | // init fifo 207 | r = *SDEDM; 208 | r &= 0x1f << 9 | 0x1f << 4; 209 | r |= 4 << 9 | 4 << 4; 210 | *SDEDM = r; 211 | 212 | wait_msec(20); 213 | *SDVDD = SDVDD_POWER_ON; 214 | wait_msec(20); 215 | 216 | *SDHCFG = HCFG_BUSY_IRPT_EN; 217 | 218 | sdhost_cmd(CMD0, 0); 219 | 220 | sdhost_cmd(CMD8, 0x000001AA); 221 | 222 | sdhost_cmd(CMD55, 0); 223 | 224 | sdhost_cmd(ACMD41, 0x51FF8000); 225 | 226 | sdhost_cmd(CMD2, 0); 227 | 228 | sd_rca = CMD3_RESP_RCA_MASK & sdhost_cmd(CMD3, 0); 229 | } 230 | 231 | void sdhost_cardselect(void) 232 | { 233 | // card select 234 | sdhost_cmd(CMD7, (uint32_t) sd_rca); 235 | 236 | // read SCR 237 | sdhost_cmd(CMD55, (uint32_t) sd_rca); 238 | sdhost_cmd(ACMD51, 0); 239 | 240 | // todo check read status 241 | sd_scr[0] = *SDDATA; 242 | sd_scr[1] = *SDDATA; 243 | uart_puts("SCR "); 244 | uart_hex(sd_scr[0]); uart_putc(' '); 245 | uart_hex(sd_scr[1]); uart_putc(' '); 246 | uart_putc('\n'); 247 | } 248 | 249 | void sdhost_readblock(void) 250 | { 251 | uint32_t buf[128]; 252 | // read single block 253 | sdhost_cmd(CMD17, 0); 254 | 255 | // todo check read status 256 | for (size_t i = 0; i < 128; i++) { 257 | buf[i] = *SDDATA; 258 | } 259 | uart_dump(buf); 260 | } 261 | 262 | void kernel_main(void) 263 | { 264 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 265 | uart_puts("sdhost02\n"); 266 | 267 | sdhost_init(); 268 | sdhost_cardselect(); 269 | sdhost_readblock(); 270 | 271 | while (1) { 272 | io_halt(); 273 | } 274 | } 275 | 276 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdhost02/sd.img: -------------------------------------------------------------------------------- 1 | SDCARD TEST IMAGE ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 2 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-linux-gnu 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -sd sd.img 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -d in_asm -sd sd.img 27 | 28 | trun : 29 | $(MAKE) kernel.elf 30 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -sd sd.img -trace events=events 31 | 32 | clean: 33 | rm -f *.o *.elf *.list 34 | 35 | .PHONY: clean 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example sdio card select on QEMU raspi3 model. 3 | 4 | This program only supports QEMU raspi3 model, and does not work on real hardware. 5 | 6 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | 17 | // address for stack pointer 18 | ldr x1, =_start 19 | 20 | // drop to EL2 21 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 22 | msr scr_el3, x2 23 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 24 | msr spsr_el3, x2 25 | adr x2, start_el2 26 | msr elr_el3, x2 27 | eret 28 | 29 | start_el2: 30 | // set sp in EL1 31 | msr sp_el1, x1 32 | // enable AArch64 in EL1 33 | mov x0, #(1 << 31) // AArch64 34 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 35 | msr hcr_el2, x0 36 | mrs x0, hcr_el2 37 | // change execution level to EL1 38 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 39 | msr spsr_el2, x2 40 | adr x2, start_el1 41 | msr elr_el2, x2 42 | eret 43 | 44 | start_el1: 45 | // set sp 46 | mov sp, x1 47 | // Clear bss. 48 | ldr x1, =__bss_start 49 | ldr w2, =__bss_size 50 | 1: cbz w2, 2f 51 | str xzr, [x1], #8 52 | sub w2, w2, #1 53 | cbnz w2, 1b 54 | 55 | 2: bl kernel_main 56 | 57 | hang: 58 | wfi 59 | b hang 60 | 61 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/events: -------------------------------------------------------------------------------- 1 | sdcard_* 2 | sdbus_* 3 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static inline void io_halt(void) 5 | { 6 | asm volatile ("wfi"); 7 | } 8 | 9 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 10 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 11 | 12 | void uart_putchar(uint8_t c) 13 | { 14 | /* wait mini uart for tx idle. */ 15 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 16 | *AUX_MU_IO = c; 17 | } 18 | 19 | void uart_puts(const char* str) 20 | { 21 | for (size_t i = 0; str[i] != '\0'; i ++) 22 | uart_putchar((uint8_t)str[i]); 23 | } 24 | 25 | void uart_puthex(uint64_t v) 26 | { 27 | const char *hexdigits = "0123456789ABCDEF"; 28 | for (int i = 28; i >= 0; i -= 4) 29 | uart_putchar(hexdigits[(v >> i) & 0xf]); 30 | } 31 | 32 | #define SD_OK 0 33 | #define SD_TIMEOUT -1 34 | #define SD_ERROR -2 35 | 36 | /* EMMC registers */ 37 | #define EMMC_ARG1 ((volatile unsigned int*)(0x3F300008)) 38 | #define EMMC_CMDTM ((volatile unsigned int*)(0x3F30000C)) 39 | #define EMMC_RESP0 ((volatile unsigned int*)(0x3F300010)) 40 | #define EMMC_RESP1 ((volatile unsigned int*)(0x3F300014)) 41 | #define EMMC_RESP2 ((volatile unsigned int*)(0x3F300018)) 42 | #define EMMC_RESP3 ((volatile unsigned int*)(0x3F30001C)) 43 | #define EMMC_STATUS ((volatile unsigned int*)(0x3F300024)) 44 | #define EMMC_STATUS_CMD_INHIBIT 0x00000001 45 | #define EMMC_INTERRUPT ((volatile unsigned int*)(0x3F300030)) 46 | #define INT_DTO_ERROR 0x00100000 47 | #define INT_CTO_ERROR 0x00010000 48 | #define INT_CMD_DONE 0x00000001 49 | #define INT_ERROR_MASK 0x017E8000 50 | #define EMMC_CONTROL0 ((volatile unsigned int*)(0x3F300028)) 51 | #define EMMC_CONTROL1 ((volatile unsigned int*)(0x3F30002C)) 52 | #define C1_SRST_HC 0x01000000 53 | #define C1_TOUNIT_MAX 0x000e0000 54 | #define C1_CLK_EN 0x00000004 55 | #define C1_CLK_STABLE 0x00000002 56 | #define C1_CLK_INTLEN 0x00000001 57 | #define EMMC_IRPT_MASK ((volatile unsigned int*)(0x3F300034)) 58 | #define EMMC_IRPT_EN ((volatile unsigned int*)(0x3F300038)) 59 | 60 | /* command flags */ 61 | #define CMD_NEED_APP 0x80000000 62 | #define CMD_ERRORS_MASK 0xfff9c004 63 | #define CMD_RCA_MASK 0xffff0000 64 | 65 | /* sd commands */ 66 | #define CMD_GO_IDLE 0x00000000 67 | #define CMD_SEND_REL_ADDR 0x03020000 68 | #define CMD5 0x05020000 69 | #define CMD7 0x07020000 70 | #define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP) 71 | #define CMD_APP_CMD 0x37000000 72 | 73 | static uint32_t sd_err; 74 | static uint64_t sd_rca; 75 | 76 | void wait_msec(uint32_t num) 77 | { 78 | (void) num; 79 | } 80 | 81 | /* wait for command ready */ 82 | int32_t sdhci_status(uint32_t mask) 83 | { 84 | int cnt = 500000; 85 | 86 | while( (*EMMC_STATUS & mask) && 87 | !(*EMMC_INTERRUPT & INT_ERROR_MASK) && 88 | cnt--) { 89 | wait_msec(1); 90 | } 91 | return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK; 92 | } 93 | 94 | /* wait for interrupt */ 95 | int32_t sdhci_int(uint32_t mask) 96 | { 97 | uint32_t r; 98 | int cnt = 1000000; 99 | 100 | //wait interrupt 101 | while( !(*EMMC_INTERRUPT & (mask | INT_ERROR_MASK)) && cnt--) wait_msec(1); 102 | 103 | // if error occur then clear interrupt 104 | r = *EMMC_INTERRUPT; 105 | if(cnt <= 0 || (r & INT_CTO_ERROR) || (r & INT_DTO_ERROR) ) { *EMMC_INTERRUPT = r; return SD_TIMEOUT; } else 106 | if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT = r; return SD_ERROR; } 107 | *EMMC_INTERRUPT = mask; 108 | return SD_OK; 109 | } 110 | 111 | int32_t sdhci_set_clk(uint32_t f) 112 | { 113 | (void) f; 114 | *EMMC_CONTROL1 &= ~C1_CLK_EN; 115 | 116 | // todo setup clock divider 117 | 118 | *EMMC_CONTROL1 |= C1_CLK_EN; 119 | wait_msec(10); 120 | 121 | return SD_OK; 122 | } 123 | 124 | int64_t sdhci_cmd(uint32_t code, uint32_t arg) 125 | { 126 | uint64_t r = 0; 127 | 128 | sd_err = SD_OK; 129 | 130 | // need to send CMD_APP before ACMD* . 131 | if(code & CMD_NEED_APP) { 132 | r = sdhci_cmd(CMD_APP_CMD, 0); 133 | if (sd_err != SD_OK) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err = SD_ERROR;return 0;} 134 | code &= ~CMD_NEED_APP; 135 | } 136 | 137 | // check sd host status. 138 | if(sdhci_status(EMMC_STATUS_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err = SD_TIMEOUT;return 0;} 139 | 140 | // send comand 141 | uart_puts("EMMC: Sending command "); 142 | uart_puthex(code); uart_puts(" arg "); uart_puthex(arg); uart_putchar('\n'); 143 | *EMMC_INTERRUPT = *EMMC_INTERRUPT; // clear intterupt 144 | *EMMC_ARG1 = arg; 145 | *EMMC_CMDTM = code; 146 | 147 | // wait CMD_DONE 148 | if((r = sdhci_int(INT_CMD_DONE))) { uart_puts("ERROR: failed to send EMMC command\n"); sd_err = r;return 0;} 149 | 150 | // no resp 151 | if(code == CMD_GO_IDLE) return 0; 152 | if(code == CMD_APP_CMD) return 0; 153 | 154 | // todo wait for resp. 155 | 156 | // recieve resp 157 | r = *EMMC_RESP0; 158 | uart_puts("EMMC: resp "); uart_puthex(*EMMC_RESP0); uart_putchar(' '); uart_puthex(*EMMC_RESP1); uart_putchar(' '); uart_puthex(*EMMC_RESP2); uart_putchar('\n'); 159 | 160 | // check resp 161 | if(code == (CMD_SEND_OP_COND & ~CMD_NEED_APP)) { return r; } else 162 | if(code == CMD_SEND_REL_ADDR) { 163 | sd_err = (( r & 0x1fff) | ((r & 0x2000) << 6) | ((r & 0x4000) << 8) | ((r & 0x8000) << 8)) & CMD_ERRORS_MASK; 164 | return r & CMD_RCA_MASK; 165 | } 166 | 167 | return 0; 168 | } 169 | 170 | int32_t sdhci_init(void) 171 | { 172 | uint32_t cnt; 173 | 174 | // todo GPIO setting 175 | 176 | // reset host controller. 177 | *EMMC_CONTROL0 = 0; 178 | *EMMC_CONTROL1 |= C1_SRST_HC; 179 | cnt = 10000; do{ wait_msec(10); } while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- ); 180 | if(cnt<=0) { 181 | uart_puts("ERROR: failed to reset EMMC\n"); 182 | return SD_ERROR; 183 | } 184 | uart_puts("reset EMMC ok\n"); 185 | 186 | // internal clock enable, set timeout to max ( TMCLK * 2^27 ). 187 | *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX; 188 | 189 | // check initial clock stable 190 | cnt = 10000; do{ wait_msec(10); } while( (*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt-- ); 191 | 192 | // set clock to 400KHz 193 | sdhci_set_clk(400000); 194 | 195 | // clear all interrupt and remove all interrupt mask. 196 | *EMMC_IRPT_EN = 0xffffffff; 197 | *EMMC_IRPT_MASK = 0xffffffff; 198 | sd_rca = sd_err = 0; 199 | 200 | // send CMD0 GO_IDLE_STATE 201 | sdhci_cmd(CMD_GO_IDLE, 0); 202 | if(sd_err) return sd_err; 203 | 204 | // set voltage 205 | sdhci_cmd(CMD5,0); 206 | 207 | // get RCA 208 | sd_rca = sdhci_cmd(CMD_SEND_REL_ADDR,0); 209 | 210 | uart_puts("EMMC: CMD_SEND_REL_ADDR returned "); 211 | uart_puthex(sd_rca & 0xFFFFFFFF); 212 | uart_putchar(' '); 213 | uart_puthex(sd_rca>>32); 214 | uart_putchar('\n'); 215 | 216 | // card select 217 | sdhci_cmd(CMD7, (uint32_t) sd_rca); 218 | 219 | return SD_OK; 220 | } 221 | 222 | void kernel_main(void) 223 | { 224 | uart_puts("sdio01\n"); 225 | 226 | sdhci_init(); 227 | 228 | while (1) { 229 | io_halt(); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio01/sd.img: -------------------------------------------------------------------------------- 1 | SDCARD TEST IMAGE ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 2 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-linux-gnu 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -sd sd.img 23 | 24 | 25 | runasm : 26 | $(MAKE) kernel.elf 27 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -d in_asm -sd sd.img 28 | 29 | trun : 30 | $(MAKE) kernel.elf 31 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -sd sd.img -trace events=events 32 | 33 | clean: 34 | rm -f *.o *.elf *.list 35 | 36 | .PHONY: clean 37 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example sdio card select with interrupts on QEMU raspi3 model. 3 | 4 | This program only supports QEMU raspi3 model, and does not work on real hardware. 5 | 6 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | // Make _start global. 4 | .globl _start 5 | 6 | _start: 7 | // in QEMU all of 4 ARM CPUs are started simultaniously 8 | // by default. I don't know if this is the real hw behaviour, 9 | // but here I jump to halt if CPU ID (stored in MPIDR 10 | // register, first 2 bits) is not 0 11 | mrs x1, mpidr_el1 12 | and x1, x1, #3 13 | cmp x1, #0 14 | bne hang 15 | 16 | // address for stack pointer 17 | ldr x1, =_start 18 | 19 | // drop to EL2 20 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 21 | msr scr_el3, x2 22 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 23 | msr spsr_el3, x2 24 | adr x2, start_el2 25 | msr elr_el3, x2 26 | eret 27 | 28 | start_el2: 29 | // set sp in EL1 30 | msr sp_el1, x1 31 | // enable AArch64 in EL1 32 | mov x0, #(1 << 31) // AArch64 33 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 34 | msr hcr_el2, x0 35 | mrs x0, hcr_el2 36 | // set vector address in EL1. 37 | ldr x0, =vector 38 | msr vbar_el1, x0 39 | // change execution level to EL1 40 | mov x2, #0x3c5 // D=1, A=1, I=1, F=1 M=EL1h 41 | msr spsr_el2, x2 42 | adr x2, start_el1 43 | msr elr_el2, x2 44 | eret 45 | 46 | start_el1: 47 | // set sp 48 | mov sp, x1 49 | // Clear bss. 50 | ldr x1, =__bss_start 51 | ldr w2, =__bss_size 52 | 1: cbz w2, 2f 53 | str xzr, [x1], #8 54 | sub w2, w2, #1 55 | cbnz w2, 1b 56 | 57 | 2: bl kernel_main 58 | 59 | hang: 60 | wfi 61 | b hang 62 | 63 | .balign 2048 64 | vector: 65 | .balign 128 66 | eret 67 | .balign 128 68 | stp x0, x1, [sp, #-16]! 69 | stp x2, x3, [sp, #-16]! 70 | stp x4, x5, [sp, #-16]! 71 | stp x6, x7, [sp, #-16]! 72 | stp x8, x9, [sp, #-16]! 73 | stp x10, x11, [sp, #-16]! 74 | stp x12, x13, [sp, #-16]! 75 | stp x14, x15, [sp, #-16]! 76 | stp x16, x17, [sp, #-16]! 77 | stp x18, x19, [sp, #-16]! 78 | // call c handler. 79 | bl c_irq_handler 80 | 81 | ldp x18, x19, [sp], #16 82 | ldp x16, x17, [sp], #16 83 | ldp x14, x15, [sp], #16 84 | ldp x12, x13, [sp], #16 85 | ldp x10, x11, [sp], #16 86 | ldp x8, x9, [sp], #16 87 | ldp x6, x7, [sp], #16 88 | ldp x4, x5, [sp], #16 89 | ldp x2, x3, [sp], #16 90 | ldp x0, x1, [sp], #16 91 | eret 92 | .balign 128 93 | b hang 94 | .balign 128 95 | b hang 96 | .balign 128 97 | b hang 98 | .balign 128 99 | stp x0, x1, [sp, #-16]! 100 | stp x2, x3, [sp, #-16]! 101 | stp x4, x5, [sp, #-16]! 102 | stp x6, x7, [sp, #-16]! 103 | stp x8, x9, [sp, #-16]! 104 | stp x10, x11, [sp, #-16]! 105 | stp x12, x13, [sp, #-16]! 106 | stp x14, x15, [sp, #-16]! 107 | stp x16, x17, [sp, #-16]! 108 | stp x18, x19, [sp, #-16]! 109 | // call c handler. 110 | bl c_irq_handler 111 | 112 | ldp x18, x19, [sp], #16 113 | ldp x16, x17, [sp], #16 114 | ldp x14, x15, [sp], #16 115 | ldp x12, x13, [sp], #16 116 | ldp x10, x11, [sp], #16 117 | ldp x8, x9, [sp], #16 118 | ldp x6, x7, [sp], #16 119 | ldp x4, x5, [sp], #16 120 | ldp x2, x3, [sp], #16 121 | ldp x0, x1, [sp], #16 122 | eret 123 | .balign 128 124 | b hang 125 | .balign 128 126 | b hang 127 | .balign 128 128 | b hang 129 | .balign 128 130 | b hang 131 | .balign 128 132 | b hang 133 | .balign 128 134 | b hang 135 | .balign 128 136 | b hang 137 | .balign 128 138 | b hang 139 | .balign 128 140 | b hang 141 | .balign 128 142 | b hang 143 | 144 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/events: -------------------------------------------------------------------------------- 1 | sdhci_* 2 | sdcard_* 3 | sdbus_* 4 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static inline void io_halt(void) 5 | { 6 | asm volatile ("wfi"); 7 | } 8 | 9 | static inline void enable_irq(void) 10 | { 11 | asm volatile ("msr daifclr, #2"); 12 | } 13 | 14 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 15 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 16 | 17 | void uart_putchar(uint8_t c) 18 | { 19 | /* wait mini uart for tx idle. */ 20 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 21 | *AUX_MU_IO = c; 22 | } 23 | 24 | void uart_puts(const char* str) 25 | { 26 | for (size_t i = 0; str[i] != '\0'; i ++) 27 | uart_putchar((uint8_t)str[i]); 28 | } 29 | 30 | void uart_puthex(uint64_t v) 31 | { 32 | const char *hexdigits = "0123456789ABCDEF"; 33 | for (int i = 28; i >= 0; i -= 4) 34 | uart_putchar(hexdigits[(v >> i) & 0xf]); 35 | } 36 | 37 | #define SD_OK 0 38 | #define SD_TIMEOUT -1 39 | #define SD_ERROR -2 40 | 41 | /* EMMC registers */ 42 | #define EMMC_ARG1 ((volatile unsigned int*)(0x3F300008)) 43 | #define EMMC_CMDTM ((volatile unsigned int*)(0x3F30000C)) 44 | #define EMMC_RESP0 ((volatile unsigned int*)(0x3F300010)) 45 | #define EMMC_RESP1 ((volatile unsigned int*)(0x3F300014)) 46 | #define EMMC_RESP2 ((volatile unsigned int*)(0x3F300018)) 47 | #define EMMC_RESP3 ((volatile unsigned int*)(0x3F30001C)) 48 | #define EMMC_STATUS ((volatile unsigned int*)(0x3F300024)) 49 | #define EMMC_STATUS_CMD_INHIBIT 0x00000001 50 | #define EMMC_INTERRUPT ((volatile unsigned int*)(0x3F300030)) 51 | #define INT_DTO_ERROR 0x00100000 52 | #define INT_CTO_ERROR 0x00010000 53 | #define INT_CMD_DONE 0x00000001 54 | #define INT_ERROR_MASK 0x017E8000 55 | #define EMMC_CONTROL0 ((volatile unsigned int*)(0x3F300028)) 56 | #define EMMC_CONTROL1 ((volatile unsigned int*)(0x3F30002C)) 57 | #define C1_SRST_CMD 0x02000000 58 | #define C1_SRST_HC 0x01000000 59 | #define C1_TOUNIT_MAX 0x000e0000 60 | #define C1_CLK_EN 0x00000004 61 | #define C1_CLK_STABLE 0x00000002 62 | #define C1_CLK_INTLEN 0x00000001 63 | #define EMMC_IRPT_MASK ((volatile unsigned int*)(0x3F300034)) 64 | #define EMMC_IRPT_EN ((volatile unsigned int*)(0x3F300038)) 65 | 66 | /* command flags */ 67 | #define CMD_NEED_APP 0x80000000 68 | #define CMD_ERRORS_MASK 0xfff9c004 69 | #define CMD_RCA_MASK 0xffff0000 70 | 71 | /* sd commands */ 72 | #define CMD_GO_IDLE 0x00000000 73 | #define CMD_SEND_REL_ADDR 0x03020000 74 | #define CMD5 0x05020000 75 | #define CMD7 0x07020000 76 | #define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP) 77 | #define CMD_APP_CMD 0x37000000 78 | 79 | static uint32_t sd_err; 80 | static uint64_t sd_rca; 81 | static uint64_t flg = 0; 82 | 83 | void wait_msec(uint32_t num) 84 | { 85 | register unsigned long f, t, r; 86 | // get the current counter frequency 87 | asm volatile ("mrs %0, cntfrq_el0" : "=r"(f)); 88 | // read the current counter 89 | asm volatile ("mrs %0, cntpct_el0" : "=r"(t)); 90 | // calculate expire value for counter 91 | t += ((f / 1000) * num) / 1000; 92 | do { asm volatile ("mrs %0, cntpct_el0" : "=r"(r)); } while (r < t); 93 | } 94 | 95 | /* wait for command ready */ 96 | int32_t sdhci_status(uint32_t mask) 97 | { 98 | int cnt = 500000; 99 | 100 | while( (*EMMC_STATUS & mask) && 101 | !(*EMMC_INTERRUPT & INT_ERROR_MASK) && 102 | cnt--) { 103 | wait_msec(1); 104 | } 105 | return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK; 106 | } 107 | 108 | int32_t sdhci_set_clk(uint32_t f) 109 | { 110 | (void) f; 111 | *EMMC_CONTROL1 &= ~C1_CLK_EN; 112 | 113 | // todo setup clock divider 114 | 115 | *EMMC_CONTROL1 |= C1_CLK_EN; 116 | wait_msec(10); 117 | 118 | return SD_OK; 119 | } 120 | 121 | int64_t sdhci_cmd(uint32_t code, uint32_t arg) 122 | { 123 | uint32_t cnt; 124 | uint64_t r = 0; 125 | 126 | sd_err = SD_OK; 127 | 128 | // need to send CMD_APP before ACMD* . 129 | if(code & CMD_NEED_APP) { 130 | r = sdhci_cmd(CMD_APP_CMD, 0); 131 | if (sd_err != SD_OK) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err = SD_ERROR;return 0;} 132 | code &= ~CMD_NEED_APP; 133 | } 134 | 135 | // check sd host status. 136 | if(sdhci_status(EMMC_STATUS_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err = SD_TIMEOUT;return 0;} 137 | 138 | // send comand 139 | uart_puts("EMMC: Sending command "); 140 | uart_puthex(code); uart_puts(" arg "); uart_puthex(arg); uart_putchar('\n'); 141 | *EMMC_INTERRUPT = *EMMC_INTERRUPT; // clear intterupt 142 | *EMMC_ARG1 = arg; 143 | *EMMC_CMDTM = code; 144 | 145 | // wait CMD_DONE 146 | cnt = 10000; do{ wait_msec(10); } while( flg == 0 && cnt-- ); 147 | flg = 0; 148 | 149 | // no resp 150 | if(code == CMD_GO_IDLE) return 0; 151 | if(code == CMD_APP_CMD) return 0; 152 | 153 | // todo wait for resp. 154 | 155 | // recieve resp 156 | r = *EMMC_RESP0; 157 | uart_puts("EMMC: resp "); uart_puthex(*EMMC_RESP0); uart_putchar(' '); uart_puthex(*EMMC_RESP1); uart_putchar(' '); uart_puthex(*EMMC_RESP2); uart_putchar('\n'); 158 | 159 | // check resp 160 | if(code == (CMD_SEND_OP_COND & ~CMD_NEED_APP)) { return r; } else 161 | if(code == CMD_SEND_REL_ADDR) { 162 | sd_err = (( r & 0x1fff) | ((r & 0x2000) << 6) | ((r & 0x4000) << 8) | ((r & 0x8000) << 8)) & CMD_ERRORS_MASK; 163 | return r & CMD_RCA_MASK; 164 | } 165 | 166 | return 0; 167 | } 168 | 169 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 170 | #define IRQ_PEND2 ((volatile uint32_t *)(0x3F00B208)) 171 | #define IRQ_ENABLE2 ((volatile uint32_t *)(0x3F00B214)) 172 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 173 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 174 | 175 | void sdhci_handler(void) 176 | { 177 | uint32_t r = *EMMC_INTERRUPT; 178 | if ( r & INT_CMD_DONE ) { 179 | // if error occur then clear interrupt 180 | *EMMC_INTERRUPT = r; 181 | } 182 | uart_puts("sdhci_handler\n"); 183 | flg = 1; 184 | } 185 | 186 | void c_irq_handler(void) 187 | { 188 | // check inteerupt source 189 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 190 | if (*IRQ_BASIC & (1 << 9)) { 191 | if (*IRQ_PEND2 & (1 << 30)) { 192 | sdhci_handler(); 193 | } 194 | } 195 | } 196 | return; 197 | } 198 | 199 | int32_t sdhci_init(void) 200 | { 201 | uint32_t cnt; 202 | 203 | // todo GPIO setting 204 | 205 | // reset host controller. 206 | *EMMC_CONTROL0 = 0; 207 | *EMMC_CONTROL1 |= C1_SRST_HC; 208 | cnt = 10000; do{ wait_msec(10); } while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- ); 209 | if(cnt<=0) { 210 | uart_puts("ERROR: failed to reset EMMC\n"); 211 | return SD_ERROR; 212 | } 213 | uart_puts("reset EMMC ok\n"); 214 | 215 | // internal clock enable, set timeout to max ( TMCLK * 2^27 ). 216 | *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX; 217 | 218 | // check initial clock stable 219 | cnt = 10000; do{ wait_msec(10); } while( (*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt-- ); 220 | 221 | // set clock to 400KHz 222 | sdhci_set_clk(400000); 223 | 224 | // set interrupt mask. 225 | *EMMC_IRPT_EN = 0x00ff0003; 226 | *EMMC_IRPT_MASK = 0x00ff0003; 227 | 228 | sd_rca = sd_err = 0; 229 | 230 | // send CMD0 GO_IDLE_STATE 231 | sdhci_cmd(CMD_GO_IDLE, 0); 232 | if(sd_err) return sd_err; 233 | 234 | // set voltage 235 | sdhci_cmd(CMD5,0); 236 | 237 | // get RCA 238 | sd_rca = sdhci_cmd(CMD_SEND_REL_ADDR,0); 239 | 240 | uart_puts("EMMC: CMD_SEND_REL_ADDR returned "); 241 | uart_puthex(sd_rca & 0xFFFFFFFF); 242 | uart_putchar(' '); 243 | uart_puthex(sd_rca>>32); 244 | uart_putchar('\n'); 245 | 246 | // card select 247 | sdhci_cmd(CMD7, (uint32_t) sd_rca); 248 | 249 | return SD_OK; 250 | } 251 | 252 | void kernel_main(void) 253 | { 254 | uart_puts("sdio01\n"); 255 | 256 | // EMMC/SDHCI interrupt routing. 257 | *IRQ_ENABLE2 = 1 << 30; 258 | 259 | // IRQ routeing to CORE0. 260 | *GPU_INTERRUPTS_ROUTING = 0x00; 261 | 262 | enable_irq(); 263 | 264 | sdhci_init(); 265 | 266 | while (1) { 267 | io_halt(); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio02/sd.img: -------------------------------------------------------------------------------- 1 | SDCARD TEST IMAGE ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 2 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-linux-gnu 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | boot.o: boot.S 14 | ${AS} ${ASM_FLAGS} -c $< -o $@ 15 | 16 | %.o : %.c Makefile 17 | $(CC) ${CFLAGS} -c -o $*.o $*.c 18 | 19 | run : 20 | $(MAKE) kernel.elf 21 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -sd sd.img 22 | 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -d in_asm -sd sd.img 26 | 27 | trun : 28 | $(MAKE) kernel.elf 29 | qemu-system-aarch64 -M raspi3 -m 128 -serial null -serial mon:stdio -nographic -kernel kernel.elf -sd sd.img -trace events=events 30 | 31 | clean: 32 | rm -f *.o *.elf *.list 33 | 34 | .PHONY: clean 35 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example sdio CMD52 read / CMD53 read on QEMU raspi3 model. 3 | 4 | This program only supports modified QEMU raspi3 model, and does not work on real hardware. 5 | 6 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | // Make _start global. 4 | .globl _start 5 | 6 | _start: 7 | // in QEMU all of 4 ARM CPUs are started simultaniously 8 | // by default. I don't know if this is the real hw behaviour, 9 | // but here I jump to halt if CPU ID (stored in MPIDR 10 | // register, first 2 bits) is not 0 11 | mrs x1, mpidr_el1 12 | and x1, x1, #3 13 | cmp x1, #0 14 | bne hang 15 | 16 | // address for stack pointer 17 | ldr x1, =_start 18 | 19 | // drop to EL2 20 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 21 | msr scr_el3, x2 22 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 23 | msr spsr_el3, x2 24 | adr x2, start_el2 25 | msr elr_el3, x2 26 | eret 27 | 28 | start_el2: 29 | // set sp in EL1 30 | msr sp_el1, x1 31 | // enable AArch64 in EL1 32 | mov x0, #(1 << 31) // AArch64 33 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 34 | msr hcr_el2, x0 35 | mrs x0, hcr_el2 36 | // set vector address in EL1. 37 | ldr x0, =vector 38 | msr vbar_el1, x0 39 | // change execution level to EL1 40 | mov x2, #0x3c5 // D=1, A=1, I=1, F=1 M=EL1h 41 | msr spsr_el2, x2 42 | adr x2, start_el1 43 | msr elr_el2, x2 44 | eret 45 | 46 | start_el1: 47 | // set sp 48 | mov sp, x1 49 | // Clear bss. 50 | ldr x1, =__bss_start 51 | ldr w2, =__bss_size 52 | 1: cbz w2, 2f 53 | str xzr, [x1], #8 54 | sub w2, w2, #1 55 | cbnz w2, 1b 56 | 57 | 2: bl kernel_main 58 | 59 | hang: 60 | wfi 61 | b hang 62 | 63 | .balign 2048 64 | vector: 65 | .balign 128 66 | eret 67 | .balign 128 68 | stp x0, x1, [sp, #-16]! 69 | stp x2, x3, [sp, #-16]! 70 | stp x4, x5, [sp, #-16]! 71 | stp x6, x7, [sp, #-16]! 72 | stp x8, x9, [sp, #-16]! 73 | stp x10, x11, [sp, #-16]! 74 | stp x12, x13, [sp, #-16]! 75 | stp x14, x15, [sp, #-16]! 76 | stp x16, x17, [sp, #-16]! 77 | stp x18, x19, [sp, #-16]! 78 | // call c handler. 79 | bl c_irq_handler 80 | 81 | ldp x18, x19, [sp], #16 82 | ldp x16, x17, [sp], #16 83 | ldp x14, x15, [sp], #16 84 | ldp x12, x13, [sp], #16 85 | ldp x10, x11, [sp], #16 86 | ldp x8, x9, [sp], #16 87 | ldp x6, x7, [sp], #16 88 | ldp x4, x5, [sp], #16 89 | ldp x2, x3, [sp], #16 90 | ldp x0, x1, [sp], #16 91 | eret 92 | .balign 128 93 | b hang 94 | .balign 128 95 | b hang 96 | .balign 128 97 | b hang 98 | .balign 128 99 | stp x0, x1, [sp, #-16]! 100 | stp x2, x3, [sp, #-16]! 101 | stp x4, x5, [sp, #-16]! 102 | stp x6, x7, [sp, #-16]! 103 | stp x8, x9, [sp, #-16]! 104 | stp x10, x11, [sp, #-16]! 105 | stp x12, x13, [sp, #-16]! 106 | stp x14, x15, [sp, #-16]! 107 | stp x16, x17, [sp, #-16]! 108 | stp x18, x19, [sp, #-16]! 109 | // call c handler. 110 | bl c_irq_handler 111 | 112 | ldp x18, x19, [sp], #16 113 | ldp x16, x17, [sp], #16 114 | ldp x14, x15, [sp], #16 115 | ldp x12, x13, [sp], #16 116 | ldp x10, x11, [sp], #16 117 | ldp x8, x9, [sp], #16 118 | ldp x6, x7, [sp], #16 119 | ldp x4, x5, [sp], #16 120 | ldp x2, x3, [sp], #16 121 | ldp x0, x1, [sp], #16 122 | eret 123 | .balign 128 124 | b hang 125 | .balign 128 126 | b hang 127 | .balign 128 128 | b hang 129 | .balign 128 130 | b hang 131 | .balign 128 132 | b hang 133 | .balign 128 134 | b hang 135 | .balign 128 136 | b hang 137 | .balign 128 138 | b hang 139 | .balign 128 140 | b hang 141 | .balign 128 142 | b hang 143 | 144 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/events: -------------------------------------------------------------------------------- 1 | sdhci_* 2 | sdcard_* 3 | sdbus_* 4 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static inline void io_halt(void) 5 | { 6 | asm volatile ("wfi"); 7 | } 8 | 9 | static inline void enable_irq(void) 10 | { 11 | asm volatile ("msr daifclr, #2"); 12 | } 13 | 14 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 15 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 16 | 17 | void uart_putchar(uint8_t c) 18 | { 19 | /* wait mini uart for tx idle. */ 20 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 21 | *AUX_MU_IO = c; 22 | } 23 | 24 | void uart_puts(const char* str) 25 | { 26 | for (size_t i = 0; str[i] != '\0'; i ++) 27 | uart_putchar((uint8_t)str[i]); 28 | } 29 | 30 | void uart_puthex(uint64_t v) 31 | { 32 | const char *hexdigits = "0123456789ABCDEF"; 33 | for (int i = 28; i >= 0; i -= 4) 34 | uart_putchar(hexdigits[(v >> i) & 0xf]); 35 | } 36 | 37 | #define SD_OK 0 38 | #define SD_TIMEOUT -1 39 | #define SD_ERROR -2 40 | 41 | /* EMMC registers */ 42 | #define EMMC_BLKSIZECNT ((volatile unsigned int*)(0x3F300004)) 43 | #define EMMC_ARG1 ((volatile unsigned int*)(0x3F300008)) 44 | #define EMMC_CMDTM ((volatile unsigned int*)(0x3F30000C)) 45 | #define EMMC_RESP0 ((volatile unsigned int*)(0x3F300010)) 46 | #define EMMC_RESP1 ((volatile unsigned int*)(0x3F300014)) 47 | #define EMMC_RESP2 ((volatile unsigned int*)(0x3F300018)) 48 | #define EMMC_RESP3 ((volatile unsigned int*)(0x3F30001C)) 49 | #define EMMC_DATA ((volatile unsigned int*)(0x3F300020)) 50 | #define EMMC_STATUS ((volatile unsigned int*)(0x3F300024)) 51 | #define EMMC_STATUS_CMD_INHIBIT 0x00000001 52 | #define EMMC_INTERRUPT ((volatile unsigned int*)(0x3F300030)) 53 | #define INT_DTO_ERROR 0x00100000 54 | #define INT_CTO_ERROR 0x00010000 55 | #define INT_CMD_DONE 0x00000001 56 | #define INT_ERROR_MASK 0x017E8000 57 | #define EMMC_CONTROL0 ((volatile unsigned int*)(0x3F300028)) 58 | #define EMMC_CONTROL1 ((volatile unsigned int*)(0x3F30002C)) 59 | #define C1_SRST_DAT 0x04000000 60 | #define C1_SRST_CMD 0x02000000 61 | #define C1_SRST_HC 0x01000000 62 | #define C1_TOUNIT_MAX 0x000e0000 63 | #define C1_CLK_EN 0x00000004 64 | #define C1_CLK_STABLE 0x00000002 65 | #define C1_CLK_INTLEN 0x00000001 66 | #define EMMC_IRPT_MASK ((volatile unsigned int*)(0x3F300034)) 67 | #define EMMC_IRPT_EN ((volatile unsigned int*)(0x3F300038)) 68 | 69 | /* command flags */ 70 | #define CMD_NEED_APP 0x80000000 71 | #define CMD_ERRORS_MASK 0xfff9c004 72 | #define CMD_RCA_MASK 0xffff0000 73 | 74 | /* sd commands */ 75 | #define CMD_GO_IDLE 0x00000000 76 | #define CMD_SEND_REL_ADDR 0x03020000 77 | #define CMD5 0x05020000 78 | #define CMD7 0x07020000 79 | #define CMD_APP_CMD 0x37000000 80 | #define CMD52 0x34020000 81 | #define CMD53 0x35220010 82 | 83 | static uint32_t sd_err; 84 | static uint64_t sd_rca; 85 | static uint64_t flg = 0; 86 | 87 | void wait_msec(uint32_t num) 88 | { 89 | register unsigned long f, t, r; 90 | // get the current counter frequency 91 | asm volatile ("mrs %0, cntfrq_el0" : "=r"(f)); 92 | // read the current counter 93 | asm volatile ("mrs %0, cntpct_el0" : "=r"(t)); 94 | // calculate expire value for counter 95 | t += ((f / 1000) * num) / 1000; 96 | do { asm volatile ("mrs %0, cntpct_el0" : "=r"(r)); } while (r < t); 97 | } 98 | 99 | /* wait for command ready */ 100 | int32_t sdhci_status(uint32_t mask) 101 | { 102 | int cnt = 500000; 103 | 104 | while( (*EMMC_STATUS & mask) && 105 | !(*EMMC_INTERRUPT & INT_ERROR_MASK) && 106 | cnt--) { 107 | wait_msec(1); 108 | } 109 | return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK; 110 | } 111 | 112 | int32_t sdhci_set_clk(uint32_t f) 113 | { 114 | (void) f; 115 | *EMMC_CONTROL1 &= ~C1_CLK_EN; 116 | 117 | // todo setup clock divider 118 | 119 | *EMMC_CONTROL1 |= C1_CLK_EN; 120 | wait_msec(10); 121 | 122 | return SD_OK; 123 | } 124 | 125 | int64_t sdhci_cmd(uint32_t code, uint32_t arg) 126 | { 127 | uint32_t cnt; 128 | uint64_t r = 0; 129 | 130 | sd_err = SD_OK; 131 | 132 | // need to send CMD_APP before ACMD* . 133 | if(code & CMD_NEED_APP) { 134 | r = sdhci_cmd(CMD_APP_CMD, 0); 135 | if (sd_err != SD_OK) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err = SD_ERROR;return 0;} 136 | code &= ~CMD_NEED_APP; 137 | } 138 | 139 | // check sd host status. 140 | if(sdhci_status(EMMC_STATUS_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err = SD_TIMEOUT;return 0;} 141 | 142 | // send comand 143 | flg = 0; 144 | uart_puts("EMMC: Sending command "); 145 | uart_puthex(code); uart_puts(" arg "); uart_puthex(arg); uart_putchar('\n'); 146 | *EMMC_INTERRUPT = *EMMC_INTERRUPT; // clear intterupt 147 | *EMMC_ARG1 = arg; 148 | *EMMC_CMDTM = code; 149 | 150 | // wait CMD_DONE 151 | cnt = 10000; do{ wait_msec(10); } while( flg == 0 && cnt-- ); 152 | flg = 0; 153 | 154 | // no resp 155 | if(code == CMD_GO_IDLE) return 0; 156 | if(code == CMD_APP_CMD) return 0; 157 | 158 | // todo wait for resp. 159 | 160 | // recieve resp 161 | r = *EMMC_RESP0; 162 | uart_puts("EMMC: resp "); uart_puthex(*EMMC_RESP0); uart_putchar(' '); uart_puthex(*EMMC_RESP1); uart_putchar(' '); uart_puthex(*EMMC_RESP2); uart_putchar('\n'); 163 | 164 | // check resp 165 | if(code == CMD_SEND_REL_ADDR) { 166 | sd_err = (( r & 0x1fff) | ((r & 0x2000) << 6) | ((r & 0x4000) << 8) | ((r & 0x8000) << 8)) & CMD_ERRORS_MASK; 167 | return r & CMD_RCA_MASK; 168 | } 169 | 170 | return 0; 171 | } 172 | 173 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 174 | #define IRQ_PEND2 ((volatile uint32_t *)(0x3F00B208)) 175 | #define IRQ_ENABLE2 ((volatile uint32_t *)(0x3F00B214)) 176 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 177 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 178 | 179 | void sdhci_handler(void) 180 | { 181 | uint32_t r = *EMMC_INTERRUPT; 182 | if (r & INT_CMD_DONE) { 183 | // if error occur then clear interrupt 184 | *EMMC_INTERRUPT = r; 185 | } 186 | uart_puts("sdhci_handler\n"); 187 | flg = 1; 188 | } 189 | 190 | void c_irq_handler(void) 191 | { 192 | // check inteerupt source 193 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 194 | if (*IRQ_BASIC & (1 << 9)) { 195 | if (*IRQ_PEND2 & (1 << 30)) { 196 | sdhci_handler(); 197 | } 198 | } 199 | } 200 | return; 201 | } 202 | 203 | int32_t sdhci_init(void) 204 | { 205 | uint32_t cnt; 206 | 207 | // todo GPIO setting 208 | 209 | // reset host controller. 210 | *EMMC_CONTROL0 = 0; 211 | *EMMC_CONTROL1 |= C1_SRST_HC; 212 | cnt = 10000; do{ wait_msec(10); } while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- ); 213 | if(cnt<=0) { 214 | uart_puts("ERROR: failed to reset EMMC\n"); 215 | return SD_ERROR; 216 | } 217 | uart_puts("reset EMMC ok\n"); 218 | 219 | // internal clock enable, set timeout to max ( TMCLK * 2^27 ). 220 | *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX; 221 | 222 | // check initial clock stable 223 | cnt = 10000; do{ wait_msec(10); } while( (*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt-- ); 224 | 225 | // set clock to 400KHz 226 | sdhci_set_clk(400000); 227 | 228 | // set interrupt mask. 229 | *EMMC_IRPT_EN = 0x00ff0001; 230 | *EMMC_IRPT_MASK = 0x00ff0001; 231 | 232 | sd_rca = sd_err = 0; 233 | 234 | // send CMD0 GO_IDLE_STATE 235 | sdhci_cmd(CMD_GO_IDLE, 0); 236 | if(sd_err) return sd_err; 237 | 238 | // set voltage 239 | sdhci_cmd(CMD5,0); 240 | 241 | // get RCA 242 | sd_rca = sdhci_cmd(CMD_SEND_REL_ADDR,0); 243 | 244 | uart_puts("EMMC: CMD_SEND_REL_ADDR returned "); 245 | uart_puthex(sd_rca & 0xFFFFFFFF); 246 | uart_putchar(' '); 247 | uart_puthex(sd_rca>>32); 248 | uart_putchar('\n'); 249 | 250 | // card select 251 | sdhci_cmd(CMD7, (uint32_t) sd_rca); 252 | 253 | return SD_OK; 254 | } 255 | 256 | void kernel_main(void) 257 | { 258 | uint32_t i,arg; 259 | uint32_t r = 0; 260 | uart_puts("sdio01\n"); 261 | 262 | // EMMC/SDHCI interrupt routing. 263 | *IRQ_ENABLE2 = 1 << 30; 264 | 265 | // IRQ routeing to CORE0. 266 | *GPU_INTERRUPTS_ROUTING = 0x00; 267 | 268 | enable_irq(); 269 | 270 | sdhci_init(); 271 | 272 | /* read test */ 273 | sdhci_cmd(CMD52, 0); 274 | 275 | /* todo enable function 1 */ 276 | 277 | *EMMC_BLKSIZECNT = 64; 278 | /* cmd53 byte read test*/ 279 | arg = 0; 280 | arg |= 1 << 28; /* fn */ 281 | arg |= 1 << 27; /* mode */ 282 | arg |= 4; /* count */ 283 | sdhci_cmd(CMD53, arg); 284 | 285 | r = *EMMC_DATA; 286 | uart_puthex(r); 287 | uart_putchar('\n'); 288 | r = *EMMC_CONTROL1; 289 | 290 | /* cmd53 byte read test */ 291 | arg = 0; 292 | arg |= 1 << 28; /* fn */ 293 | arg |= 1 << 27; /* mode */ 294 | arg |= 4; /* count */ 295 | sdhci_cmd(CMD53, arg); 296 | 297 | r = *EMMC_DATA; 298 | uart_puthex(r&0xffffffff); 299 | uart_putchar('\n'); 300 | 301 | /* cmd53 single block read test */ 302 | arg = 0; 303 | arg |= 1 << 28; /* fn */ 304 | arg |= 0 << 27; /* mode */ 305 | arg |= 1; /* count */ 306 | sdhci_cmd(CMD53, arg); 307 | 308 | for (i = 0; i < 16; i++) { 309 | uart_puthex(*EMMC_DATA); 310 | uart_putchar('\n'); 311 | } 312 | 313 | /* cmd53 single block read test */ 314 | arg = 0; 315 | arg |= 1 << 28; /* fn */ 316 | arg |= 0 << 27; /* mode */ 317 | arg |= 1; /* count */ 318 | sdhci_cmd(CMD53, arg); 319 | 320 | for (i = 0; i < 16; i++) { 321 | uart_puthex(*EMMC_DATA); 322 | uart_putchar('\n'); 323 | } 324 | 325 | 326 | while (1) { 327 | io_halt(); 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/sdio03/sd.img: -------------------------------------------------------------------------------- 1 | SDCARD TEST IMAGE ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 2 | -------------------------------------------------------------------------------- /qemu-raspi3/task01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o asmfunc.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | boot.o: boot.S 14 | ${AS} ${ASM_FLAGS} -c $< -o $@ 15 | 16 | %.o : %.c Makefile 17 | $(CC) ${CFLAGS} -c -o $*.o $*.c 18 | 19 | run : 20 | $(MAKE) kernel.elf 21 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 22 | 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 26 | 27 | clean: 28 | rm -f *.o *.elf *.list 29 | 30 | .PHONY: clean 31 | -------------------------------------------------------------------------------- /qemu-raspi3/task01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example start another task on QEMU raspi3 model. 3 | 4 | This program only supports QEMU raspi3 model, and does not work on real hardware. 5 | 6 | ``` 7 | $ make run 8 | make kernel.elf 9 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 10 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 11 | task01 12 | 0000000000040000 13 | 000000000003FF00: B0 11 08 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 14 | 000000000003FF10: 28 28 28 28 28 28 28 28 29 29 29 29 29 29 29 29 (((((((()))))))) 15 | 000000000003FF20: 26 26 26 26 26 26 26 26 27 27 27 27 27 27 27 27 &&&&&&&&'''''''' 16 | 000000000003FF30: 24 24 24 24 24 24 24 24 25 25 25 25 25 25 25 25 $$$$$$$$%%%%%%%% 17 | 000000000003FF40: 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 """"""""######## 18 | 000000000003FF50: 20 20 20 20 20 20 20 20 21 21 21 21 21 21 21 21 !!!!!!!! 19 | 000000000003FF60: 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 ................ 20 | 000000000003FF70: 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 ................ 21 | 000000000003FF80: 14 14 14 14 14 14 14 14 15 15 15 15 15 15 15 15 ................ 22 | 000000000003FF90: 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 ................ 23 | 000000000003FFA0: 10 10 10 10 10 10 10 10 11 11 11 11 11 11 11 11 ................ 24 | 000000000003FFB0: 08 08 08 08 08 08 08 08 09 09 09 09 09 09 09 09 ................ 25 | 000000000003FFC0: 06 06 06 06 06 06 06 06 07 07 07 07 07 07 07 07 ................ 26 | 000000000003FFD0: 04 04 04 04 04 04 04 04 05 05 05 05 05 05 05 05 ................ 27 | 000000000003FFE0: 02 02 02 02 02 02 02 02 03 03 03 03 03 03 03 03 ................ 28 | 000000000003FFF0: 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 ................ 29 | 0000000000040000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 30 | 000000000003FF00 31 | task A 000000000007FFE0 32 | a c_irq_handler 33 | 000000000006FF40 34 | task B 000000000003FFF0 35 | b c_irq_handler 36 | 000000000006FF40 37 | ``` 38 | -------------------------------------------------------------------------------- /qemu-raspi3/task01/asmfunc.S: -------------------------------------------------------------------------------- 1 | 2 | .globl switch_task 3 | switch_task: 4 | 5 | /* switch sp */ 6 | mov sp, x0 7 | 8 | /* restore context */ 9 | ldp x30, xzr, [sp], #16 10 | ldp x28, x29, [sp], #16 11 | ldp x26, x27, [sp], #16 12 | ldp x24, x25, [sp], #16 13 | ldp x22, x23, [sp], #16 14 | ldp x20, x21, [sp], #16 15 | ldp x18, x19, [sp], #16 16 | ldp x16, x17, [sp], #16 17 | ldp x14, x15, [sp], #16 18 | ldp x12, x13, [sp], #16 19 | ldp x10, x11, [sp], #16 20 | ldp x8, x9, [sp], #16 21 | ldp x6, x7, [sp], #16 22 | ldp x4, x5, [sp], #16 23 | ldp x2, x3, [sp], #16 24 | ldp x0, x1, [sp], #16 25 | 26 | ret 27 | 28 | -------------------------------------------------------------------------------- /qemu-raspi3/task01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | //ldr x1, =_start 18 | ldr x1, =0x80000 19 | // drop to EL2. 20 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 21 | msr scr_el3, x2 22 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 23 | msr spsr_el3, x2 24 | adr x2, start_el2 25 | msr elr_el3, x2 26 | eret 27 | 28 | start_el2: 29 | // set sp in EL1. 30 | ldr x1, =0x70000 31 | msr sp_el1, x1 32 | ldr x1, =0x80000 33 | // enable AArch64 in EL1. 34 | mov x0, #(1 << 31) // AArch64 35 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 36 | msr hcr_el2, x0 37 | mrs x0, hcr_el2 38 | // set vector address in EL1. 39 | ldr x0, =vector 40 | msr vbar_el1, x0 41 | // change execution level to EL1. 42 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 43 | msr spsr_el2, x2 44 | adr x2, start_el1 45 | msr elr_el2, x2 46 | eret 47 | 48 | start_el1: 49 | // set sp 50 | mov sp, x1 51 | // clear bss. 52 | ldr x1, =__bss_start 53 | ldr w2, =__bss_size 54 | 1: cbz w2, 2f 55 | str xzr, [x1], #8 56 | sub w2, w2, #1 57 | cbnz w2, 1b 58 | 59 | 2: bl kernel_main 60 | 61 | hang: 62 | wfi 63 | b hang 64 | 65 | .globl enable_irq 66 | enable_irq: 67 | msr daifclr, #2 68 | ret 69 | 70 | .globl disable_irq 71 | disable_irq: 72 | msr daifset, #2 73 | ret 74 | 75 | .balign 2048 76 | vector: 77 | .balign 128 78 | b hang 79 | .balign 128 80 | stp x0, x1, [sp, #-16]! 81 | stp x2, x3, [sp, #-16]! 82 | stp x4, x5, [sp, #-16]! 83 | stp x6, x7, [sp, #-16]! 84 | stp x8, x9, [sp, #-16]! 85 | stp x10, x11, [sp, #-16]! 86 | stp x12, x13, [sp, #-16]! 87 | stp x14, x15, [sp, #-16]! 88 | stp x16, x17, [sp, #-16]! 89 | stp x18, x19, [sp, #-16]! 90 | // call c handler. 91 | bl c_irq_handler 92 | 93 | ldp x18, x19, [sp], #16 94 | ldp x16, x17, [sp], #16 95 | ldp x14, x15, [sp], #16 96 | ldp x12, x13, [sp], #16 97 | ldp x10, x11, [sp], #16 98 | ldp x8, x9, [sp], #16 99 | ldp x6, x7, [sp], #16 100 | ldp x4, x5, [sp], #16 101 | ldp x2, x3, [sp], #16 102 | ldp x0, x1, [sp], #16 103 | eret 104 | .balign 128 105 | b hang 106 | .balign 128 107 | b hang 108 | .balign 128 109 | b hang 110 | .balign 128 111 | b hang 112 | .balign 128 113 | b hang 114 | .balign 128 115 | b hang 116 | .balign 128 117 | b hang 118 | .balign 128 119 | b hang 120 | .balign 128 121 | b hang 122 | .balign 128 123 | b hang 124 | .balign 128 125 | b hang 126 | .balign 128 127 | b hang 128 | .balign 128 129 | b hang 130 | .balign 128 131 | b hang 132 | 133 | -------------------------------------------------------------------------------- /qemu-raspi3/task01/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * task01 : simple start another task. 3 | */ 4 | #include 5 | #include 6 | 7 | extern void enable_irq(void); 8 | extern void disable_irq(void); 9 | 10 | extern void switch_task(uint64_t *next_task_top_of_stack); 11 | void task_b(void); 12 | 13 | uint64_t *task_b_top_of_stack; 14 | int32_t switch_flg = 0; 15 | 16 | static inline void io_halt(void) 17 | { 18 | asm volatile ("wfi"); 19 | } 20 | 21 | #define UART0_DR ((volatile uint32_t *)(0x3F201000)) 22 | #define UART0_FR ((volatile uint32_t *)(0x3F201018)) 23 | #define UART0_IMSC ((volatile uint32_t *)(0x3F201038)) 24 | #define UART0_MIS ((volatile uint32_t *)(0x3F201040)) 25 | 26 | void uart_putc(unsigned char c) 27 | { 28 | // Wait for UART to become ready to transmit. 29 | while (*UART0_FR & (1 << 5)) { } 30 | *UART0_DR = c; 31 | } 32 | 33 | void uart_puts(const char* str) 34 | { 35 | for (size_t i = 0; str[i] != '\0'; i ++) 36 | uart_putc((unsigned char)str[i]); 37 | } 38 | 39 | void uart_puthex(uint64_t n) 40 | { 41 | const char *hexdigits = "0123456789ABCDEF"; 42 | for (int i = 60; i >= 0; i -= 4) 43 | uart_putc(hexdigits[(n >> i) & 0xf]); 44 | } 45 | 46 | void uart_dump(void *ptr) 47 | { 48 | uint64_t a,b,d; 49 | uint8_t c; 50 | for ( a =(uint64_t) ptr; a < (uint64_t) ptr + 256 + 16; a += 16) { 51 | uart_puthex(a); uart_puts(": "); 52 | for(b = 0; b < 16; b++) { 53 | c = *((uint8_t *)(a + b)); 54 | d = (uint64_t) c; d >>= 4; d &= 0xF; d += d > 9 ? 0x37: 0x30; uart_putc(d); 55 | d = (uint64_t) c; d &= 0xF; d += d > 9 ? 0x37 : 0x30; uart_putc(d); 56 | uart_putc(' '); 57 | if(b % 4 == 3) 58 | uart_putc(' '); 59 | } 60 | for(b = 0; b < 16; b++) { 61 | c = *((uint8_t *)(a + b)); 62 | uart_putc(c < 32 || c >= 127 ? '.' : c); 63 | } 64 | uart_putc('\n'); 65 | } 66 | } 67 | 68 | #define IRQ_PEND2 ((volatile uint32_t *)(0x3F00B208)) 69 | #define IRQ_ENABLE2 ((volatile uint32_t *)(0x3F00B214)) 70 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 71 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 72 | 73 | uint64_t get_sp(void) 74 | { 75 | uint64_t sp; 76 | asm volatile ("mov %0, sp" : "=r" (sp)); 77 | return sp; 78 | } 79 | 80 | void c_irq_handler(void) 81 | { 82 | char c; 83 | 84 | disable_irq(); 85 | // check inteerupt source 86 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 87 | if (*IRQ_PEND2 & (1 << 25)) { 88 | if (*UART0_MIS & (1 << 4)) { 89 | c = (unsigned char) *UART0_DR; // read for clear tx interrupt. 90 | enable_irq(); 91 | uart_putc(c); 92 | uart_puts(" c_irq_handler\n"); 93 | uart_puthex(get_sp()); uart_putc('\n'); 94 | switch_flg = 1; // set task_b start flag 95 | return; 96 | } 97 | } 98 | } 99 | enable_irq(); 100 | return; 101 | } 102 | 103 | uint64_t *setup_task_b_stack(void) 104 | { 105 | uint64_t *p = (uint64_t *) 0x40000; 106 | 107 | uart_puthex((uint64_t) p); 108 | uart_putc('\n'); 109 | 110 | /* prepare data in stack */ 111 | p--; 112 | *p = 0x0101010101010101ULL; /* x1 */ 113 | p--; 114 | *p = 0x00000000000000000LL; /* x0 */ 115 | p--; 116 | *p = 0x0303030303030303ULL; /* x3 */ 117 | p--; 118 | *p = 0x0202020202020202ULL; /* x2 */ 119 | p--; 120 | *p = 0x0505050505050505ULL; /* x5 */ 121 | p--; 122 | *p = 0x0404040404040404ULL; /* x4 */ 123 | p--; 124 | *p = 0x0707070707070707ULL; /* x7 */ 125 | p--; 126 | *p = 0x0606060606060606ULL; /* x6 */ 127 | p--; 128 | *p = 0x0909090909090909ULL; /* x9 */ 129 | p--; 130 | *p = 0x0808080808080808ULL; /* x8 */ 131 | p--; 132 | *p = 0x1111111111111111ULL; /* x11 */ 133 | p--; 134 | *p = 0x1010101010101010ULL; /* x10 */ 135 | p--; 136 | *p = 0x1313131313131313ULL; /* x13 */ 137 | p--; 138 | *p = 0x1212121212121212ULL; /* x12 */ 139 | p--; 140 | *p = 0x1515151515151515ULL; /* x15 */ 141 | p--; 142 | *p = 0x1414141414141414ULL; /* x14 */ 143 | p--; 144 | *p = 0x1717171717171717ULL; /* x17 */ 145 | p--; 146 | *p = 0x1616161616161616ULL; /* x16 */ 147 | p--; 148 | *p = 0x1919191919191919ULL; /* x19 */ 149 | p--; 150 | *p = 0x1818181818181818ULL; /* x18 */ 151 | p--; 152 | *p = 0x2121212121212121ULL; /* x21 */ 153 | p--; 154 | *p = 0x2020202020202020ULL; /* x20 */ 155 | p--; 156 | *p = 0x2323232323232323ULL; /* x23 */ 157 | p--; 158 | *p = 0x2222222222222222ULL; /* x22 */ 159 | p--; 160 | *p = 0x2525252525252525ULL; /* x25 */ 161 | p--; 162 | *p = 0x2424242424242424ULL; /* x24 */ 163 | p--; 164 | *p = 0x2727272727272727ULL; /* x27 */ 165 | p--; 166 | *p = 0x2626262626262626ULL; /* x26 */ 167 | p--; 168 | *p = 0x2929292929292929ULL; /* x29 */ 169 | p--; 170 | *p = 0x2828282828282828ULL; /* x28 */ 171 | p--; 172 | *p = ( uint64_t ) 0x00; /* xzr - has no effect, used so there are an even number of registers. */ 173 | p--; 174 | *p = ( uint64_t ) task_b; /* x30 - procedure call link register. */ 175 | 176 | uart_dump(p); 177 | uart_puthex((uint64_t) p); 178 | uart_putc('\n'); 179 | return p; 180 | } 181 | 182 | 183 | void task_b(void) 184 | { 185 | uart_puts("task B "); 186 | uart_puthex(get_sp()); uart_putc('\n'); 187 | switch_flg = 0; 188 | for (;;) { 189 | io_halt(); 190 | } 191 | } 192 | 193 | 194 | void kernel_main(void) 195 | { 196 | uint64_t *task_b_top_of_stack; 197 | 198 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 199 | uart_puts("task01\n"); 200 | 201 | // enable UART RX interrupt. 202 | *UART0_IMSC = 1 << 4; 203 | 204 | // UART interrupt routing. 205 | *IRQ_ENABLE2 = 1 << 25; 206 | 207 | // IRQ routeing to CORE0. 208 | *GPU_INTERRUPTS_ROUTING = 0x00; 209 | 210 | task_b_top_of_stack = setup_task_b_stack(); 211 | 212 | enable_irq(); 213 | 214 | uart_puts("task A "); 215 | uart_puthex(get_sp()); uart_putc('\n'); 216 | while (1) { 217 | if(switch_flg) { 218 | switch_task(task_b_top_of_stack); 219 | } else { 220 | io_halt(); 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /qemu-raspi3/task01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/task02/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o asmfunc.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | boot.o: boot.S 14 | ${AS} ${ASM_FLAGS} -c $< -o $@ 15 | 16 | %.o : %.c Makefile 17 | $(CC) ${CFLAGS} -c -o $*.o $*.c 18 | 19 | run : 20 | $(MAKE) kernel.elf 21 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 22 | 23 | runasm : 24 | $(MAKE) kernel.elf 25 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 26 | 27 | clean: 28 | rm -f *.o *.elf *.list 29 | 30 | .PHONY: clean 31 | -------------------------------------------------------------------------------- /qemu-raspi3/task02/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example switch task on QEMU raspi3 model. 3 | 4 | This program only supports QEMU raspi3 model, and does not work on real hardware. 5 | 6 | ``` 7 | $ make run 8 | make kernel.elf 9 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 10 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 11 | task02 12 | 0000000000040000 13 | 000000000003FF00: B0 11 08 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 14 | 000000000003FF10: 28 28 28 28 28 28 28 28 29 29 29 29 29 29 29 29 (((((((()))))))) 15 | 000000000003FF20: 26 26 26 26 26 26 26 26 27 27 27 27 27 27 27 27 &&&&&&&&'''''''' 16 | 000000000003FF30: 24 24 24 24 24 24 24 24 25 25 25 25 25 25 25 25 $$$$$$$$%%%%%%%% 17 | 000000000003FF40: 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 """"""""######## 18 | 000000000003FF50: 20 20 20 20 20 20 20 20 21 21 21 21 21 21 21 21 !!!!!!!! 19 | 000000000003FF60: 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 ................ 20 | 000000000003FF70: 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 ................ 21 | 000000000003FF80: 14 14 14 14 14 14 14 14 15 15 15 15 15 15 15 15 ................ 22 | 000000000003FF90: 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 ................ 23 | 000000000003FFA0: 10 10 10 10 10 10 10 10 11 11 11 11 11 11 11 11 ................ 24 | 000000000003FFB0: 08 08 08 08 08 08 08 08 09 09 09 09 09 09 09 09 ................ 25 | 000000000003FFC0: 06 06 06 06 06 06 06 06 07 07 07 07 07 07 07 07 ................ 26 | 000000000003FFD0: 04 04 04 04 04 04 04 04 05 05 05 05 05 05 05 05 ................ 27 | 000000000003FFE0: 02 02 02 02 02 02 02 02 03 03 03 03 03 03 03 03 ................ 28 | 000000000003FFF0: 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 ................ 29 | 0000000000040000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 30 | 000000000003FF00 31 | task A 000000000007FFC0 32 | a c_irq_handler 000000000006FF50 33 | task B 000000000003FFD0 34 | b c_irq_handler 000000000006FF50 35 | task A 000000000007FFC0 36 | c c_irq_handler 000000000006FF50 37 | task B 000000000003FFD0 38 | ``` 39 | -------------------------------------------------------------------------------- /qemu-raspi3/task02/asmfunc.S: -------------------------------------------------------------------------------- 1 | 2 | .globl switch_task 3 | switch_task: 4 | 5 | /* save context */ 6 | stp x0, x1, [sp, #-16]! 7 | stp x2, x3, [sp, #-16]! 8 | stp x4, x5, [sp, #-16]! 9 | stp x6, x7, [sp, #-16]! 10 | stp x8, x9, [sp, #-16]! 11 | stp x10, x11, [sp, #-16]! 12 | stp x12, x13, [sp, #-16]! 13 | stp x14, x15, [sp, #-16]! 14 | stp x16, x17, [sp, #-16]! 15 | stp x18, x19, [sp, #-16]! 16 | stp x20, x21, [sp, #-16]! 17 | stp x22, x23, [sp, #-16]! 18 | stp x24, x25, [sp, #-16]! 19 | stp x26, x27, [sp, #-16]! 20 | stp x28, x29, [sp, #-16]! 21 | stp x30, xzr, [sp, #-16]! 22 | 23 | /* store sp */ 24 | mov x19, sp 25 | str x19, [x0] 26 | 27 | /* switch sp */ 28 | ldr x19, [x1] 29 | mov sp, x19 30 | 31 | /* restore context */ 32 | ldp x30, xzr, [sp], #16 33 | ldp x28, x29, [sp], #16 34 | ldp x26, x27, [sp], #16 35 | ldp x24, x25, [sp], #16 36 | ldp x22, x23, [sp], #16 37 | ldp x20, x21, [sp], #16 38 | ldp x18, x19, [sp], #16 39 | ldp x16, x17, [sp], #16 40 | ldp x14, x15, [sp], #16 41 | ldp x12, x13, [sp], #16 42 | ldp x10, x11, [sp], #16 43 | ldp x8, x9, [sp], #16 44 | ldp x6, x7, [sp], #16 45 | ldp x4, x5, [sp], #16 46 | ldp x2, x3, [sp], #16 47 | ldp x0, x1, [sp], #16 48 | 49 | ret 50 | 51 | -------------------------------------------------------------------------------- /qemu-raspi3/task02/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | //ldr x1, =_start 18 | ldr x1, =0x80000 19 | // drop to EL2. 20 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 21 | msr scr_el3, x2 22 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 23 | msr spsr_el3, x2 24 | adr x2, start_el2 25 | msr elr_el3, x2 26 | eret 27 | 28 | start_el2: 29 | // set sp in EL1. 30 | ldr x1, =0x70000 31 | msr sp_el1, x1 32 | ldr x1, =0x80000 33 | // enable AArch64 in EL1. 34 | mov x0, #(1 << 31) // AArch64 35 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 36 | msr hcr_el2, x0 37 | mrs x0, hcr_el2 38 | // set vector address in EL1. 39 | ldr x0, =vector 40 | msr vbar_el1, x0 41 | // change execution level to EL1. 42 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 43 | msr spsr_el2, x2 44 | adr x2, start_el1 45 | msr elr_el2, x2 46 | eret 47 | 48 | start_el1: 49 | // set sp 50 | mov sp, x1 51 | // clear bss. 52 | ldr x1, =__bss_start 53 | ldr w2, =__bss_size 54 | 1: cbz w2, 2f 55 | str xzr, [x1], #8 56 | sub w2, w2, #1 57 | cbnz w2, 1b 58 | 59 | 2: bl kernel_main 60 | 61 | hang: 62 | wfi 63 | b hang 64 | 65 | .globl enable_irq 66 | enable_irq: 67 | msr daifclr, #2 68 | ret 69 | 70 | .globl disable_irq 71 | disable_irq: 72 | msr daifset, #2 73 | ret 74 | 75 | .balign 2048 76 | vector: 77 | .balign 128 78 | b hang 79 | .balign 128 80 | stp x0, x1, [sp, #-16]! 81 | stp x2, x3, [sp, #-16]! 82 | stp x4, x5, [sp, #-16]! 83 | stp x6, x7, [sp, #-16]! 84 | stp x8, x9, [sp, #-16]! 85 | stp x10, x11, [sp, #-16]! 86 | stp x12, x13, [sp, #-16]! 87 | stp x14, x15, [sp, #-16]! 88 | stp x16, x17, [sp, #-16]! 89 | stp x18, x19, [sp, #-16]! 90 | // call c handler. 91 | bl c_irq_handler 92 | 93 | ldp x18, x19, [sp], #16 94 | ldp x16, x17, [sp], #16 95 | ldp x14, x15, [sp], #16 96 | ldp x12, x13, [sp], #16 97 | ldp x10, x11, [sp], #16 98 | ldp x8, x9, [sp], #16 99 | ldp x6, x7, [sp], #16 100 | ldp x4, x5, [sp], #16 101 | ldp x2, x3, [sp], #16 102 | ldp x0, x1, [sp], #16 103 | eret 104 | .balign 128 105 | b hang 106 | .balign 128 107 | b hang 108 | .balign 128 109 | b hang 110 | .balign 128 111 | b hang 112 | .balign 128 113 | b hang 114 | .balign 128 115 | b hang 116 | .balign 128 117 | b hang 118 | .balign 128 119 | b hang 120 | .balign 128 121 | b hang 122 | .balign 128 123 | b hang 124 | .balign 128 125 | b hang 126 | .balign 128 127 | b hang 128 | .balign 128 129 | b hang 130 | .balign 128 131 | b hang 132 | 133 | -------------------------------------------------------------------------------- /qemu-raspi3/task02/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * task02 : simple switch task 3 | */ 4 | #include 5 | #include 6 | 7 | extern void enable_irq(void); 8 | extern void disable_irq(void); 9 | 10 | extern void switch_task(uint64_t **prev_task_top_of_stack, uint64_t **next_task_top_of_stack); 11 | void task_b(void); 12 | 13 | static uint64_t *task_a_top_of_stack; 14 | static uint64_t *task_b_top_of_stack; 15 | static int32_t switch_flg = 0; 16 | 17 | static inline void io_halt(void) 18 | { 19 | asm volatile ("wfi"); 20 | } 21 | 22 | #define UART0_DR ((volatile uint32_t *)(0x3F201000)) 23 | #define UART0_FR ((volatile uint32_t *)(0x3F201018)) 24 | #define UART0_IMSC ((volatile uint32_t *)(0x3F201038)) 25 | #define UART0_MIS ((volatile uint32_t *)(0x3F201040)) 26 | 27 | void uart_putc(unsigned char c) 28 | { 29 | // Wait for UART to become ready to transmit. 30 | while (*UART0_FR & (1 << 5)) { } 31 | *UART0_DR = c; 32 | } 33 | 34 | void uart_puts(const char* str) 35 | { 36 | for (size_t i = 0; str[i] != '\0'; i ++) 37 | uart_putc((unsigned char)str[i]); 38 | } 39 | 40 | void uart_puthex(uint64_t n) 41 | { 42 | const char *hexdigits = "0123456789ABCDEF"; 43 | for (int i = 60; i >= 0; i -= 4) 44 | uart_putc(hexdigits[(n >> i) & 0xf]); 45 | } 46 | 47 | void uart_dump(void *ptr) 48 | { 49 | uint64_t a,b,d; 50 | uint8_t c; 51 | for ( a =(uint64_t) ptr; a < (uint64_t) ptr + 256 + 16; a += 16) { 52 | uart_puthex(a); uart_puts(": "); 53 | for(b = 0; b < 16; b++) { 54 | c = *((uint8_t *)(a + b)); 55 | d = (uint64_t) c; d >>= 4; d &= 0xF; d += d > 9 ? 0x37: 0x30; uart_putc(d); 56 | d = (uint64_t) c; d &= 0xF; d += d > 9 ? 0x37 : 0x30; uart_putc(d); 57 | uart_putc(' '); 58 | if(b % 4 == 3) 59 | uart_putc(' '); 60 | } 61 | for(b = 0; b < 16; b++) { 62 | c = *((uint8_t *)(a + b)); 63 | uart_putc(c < 32 || c >= 127 ? '.' : c); 64 | } 65 | uart_putc('\n'); 66 | } 67 | } 68 | 69 | #define IRQ_PEND2 ((volatile uint32_t *)(0x3F00B208)) 70 | #define IRQ_ENABLE2 ((volatile uint32_t *)(0x3F00B214)) 71 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 72 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 73 | 74 | uint64_t get_sp(void) 75 | { 76 | uint64_t sp; 77 | asm volatile ("mov %0, sp" : "=r" (sp)); 78 | return sp; 79 | } 80 | 81 | void c_irq_handler(void) 82 | { 83 | char c; 84 | 85 | // check inteerupt source 86 | if (*CORE0_INTERRUPT_SOURCE & (1 << 8)) { 87 | if (*IRQ_PEND2 & (1 << 25)) { 88 | if (*UART0_MIS & (1 << 4)) { 89 | c = (unsigned char) *UART0_DR; // read for clear tx interrupt. 90 | uart_putc(c); 91 | uart_puts(" c_irq_handler "); 92 | uart_puthex(get_sp()); uart_putc('\n'); 93 | if (switch_flg == 0) { 94 | switch_flg = 1; 95 | } else if (switch_flg == 2 ) { 96 | switch_flg = 3; 97 | } 98 | return; 99 | } 100 | } 101 | } 102 | return; 103 | } 104 | 105 | uint64_t *setup_task_b_stack(void) 106 | { 107 | uint64_t *p = (uint64_t *) 0x40000; 108 | 109 | uart_puthex((uint64_t) p); 110 | uart_putc('\n'); 111 | 112 | /* prepare data in stack */ 113 | p--; 114 | *p = 0x0101010101010101ULL; /* x1 */ 115 | p--; 116 | *p = 0x00000000000000000LL; /* x0 */ 117 | p--; 118 | *p = 0x0303030303030303ULL; /* x3 */ 119 | p--; 120 | *p = 0x0202020202020202ULL; /* x2 */ 121 | p--; 122 | *p = 0x0505050505050505ULL; /* x5 */ 123 | p--; 124 | *p = 0x0404040404040404ULL; /* x4 */ 125 | p--; 126 | *p = 0x0707070707070707ULL; /* x7 */ 127 | p--; 128 | *p = 0x0606060606060606ULL; /* x6 */ 129 | p--; 130 | *p = 0x0909090909090909ULL; /* x9 */ 131 | p--; 132 | *p = 0x0808080808080808ULL; /* x8 */ 133 | p--; 134 | *p = 0x1111111111111111ULL; /* x11 */ 135 | p--; 136 | *p = 0x1010101010101010ULL; /* x10 */ 137 | p--; 138 | *p = 0x1313131313131313ULL; /* x13 */ 139 | p--; 140 | *p = 0x1212121212121212ULL; /* x12 */ 141 | p--; 142 | *p = 0x1515151515151515ULL; /* x15 */ 143 | p--; 144 | *p = 0x1414141414141414ULL; /* x14 */ 145 | p--; 146 | *p = 0x1717171717171717ULL; /* x17 */ 147 | p--; 148 | *p = 0x1616161616161616ULL; /* x16 */ 149 | p--; 150 | *p = 0x1919191919191919ULL; /* x19 */ 151 | p--; 152 | *p = 0x1818181818181818ULL; /* x18 */ 153 | p--; 154 | *p = 0x2121212121212121ULL; /* x21 */ 155 | p--; 156 | *p = 0x2020202020202020ULL; /* x20 */ 157 | p--; 158 | *p = 0x2323232323232323ULL; /* x23 */ 159 | p--; 160 | *p = 0x2222222222222222ULL; /* x22 */ 161 | p--; 162 | *p = 0x2525252525252525ULL; /* x25 */ 163 | p--; 164 | *p = 0x2424242424242424ULL; /* x24 */ 165 | p--; 166 | *p = 0x2727272727272727ULL; /* x27 */ 167 | p--; 168 | *p = 0x2626262626262626ULL; /* x26 */ 169 | p--; 170 | *p = 0x2929292929292929ULL; /* x29 */ 171 | p--; 172 | *p = 0x2828282828282828ULL; /* x28 */ 173 | p--; 174 | *p = ( uint64_t ) 0x00; /* xzr - has no effect, used so there are an even number of registers. */ 175 | p--; 176 | *p = ( uint64_t ) task_b; /* x30 - procedure call link register. */ 177 | 178 | uart_dump(p); 179 | uart_puthex((uint64_t) p); 180 | uart_putc('\n'); 181 | return p; 182 | } 183 | 184 | void task_b(void) 185 | { 186 | for (;;) { 187 | if (switch_flg == 1 ) { 188 | uart_puts("task B "); 189 | uart_puthex(get_sp()); uart_putc('\n'); 190 | switch_flg = 2; 191 | } else if(switch_flg == 3) { 192 | switch_task(&task_b_top_of_stack, &task_a_top_of_stack); 193 | } else { 194 | io_halt(); 195 | } 196 | } 197 | } 198 | 199 | void kernel_main(void) 200 | { 201 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 202 | uart_puts("task02\n"); 203 | 204 | // enable UART RX interrupt. 205 | *UART0_IMSC = 1 << 4; 206 | 207 | // UART interrupt routing. 208 | *IRQ_ENABLE2 = 1 << 25; 209 | 210 | // IRQ routeing to CORE0. 211 | *GPU_INTERRUPTS_ROUTING = 0x00; 212 | 213 | task_b_top_of_stack = setup_task_b_stack(); 214 | 215 | enable_irq(); 216 | 217 | uart_puts("task A "); 218 | uart_puthex(get_sp()); uart_putc('\n'); 219 | while (1) { 220 | if(switch_flg == 1) { 221 | switch_task(&task_a_top_of_stack, &task_b_top_of_stack); 222 | } else if (switch_flg == 3 ) { 223 | uart_puts("task A "); 224 | uart_puthex(get_sp()); uart_putc('\n'); 225 | switch_flg = 0; 226 | } else { 227 | io_halt(); 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /qemu-raspi3/task02/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/timer01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS = aarch64-none-elf 2 | CC = ${CROSS}-gcc 3 | AS = ${CROSS}-as 4 | OBJDUMP = ${CROSS}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf -d in_asm 27 | 28 | clean: 29 | rm -f *.o *.elf *.list 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /qemu-raspi3/timer01/README.md: -------------------------------------------------------------------------------- 1 | 2 | This simple example set generic timer to 1 sec on QEMU raspi3 model. 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | 6 | ``` 7 | $ make run 8 | qemu-system-aarch64 -M raspi3 -m 1024 -serial mon:stdio -nographic -kernel kernel.elf 9 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 10 | timer01 11 | CNTFRQ : 0x3B9ACA0 12 | CNTV_TVAL: 0x3B97F82 13 | handler CNTV_TVAL: 0xFFFDFFCB 14 | handler CNTVCT : 0x3C18444 15 | handler CNTV_TVAL: 0xFFFE14A5 16 | handler CNTVCT : 0x77D3EEA 17 | ``` 18 | -------------------------------------------------------------------------------- /qemu-raspi3/timer01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | 17 | // address for stack pointer 18 | ldr x1, =_start 19 | 20 | // drop to EL2 21 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 22 | msr scr_el3, x2 23 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 24 | msr spsr_el3, x2 25 | adr x2, start_el2 26 | msr elr_el3, x2 27 | eret 28 | 29 | start_el2: 30 | // set sp in EL1 31 | msr sp_el1, x1 32 | // enable AArch64 in EL1 33 | mov x0, #(1 << 31) // AArch64 34 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 35 | msr hcr_el2, x0 36 | mrs x0, hcr_el2 37 | // set vector address in EL1. 38 | ldr x0, =vector 39 | msr vbar_el1, x0 40 | // change execution level to EL1 41 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 42 | msr spsr_el2, x2 43 | adr x2, start_el1 44 | msr elr_el2, x2 45 | eret 46 | 47 | start_el1: 48 | // set sp 49 | mov sp, x1 50 | // Clear bss. 51 | ldr x1, =__bss_start 52 | ldr w2, =__bss_size 53 | 1: cbz w2, 2f 54 | str xzr, [x1], #8 55 | sub w2, w2, #1 56 | cbnz w2, 1b 57 | 58 | 2: bl kernel_main 59 | 60 | hang: 61 | wfi 62 | b hang 63 | 64 | .globl enable_irq 65 | enable_irq: 66 | msr daifclr, #2 67 | ret 68 | 69 | .globl disable_irq 70 | disable_irq: 71 | msr daifset, #2 72 | ret 73 | 74 | irq: 75 | stp x0, x1, [sp, #-16]! 76 | stp x2, x3, [sp, #-16]! 77 | stp x4, x5, [sp, #-16]! 78 | stp x6, x7, [sp, #-16]! 79 | stp x8, x9, [sp, #-16]! 80 | stp x10, x11, [sp, #-16]! 81 | stp x12, x13, [sp, #-16]! 82 | stp x14, x15, [sp, #-16]! 83 | stp x16, x17, [sp, #-16]! 84 | stp x18, x19, [sp, #-16]! 85 | 86 | bl c_irq_handler 87 | 88 | ldp x18, x19, [sp], #16 89 | ldp x16, x17, [sp], #16 90 | ldp x14, x15, [sp], #16 91 | ldp x12, x13, [sp], #16 92 | ldp x10, x11, [sp], #16 93 | ldp x8, x9, [sp], #16 94 | ldp x6, x7, [sp], #16 95 | ldp x4, x5, [sp], #16 96 | ldp x2, x3, [sp], #16 97 | ldp x0, x1, [sp], #16 98 | eret 99 | 100 | .balign 4096 101 | vector: 102 | .balign 128 103 | b hang 104 | .balign 128 105 | b irq 106 | .balign 128 107 | b hang 108 | .balign 128 109 | b hang 110 | .balign 128 111 | b hang 112 | .balign 128 113 | b irq 114 | .balign 128 115 | b hang 116 | .balign 128 117 | b hang 118 | .balign 128 119 | b hang 120 | .balign 128 121 | b irq 122 | .balign 128 123 | b hang 124 | .balign 128 125 | b hang 126 | .balign 128 127 | b hang 128 | .balign 128 129 | b irq 130 | .balign 128 131 | b hang 132 | .balign 128 133 | b hang 134 | 135 | -------------------------------------------------------------------------------- /qemu-raspi3/timer01/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * timer01 : simple generic timer 3 | */ 4 | #include 5 | #include 6 | 7 | extern void enable_irq(void); 8 | extern void disable_irq(void); 9 | 10 | // Memory-Mapped I/O output 11 | static inline void mmio_write(intptr_t reg, uint32_t data) 12 | { 13 | *(volatile uint32_t*) reg = data; 14 | } 15 | 16 | // Memory-Mapped I/O input 17 | static inline uint32_t mmio_read(intptr_t reg) 18 | { 19 | return *(volatile uint32_t*) reg; 20 | } 21 | 22 | static inline void io_halt(void) 23 | { 24 | asm volatile ("wfi"); 25 | } 26 | 27 | #define UART0_DR 0x3F201000 28 | #define UART0_FR 0x3F201018 29 | #define UART0_IMSC 0x3F201038 30 | 31 | void uart_putc(unsigned char c) 32 | { 33 | // Wait for UART to become ready to transmit. 34 | while (mmio_read(UART0_FR) & (1 << 5)) { } 35 | mmio_write(UART0_DR, c); 36 | } 37 | 38 | void uart_puts(const char* str) 39 | { 40 | for (size_t i = 0; str[i] != '\0'; i ++) 41 | uart_putc((unsigned char)str[i]); 42 | } 43 | 44 | void uart_hex_puts(uint64_t num) 45 | { 46 | int n = 0; 47 | uint64_t base = 16; 48 | uint64_t d = 1; 49 | char buf[32], *bf; 50 | 51 | bf = buf; 52 | *bf++ = '0'; 53 | *bf++ = 'x'; 54 | 55 | while ( num / d >= base) 56 | d *= base; 57 | 58 | while (d != 0) { 59 | int dgt = num / d; 60 | num %= d; 61 | d /= base; 62 | if (n || dgt > 0 || d == 0) { 63 | *bf++ = dgt + (dgt < 10 ? '0' : ('A') - 10); 64 | ++n; 65 | } 66 | } 67 | *bf++ = '\n'; 68 | *bf = 0; 69 | 70 | uart_puts(buf); 71 | } 72 | 73 | #define CORE0_TIMER_IRQCNTL 0x40000040 74 | #define CORE0_IRQ_SOURCE 0x40000060 75 | 76 | void routing_core0cntv_to_core0irq(void) 77 | { 78 | mmio_write(CORE0_TIMER_IRQCNTL, 0x08); 79 | } 80 | 81 | uint32_t read_core0timer_pending(void) 82 | { 83 | uint32_t tmp; 84 | tmp = mmio_read(CORE0_IRQ_SOURCE); 85 | return tmp; 86 | } 87 | 88 | static uint32_t cntfrq = 0; 89 | 90 | void enable_cntv(void) 91 | { 92 | uint32_t cntv_ctl; 93 | cntv_ctl = 1; 94 | asm volatile ("msr cntv_ctl_el0, %0" :: "r" (cntv_ctl)); 95 | } 96 | 97 | void disable_cntv(void) 98 | { 99 | uint32_t cntv_ctl; 100 | cntv_ctl = 0; 101 | asm volatile ("msr cntv_ctl_el0, %0" :: "r" (cntv_ctl)); 102 | } 103 | 104 | uint64_t read_cntvct(void) 105 | { 106 | uint64_t val; 107 | asm volatile("mrs %0, cntvct_el0" : "=r" (val)); 108 | return (val); 109 | } 110 | 111 | uint32_t read_cntv_tval(void) 112 | { 113 | uint32_t val; 114 | asm volatile ("mrs %0, cntv_tval_el0" : "=r" (val)); 115 | return val; 116 | } 117 | 118 | void write_cntv_tval(uint32_t val) 119 | { 120 | asm volatile ("msr cntv_tval_el0, %0" :: "r" (val)); 121 | return; 122 | } 123 | 124 | uint32_t read_cntfrq(void) 125 | { 126 | uint32_t val; 127 | asm volatile ("mrs %0, cntfrq_el0" : "=r" (val)); 128 | return val; 129 | } 130 | 131 | void c_irq_handler(void) 132 | { 133 | uint32_t cntvct; 134 | uint32_t val; 135 | 136 | disable_irq(); 137 | if (read_core0timer_pending() & 0x08 ) { 138 | uart_puts("handler CNTV_TVAL: "); 139 | val = read_cntv_tval(); 140 | uart_hex_puts(val); 141 | 142 | write_cntv_tval(cntfrq); // clear cntv interrupt and set next 1sec timer. 143 | 144 | uart_puts("handler CNTVCT : "); 145 | cntvct = read_cntvct(); 146 | uart_hex_puts(cntvct); 147 | } 148 | enable_irq(); 149 | return; 150 | } 151 | 152 | void kernel_main(void) 153 | { 154 | uint32_t val; 155 | 156 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 157 | uart_puts("timer01\n"); 158 | 159 | uart_puts("CNTFRQ : "); 160 | cntfrq = read_cntfrq(); 161 | uart_hex_puts(cntfrq); 162 | 163 | write_cntv_tval(cntfrq); // clear cntv interrupt and set next 1 sec timer. 164 | uart_puts("CNTV_TVAL: "); 165 | val = read_cntv_tval(); 166 | uart_hex_puts(val); 167 | 168 | routing_core0cntv_to_core0irq(); 169 | enable_cntv(); 170 | enable_irq(); 171 | 172 | while (1) { 173 | io_halt(); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /qemu-raspi3/timer01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/usb01/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = aarch64-none-elf 2 | CC = ${CROSS_COMPILE}-gcc 3 | AS = ${CROSS_COMPILE}-as 4 | OBJDUMP = ${CROSS_COMPILE}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -d in_asm 27 | 28 | trun : 29 | $(MAKE) kernel.elf 30 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -trace events=events 31 | 32 | clean: 33 | rm -f *.o *.elf *.list 34 | 35 | .PHONY: clean 36 | -------------------------------------------------------------------------------- /qemu-raspi3/usb01/README.md: -------------------------------------------------------------------------------- 1 | Simple example of USB host interrupt on QEMU raspi3 model. 2 | 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | ``` 6 | $ make run 7 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf 8 | usb01 9 | USB_CORE_GUID 00000000 10 | USB_CORE_GSNPSID 4F54294A 11 | HPRT 00021003 12 | 15000029 usb interrupt 13 | Connector ID Status Change 14 | ``` 15 | 16 | If you use QEMU built with trace, you can output traces. 17 | 18 | ``` 19 | $ make trun 20 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -trace events=events 21 | usb_port_claim bus 0, port 1 22 | usb_hub_reset dev 0 23 | usb_port_attach bus 0, port 1, devspeed full, portspeed full+high 24 | usb_dwc2_attach port 0x7fef57f7e7d0 25 | usb_dwc2_attach_speed full-speed device attached 26 | usb_dwc2_bus_start start SOFs 27 | usb_dwc2_raise_global_irq 0x01000000 28 | usb_port_claim bus 0, port 1.1 29 | usb_port_attach bus 0, port 1.1, devspeed full+high, portspeed full 30 | usb_hub_attach dev 0, port 1 31 | usb_dwc2_reset_enter === RESET enter === 32 | usb_dwc2_detach port 0x7fef57f7e7d0 33 | usb_dwc2_bus_stop stop SOFs 34 | usb_dwc2_bus_stop stop SOFs 35 | usb_dwc2_reset_hold === RESET hold === 36 | usb_dwc2_reset_exit === RESET exit === 37 | usb_dwc2_attach port 0x7fef57f7e7d0 38 | usb_dwc2_attach_speed full-speed device attached 39 | usb_dwc2_bus_start start SOFs 40 | usb_dwc2_raise_global_irq 0x01000000 41 | usb_hub_reset dev 0 42 | usb01 43 | usb_dwc2_raise_global_irq 0x00000008 44 | USB_CORE_GUID usb_dwc2_glbreg_read 0x003c GUID val 0x00000000 45 | 00000000 46 | USB_CORE_GSNPSID usb_dwc2_glbreg_read 0x0040 GSNPSID val 0x4f54294a 47 | 4F54294A 48 | HPRT usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021003 49 | 00021003 50 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021003 51 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021003 old 0x00021003 result 0x00021001 52 | usb_dwc2_hreg0_action disable PRTINT 53 | usb_dwc2_lower_global_irq 0x01000000 54 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021001 55 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021001 old 0x00021001 result 0x00021001 56 | usb_dwc2_hreg0_action disable PRTINT 57 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021001 58 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021101 old 0x00021001 result 0x00021101 59 | usb_dwc2_hreg0_action disable PRTINT 60 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021101 61 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021101 old 0x00021101 result 0x00021101 62 | usb_dwc2_hreg0_action disable PRTINT 63 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021101 64 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021105 old 0x00021101 result 0x00021101 65 | usb_dwc2_hreg0_action disable PRTINT 66 | usb_dwc2_glbreg_read 0x0008 GAHBCFG val 0x00000000 67 | usb_dwc2_glbreg_write 0x0008 GAHBCFG val 0x00000001 old 0x00000000 result 0x00000001 68 | usb_dwc2_glbreg_write 0x0018 GINTMSK val 0x10000000 old 0x00000000 result 0x10000000 69 | usb_dwc2_update_irq level=1 70 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x0000000a old 0x00021101 result 0x0002000d 71 | usb_dwc2_hreg0_action call usb_port_reset 72 | usb_dwc2_detach port 0x7fef57f7e7d0 73 | usb_dwc2_bus_stop stop SOFs 74 | usb_dwc2_raise_global_irq 0x01000000 75 | usb_dwc2_attach port 0x7fef57f7e7d0 76 | usb_dwc2_attach_speed full-speed device attached 77 | usb_dwc2_bus_start start SOFs 78 | usb_hub_reset dev 0 79 | usb_dwc2_hreg0_action enable PRTINT 80 | usb_dwc2_hreg1_read 0x0500 HCCHAR 40 val 0x00000000 81 | usb_dwc2_hreg1_write 0x0500 HCCHAR 0 val 0x80000000 old 0x00000000 result 0x80000000 82 | usb_dwc2_find_device 0 83 | usb_dwc2_device_found device found on port 0 84 | usb_dwc2_enable_chan ch 0 dev 0x55c602be63c0 pkt 0x7fef57f7e818 ep 0 85 | usb_dwc2_handle_packet ch 0 dev 0x55c602be63c0 pkt 0x7fef57f7e818 ep 0 type Ctrl dir Out mps 0 len 0 pcnt 0 86 | usb_dwc2_work_bh 87 | usb_dwc2_glbreg_read 0x0014 GINTSTS val 0x15000029 88 | usb_dwc2_glbreg_write 0x0014 GINTSTS val 0x15000029 old 0x15000029 result 0xffffffff05000021 89 | usb_dwc2_update_irq level=0 90 | 15000029 usb interrupt 91 | Connector ID Status Change 92 | usb_dwc2_raise_global_irq 0x00000008 93 | ``` 94 | -------------------------------------------------------------------------------- /qemu-raspi3/usb01/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | ldr x1, =_start 18 | // drop to EL2. 19 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 20 | msr scr_el3, x2 21 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 22 | msr spsr_el3, x2 23 | adr x2, start_el2 24 | msr elr_el3, x2 25 | eret 26 | 27 | start_el2: 28 | // set sp in EL1. 29 | msr sp_el1, x1 30 | // enable AArch64 in EL1. 31 | mov x0, #(1 << 31) // AArch64 32 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 33 | msr hcr_el2, x0 34 | mrs x0, hcr_el2 35 | // set vector address in EL1. 36 | ldr x0, =vector 37 | msr vbar_el1, x0 38 | // change execution level to EL1. 39 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 40 | msr spsr_el2, x2 41 | adr x2, start_el1 42 | msr elr_el2, x2 43 | eret 44 | 45 | start_el1: 46 | // set sp 47 | mov sp, x1 48 | // clear bss. 49 | ldr x1, =__bss_start 50 | ldr w2, =__bss_size 51 | 1: cbz w2, 2f 52 | str xzr, [x1], #8 53 | sub w2, w2, #1 54 | cbnz w2, 1b 55 | 56 | 2: bl kernel_main 57 | 58 | hang: 59 | wfi 60 | b hang 61 | 62 | .balign 2048 63 | vector: 64 | .balign 128 65 | b hang 66 | .balign 128 67 | stp x0, x1, [sp, #-16]! 68 | stp x2, x3, [sp, #-16]! 69 | stp x4, x5, [sp, #-16]! 70 | stp x6, x7, [sp, #-16]! 71 | stp x8, x9, [sp, #-16]! 72 | stp x10, x11, [sp, #-16]! 73 | stp x12, x13, [sp, #-16]! 74 | stp x14, x15, [sp, #-16]! 75 | stp x16, x17, [sp, #-16]! 76 | stp x18, x19, [sp, #-16]! 77 | // call c handler. 78 | bl c_irq_handler 79 | 80 | ldp x18, x19, [sp], #16 81 | ldp x16, x17, [sp], #16 82 | ldp x14, x15, [sp], #16 83 | ldp x12, x13, [sp], #16 84 | ldp x10, x11, [sp], #16 85 | ldp x8, x9, [sp], #16 86 | ldp x6, x7, [sp], #16 87 | ldp x4, x5, [sp], #16 88 | ldp x2, x3, [sp], #16 89 | ldp x0, x1, [sp], #16 90 | eret 91 | .balign 128 92 | b hang 93 | .balign 128 94 | b hang 95 | .balign 128 96 | b hang 97 | .balign 128 98 | b hang 99 | .balign 128 100 | b hang 101 | .balign 128 102 | b hang 103 | .balign 128 104 | b hang 105 | .balign 128 106 | b hang 107 | .balign 128 108 | b hang 109 | .balign 128 110 | b hang 111 | .balign 128 112 | b hang 113 | .balign 128 114 | b hang 115 | .balign 128 116 | b hang 117 | .balign 128 118 | b hang 119 | 120 | -------------------------------------------------------------------------------- /qemu-raspi3/usb01/events: -------------------------------------------------------------------------------- 1 | usb_* 2 | usb_dwc2_* 3 | -usb_dwc2_sof 4 | -------------------------------------------------------------------------------- /qemu-raspi3/usb01/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static inline void io_halt(void) 6 | { 7 | asm volatile ("wfi"); 8 | } 9 | 10 | static inline void enable_irq(void) 11 | { 12 | asm volatile ("msr daifclr, #2"); 13 | } 14 | 15 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 16 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 17 | 18 | void uart_putchar(uint8_t c) 19 | { 20 | /* wait mini uart for tx idle. */ 21 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 22 | *AUX_MU_IO = c; 23 | } 24 | 25 | void uart_puts(const char* str) 26 | { 27 | for (size_t i = 0; str[i] != '\0'; i ++) 28 | uart_putchar((uint8_t)str[i]); 29 | } 30 | 31 | void uart_puthex(uint64_t v) 32 | { 33 | const char *hexdigits = "0123456789ABCDEF"; 34 | for (int i = 28; i >= 0; i -= 4) 35 | uart_putchar(hexdigits[(v >> i) & 0xf]); 36 | } 37 | 38 | #define USB_BASE 0x3F980000 39 | //CORE 40 | #define USB_CORE_GAHBCFG ((volatile uint32_t *)(0x8 + USB_BASE)) 41 | #define USB_CORE_GINTSTS ((volatile uint32_t *)(0x14 + USB_BASE)) 42 | #define USB_CORE_GINTMSK ((volatile uint32_t *)(0x18 + USB_BASE)) 43 | #define USB_CORE_GUID ((volatile uint32_t *)(0x3C + USB_BASE)) 44 | #define USB_CORE_GSNPSID ((volatile uint32_t *)(0x40 + USB_BASE)) 45 | //HOST 46 | #define USB_HOST_HCFG ((volatile uint32_t *)(0x400 + USB_BASE)) 47 | #define USB_HOST_HPRT ((volatile uint32_t *)(0x440 + USB_BASE)) 48 | #define USB_HOST_HCCHAR0 ((volatile uint32_t *)(0x500 + USB_BASE)) 49 | //INTC 50 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 51 | #define IRQ_PEND1 ((volatile uint32_t *)(0x3F00B204)) 52 | #define IRQ_ENABLE1 ((volatile uint32_t *)(0x3F00B210)) 53 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 54 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 55 | 56 | void c_irq_handler(void) 57 | { 58 | /* check inteerupt source */ 59 | if ( *CORE0_INTERRUPT_SOURCE & (1 << 8) 60 | && *IRQ_BASIC & (1 << 8) 61 | && *IRQ_PEND1 & (1 << 9)) { 62 | 63 | uint32_t reg = *USB_CORE_GINTSTS; 64 | *USB_CORE_GINTSTS = reg; //clear 65 | uart_puthex(reg); 66 | uart_puts(" usb interrupt\n"); 67 | if (reg & 1 << 28) { 68 | uart_puts("Connector ID Status Change\n"); 69 | } 70 | } 71 | return; 72 | } 73 | 74 | void usbhost_id(void) 75 | { 76 | uart_puts("USB_CORE_GUID "); 77 | uart_puthex(*USB_CORE_GUID); 78 | uart_putchar('\n'); 79 | 80 | uart_puts("USB_CORE_GSNPSID "); 81 | uart_puthex(*USB_CORE_GSNPSID); 82 | uart_putchar('\n'); 83 | } 84 | 85 | void usbhost_start(void) 86 | { 87 | // Host Power on 88 | // HPRT.PrtPwr = 1'b1 89 | // HPRT.PrtRst = 1'b1 90 | // wait 60msec 91 | // HPRT.PrtRst = 1'b0 92 | uart_puts("HPRT "); 93 | uart_puthex(*USB_HOST_HPRT); 94 | uart_putchar('\n'); 95 | *USB_HOST_HPRT |= 0 << 8; 96 | *USB_HOST_HPRT |= 1 << 12; 97 | *USB_HOST_HPRT |= 1 << 8; 98 | uint32_t count = 0; 99 | count = 0; 100 | do { 101 | ; 102 | } while (count++ >= 0x100000) ; 103 | *USB_HOST_HPRT |= 0 << 8; 104 | *USB_HOST_HPRT |= 1 << 2; 105 | 106 | //enable irq 107 | *USB_CORE_GAHBCFG |= 1; 108 | *USB_CORE_GINTMSK = 1 << 28 | 0 << 24 | 0 << 3; 109 | 110 | // port enable and retry detect 111 | *USB_HOST_HPRT = 1 << 3| 1 << 1; 112 | 113 | // setup channel 114 | *USB_HOST_HCCHAR0 |= 1<<31; 115 | } 116 | 117 | void intc_setup(void) 118 | { 119 | // IRQ routeing to CORE0. 120 | *GPU_INTERRUPTS_ROUTING = 0x00; 121 | 122 | // USB interrupt routing. 123 | *IRQ_ENABLE1 = 1 << 9; 124 | 125 | enable_irq(); 126 | } 127 | 128 | void kernel_main(void) 129 | { 130 | uart_puts("usb01\n"); 131 | 132 | intc_setup(); 133 | 134 | usbhost_id(); 135 | usbhost_start(); 136 | 137 | while (1) { 138 | io_halt(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /qemu-raspi3/usb01/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/usb02/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = aarch64-none-elf 2 | CC = ${CROSS_COMPILE}-gcc 3 | AS = ${CROSS_COMPILE}-as 4 | OBJDUMP = ${CROSS_COMPILE}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -d in_asm 27 | 28 | trun : 29 | $(MAKE) kernel.elf 30 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -trace events=events 31 | 32 | clean: 33 | rm -f *.o *.elf *.list 34 | 35 | .PHONY: clean 36 | -------------------------------------------------------------------------------- /qemu-raspi3/usb02/README.md: -------------------------------------------------------------------------------- 1 | USB host send control packet tx / rx and display GET_DESCRIPTOR result. 2 | 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | 5 | ``` 6 | $ make run 7 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf 8 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 9 | usb02 10 | usb_buffer0:00083100 11 | usb_buffer1:00083000 12 | USB_CORE_GUID 00000000 13 | USB_CORE_GSNPSID 4F54294A 14 | 14000029 usb interrupt 15 | Connector ID Status Change 16 | Periodic TxFIFO Empty 17 | Non-periodic TxFIFO Empty 18 | Host and Device Start of Frame 19 | GET_DESCRIPTOR 20 | 0000000A 21 | 00000029 22 | 00000008 23 | 0000000A 24 | 00000000 25 | 00000001 26 | 00000000 27 | 00000000 28 | 00000000 29 | 000000FF 30 | 00000000 31 | 00000000 32 | 00000000 33 | 00000000 34 | 00000000 35 | 00000000 36 | 00000000 37 | 00000000 38 | ``` 39 | 40 | If you use QEMU built with trace, you can output traces. 41 | 42 | ``` 43 | $ make trun 44 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -trace events=events 45 | usb_port_claim bus 0, port 1 46 | usb_hub_reset dev 0 47 | usb_port_attach bus 0, port 1, devspeed full, portspeed full+high 48 | usb_dwc2_attach port 0x7f16f50c77d0 49 | usb_dwc2_attach_speed full-speed device attached 50 | usb_dwc2_bus_start start SOFs 51 | usb_dwc2_raise_global_irq 0x01000000 52 | usb_port_claim bus 0, port 1.1 53 | usb_port_attach bus 0, port 1.1, devspeed full+high, portspeed full 54 | usb_hub_attach dev 0, port 1 55 | usb_dwc2_reset_enter === RESET enter === 56 | usb_dwc2_detach port 0x7f16f50c77d0 57 | usb_dwc2_bus_stop stop SOFs 58 | usb_dwc2_bus_stop stop SOFs 59 | usb_dwc2_reset_hold === RESET hold === 60 | usb_dwc2_reset_exit === RESET exit === 61 | usb_dwc2_attach port 0x7f16f50c77d0 62 | usb_dwc2_attach_speed full-speed device attached 63 | usb_dwc2_bus_start start SOFs 64 | usb_dwc2_raise_global_irq 0x01000000 65 | usb_hub_reset dev 0 66 | qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c 67 | usb02 68 | usb_buffer0:usb_dwc2_raise_global_irq 0x00000008 69 | 00083100 70 | usb_buffer1:00083000 71 | USB_CORE_GUID usb_dwc2_glbreg_read 0x003c GUID val 0x00000000 72 | 00000000 73 | USB_CORE_GSNPSID usb_dwc2_glbreg_read 0x0040 GSNPSID val 0x4f54294a 74 | 4F54294A 75 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021003 76 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021003 old 0x00021003 result 0x00021001 77 | usb_dwc2_hreg0_action disable PRTINT 78 | usb_dwc2_lower_global_irq 0x01000000 79 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021001 80 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021101 old 0x00021001 result 0x00021101 81 | usb_dwc2_hreg0_action disable PRTINT 82 | usb_dwc2_hreg0_read 0x0440 HPRT0 val 0x00021101 83 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x00021001 old 0x00021101 result 0x0002100d 84 | usb_dwc2_hreg0_action call usb_port_reset 85 | usb_dwc2_detach port 0x7f16f50c77d0 86 | usb_dwc2_bus_stop stop SOFs 87 | usb_dwc2_raise_global_irq 0x01000000 88 | usb_dwc2_attach port 0x7f16f50c77d0 89 | usb_dwc2_attach_speed full-speed device attached 90 | usb_dwc2_bus_start start SOFs 91 | usb_hub_reset dev 0 92 | usb_dwc2_hreg0_action enable PRTINT 93 | usb_dwc2_glbreg_read 0x0008 GAHBCFG val 0x00000000 94 | usb_dwc2_glbreg_write 0x0008 GAHBCFG val 0x00000001 old 0x00000000 result 0x00000001 95 | usb_dwc2_glbreg_write 0x0018 GINTMSK val 0x11000000 old 0x00000000 result 0x11000000 96 | usb_dwc2_update_irq level=1 97 | usb_dwc2_hreg0_write 0x0440 HPRT0 val 0x0000100a old 0x0002100d result 0x00021005 98 | usb_dwc2_hreg0_action disable PRTINT 99 | usb_dwc2_lower_global_irq 0x01000000 100 | usb_dwc2_hreg0_read 0x0418 HAINTMSK val 0x00000000 101 | usb_dwc2_hreg0_write 0x0418 HAINTMSK val 0x00000003 old 0x00000000 result 0x00000003 102 | usb_dwc2_hreg1_read 0x050c HCINTMSK40 val 0x00000000 103 | usb_dwc2_hreg1_write 0x050c HCINTMSK0 val 0x00000001 old 0x00000000 result 0x00000001 104 | usb_dwc2_hreg1_read 0x052c HCINTMSK41 val 0x00000000 105 | usb_dwc2_hreg1_write 0x052c HCINTMSK1 val 0x00000001 old 0x00000000 result 0x00000001 106 | usb_dwc2_hreg1_read 0x0500 HCCHAR 40 val 0x00000000 107 | usb_dwc2_hreg1_write 0x0500 HCCHAR 0 val 0x00000040 old 0x00000000 result 0x00000040 108 | usb_dwc2_hreg1_read 0x0520 HCCHAR 41 val 0x00000000 109 | usb_dwc2_hreg1_write 0x0520 HCCHAR 1 val 0x00008040 old 0x00000000 result 0x00008040 110 | usb_dwc2_glbreg_read 0x0014 GINTSTS val 0x14000029 111 | usb_dwc2_glbreg_write 0x0014 GINTSTS val 0x14000029 old 0x14000029 result 0xffffffff04000021 112 | usb_dwc2_update_irq level=0 113 | 14000029usb_dwc2_raise_global_irq 0x00000008 114 | usb interrupt 115 | Connector ID Status Change 116 | Periodic TxFIFO Empty 117 | Non-periodic TxFIFO Empty 118 | Host and Device Start of Frame 119 | usb_dwc2_hreg1_read 0x0500 HCCHAR 40 val 0x00000040 120 | usb_dwc2_hreg1_write 0x0500 HCCHAR 0 val 0x00000040 old 0x00000040 result 0x00000040 121 | usb_dwc2_hreg1_read 0x0520 HCCHAR 41 val 0x00008040 122 | usb_dwc2_hreg1_write 0x0520 HCCHAR 1 val 0x00008040 old 0x00008040 result 0x00008040 123 | usb_dwc2_hreg1_write 0x0514 HCDMA 0 val 0x00083100 old 0x00000000 result 0x00083100 124 | usb_dwc2_hreg1_read 0x0514 HCDMA 40 val 0x00083100 125 | usb_dwc2_hreg1_write 0x0514 HCDMA 0 val 0xc0083100 old 0x00083100 result 0xc0083100 126 | usb_dwc2_hreg1_write 0x0510 HCTSIZ 0 val 0x60080008 old 0x00000000 result 0x60080008 127 | usb_dwc2_hreg1_read 0x0500 HCCHAR 40 val 0x00000040 128 | usb_dwc2_hreg1_write 0x0500 HCCHAR 0 val 0x80000040 old 0x00000040 result 0x80000040 129 | usb_dwc2_find_device 0 130 | usb_dwc2_device_found device found on port 0 131 | usb_dwc2_enable_chan ch 0 dev 0x55df43b7cdb0 pkt 0x7f16f50c7818 ep 0 132 | usb_dwc2_handle_packet ch 0 dev 0x55df43b7cdb0 pkt 0x7f16f50c7818 ep 0 type Ctrl dir Out mps 64 len 8 pcnt 1 133 | usb_dwc2_memory_read addr -1073204992 len 8 134 | usb_packet_state_change bus 0, port 1, ep 0, packet 0x7f16f50c7818, state undef -> setup 135 | usb_hub_control dev 0, req 0xa006, value 256, index 0, langth 64 136 | usb_packet_state_change bus 0, port 1, ep 0, packet 0x7f16f50c7818, state setup -> complete 137 | usb_dwc2_packet_status status USB_RET_SUCCESS len 8 138 | usb_dwc2_packet_done status USB_RET_SUCCESS actual 8 len 0 pcnt 0 139 | usb_dwc2_raise_host_irq 0x0001 140 | usb_dwc2_raise_global_irq 0x02000000 141 | usb_dwc2_hreg1_write 0x0534 HCDMA 1 val 0x00083000 old 0x00000000 result 0x00083000 142 | usb_dwc2_hreg1_read 0x0534 HCDMA 41 val 0x00083000 143 | usb_dwc2_hreg1_write 0x0534 HCDMA 1 val 0xc0083000 old 0x00083000 result 0xc0083000 144 | usb_dwc2_hreg1_write 0x0530 HCTSIZ 1 val 0x40080040 old 0x00000000 result 0x40080040 145 | usb_dwc2_hreg1_read 0x0520 HCCHAR 41 val 0x00008040 146 | usb_dwc2_hreg1_write 0x0520 HCCHAR 1 val 0x80008040 old 0x00008040 result 0x80008040 147 | usb_dwc2_find_device 0 148 | usb_dwc2_device_found device found on port 0 149 | usb_dwc2_enable_chan ch 1 dev 0x55df43b7cdb0 pkt 0x7f16f50c78c8 ep 0 150 | usb_dwc2_handle_packet ch 1 dev 0x55df43b7cdb0 pkt 0x7f16f50c78c8 ep 0 type Ctrl dir In mps 64 len 64 pcnt 1 151 | usb_packet_state_change bus 0, port 1, ep 0, packet 0x7f16f50c78c8, state undef -> setup 152 | usb_packet_state_change bus 0, port 1, ep 0, packet 0x7f16f50c78c8, state setup -> complete 153 | usb_dwc2_packet_status status USB_RET_SUCCESS len 10 154 | usb_dwc2_memory_write addr -1073205248 len 10 155 | usb_dwc2_packet_done status USB_RET_SUCCESS actual 10 len 54 pcnt 0 156 | usb_dwc2_raise_host_irq 0x0002 157 | GET_DESCRIPTOR 158 | 0000000A 159 | 00000029 160 | 00000008 161 | 0000000A 162 | 00000000 163 | 00000001 164 | 00000000 165 | 00000000 166 | 00000000 167 | 000000FF 168 | 00000000 169 | 00000000 170 | 00000000 171 | 00000000 172 | 00000000 173 | 00000000 174 | 00000000 175 | 00000000 176 | usb_dwc2_work_bh 177 | ``` 178 | -------------------------------------------------------------------------------- /qemu-raspi3/usb02/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | ldr x1, =_start 18 | // drop to EL2. 19 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 20 | msr scr_el3, x2 21 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 22 | msr spsr_el3, x2 23 | adr x2, start_el2 24 | msr elr_el3, x2 25 | eret 26 | 27 | start_el2: 28 | // set sp in EL1. 29 | msr sp_el1, x1 30 | // enable AArch64 in EL1. 31 | mov x0, #(1 << 31) // AArch64 32 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 33 | msr hcr_el2, x0 34 | mrs x0, hcr_el2 35 | // set vector address in EL1. 36 | ldr x0, =vector 37 | msr vbar_el1, x0 38 | // change execution level to EL1. 39 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 40 | msr spsr_el2, x2 41 | adr x2, start_el1 42 | msr elr_el2, x2 43 | eret 44 | 45 | start_el1: 46 | // set sp 47 | mov sp, x1 48 | // clear bss. 49 | ldr x1, =__bss_start 50 | ldr w2, =__bss_size 51 | 1: cbz w2, 2f 52 | str xzr, [x1], #8 53 | sub w2, w2, #1 54 | cbnz w2, 1b 55 | 56 | 2: bl kernel_main 57 | 58 | hang: 59 | wfi 60 | b hang 61 | 62 | .balign 2048 63 | vector: 64 | .balign 128 65 | b hang 66 | .balign 128 67 | stp x0, x1, [sp, #-16]! 68 | stp x2, x3, [sp, #-16]! 69 | stp x4, x5, [sp, #-16]! 70 | stp x6, x7, [sp, #-16]! 71 | stp x8, x9, [sp, #-16]! 72 | stp x10, x11, [sp, #-16]! 73 | stp x12, x13, [sp, #-16]! 74 | stp x14, x15, [sp, #-16]! 75 | stp x16, x17, [sp, #-16]! 76 | stp x18, x19, [sp, #-16]! 77 | // call c handler. 78 | bl c_irq_handler 79 | 80 | ldp x18, x19, [sp], #16 81 | ldp x16, x17, [sp], #16 82 | ldp x14, x15, [sp], #16 83 | ldp x12, x13, [sp], #16 84 | ldp x10, x11, [sp], #16 85 | ldp x8, x9, [sp], #16 86 | ldp x6, x7, [sp], #16 87 | ldp x4, x5, [sp], #16 88 | ldp x2, x3, [sp], #16 89 | ldp x0, x1, [sp], #16 90 | eret 91 | .balign 128 92 | b hang 93 | .balign 128 94 | b hang 95 | .balign 128 96 | b hang 97 | .balign 128 98 | b hang 99 | .balign 128 100 | b hang 101 | .balign 128 102 | b hang 103 | .balign 128 104 | b hang 105 | .balign 128 106 | b hang 107 | .balign 128 108 | b hang 109 | .balign 128 110 | b hang 111 | .balign 128 112 | b hang 113 | .balign 128 114 | b hang 115 | .balign 128 116 | b hang 117 | .balign 128 118 | b hang 119 | 120 | -------------------------------------------------------------------------------- /qemu-raspi3/usb02/events: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | usb_* 5 | usb_hub_* 6 | usb_dwc2_* 7 | -usb_dwc2_sof 8 | -------------------------------------------------------------------------------- /qemu-raspi3/usb02/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * usb02.c : USB packet tx / rx and display GET_DESCRIPTOR result 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static inline void io_halt(void) 11 | { 12 | asm volatile ("wfi"); 13 | } 14 | 15 | static inline void enable_irq(void) 16 | { 17 | asm volatile ("msr daifclr, #2"); 18 | } 19 | 20 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 21 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 22 | 23 | void my_memcpy(void *dest, void *src, size_t n) { 24 | char *src_char = (char *)src; 25 | char *dest_char = (char *)dest; 26 | for (size_t i=0; i= 0; i -= 4) 48 | uart_putchar(hexdigits[(v >> i) & 0xf]); 49 | } 50 | 51 | //INTC 52 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 53 | #define IRQ_PEND1 ((volatile uint32_t *)(0x3F00B204)) 54 | #define IRQ_ENABLE1 ((volatile uint32_t *)(0x3F00B210)) 55 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 56 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 57 | 58 | #define USB_BASE 0x3F980000 59 | //CORE 60 | #define USB_CORE_GAHBCFG ((volatile uint32_t *)(0x8 + USB_BASE)) 61 | #define USB_CORE_GINTSTS ((volatile uint32_t *)(0x14 + USB_BASE)) 62 | #define USB_CORE_GINTMSK ((volatile uint32_t *)(0x18 + USB_BASE)) 63 | #define USB_CORE_GUID ((volatile uint32_t *)(0x3C + USB_BASE)) 64 | #define USB_CORE_GSNPSID ((volatile uint32_t *)(0x40 + USB_BASE)) 65 | //HOST 66 | #define USB_HOST_HCFG ((volatile uint32_t *)(0x400 + USB_BASE)) 67 | #define USB_HOST_HAINTMSK ((volatile uint32_t *)(0x418 + USB_BASE)) 68 | #define USB_HOST_HPRT ((volatile uint32_t *)(0x440 + USB_BASE)) 69 | //CHANNEL 70 | #define USB_HOST_HCCHAR0 ((volatile uint32_t *)(0x500 + USB_BASE)) 71 | #define USB_HOST_HCINTMSK0 ((volatile uint32_t *)(0x50C + USB_BASE)) 72 | #define USB_HOST_HCTSIZ0 ((volatile uint32_t *)(0x510 + USB_BASE)) 73 | #define USB_HOST_HCDMA0 ((volatile uint32_t *)(0x514 + USB_BASE)) 74 | #define USB_HOST_HCCHAR1 ((volatile uint32_t *)(0x520 + USB_BASE)) 75 | #define USB_HOST_HCINTMSK1 ((volatile uint32_t *)(0x52C + USB_BASE)) 76 | #define USB_HOST_HCTSIZ1 ((volatile uint32_t *)(0x530 + USB_BASE)) 77 | #define USB_HOST_HCDMA1 ((volatile uint32_t *)(0x534 + USB_BASE)) 78 | 79 | uint8_t usb_buffer0[256] = {0}; 80 | uint8_t usb_buffer1[256] = {0}; 81 | 82 | struct UsbDeviceRequest { 83 | uint8_t Type; 84 | uint8_t Request; 85 | uint16_t Value; 86 | uint16_t Index; 87 | uint16_t Length; 88 | } __attribute__((__packed__)); 89 | 90 | void c_irq_handler(void) 91 | { 92 | /* check inteerupt source */ 93 | if ( *CORE0_INTERRUPT_SOURCE & (1 << 8) 94 | && *IRQ_BASIC & (1 << 8) 95 | && *IRQ_PEND1 & (1 << 9)) { 96 | 97 | uint32_t reg = *USB_CORE_GINTSTS; 98 | *USB_CORE_GINTSTS = reg; //clear 99 | uart_puthex(reg); 100 | uart_puts(" usb interrupt\n"); 101 | if (reg & 1 << 28) { uart_puts("Connector ID Status Change\n"); } 102 | if (reg & 1 << 27) { uart_puts("LPM Transaction Received Interrupt\n"); } 103 | if (reg & 1 << 26) { uart_puts("Periodic TxFIFO Empty\n"); } 104 | if (reg & 1 << 25) { uart_puts("Host Channels Interrupt\n"); 105 | } 106 | if (reg & 1 << 24) { *USB_HOST_HPRT |= 1 << 1; //clear host port interrupt 107 | uart_puts("Host Port Interrupt\n"); } 108 | if (reg & 1 << 6) { uart_puts("Global IN Non-periodic NAK Effective\n"); } 109 | if (reg & 1 << 5) { uart_puts("Non-periodic TxFIFO Empty\n"); } 110 | if (reg & 1 << 4) { uart_puts("Host and Device RxFIFO Non-Empty (RxFLvl) \n"); } 111 | if (reg & 1 << 3) { uart_puts("Host and Device Start of Frame\n"); } 112 | if (reg & 1 << 2) { uart_puts("OTG Interrupt\n"); } 113 | if (reg & 1 << 1) { uart_puts("Mode Mismatch Interrupt\n"); } 114 | } 115 | return; 116 | } 117 | 118 | void usbhost_id(void) 119 | { 120 | uart_puts("USB_CORE_GUID "); 121 | uart_puthex(*USB_CORE_GUID); 122 | uart_putchar('\n'); 123 | 124 | uart_puts("USB_CORE_GSNPSID "); 125 | uart_puthex(*USB_CORE_GSNPSID); 126 | uart_putchar('\n'); 127 | } 128 | 129 | static void txrx_control_msg(uint8_t txlen) 130 | { 131 | // send setup & control packet 132 | // set dma buffer 133 | *USB_HOST_HCDMA0 = (uint64_t) usb_buffer0; 134 | *USB_HOST_HCDMA0 |= 0xC0000000; 135 | // HCTSIZ0.Pid = 2'd3 (SETUP) , HCTSIZ0.PktCnt = 10'h1 , HCTSIZ0.XferSize = 18'd8 136 | *USB_HOST_HCTSIZ0 = 3 << 29 | 1 << 19 | txlen; 137 | // HCCAR1.ChEna = 1'b1 138 | *USB_HOST_HCCHAR0 |= 1<<31; 139 | 140 | // recieve control packet 141 | // set dma buffer 142 | *USB_HOST_HCDMA1 = (uint64_t) usb_buffer1; 143 | *USB_HOST_HCDMA1 |= 0xC0000000; 144 | // HCTSIZ1.Pid = 2'd2 (DATA1) , HCTSIZ1.PktCnt = 10'h1 , HCTSIZ1.XferSize = 18'd64 145 | *USB_HOST_HCTSIZ1 = 2 << 29 | 1 << 19 | 64; 146 | // HCCAR1.ChEna = 1'b1 147 | *USB_HOST_HCCHAR1 |= 1<<31; 148 | } 149 | 150 | void usbhost_start(void) 151 | { 152 | uint32_t count = 0; 153 | 154 | // USB Host power on 155 | // HPRT.PrtPwr = 1'b1 -> HPRT.PrtRst = 1'b1 -> wait 60msec -> HPRT.PrtRst = 1'b0 156 | *USB_HOST_HPRT |= 1 << 12; 157 | *USB_HOST_HPRT |= 1 << 8; 158 | count = 0; 159 | do { 160 | ; 161 | } while (count++ >= 0x100000) ; 162 | *USB_HOST_HPRT &= ~(1 << 8); 163 | 164 | // enable irq 165 | // GAHBCFG.GlblIntrMsk = 1'b1 166 | // GINTMSK.ConIDStsChngMsk = 1'b1, GINTMSK.PrtIntMsk = 1'b1, GINTMSK.SofMsk = 1'b1 167 | *USB_CORE_GAHBCFG |= 1; 168 | *USB_CORE_GINTMSK = 1 << 28 | 1 << 24 | 0 << 3; 169 | 170 | // port enable and retry detect 171 | // HPRT.PrtPwr = 1'b1, HPRT.PrtEnChng = 1'b1, HPRT.PrtConnDet = 1'b1 172 | *USB_HOST_HPRT = 1 << 12 | 1 << 3 | 1 << 1; 173 | 174 | // enable channel irq 175 | // HAINTMASK.HAINTMsk = 16'h3 176 | // HCINTMSK0.XferComplMsk = 1'b1 177 | *USB_HOST_HAINTMSK |= 0x3; 178 | *USB_HOST_HCINTMSK0 |= 1; 179 | *USB_HOST_HCINTMSK1 |= 1; 180 | 181 | // HCCAR1.EPDir = 1'b0 (OUT) / 1'b01(IN), HCCAR1.MPS = 11'h40 182 | *USB_HOST_HCCHAR0 |= 0x40; // OUT 183 | *USB_HOST_HCCHAR1 |= 1 << 15 | 0x40; // IN 184 | 185 | } 186 | 187 | void send_packet(void) 188 | { 189 | // HCCAR1.EPDir = 1'b0 (OUT) / 1'b01(IN), HCCAR1.MPS = 11'h40 190 | *USB_HOST_HCCHAR0 |= 0x40; // OUT 191 | *USB_HOST_HCCHAR1 |= 1 << 15 | 0x40; // IN 192 | 193 | // build packet 194 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 195 | .Type = 0xA0, // DEVICE_TO_HOST | STDANDAD | DEVICE 196 | .Request = 0x06, // GET_DESCRIPTOR 197 | .Value = 0x0100, // descriptor.type = 0x01, decriptor.index = 0x00 198 | .Index = 0, 199 | .Length = 64, 200 | }, 8); 201 | 202 | txrx_control_msg(8); 203 | } 204 | 205 | void intc_setup(void) 206 | { 207 | // IRQ routeing to CORE0. 208 | *GPU_INTERRUPTS_ROUTING = 0x00; 209 | 210 | // USB interrupt routing. 211 | *IRQ_ENABLE1 = 1 << 9; 212 | 213 | enable_irq(); 214 | } 215 | 216 | void kernel_main(void) 217 | { 218 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 219 | uart_puts("usb02\n"); 220 | uart_puts("usb_buffer0:"); 221 | uart_puthex((uint64_t)usb_buffer0); 222 | uart_puts("\n"); 223 | uart_puts("usb_buffer1:"); 224 | uart_puthex((uint64_t)usb_buffer1); 225 | uart_puts("\n"); 226 | 227 | intc_setup(); 228 | 229 | usbhost_id(); 230 | usbhost_start(); 231 | 232 | send_packet(); 233 | 234 | uart_puts("GET_DESCRIPTOR\n"); 235 | for (int i = 0; i < 18; i++) { 236 | uart_puthex(usb_buffer1[i]); 237 | uart_puts("\n"); 238 | } 239 | 240 | while (1) { 241 | io_halt(); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /qemu-raspi3/usb02/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /qemu-raspi3/usb03/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = aarch64-none-elf 2 | CC = ${CROSS_COMPILE}-gcc 3 | AS = ${CROSS_COMPILE}-as 4 | OBJDUMP = ${CROSS_COMPILE}-objdump 5 | CFLAGS = -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra 6 | ASM_FLAGS = -mcpu=cortex-a53 7 | OBJ = boot.o kernel.o 8 | 9 | kernel.elf: ${OBJ} 10 | ${CC} -Wl,--build-id=none -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ} 11 | ${OBJDUMP} -D kernel.elf > kernel.list 12 | 13 | 14 | boot.o: boot.S 15 | ${AS} ${ASM_FLAGS} -c $< -o $@ 16 | 17 | %.o : %.c Makefile 18 | $(CC) ${CFLAGS} -c -o $*.o $*.c 19 | 20 | run : 21 | $(MAKE) kernel.elf 22 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf 23 | 24 | runasm : 25 | $(MAKE) kernel.elf 26 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -d in_asm 27 | 28 | trun : 29 | $(MAKE) kernel.elf 30 | qemu-system-aarch64 -M raspi3 -m 1024 -serial null -serial mon:stdio -nographic -device usb-kbd -kernel kernel.elf -trace events=events 31 | 32 | clean: 33 | rm -f *.o *.elf *.list 34 | 35 | .PHONY: clean 36 | -------------------------------------------------------------------------------- /qemu-raspi3/usb03/README.md: -------------------------------------------------------------------------------- 1 | USB host : USB enumuration. 2 | 3 | This program only supports QEMU raspi3 model, and does not work on real hardware. 4 | -------------------------------------------------------------------------------- /qemu-raspi3/usb03/boot.S: -------------------------------------------------------------------------------- 1 | // To keep this in the first portion of the binary. 2 | .section ".text.boot" 3 | 4 | // Make _start global. 5 | .globl _start 6 | 7 | _start: 8 | // in QEMU all of 4 ARM CPUs are started simultaniously 9 | // by default. I don't know if this is the real hw behaviour, 10 | // but here I jump to halt if CPU ID (stored in MPIDR 11 | // register, first 2 bits) is not 0 12 | mrs x1, mpidr_el1 13 | and x1, x1, #3 14 | cmp x1, #0 15 | bne hang 16 | // address for stack pointer. 17 | ldr x1, =_start 18 | // drop to EL2. 19 | mov x2, #0x5b1 // RW=1, HCE=1, SMD=1, RES=1, NS=1 20 | msr scr_el3, x2 21 | mov x2, #0x3c9 // D=1, A=1, I=1, F=1 M=EL2h 22 | msr spsr_el3, x2 23 | adr x2, start_el2 24 | msr elr_el3, x2 25 | eret 26 | 27 | start_el2: 28 | // set sp in EL1. 29 | msr sp_el1, x1 30 | // disable coprocessor traps for printf 31 | mov x0, #0x33FF 32 | msr cptr_el2, x0 33 | msr hstr_el2, xzr 34 | mov x0, #(3 << 20) 35 | msr cpacr_el1, x0 36 | // enable AArch64 in EL1. 37 | mov x0, #(1 << 31) // AArch64 38 | orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 39 | msr hcr_el2, x0 40 | mrs x0, hcr_el2 41 | // set vector address in EL1. 42 | ldr x0, =vector 43 | msr vbar_el1, x0 44 | // change execution level to EL1. 45 | mov x2, #0x3c4 // D=1, A=1, I=1, F=1 M=EL1t 46 | msr spsr_el2, x2 47 | adr x2, start_el1 48 | msr elr_el2, x2 49 | eret 50 | 51 | start_el1: 52 | // set sp 53 | mov sp, x1 54 | // clear bss. 55 | ldr x1, =__bss_start 56 | ldr w2, =__bss_size 57 | 1: cbz w2, 2f 58 | str xzr, [x1], #8 59 | sub w2, w2, #1 60 | cbnz w2, 1b 61 | 62 | 2: bl kernel_main 63 | 64 | hang: 65 | wfi 66 | b hang 67 | 68 | .balign 2048 69 | vector: 70 | .balign 128 71 | b hang 72 | .balign 128 73 | stp x0, x1, [sp, #-16]! 74 | stp x2, x3, [sp, #-16]! 75 | stp x4, x5, [sp, #-16]! 76 | stp x6, x7, [sp, #-16]! 77 | stp x8, x9, [sp, #-16]! 78 | stp x10, x11, [sp, #-16]! 79 | stp x12, x13, [sp, #-16]! 80 | stp x14, x15, [sp, #-16]! 81 | stp x16, x17, [sp, #-16]! 82 | stp x18, x19, [sp, #-16]! 83 | // call c handler. 84 | bl c_irq_handler 85 | 86 | ldp x18, x19, [sp], #16 87 | ldp x16, x17, [sp], #16 88 | ldp x14, x15, [sp], #16 89 | ldp x12, x13, [sp], #16 90 | ldp x10, x11, [sp], #16 91 | ldp x8, x9, [sp], #16 92 | ldp x6, x7, [sp], #16 93 | ldp x4, x5, [sp], #16 94 | ldp x2, x3, [sp], #16 95 | ldp x0, x1, [sp], #16 96 | eret 97 | .balign 128 98 | b hang 99 | .balign 128 100 | b hang 101 | .balign 128 102 | b hang 103 | .balign 128 104 | b hang 105 | .balign 128 106 | b hang 107 | .balign 128 108 | b hang 109 | .balign 128 110 | b hang 111 | .balign 128 112 | b hang 113 | .balign 128 114 | b hang 115 | .balign 128 116 | b hang 117 | .balign 128 118 | b hang 119 | .balign 128 120 | b hang 121 | .balign 128 122 | b hang 123 | .balign 128 124 | b hang 125 | 126 | -------------------------------------------------------------------------------- /qemu-raspi3/usb03/events: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | usb_* 5 | usb_desc_* 6 | usb_hub_* 7 | usb_dwc2_* 8 | -usb_dwc2_hr* 9 | -usb_dwc2_sof 10 | -------------------------------------------------------------------------------- /qemu-raspi3/usb03/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * usb03.c : USB enumuration 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void my_memcpy(void *dest, void *src, size_t n) { 11 | int i; 12 | char *src_char = (char *)src; 13 | char *dest_char = (char *)dest; 14 | for (i=0; i 0) 25 | *p++ = uc; 26 | 27 | return (s); 28 | } 29 | 30 | static inline void io_halt(void) 31 | { 32 | asm volatile ("wfi"); 33 | } 34 | 35 | static inline void enable_irq(void) 36 | { 37 | asm volatile ("msr daifclr, #2"); 38 | } 39 | 40 | #define AUX_MU_IO ((volatile uint32_t *)(0x3F215040)) 41 | #define AUX_MU_LSR ((volatile uint32_t *)(0x3F215054)) 42 | 43 | void uart_putchar(uint8_t c) 44 | { 45 | /* wait mini uart for tx idle. */ 46 | while ( !(*AUX_MU_LSR & (1 << 5)) ) { } 47 | *AUX_MU_IO = c; 48 | } 49 | 50 | void uart_puts(const char* str) 51 | { 52 | for (size_t i = 0; str[i] != '\0'; i ++) 53 | uart_putchar((uint8_t)str[i]); 54 | } 55 | 56 | void uart_puthex(uint64_t v) 57 | { 58 | const char *hexdigits = "0123456789ABCDEF"; 59 | for (int i = 28; i >= 0; i -= 4) 60 | uart_putchar(hexdigits[(v >> i) & 0xf]); 61 | } 62 | 63 | void vprintf(const char* fmt, va_list args) 64 | { 65 | bool zeropadding = false; 66 | int64_t num = 0; 67 | char tmpstr[19] = {0}; 68 | char *p; 69 | int len = 0; 70 | 71 | if (fmt == NULL) { return; } 72 | 73 | while (*fmt) { 74 | if ( *fmt == '%' ) { 75 | fmt++; 76 | 77 | if ( '0' == *fmt ) { 78 | zeropadding = true; 79 | fmt++; 80 | } 81 | 82 | while ( '0' <= *fmt && *fmt <= '9' ) { 83 | len = len*10 + (*fmt - '0'); 84 | fmt++; 85 | } 86 | 87 | if ( *fmt == 'd') { 88 | int i = 18; 89 | tmpstr[i]=0; 90 | 91 | num = va_arg(args, int); 92 | tmpstr[i]=0; 93 | do { 94 | tmpstr[--i] = '0'+ ( num % 10 ); 95 | num/=10; 96 | } while ( num != 0 && i > 0); 97 | 98 | p = &tmpstr[i]; 99 | goto putstring; 100 | } 101 | else if ( *fmt == 'x') { 102 | int i = 16; 103 | tmpstr[i]=0; 104 | num = va_arg(args, int); 105 | 106 | do { 107 | char n = num & 0xf; 108 | tmpstr[--i] = n + ( n > 9 ? 'a' - 10 : '0'); 109 | num>>=4; 110 | } while ( num != 0 && i > 0 ); 111 | 112 | if ( zeropadding && len > 0 && len <= 16) { 113 | while( i > 16 - len && i > 0) { 114 | tmpstr[--i] = '0'; 115 | } 116 | } 117 | 118 | p = &tmpstr[i]; 119 | putstring: 120 | while(*p) { 121 | uart_putchar(*p++); 122 | } 123 | } 124 | } else { 125 | uart_putchar(*fmt); 126 | } 127 | fmt++; 128 | } 129 | return; 130 | } 131 | 132 | void uart_printf(const char *format, ...) { 133 | va_list args; 134 | va_start(args, format); 135 | vprintf(format, args); 136 | va_end(args); 137 | } 138 | 139 | 140 | #define IRQ_BASIC ((volatile uint32_t *)(0x3F00B200)) 141 | #define IRQ_PEND1 ((volatile uint32_t *)(0x3F00B204)) 142 | #define IRQ_ENABLE1 ((volatile uint32_t *)(0x3F00B210)) 143 | #define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) 144 | #define CORE0_INTERRUPT_SOURCE ((volatile uint32_t *)(0x40000060)) 145 | 146 | void intc_setup(void) 147 | { 148 | // IRQ routeing to CORE0. 149 | *GPU_INTERRUPTS_ROUTING = 0x00; 150 | 151 | // USB interrupt routing. 152 | *IRQ_ENABLE1 = 1 << 9; 153 | 154 | enable_irq(); 155 | } 156 | 157 | #define USB_BASE 0x3F980000 158 | //CORE 159 | #define USB_CORE_GAHBCFG ((volatile uint32_t *)(0x8 + USB_BASE)) 160 | #define USB_CORE_GINTSTS ((volatile uint32_t *)(0x14 + USB_BASE)) 161 | #define USB_CORE_GINTMSK ((volatile uint32_t *)(0x18 + USB_BASE)) 162 | #define USB_CORE_GUID ((volatile uint32_t *)(0x3C + USB_BASE)) 163 | #define USB_CORE_GSNPSID ((volatile uint32_t *)(0x40 + USB_BASE)) 164 | //HOST 165 | #define USB_HOST_HCFG ((volatile uint32_t *)(0x400 + USB_BASE)) 166 | #define USB_HOST_HAINTMSK ((volatile uint32_t *)(0x418 + USB_BASE)) 167 | #define USB_HOST_HPRT ((volatile uint32_t *)(0x440 + USB_BASE)) 168 | //CHANNEL 169 | #define USB_HOST_HCCHAR0 ((volatile uint32_t *)(0x500 + USB_BASE)) 170 | #define USB_HOST_HCINTMSK0 ((volatile uint32_t *)(0x50C + USB_BASE)) 171 | #define USB_HOST_HCTSIZ0 ((volatile uint32_t *)(0x510 + USB_BASE)) 172 | #define USB_HOST_HCDMA0 ((volatile uint32_t *)(0x514 + USB_BASE)) 173 | #define USB_HOST_HCCHAR1 ((volatile uint32_t *)(0x520 + USB_BASE)) 174 | #define USB_HOST_HCINTMSK1 ((volatile uint32_t *)(0x52C + USB_BASE)) 175 | #define USB_HOST_HCTSIZ1 ((volatile uint32_t *)(0x530 + USB_BASE)) 176 | #define USB_HOST_HCDMA1 ((volatile uint32_t *)(0x534 + USB_BASE)) 177 | 178 | #define USB_HOST_HCCHAR2 ((volatile uint32_t *)(0x540 + USB_BASE)) 179 | #define USB_HOST_HCINTMSK2 ((volatile uint32_t *)(0x54C + USB_BASE)) 180 | #define USB_HOST_HCTSIZ2 ((volatile uint32_t *)(0x550 + USB_BASE)) 181 | #define USB_HOST_HCDMA2 ((volatile uint32_t *)(0x554 + USB_BASE)) 182 | #define USB_HOST_HCCHAR3 ((volatile uint32_t *)(0x560 + USB_BASE)) 183 | #define USB_HOST_HCINTMSK3 ((volatile uint32_t *)(0x56C + USB_BASE)) 184 | #define USB_HOST_HCTSIZ3 ((volatile uint32_t *)(0x570 + USB_BASE)) 185 | #define USB_HOST_HCDMA3 ((volatile uint32_t *)(0x574 + USB_BASE)) 186 | 187 | uint8_t usb_buffer0[256]; 188 | uint8_t usb_buffer1[256]; 189 | uint8_t usb_buffer3[256]; 190 | 191 | struct UsbDeviceRequest { 192 | uint8_t Type; 193 | uint8_t Request; 194 | uint16_t Value; 195 | uint16_t Index; 196 | uint16_t Length; 197 | } __attribute__((__packed__)); 198 | 199 | void c_irq_handler(void) 200 | { 201 | /* check inteerupt source */ 202 | if ( *CORE0_INTERRUPT_SOURCE & (1 << 8) 203 | && *IRQ_BASIC & (1 << 8) 204 | && *IRQ_PEND1 & (1 << 9)) { 205 | 206 | uint32_t reg = *USB_CORE_GINTSTS; 207 | *USB_CORE_GINTSTS = reg; //clear 208 | uart_puts(" usb interrupt "); 209 | uart_puthex(reg); 210 | uart_puts("\n"); 211 | if (reg & 1 << 28) { uart_puts(" Connector ID Status Change\n"); } 212 | if (reg & 1 << 27) { uart_puts(" LPM Transaction Received Interrupt\n"); } 213 | if (reg & 1 << 26) { uart_puts(" Periodic TxFIFO Empty\n"); } 214 | if (reg & 1 << 25) { uart_puts(" Host Channels Interrupt\n"); 215 | } 216 | if (reg & 1 << 24) { *USB_HOST_HPRT |= 1 << 1; //clear host port interrupt 217 | uart_puts(" Host Port Interrupt\n"); } 218 | if (reg & 1 << 6) { uart_puts(" Global IN Non-periodic NAK Effective\n"); } 219 | if (reg & 1 << 5) { uart_puts(" Non-periodic TxFIFO Empty\n"); } 220 | if (reg & 1 << 4) { uart_puts(" Host and Device RxFIFO Non-Empty (RxFLvl) \n"); } 221 | if (reg & 1 << 3) { uart_puts(" Host and Device Start of Frame\n"); } 222 | if (reg & 1 << 2) { uart_puts(" OTG Interrupt\n"); } 223 | if (reg & 1 << 1) { uart_puts(" Mode Mismatch Interrupt\n"); } 224 | } 225 | return; 226 | } 227 | 228 | void usbhost_id(void) 229 | { 230 | uart_printf("USB_CORE_GUID %x\n", *USB_CORE_GUID); 231 | uart_printf("USB_CORE_GSNPSID %x\n", *USB_CORE_GSNPSID); 232 | } 233 | 234 | void usbhost_start(void) 235 | { 236 | uint32_t count = 0; 237 | 238 | // USB Host power on 239 | // HPRT.PrtPwr = 1'b1 -> HPRT.PrtRst = 1'b1 -> wait 60msec -> HPRT.PrtRst = 1'b0 240 | *USB_HOST_HPRT |= 1 << 12; 241 | *USB_HOST_HPRT |= 1 << 8; 242 | count = 0; 243 | do { 244 | ; 245 | } while (count++ >= 0x100000) ; 246 | *USB_HOST_HPRT &= ~(1 << 8); 247 | 248 | // enable irq 249 | // GAHBCFG.GlblIntrMsk = 1'b1 250 | // GINTMSK.ConIDStsChngMsk = 1'b1, GINTMSK.PrtIntMsk = 1'b1, GINTMSK.SofMsk = 1'b1 251 | *USB_CORE_GAHBCFG |= 1; 252 | *USB_CORE_GINTMSK = 1 << 28 | 1 << 24 | 0 << 3; 253 | 254 | // port enable and retry detect 255 | // HPRT.PrtPwr = 1'b1, HPRT.PrtEnChng = 1'b1, HPRT.PrtConnDet = 1'b1 256 | *USB_HOST_HPRT = 1 << 12 | 1 << 3 | 1 << 1; 257 | 258 | // enable channel irq 259 | // HAINTMASK.HAINTMsk = 16'h3 260 | // HCINTMSK0.XferComplMsk = 1'b1 261 | *USB_HOST_HAINTMSK |= 0x3; 262 | *USB_HOST_HCINTMSK0 |= 1; 263 | *USB_HOST_HCINTMSK1 |= 1; 264 | } 265 | 266 | static void usbhost_poll_intr(void) 267 | { 268 | uint8_t dev = 2; 269 | 270 | my_memset(usb_buffer3, 0, 256); 271 | 272 | // HCCAR3.EPType = 2'b11 (Interupt), HCCAR3.EPDir = 1'b01(IN), HCCAR3.MPS = 11'h40 273 | *USB_HOST_HCCHAR3 |= 3 << 18 | 1 << 15 | 1 << 11 | 0x40; // IN 274 | *USB_HOST_HCCHAR3 |= dev << 22 ; 275 | 276 | // recieve interrupt transfer 277 | // set dma buffer 278 | *USB_HOST_HCDMA3 = (uint64_t) usb_buffer3; 279 | *USB_HOST_HCDMA3 |= 0xC0000000; 280 | // HCTSIZ1.Pid = 2'd2 (DATA1) , HCTSIZ1.PktCnt = 10'h1 , HCTSIZ1.XferSize = 18'd64 281 | *USB_HOST_HCTSIZ3 = 2 << 29 | 1 << 19 | 64; 282 | // HCCAR1.ChEna = 1'b1 283 | *USB_HOST_HCCHAR3 |= 1<<31; 284 | 285 | uart_printf("HUB INT "); 286 | for (int i = 0; i < 2; i++) { 287 | uart_printf("%02x ",usb_buffer3[i]); 288 | } 289 | uart_printf("\n"); 290 | } 291 | 292 | static void prepare_control_msg(void) 293 | { 294 | my_memset(usb_buffer0, 0, 256); 295 | my_memset(usb_buffer1, 0, 256); 296 | 297 | // HCCAR1.EPDir = 1'b0 (OUT) / 1'b01(IN), HCCAR1.MPS = 11'h40 298 | *USB_HOST_HCCHAR0 |= 0x40; // OUT 299 | *USB_HOST_HCCHAR1 |= 1 << 15 | 0x40; // IN 300 | 301 | //clear dev 302 | *USB_HOST_HCCHAR0 &= ~(0x7f << 22); 303 | *USB_HOST_HCCHAR1 &= ~(0x7f << 22); 304 | } 305 | 306 | static void txrx_control_msg(uint8_t txlen) 307 | { 308 | // send setup & control packet 309 | // set dma buffer 310 | *USB_HOST_HCDMA0 = (uint64_t) usb_buffer0; 311 | *USB_HOST_HCDMA0 |= 0xC0000000; 312 | // HCTSIZ0.Pid = 2'd3 (SETUP) , HCTSIZ0.PktCnt = 10'h1 , HCTSIZ0.XferSize = 18'd8 313 | *USB_HOST_HCTSIZ0 = 3 << 29 | 1 << 19 | txlen; 314 | // HCCAR1.ChEna = 1'b1 315 | *USB_HOST_HCCHAR0 |= 1<<31; 316 | 317 | // recieve control packet 318 | // set dma buffer 319 | *USB_HOST_HCDMA1 = (uint64_t) usb_buffer1; 320 | *USB_HOST_HCDMA1 |= 0xC0000000; 321 | // HCTSIZ1.Pid = 2'd2 (DATA1) , HCTSIZ1.PktCnt = 10'h1 , HCTSIZ1.XferSize = 18'd64 322 | *USB_HOST_HCTSIZ1 = 2 << 29 | 1 << 19 | 64; 323 | // HCCAR1.ChEna = 1'b1 324 | *USB_HOST_HCCHAR1 |= 1<<31; 325 | } 326 | 327 | 328 | void usbhost_get_descriptor(uint8_t dev, uint8_t descriptor_type, bool is_hub) 329 | { 330 | prepare_control_msg(); 331 | 332 | *USB_HOST_HCCHAR0 |= dev << 22; 333 | *USB_HOST_HCCHAR1 |= dev << 22; 334 | 335 | // build packet 336 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 337 | .Type = is_hub ? 0xA0 : 0x80, // DEVICE_TO_HOST | STANDARD | DEVICE 338 | .Request = 0x06, // GET_DESCRIPTOR 339 | .Value = descriptor_type << 8 | 0x00, // descriptor.type = 0x01, decriptor.index = 0x00 340 | .Index = 0, 341 | .Length = 64, 342 | }, 8); 343 | 344 | txrx_control_msg(8); 345 | } 346 | 347 | void usbhost_get_portstatus(uint8_t dev, uint8_t port, bool is_hub) 348 | { 349 | prepare_control_msg(); 350 | 351 | *USB_HOST_HCCHAR0 |= dev << 22; 352 | *USB_HOST_HCCHAR1 |= dev << 22; 353 | 354 | // build packet 355 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 356 | .Type = is_hub ? 0xA3 : 0x80, // DEVICE_TO_HOST | CLASS or STANDARD | DEVICE 357 | .Request = 0x00, // GET_STATUS 358 | .Index = port, 359 | .Length = 4, 360 | }, 8); 361 | 362 | txrx_control_msg(8); 363 | 364 | uart_printf("PORT STAtUS %d ", port); 365 | for (int i = 0; i < 4; i++) { 366 | uart_printf("%02x ",usb_buffer1[i]); 367 | } 368 | uart_puts("\n"); 369 | } 370 | 371 | void usbhost_set_address(uint8_t address) 372 | { 373 | prepare_control_msg(); 374 | 375 | // build packet 376 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 377 | .Type = 0, 378 | .Request = 5, // Set address request 379 | .Value = address, // Address to set 380 | }, 8); 381 | 382 | txrx_control_msg(8); 383 | } 384 | 385 | void usbhost_set_config(uint8_t dev, uint8_t config) 386 | { 387 | prepare_control_msg(); 388 | 389 | *USB_HOST_HCCHAR0 |= dev << 22; 390 | *USB_HOST_HCCHAR1 |= dev << 22; 391 | 392 | // build packet 393 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 394 | .Type = 0, 395 | .Request = 9, // Set config 396 | .Value = config, // Address to set 397 | .Length = 0, 398 | }, 8); 399 | 400 | txrx_control_msg(8); 401 | } 402 | 403 | void usbhost_set_portfeature(uint8_t dev, uint8_t port, uint16_t feature) 404 | { 405 | prepare_control_msg(); 406 | 407 | *USB_HOST_HCCHAR0 |= dev << 22; 408 | *USB_HOST_HCCHAR1 |= dev << 22; 409 | 410 | // build packet 411 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 412 | .Type = 0x23, // ?? 413 | .Request = 0x03, // SET_FEATURE 414 | .Value = (uint16_t)feature, // Feature we are changing 415 | .Index = port, 416 | .Length = 0, 417 | }, 8); 418 | 419 | txrx_control_msg(8); 420 | } 421 | 422 | void usbhost_clear_portfeature(uint8_t dev, uint8_t port, uint16_t feature) 423 | { 424 | prepare_control_msg(); 425 | 426 | *USB_HOST_HCCHAR0 |= dev << 22; 427 | *USB_HOST_HCCHAR1 |= dev << 22; 428 | 429 | // build packet 430 | my_memcpy(usb_buffer0, &(struct UsbDeviceRequest) { 431 | .Type = 0x23, // ?? 432 | .Request = 0x01, // CLEAR_FEATURE 433 | .Value = feature, 434 | .Index = port, 435 | .Length = 0, 436 | }, 8); 437 | 438 | txrx_control_msg(8); 439 | } 440 | void kernel_main(void) 441 | { 442 | uart_puts("qemu exit: Ctrl-A x / qemu monitor: Ctrl-A c\n"); 443 | uart_puts("usb03\n"); 444 | uart_printf("usb_buffer0: %02x\n", usb_buffer0); 445 | uart_printf("usb_buffer1: %02x\n", usb_buffer1); 446 | uart_printf("usb_buffer3: %02x\n", usb_buffer3); 447 | 448 | intc_setup(); 449 | 450 | usbhost_id(); 451 | usbhost_start(); 452 | 453 | uart_puts("GET DEVICE_DESCRIPTOR\n"); 454 | usbhost_get_descriptor(0, 0x01, false); 455 | for (int i = 0; i < 18; i++) { 456 | uart_printf("%02x ",usb_buffer1[i]); 457 | } 458 | uart_puts("\n"); 459 | 460 | uart_puts("SET ADDRESS 2\n"); 461 | usbhost_set_address(2); 462 | 463 | uart_puts("GET CONFIG_DESCRIPTOR\n"); 464 | usbhost_get_descriptor(2, 0x02, false); 465 | for (int i = 0; i < 18; i++) { 466 | uart_printf("%02x ",usb_buffer1[i]); 467 | } 468 | uart_puts("\n"); 469 | 470 | uart_puts("SET CONFIG 1\n"); 471 | usbhost_set_config(2, 1); 472 | 473 | uart_puts("GET HUB_DESCRIPTOR\n"); 474 | usbhost_get_descriptor(2, 41, true); 475 | for (int i = 0; i < 18; i++) { 476 | uart_printf("%02x ",usb_buffer1[i]); 477 | } 478 | uart_puts("\n"); 479 | uart_printf("Hub device %d has %d ports\n", 0, usb_buffer1[2]); 480 | 481 | usbhost_get_portstatus(2, 0, false); 482 | usbhost_get_portstatus(2, 1, true); 483 | usbhost_clear_portfeature(2, 1, 0x0010); 484 | usbhost_get_portstatus(2, 1, true); 485 | 486 | uart_puts("SET PORT 1 POWER ON\n"); 487 | usbhost_set_portfeature(2, 1, 0x0008); 488 | usbhost_get_portstatus(2, 1, true); 489 | 490 | uint32_t count = 0; 491 | count = 0; 492 | do { ; } while (count++ >= 0x100000); 493 | 494 | uart_puts("CLEAR PORT FEATURE\n"); 495 | usbhost_clear_portfeature(2, 1, 0x0010); 496 | // usbhost_get_portstatus(2, 1, true); 497 | // usbhost_poll_intr(); 498 | 499 | uart_puts("SET PORT 1 RESET\n"); 500 | usbhost_set_portfeature(2, 1, 0x0004); 501 | // usbhost_poll_intr(); 502 | 503 | uart_puts("CLEAR PORT FEATURE\n"); 504 | usbhost_clear_portfeature(2, 1, 0x0014); 505 | usbhost_clear_portfeature(2, 1, 0x0011); 506 | // usbhost_get_portstatus(2, 1, true); 507 | // usbhost_poll_intr(); 508 | 509 | uart_puts("GET DEVICE_DESCRIPTOR\n"); 510 | usbhost_get_descriptor(0, 0x01, false); 511 | for (int i = 0; i < 18; i++) { 512 | uart_printf("%02x ",usb_buffer1[i]); 513 | } 514 | uart_puts("\n"); 515 | 516 | usbhost_set_address(3); 517 | uart_puts("GET CONFIG_DESCRIPTOR\n"); 518 | usbhost_get_descriptor(3, 0x02, false); 519 | for (int i = 0; i < 18; i++) { 520 | uart_printf("%02x ",usb_buffer1[i]); 521 | } 522 | uart_puts("\n"); 523 | 524 | while (1) { 525 | io_halt(); 526 | } 527 | } 528 | -------------------------------------------------------------------------------- /qemu-raspi3/usb03/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | /* Starts at LOADER_ADDR. */ 6 | . = 0x80000; 7 | __start = .; 8 | __text_start = .; 9 | .text : 10 | { 11 | KEEP(*(.text.boot)) 12 | *(.text) 13 | } 14 | . = ALIGN(4096); /* align to page size */ 15 | __text_end = .; 16 | 17 | __data_start = .; 18 | .data : 19 | { 20 | *(.data) 21 | } 22 | . = ALIGN(4096); /* align to page size */ 23 | __data_end = .; 24 | 25 | __bss_start = .; 26 | .bss : 27 | { 28 | bss = .; 29 | *(.bss) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | __bss_end = .; 33 | __end = .; 34 | } 35 | __bss_size = (__bss_end - __bss_start)>>3; 36 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | Raspberry Pi bare metal code. 3 | 4 | 5 | # qemu-raspi2 6 | 7 | | name | | 8 | | -------- | ------------- | 9 | | [framebuffer01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi2/framebuffer01) | draw framebuffer | 10 | | [int01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi2/int01) | uart rx interrupt handling | 11 | | [timer01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi2/timer01) | arm generic timer every 1 secnod | 12 | 13 | # qemu-raspi3 14 | 15 | | name | | 16 | | -------- | ------------- | 17 | | [dma01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/dma01) | dma memory to meory | 18 | | [framebuffer01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/framebuffer01) | draw framebuffer | 19 | | [int01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/int01) | uart rx interrupt handling | 20 | | [int02](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/int02) | mini uart rx interrupt handling | 21 | | [sdhost01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/sdhost01) | sdhost initialize | 22 | | [sdhost02](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/sdhost02) | sdhost readblock | 23 | | [task01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/task01) | task create | 24 | | [task02](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/task01) | task switch | 25 | | [timer01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/timer01) | arm generic timer every 1 secnod | 26 | | [usb01](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/usb01) | usb host : usb device detect | 27 | | [usb02](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/usb02) | usb host : control transfer| 28 | | [usb03](https://github.com/eggman/raspberrypi/tree/master/qemu-raspi3/usb03) | usb host : enumuration | 29 | 30 | 31 | # toolchain 32 | 33 | arm and aarch64 toolchain ( arm-none-eabi and aarch64-none-elf) 34 | * https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads 35 | 36 | # qemu 37 | 38 | I use QEMU 6.1.0 raspi2 model and raspi3 model. 39 | 40 | ``` 41 | $ qemu-system-arm -m 1024 -M raspi2 -nographic -kernel kernel.elf 42 | ``` 43 | 44 | ``` 45 | $ qemu-system-aarch64 -m 1024 -M raspi3 -nographic -kernel kernel.elf 46 | ``` 47 | --------------------------------------------------------------------------------