├── README.md ├── hello1 ├── Makefile ├── boot.asm ├── helloworld.c ├── linker.ld └── run_pi.sh ├── hellworld2 ├── Makefile ├── include │ ├── mmio.h │ └── uart.h ├── ld-scrp ├── link-arm-eabi.ld ├── main.c ├── main.d ├── run_pi.sh ├── start.S ├── start.d ├── uart.c └── uart.d ├── labInterrupt ├── Makefile ├── README ├── RESULT ├── boot.c ├── interrupt.c ├── ld-scr.lds ├── lib │ └── print.c ├── mmu.c ├── run_pi.sh └── start.S ├── labMMU ├── Makefile ├── README ├── RESULT ├── boot.c ├── ld-scr.lds ├── lib │ └── print.c ├── mmu.c ├── run_pi.sh └── start.S ├── labMem ├── .boot.c.swp ├── .mem.c.swp ├── Makefile ├── README ├── RESULT ├── boot.c ├── interrupt.c ├── ld-scr.lds ├── lib │ └── print.c ├── mem.c ├── mmu.c ├── run_pi.sh └── start.S ├── mimiOS ├── Makefile ├── README ├── RESULT ├── boot.c ├── interrupt.c ├── ld-scr.lds ├── lib │ └── print.c ├── mem.c ├── mmu.c ├── process.c ├── process.h ├── run_pi.sh ├── scheduler.c ├── scheduler.h ├── start.S ├── syscall.c └── syscall.h └── pi-baremetal ├── COPYING ├── Makefile ├── README ├── atags.c ├── atags.h ├── barrier.h ├── divby0.c ├── framebuffer.c ├── framebuffer.h ├── initsys.c ├── interrupts.c ├── interrupts.h ├── led.c ├── led.h ├── linkscript ├── mailbox.c ├── mailbox.h ├── main.c ├── memory.c ├── memory.h ├── memutils.c ├── memutils.h ├── process.c ├── process.h ├── rpi-libgcc ├── COPYING.RUNTIME ├── COPYING3 ├── README └── libgcc.a ├── run_pi.sh ├── scheduler.c ├── scheduler.h ├── start.s ├── syscall.c ├── syscall.h ├── teletext.h ├── textutils.c └── textutils.h /README.md: -------------------------------------------------------------------------------- 1 | 2 | Raspbery Pi (ARMv6) baremetal microkernel OS development 3 | 4 | 5 | hello1 - bare metal helloworld example. 6 | 7 | labMMU - MMU initialization(啟動跟初始化MMU). 8 | 9 | labInterrupt - ARM interrupt example. 10 | 11 | labMem - Buddy system memory allocation example. 12 | 13 | mimiOS - system call , round robin scheduling and process fork example. 14 | 15 | 16 | 17 | 18 | 19 | pi-baremetal - A nice Raspberry Pi example, Merged brianwiddas and Daniel Santos Bathke examples. (Brianwiddas's origional code has MMU, interrupt, mailbox, atgs but no process, referenced Daniel's tutorial merged system call, process, fork, scheduler into it。) 20 | 21 | check my blog for details 22 | http://karosesblog.blogspot.tw/ 23 | 24 | Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license. 25 | http://creativecommons.org/licenses/by/4.0/deed.en 26 | -------------------------------------------------------------------------------- /hello1/Makefile: -------------------------------------------------------------------------------- 1 | ARMGNU = arm-none-eabi 2 | 3 | AOPS = --warn --fatal-warnings 4 | COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding 5 | 6 | boot.bin: boot.asm 7 | $(ARMGNU)-gcc -O2 -c helloworld.c 8 | $(ARMGNU)-as boot.asm -o boot.o 9 | $(ARMGNU)-ld -T linker.ld boot.o helloworld.o -o boot.elf 10 | $(ARMGNU)-objcopy boot.elf -O binary boot.bin 11 | 12 | clean: 13 | rm *.elf *.o *.bin -f 14 | -------------------------------------------------------------------------------- /hello1/boot.asm: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # reference: 4 | # david leels 5 | # http://stackoverflow.com/questions/6870712/beagleboard-bare-metal-programming 6 | # 7 | 8 | #UART3 THR_REG register address 9 | .equ UART3_THR_REG, 0x20201000 10 | 11 | .arm 12 | 13 | _start: 14 | ldr r0,=UART3_THR_REG 15 | adr r1,.L0 16 | bl helloworld 17 | .L1: 18 | b .L1 19 | 20 | .align 2 21 | .L0: 22 | .ascii "helloworld\n\0" 23 | -------------------------------------------------------------------------------- /hello1/helloworld.c: -------------------------------------------------------------------------------- 1 | /* 2 | helloworld.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | 20 | // this will call by bl helloworld, *addr is r0 , *p is r1 21 | int helloworld(unsigned int *addr,const char *p){ 22 | while(*p){ 23 | *addr=*p++; 24 | }; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /hello1/linker.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * reference: 3 | * http://stackoverflow.com/questions/6870712/beagleboard-bare-metal-programming 4 | */ 5 | 6 | /* rammap */ 7 | MEMORY 8 | { 9 | ram : ORIGIN = 0x80000000, LENGTH = 0x10000 10 | } 11 | 12 | SECTIONS 13 | { 14 | .text : { *(.text*) } > ram 15 | } 16 | -------------------------------------------------------------------------------- /hello1/run_pi.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/qemu-system-arm -kernel boot.bin -cpu arm1176 -m 256 -M raspi -serial stdio 2 | -------------------------------------------------------------------------------- /hellworld2/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile - build script */ 2 | 3 | # build environment 4 | PREFIX ?= /opt/arm-2008q3/ 5 | ARMGNU ?= $(PREFIX)/bin/arm-none-eabi 6 | 7 | # source files 8 | SOURCES_ASM := $(wildcard *.S) 9 | SOURCES_C := $(wildcard *.c) 10 | 11 | # object files 12 | OBJS := $(patsubst %.S,%.o,$(SOURCES_ASM)) 13 | OBJS += $(patsubst %.c,%.o,$(SOURCES_C)) 14 | 15 | # Build flags 16 | DEPENDFLAGS := -MD -MP 17 | INCLUDES := -I include 18 | BASEFLAGS := -O2 -fpic -pedantic -pedantic-errors -nostdlib 19 | BASEFLAGS += -ffreestanding -mcpu=arm1176jzf-s 20 | ASFLAGS := $(INCLUDES) $(DEPENDFLAGS) -D__ASSEMBLY__ 21 | CFLAGS := $(INCLUDES) $(DEPENDFLAGS) $(BASEFLAGS) $(WARNFLAGS) 22 | CFLAGS += -std=gnu99 23 | 24 | # build rules 25 | all: kernel.img 26 | 27 | include $(wildcard *.d) 28 | 29 | kernel.elf: $(OBJS) link-arm-eabi.ld 30 | $(ARMGNU)-ld $(OBJS) -Tlink-arm-eabi.ld -o $@ 31 | 32 | kernel.img: kernel.elf 33 | $(ARMGNU)-objcopy kernel.elf -O binary kernel.img 34 | 35 | clean: 36 | $(RM) -f $(OBJS) kernel.elf kernel.img 37 | 38 | distclean: clean 39 | $(RM) -f *.d 40 | 41 | # C. 42 | %.o: %.c Makefile 43 | $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ 44 | 45 | # AS. 46 | %.o: %.S Makefile 47 | $(ARMGNU)-gcc $(ASFLAGS) -c $< -o $@ 48 | -------------------------------------------------------------------------------- /hellworld2/include/mmio.h: -------------------------------------------------------------------------------- 1 | /* mmio.h - access to MMIO registers */ 2 | 3 | #ifndef MMIO_H 4 | #define MMIO_H 5 | 6 | #include 7 | 8 | // write to MMIO register 9 | static inline void mmio_write(uint32_t reg, uint32_t data) { 10 | uint32_t *ptr = (uint32_t*)reg; 11 | asm volatile("str %[data], [%[reg]]" 12 | : : [reg]"r"(ptr), [data]"r"(data)); 13 | } 14 | 15 | // read from MMIO register 16 | static inline uint32_t mmio_read(uint32_t reg) { 17 | uint32_t *ptr = (uint32_t*)reg; 18 | uint32_t data; 19 | asm volatile("ldr %[data], [%[reg]]" 20 | : [data]"=r"(data) : [reg]"r"(ptr)); 21 | return data; 22 | } 23 | 24 | #endif // #ifndef MMIO_H 25 | -------------------------------------------------------------------------------- /hellworld2/include/uart.h: -------------------------------------------------------------------------------- 1 | /* uart.h - UART initialization & communication */ 2 | 3 | #ifndef UART_H 4 | #define UART_H 5 | 6 | #include 7 | 8 | /* 9 | * Initialize UART0. 10 | */ 11 | void uart_init(); 12 | 13 | /* 14 | * Transmit a byte via UART0. 15 | * uint8_t Byte: byte to send. 16 | */ 17 | void uart_putc(uint8_t byte); 18 | 19 | /* 20 | * print a string to the UART one character at a time 21 | * const char *str: 0-terminated string 22 | */ 23 | void uart_puts(const char *str); 24 | 25 | #endif // #ifndef UART_H 26 | -------------------------------------------------------------------------------- /hellworld2/ld-scrp: -------------------------------------------------------------------------------- 1 | /* link-arm-eabi.ld - linker script for arm eabi */ 2 | ENTRY(Start) 3 | 4 | SECTIONS 5 | { 6 | /* Starts at LOADER_ADDR. */ 7 | . = 0x8000; 8 | _start = .; 9 | _text_start = .; 10 | .text : 11 | { 12 | KEEP(*(.text.boot)) 13 | *(.text) 14 | } 15 | . = ALIGN(4096); /* align to page size */ 16 | _text_end = .; 17 | 18 | _rodata_start = .; 19 | .rodata : 20 | { 21 | *(.rodata) 22 | } 23 | . = ALIGN(4096); /* align to page size */ 24 | _rodata_end = .; 25 | 26 | _data_start = .; 27 | .data : 28 | { 29 | *(.data) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | _data_end = .; 33 | 34 | _bss_start = .; 35 | .bss : 36 | { 37 | bss = .; 38 | *(.bss) 39 | } 40 | . = ALIGN(4096); /* align to page size */ 41 | _bss_end = .; 42 | _end = .; 43 | } 44 | -------------------------------------------------------------------------------- /hellworld2/link-arm-eabi.ld: -------------------------------------------------------------------------------- 1 | /* link-arm-eabi.ld - linker script for arm eabi */ 2 | ENTRY(Start) 3 | 4 | SECTIONS 5 | { 6 | /* Starts at LOADER_ADDR. */ 7 | . = 0x8000; 8 | _start = .; 9 | _text_start = .; 10 | .text : 11 | { 12 | KEEP(*(.text.boot)) 13 | *(.text) 14 | } 15 | . = ALIGN(4096); /* align to page size */ 16 | _text_end = .; 17 | 18 | _rodata_start = .; 19 | .rodata : 20 | { 21 | *(.rodata) 22 | } 23 | . = ALIGN(4096); /* align to page size */ 24 | _rodata_end = .; 25 | 26 | _data_start = .; 27 | .data : 28 | { 29 | *(.data) 30 | } 31 | . = ALIGN(4096); /* align to page size */ 32 | _data_end = .; 33 | 34 | _bss_start = .; 35 | .bss : 36 | { 37 | bss = .; 38 | *(.bss) 39 | } 40 | . = ALIGN(4096); /* align to page size */ 41 | _bss_end = .; 42 | _end = .; 43 | } 44 | -------------------------------------------------------------------------------- /hellworld2/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - the entry point for the kernel */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #define UNUSED(x) (void)(x) 8 | 9 | const char hello[] = "\r\nHello World\r\n"; 10 | const char halting[] = "\r\n*** system halting ***"; 11 | 12 | // kernel main function, it all begins here 13 | void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) { 14 | UNUSED(r0); 15 | UNUSED(r1); 16 | UNUSED(atags); 17 | 18 | uart_init(); 19 | 20 | uart_puts(hello); 21 | 22 | // Wait a bit 23 | for(volatile int i = 0; i < 10000000; ++i) { } 24 | 25 | uart_puts(halting); 26 | } 27 | -------------------------------------------------------------------------------- /hellworld2/main.d: -------------------------------------------------------------------------------- 1 | main.o: main.c \ 2 | /opt/arm-2008q3/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/include/stdint.h \ 3 | include/uart.h 4 | 5 | /opt/arm-2008q3/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/include/stdint.h: 6 | 7 | include/uart.h: 8 | -------------------------------------------------------------------------------- /hellworld2/run_pi.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/qemu-system-arm -kernel kernel.elf -cpu arm1176 -m 256 -M raspi -serial stdio 2 | 3 | -------------------------------------------------------------------------------- /hellworld2/start.S: -------------------------------------------------------------------------------- 1 | /* boot.S - assembly startup code */ 2 | 3 | // To keep this in the first portion of the binary. 4 | .section ".text.boot" 5 | 6 | // Make Start global. 7 | .globl Start 8 | 9 | // Entry point for the kernel. 10 | // r15 -> should begin execution at 0x8000. 11 | // r0 -> 0x00000000 12 | // r1 -> 0x00000C42 13 | // r2 -> 0x00000100 - start of ATAGS 14 | // preserve these registers as argument for kernel_main 15 | Start: 16 | // Setup the stack. 17 | mov sp, #0x8000 18 | 19 | // Clear out bss. 20 | ldr r4, =_bss_start 21 | ldr r9, =_bss_end 22 | mov r5, #0 23 | mov r6, #0 24 | mov r7, #0 25 | mov r8, #0 26 | b 2f 27 | 28 | 1: 29 | // store multiple at r4. 30 | stmia r4!, {r5-r8} 31 | 32 | // If we are still below bss_end, loop. 33 | 2: 34 | cmp r4, r9 35 | blo 1b 36 | 37 | // Call kernel_main 38 | ldr r3, =kernel_main 39 | blx r3 40 | 41 | // halt 42 | halt: 43 | wfe 44 | b halt 45 | -------------------------------------------------------------------------------- /hellworld2/start.d: -------------------------------------------------------------------------------- 1 | start.o: start.S 2 | -------------------------------------------------------------------------------- /hellworld2/uart.c: -------------------------------------------------------------------------------- 1 | /* uart.c - UART initialization & communication */ 2 | /* Reference material: 3 | * http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf 4 | * Chapter 13: UART 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | enum { 12 | // The GPIO registers base address. 13 | GPIO_BASE = 0x20200000, 14 | 15 | // The offsets for reach register. 16 | 17 | // Controls actuation of pull up/down to ALL GPIO pins. 18 | GPPUD = (GPIO_BASE + 0x94), 19 | 20 | // Controls actuation of pull up/down for specific GPIO pin. 21 | GPPUDCLK0 = (GPIO_BASE + 0x98), 22 | 23 | // The base address for UART. 24 | UART0_BASE = 0x20201000, 25 | 26 | // The offsets for reach register for the UART. 27 | UART0_DR = (UART0_BASE + 0x00), 28 | UART0_RSRECR = (UART0_BASE + 0x04), 29 | UART0_FR = (UART0_BASE + 0x18), 30 | UART0_ILPR = (UART0_BASE + 0x20), 31 | UART0_IBRD = (UART0_BASE + 0x24), 32 | UART0_FBRD = (UART0_BASE + 0x28), 33 | UART0_LCRH = (UART0_BASE + 0x2C), 34 | UART0_CR = (UART0_BASE + 0x30), 35 | UART0_IFLS = (UART0_BASE + 0x34), 36 | UART0_IMSC = (UART0_BASE + 0x38), 37 | UART0_RIS = (UART0_BASE + 0x3C), 38 | UART0_MIS = (UART0_BASE + 0x40), 39 | UART0_ICR = (UART0_BASE + 0x44), 40 | UART0_DMACR = (UART0_BASE + 0x48), 41 | UART0_ITCR = (UART0_BASE + 0x80), 42 | UART0_ITIP = (UART0_BASE + 0x84), 43 | UART0_ITOP = (UART0_BASE + 0x88), 44 | UART0_TDR = (UART0_BASE + 0x8C), 45 | }; 46 | 47 | /* 48 | * delay function 49 | * int32_t delay: number of cycles to delay 50 | * 51 | * This just loops times in a way that the compiler 52 | * wont optimize away. 53 | */ 54 | static void delay(int32_t count) { 55 | asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" 56 | : : [count]"r"(count) : "cc"); 57 | } 58 | 59 | /* 60 | * Initialize UART0. 61 | */ 62 | void uart_init() { 63 | // Disable UART0. 64 | mmio_write(UART0_CR, 0x00000000); 65 | // Setup the GPIO pin 14 && 15. 66 | 67 | // Disable pull up/down for all GPIO pins & delay for 150 cycles. 68 | mmio_write(GPPUD, 0x00000000); 69 | delay(150); 70 | 71 | // Disable pull up/down for pin 14,15 & delay for 150 cycles. 72 | mmio_write(GPPUDCLK0, (1 << 14) | (1 << 15)); 73 | delay(150); 74 | 75 | // Write 0 to GPPUDCLK0 to make it take effect. 76 | mmio_write(GPPUDCLK0, 0x00000000); 77 | 78 | // Clear pending interrupts. 79 | mmio_write(UART0_ICR, 0x7FF); 80 | 81 | // Set integer & fractional part of baud rate. 82 | // Divider = UART_CLOCK/(16 * Baud) 83 | // Fraction part register = (Fractional part * 64) + 0.5 84 | // UART_CLOCK = 3000000; Baud = 115200. 85 | 86 | // Divider = 3000000/(16 * 115200) = 1.627 = ~1. 87 | // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. 88 | mmio_write(UART0_IBRD, 1); 89 | mmio_write(UART0_FBRD, 40); 90 | 91 | // Enable FIFO & 8 bit data transmissio (1 stop bit, no parity). 92 | mmio_write(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); 93 | 94 | // Mask all interrupts. 95 | mmio_write(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | 96 | (1 << 6) | (1 << 7) | (1 << 8) | 97 | (1 << 9) | (1 << 10)); 98 | 99 | // Enable UART0, receive & transfer part of UART. 100 | mmio_write(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); 101 | } 102 | 103 | /* 104 | * Transmit a byte via UART0. 105 | * uint8_t Byte: byte to send. 106 | */ 107 | void uart_putc(uint8_t byte) { 108 | // wait for UART to become ready to transmit 109 | while (1) { 110 | if (!(mmio_read(UART0_FR) & (1 << 5))) { 111 | break; 112 | } 113 | } 114 | mmio_write(UART0_DR, byte); 115 | } 116 | 117 | /* 118 | * print a string to the UART one character at a time 119 | * const char *str: 0-terminated string 120 | */ 121 | void uart_puts(const char *str) { 122 | while (*str) { 123 | uart_putc(*str++); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /hellworld2/uart.d: -------------------------------------------------------------------------------- 1 | uart.o: uart.c \ 2 | /opt/arm-2008q3/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/include/stdint.h \ 3 | include/mmio.h include/uart.h 4 | 5 | /opt/arm-2008q3/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/include/stdint.h: 6 | 7 | include/mmio.h: 8 | 9 | include/uart.h: 10 | -------------------------------------------------------------------------------- /labInterrupt/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = arm-none-eabi- 2 | CC = $(CROSS_COMPILE)gcc 3 | OBJCOPY = $(CROSS_COMPILE)objcopy 4 | LD = $(CROSS_COMPILE)ld 5 | ARCH = $(CROSS_COMPILE)ar 6 | IMAGE = boot 7 | 8 | 9 | 10 | 11 | CFLAGS = \ 12 | -fno-builtin \ 13 | -O0 -g -fomit-frame-pointer -fno-strict-aliasing -mcpu=arm1176jzf-s 14 | 15 | LDSCRIPT := ld-scr.lds 16 | LDFLAGS = \ 17 | -nostdlib -static -nostartfiles \ 18 | -T $(LDSCRIPT) 19 | 20 | OBJCOPYFLAGS = \ 21 | -O binary \ 22 | -S 23 | 24 | C_SRC = ./boot.c ./mmu.c ./interrupt.c \ 25 | ./lib/print.c 26 | ASM_SRC = ./start.S 27 | 28 | 29 | C_OBJ = $(C_SRC:.c=.o) 30 | HW_DEP_ASM_OBJ = $(ASM_SRC:.S=.o) 31 | 32 | 33 | $(IMAGE).bin: $(IMAGE).elf 34 | $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ 35 | 36 | $(IMAGE).elf: $(C_OBJ) $(HW_DEP_ASM_OBJ) 37 | $(CC) $(LDFLAGS) -o $(IMAGE).elf \ 38 | $(C_OBJ) $(HW_DEP_ASM_OBJ) -lgcc 39 | 40 | $(C_OBJ) : %.o : %.c 41 | $(CC) -c $(CFLAGS) $< -o $@ 42 | 43 | 44 | $(HW_DEP_ASM_OBJ) : %.o : %.S 45 | $(CC) -c $(CFLAGS) $< -o $@ 46 | 47 | 48 | 49 | 50 | clean: 51 | rm -f ./*.o \ 52 | ./lib/*.o \ 53 | $(IMAGE).bin $(IMAGE).elf \ 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /labInterrupt/README: -------------------------------------------------------------------------------- 1 | 2 | Raspberry Pi (ARMv6) Interrupt example 3 | 4 | 5 | check my blog for details 6 | http://karosesblog.blogspot.tw/ 7 | 8 | Reference: 9 | brianwiddas https://github.com/brianwiddas/pi-baremetal 10 | tnishinaga book:"BareMetalで遊ぶ Raspberry Pi" 11 | -------------------------------------------------------------------------------- /labInterrupt/RESULT: -------------------------------------------------------------------------------- 1 | HelloWorld 2 | PRINTK TEST 3 | page_table[2560]addr=0x16800, section=0x20000412 4 | page_table[2561]addr=0x16804, section=0x20100412 5 | page_table[2562]addr=0x16808, section=0x20200412 6 | page_table[2563]addr=0x1680c, section=0x20300412 7 | page_table[2564]addr=0x16810, section=0x20400412 8 | page_table[2565]addr=0x16814, section=0x20500412 9 | page_table[2566]addr=0x16818, section=0x20600412 10 | page_table[2567]addr=0x1681c, section=0x20700412 11 | page_table[2568]addr=0x16820, section=0x20800412 12 | page_table[2569]addr=0x16824, section=0x20900412 13 | page_table[2570]addr=0x16828, section=0x20a00412 14 | page_table[2571]addr=0x1682c, section=0x20b00412 15 | page_table[2572]addr=0x16830, section=0x20c00412 16 | page_table[2573]addr=0x16834, section=0x20d00412 17 | page_table[2574]addr=0x16838, section=0x20e00412 18 | page_table[2575]addr=0x1683c, section=0x20f00412 19 | page_table[2576]addr=0x16840, section=0x21000412 20 | page_talble base=0x14000 page_table409=0x17ffc 21 | test_mmu 22 | Finish TEST 23 | IRQ_handler 24 | IRQ_handler 25 | IRQ_handler 26 | 27 | -------------------------------------------------------------------------------- /labInterrupt/boot.c: -------------------------------------------------------------------------------- 1 | /* 2 | boot.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Hzu Hang modifed. 19 | */ 20 | 21 | 22 | 23 | 24 | typedef void (*init_func)(void); 25 | 26 | #define UFCON0 ((volatile unsigned int *)(0x20201000)) 27 | 28 | void helloworld(void){ 29 | const char *p="HelloWorld\n"; 30 | while(*p){ 31 | *UFCON0=*p++; 32 | }; 33 | } 34 | 35 | void test_mmu(void){ 36 | const char *p="test_mmu\n"; 37 | while(*p){ 38 | *(volatile unsigned int *)0xa0201000=*p++; 39 | }; 40 | } 41 | 42 | 43 | static init_func init[]={ 44 | helloworld, 45 | 0, 46 | }; 47 | 48 | 49 | 50 | void plat_boot(void){ 51 | int i; 52 | for(i=0;init[i];i++){ 53 | init[i](); 54 | } 55 | 56 | printk("PRINTK TEST\n"); 57 | enable_mmu2(); 58 | test_mmu(); 59 | IRQ_init(); 60 | printk("Finish TEST\n"); 61 | while(1); 62 | } 63 | -------------------------------------------------------------------------------- /labInterrupt/interrupt.c: -------------------------------------------------------------------------------- 1 | /* 2 | interrupt.s 3 | Carlos Hsu 4 | 5 | reference:brianwiddas https://github.com/brianwiddas/pi-baremetal 6 | tnishinaga book:"BareMetalで遊ぶ Raspberry Pi" 7 | */ 8 | static volatile unsigned int *irqEnable1 = (unsigned int *)0x2000b210; 9 | static volatile unsigned int *irqEnable2 = (unsigned int *) 0x2000b214; 10 | static volatile unsigned int *irqEnableBasic = (unsigned int *) 0x2000b218; 11 | 12 | static volatile unsigned int *armTimerLoad = (unsigned int *) 0x2000b400; 13 | static volatile unsigned int *armTimerValue = (unsigned int *) 0x2000b404; 14 | static volatile unsigned int *armTimerControl = (unsigned int *) 0x2000b408; 15 | static volatile unsigned int *armTimerIRQClear = (unsigned int *) 0x2000b40c; 16 | 17 | 18 | __attribute__ ((naked, aligned(32))) static void interrupt_vectors(void) 19 | { 20 | asm volatile("b __vector_reset\n" /* RESET */ 21 | "b __vector_undefined\n" /* UNDEF */ 22 | "b __vector_swi\n" 23 | "b __vector_prefetch_abort \n" 24 | "b __vector_data_abort \n" 25 | "b __vector_reserved;\n" /* Unused vector */ 26 | "b __vector_irq \n" /*IRQ*/ 27 | "b __vector_fiq\n" /* FIQ */ 28 | ); 29 | } 30 | 31 | 32 | void IRQ_handler() 33 | { 34 | disable_IRQ(); 35 | printk("IRQ_handler\n"); 36 | 37 | /*reset timer*/ 38 | *armTimerIRQClear = 0; 39 | 40 | enable_IRQ(); 41 | } 42 | 43 | void IRQ_init() 44 | { 45 | 46 | /* Set interrupt base register */ 47 | asm volatile("mcr p15, 0, %[addr], c12, c0, 0" : : [addr] "r" (&interrupt_vectors)); 48 | 49 | /* Turn on interrupts */ 50 | asm volatile("cpsie i"); 51 | printk("irq init \n"); 52 | 53 | /* Use the ARM timer - BCM 2832 peripherals doc, p.196 */ 54 | /* Enable ARM timer IRQ */ 55 | *irqEnableBasic = 0x00000001; 56 | 57 | /* Interrupt every 1024 * 256 (prescaler) timer ticks */ 58 | *armTimerLoad = 0x00000400; 59 | 60 | /* Timer enabled, interrupt enabled, prescale=256, "23 bit" counter 61 | * (did they mean 32 bit?) 62 | */ 63 | *armTimerControl = 0x000000aa; 64 | } 65 | -------------------------------------------------------------------------------- /labInterrupt/ld-scr.lds: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | SECTIONS 6 | { 7 | . = 0x00010000; 8 | .text : 9 | { 10 | *(.startup) 11 | *(.text) 12 | } 13 | . = ALIGN(32); 14 | 15 | .data : 16 | { 17 | *(.data) 18 | } 19 | 20 | . = ALIGN(32); 21 | __bss_start__ = .; 22 | .bss : 23 | { 24 | *(.bss) 25 | } 26 | __bss_end__ = .; 27 | } 28 | -------------------------------------------------------------------------------- /labInterrupt/lib/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | print.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | 20 | typedef char * va_list; 21 | #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 22 | #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 23 | #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 24 | #define va_end(ap) ( ap = (va_list)0 ) 25 | 26 | const char *digits="0123456789abcdef"; 27 | char numbers[68]; 28 | 29 | static char print_buf[1024]; 30 | 31 | #define FORMAT_TYPE_MASK 0xff00 32 | #define FORMAT_TYPE_SIGN_BIT 0x0100 33 | #define FORMAT_TYPE_NONE 0x000 34 | #define FORMAT_TYPE_CHAR 0x100 35 | #define FORMAT_TYPE_UCHAR 0x200 36 | #define FORMAT_TYPE_SHORT 0x300 37 | #define FORMAT_TYPE_USHORT 0x400 38 | #define FORMAT_TYPE_INT 0x500 39 | #define FORMAT_TYPE_UINT 0x600 40 | #define FORMAT_TYPE_LONG 0x700 41 | #define FORMAT_TYPE_ULONG 0x800 42 | #define FORMAT_TYPE_STR 0xd00 43 | #define FORMAT_TYPE_PTR 0x900 44 | #define FORMAT_TYPE_SIZE_T 0xb00 45 | 46 | #define FORMAT_TYPE(x) ((x)&FORMAT_TYPE_MASK) 47 | #define SET_FORMAT_TYPE(x,t) do{\ 48 | (x)&=~FORMAT_TYPE_MASK;(x)|=(t);\ 49 | }while(0) 50 | #define FORMAT_SIGNED(x) ((x)&FORMAT_TYPE_SIGN_BIT) 51 | 52 | #define FORMAT_FLAG_MASK 0xffff0000 53 | #define FORMAT_FLAG_SPACE 0x10000 54 | #define FORMAT_FLAG_ZEROPAD 0x20000 55 | #define FORMAT_FLAG_LEFT 0x40000 56 | #define FORMAT_FLAG_WIDTH 0x100000 57 | 58 | #define FORMAT_FLAG(x) ((x)&FORMAT_FLAG_MASK) 59 | #define SET_FORMAT_FLAG(x,f) ((x)|=(f)) 60 | 61 | #define FORMAT_BASE_MASK 0xff 62 | #define FORMAT_BASE_O 0x08 63 | #define FORMAT_BASE_X 0x10 64 | #define FORMAT_BASE_D 0x0a 65 | #define FORMAT_BASE_B 0x02 66 | 67 | #define FORMAT_BASE(x) (FORMAT_BASE_MASK&(x)) 68 | #define SET_FORMAT_BASE(x,t) do{(x)&=~FORMAT_BASE_MASK;(x)|=(t);}while(0) 69 | 70 | #define do_div(n,base) ({ \ 71 | int __res; \ 72 | __res = ((unsigned int) n) % (unsigned int) base; \ 73 | n = ((unsigned int) n) / (unsigned int) base; \ 74 | __res; }) 75 | 76 | void __put_char(char *p,int num){ 77 | while(*p&&num--){ 78 | *(volatile unsigned int *)0x20201000=*p++; 79 | }; 80 | } 81 | 82 | void * memcpy(void * dest,const void *src,unsigned int count) 83 | { 84 | char *tmp = (char *) dest, *s = (char *) src; 85 | while (count--) 86 | *tmp++ = *s++; 87 | return dest; 88 | } 89 | 90 | char *number(char *str, int num,int base,unsigned int flags){ 91 | int i=0; 92 | int sign=0; 93 | 94 | if(FORMAT_SIGNED(flags)&&(signed int)num<0){ 95 | sign=1; 96 | num=~num+1; 97 | } 98 | 99 | do{ 100 | numbers[i++]=digits[do_div(num,base)]; 101 | }while(num!=0); 102 | 103 | 104 | if(FORMAT_BASE(flags)==FORMAT_BASE_O){ 105 | numbers[i++]='0'; 106 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_X){ 107 | numbers[i++]='x'; 108 | numbers[i++]='0'; 109 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_B){ 110 | numbers[i++]='b'; 111 | numbers[i++]='0'; 112 | } 113 | if(sign) 114 | numbers[i++]='-'; 115 | 116 | while (i-- > 0) 117 | *str++ = numbers[i]; 118 | return str; 119 | } 120 | 121 | int format_decode(const char *fmt,unsigned int *flags){ 122 | const char *start = fmt; 123 | 124 | *flags &= ~FORMAT_TYPE_MASK; 125 | *flags |= FORMAT_TYPE_NONE; 126 | for (; *fmt ; ++fmt) { 127 | if (*fmt == '%') 128 | break; 129 | } 130 | 131 | if (fmt != start || !*fmt) 132 | return fmt - start; 133 | 134 | do{ 135 | fmt++; 136 | switch(*fmt){ 137 | case 'l': 138 | SET_FORMAT_FLAG(*flags,FORMAT_FLAG_WIDTH); 139 | break; 140 | default: 141 | break; 142 | } 143 | }while(0); 144 | 145 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 146 | switch (*fmt) { 147 | case 'c': 148 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_CHAR); 149 | break; 150 | 151 | case 's': 152 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_STR); 153 | break; 154 | 155 | case 'o': 156 | SET_FORMAT_BASE(*flags,FORMAT_BASE_O); 157 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 158 | break; 159 | 160 | case 'x': 161 | case 'X': 162 | SET_FORMAT_BASE(*flags,FORMAT_BASE_X); 163 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 164 | break; 165 | 166 | case 'd': 167 | case 'i': 168 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_INT); 169 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 170 | break; 171 | case 'u': 172 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 173 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 174 | break; 175 | 176 | default: 177 | break; 178 | } 179 | return ++fmt-start; 180 | } 181 | 182 | int vsnprintf(char *buf, int size, const char *fmt, va_list args){ 183 | int num; 184 | char *str, *end, c,*s; 185 | int read; 186 | unsigned int spec=0; 187 | 188 | str = buf; 189 | end = buf + size; 190 | 191 | if (end < buf) { 192 | end = ((void *)-1); 193 | size = end - buf; 194 | } 195 | 196 | while (*fmt) { 197 | const char *old_fmt = fmt; 198 | 199 | read = format_decode(fmt, &spec); 200 | fmt += read; 201 | 202 | if((FORMAT_TYPE(spec))==FORMAT_TYPE_NONE){ 203 | int copy = read; 204 | if (str < end) { 205 | if (copy > end - str) 206 | copy = end - str; 207 | memcpy(str, old_fmt, copy); 208 | } 209 | str += read; 210 | 211 | }else if(spec&FORMAT_FLAG_WIDTH){ 212 | //do nothing 213 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_CHAR){ 214 | c = (unsigned char) va_arg(args, int); 215 | if (str < end) 216 | *str = c; 217 | ++str; 218 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_STR){ 219 | s = (char *) va_arg(args, char *); 220 | while(str 0) { 243 | if (str < end) 244 | *str = '\0'; 245 | else 246 | end[-1] = '\0'; 247 | } 248 | return str-buf; 249 | } 250 | 251 | void printk(const char *fmt, ...) 252 | { 253 | va_list args; 254 | unsigned int i; 255 | 256 | va_start (args, fmt); 257 | i = vsnprintf (print_buf, sizeof(print_buf),fmt, args); 258 | va_end (args); 259 | 260 | __put_char (print_buf,i); 261 | } 262 | 263 | void test_printk(void){ 264 | char *p="this is %s test"; 265 | char c='H'; 266 | int d=-256; 267 | int k=0; 268 | printk("testing printk\n"); 269 | printk("test string ::: %s\ntest char ::: %c\ntest digit ::: %d\ntest X ::: %x\ntest unsigned ::: %u\ntest zero ::: %d\n",p,c,d,d,d,k); 270 | } 271 | -------------------------------------------------------------------------------- /labInterrupt/mmu.c: -------------------------------------------------------------------------------- 1 | #define NUM_PAGE_TABLE_ENTRIES 4096 /* 1 entry per 1MB, so this covers 4G address space */ 2 | #define CACHE_DISABLED 0x12 3 | #define SDRAM_START 0x80000000 4 | #define SDRAM_END 0x8fffffff 5 | #define CACHE_WRITEBACK 0x1e 6 | 7 | #define U32 unsigned int 8 | 9 | void enable_mmu2(void) 10 | { 11 | static unsigned int *page_table=(unsigned int *const)0x14000; 12 | 13 | int i; 14 | U32 reg; 15 | 16 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 17 | { 18 | /* map 0x20000000~0x210000000 to 0xa0000000~0xa1000000 */ 19 | if (i >= (0xa0000000 >> 20) && i <= ( 0xa1000000 >> 20)) 20 | { 21 | page_table[i] = (i-2048)<<20 | 0x0410 | 2; 22 | printk("page_table[%d]addr=%x, section=%x \n",i,&page_table[i],page_table[i]); 23 | } 24 | else 25 | /*not mapping yet*/ 26 | page_table[i]= i<<20| 0x0410|2 ; 27 | } 28 | printk("page_talble base=%x page_table409=%x \n",page_table,&page_table[4095]); 29 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 30 | /* Copy the page table address to cp15 */ 31 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 32 | : : "r" (page_table) : "memory"); 33 | /* Set the access control to all-supervisor */ 34 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 35 | 36 | /* Enable the MMU */ 37 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 38 | reg|=0x1; 39 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 40 | } 41 | 42 | void enable_mmu(void) 43 | { 44 | static U32 __attribute__((aligned(16384))) page_table[NUM_PAGE_TABLE_ENTRIES]; 45 | int i; 46 | U32 reg; 47 | 48 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 49 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 50 | page_table[i] = i << 20 | (3 << 10) | CACHE_DISABLED; 51 | /* Then, enable cacheable and bufferable for RAM only */ 52 | for (i = SDRAM_START >> 20; i < SDRAM_END >> 20; i++) 53 | { 54 | page_table[i] = i << 20 | (3 << 10) | CACHE_WRITEBACK; 55 | } 56 | 57 | /* Copy the page table address to cp15 */ 58 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 59 | : : "r" (page_table) : "memory"); 60 | /* Set the access control to all-supervisor */ 61 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 62 | 63 | /* Enable the MMU */ 64 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 65 | reg|=0x1; 66 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 67 | } 68 | -------------------------------------------------------------------------------- /labInterrupt/run_pi.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/qemu-system-arm -kernel boot.bin -cpu arm1176 -m 256 -M raspi -serial stdio 2 | -------------------------------------------------------------------------------- /labInterrupt/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | start.s: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Modified by Carlos Hsu 19 | */ 20 | 21 | 22 | 23 | .global _start 24 | .global __vector_reset 25 | .global __vector_undefined 26 | .global __vector_swi 27 | .global __vector_prefetch_abort 28 | .global __vector_data_abort 29 | .global __vector_reserved 30 | .global __vector_irq 31 | .global __vector_fiq 32 | 33 | .equ DISABLE_IRQ, 0x80 /* when I bit is set, IRQ is disabled */ 34 | .equ DISABLE_FIQ, 0x40 /* when F bit is set, FIQ is disabled */ 35 | .equ SYS_MOD, 0x1f /* System Mode */ 36 | .equ IRQ_MOD, 0x12 /* IRQ Mode */ 37 | .equ FIQ_MOD, 0x11 /* FIQ Mode */ 38 | .equ SVC_MOD, 0x13 /* Supervisor Mode */ 39 | .equ ABT_MOD, 0x17 /* Abort Mode */ 40 | .equ UND_MOD, 0x1b /* Undefined Mode */ 41 | 42 | .equ MEM_SIZE, 0x7A00000 43 | .equ TEXT_BASE, 0x0008000 44 | 45 | .equ _SVC_STACK, (TEXT_BASE+MEM_SIZE-4) 46 | .equ _IRQ_STACK, (_SVC_STACK-0x400) 47 | .equ _FIQ_STACK, (_IRQ_STACK-0x400) 48 | .equ _ABT_STACK, (_FIQ_STACK-0x400) 49 | .equ _UND_STACK, (_ABT_STACK-0x400) 50 | .equ _SYS_STACK, (_UND_STACK-0x400) 51 | 52 | .text 53 | .code 32 54 | 55 | __vector_undefined: 56 | nop 57 | __vector_swi: 58 | nop 59 | __vector_prefetch_abort: 60 | nop 61 | __vector_data_abort: 62 | nop 63 | __vector_reserved: 64 | nop 65 | __vector_irq: 66 | // save registers 67 | stmfd r13!, {r0-r12,lr} 68 | // call interrupt handler 69 | bl IRQ_handler 70 | // restore registers 71 | ldmfd r13!, {r0-r12,lr} 72 | // return address(IRQ lr-4) 73 | subs pc,lr, #4 74 | __vector_fiq: 75 | nop 76 | 77 | // IRQ enable set CPSR 78 | .global enable_IRQ 79 | enable_IRQ: 80 | mrs r0, cpsr 81 | bic r0, r0, #0x80 82 | msr cpsr_c,r0 83 | bx lr 84 | 85 | // IRQ disable set CPSR 86 | .global disable_IRQ 87 | disable_IRQ: 88 | mrs r0, cpsr 89 | ldr r1, =0x80 90 | orr r0, r0, r1 91 | msr cpsr_c, r0 92 | bx lr 93 | 94 | .extern plat_boot 95 | .extern __bss_start__ 96 | .extern __bss_end__ 97 | 98 | /*set stack*/ 99 | __vector_reset: 100 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SVC_MOD) 101 | ldr sp,=_SVC_STACK 102 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|IRQ_MOD) 103 | ldr sp,=_IRQ_STACK 104 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|FIQ_MOD) 105 | ldr sp,=_FIQ_STACK 106 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|ABT_MOD) 107 | ldr sp,=_ABT_STACK 108 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|UND_MOD) 109 | ldr sp,=_UND_STACK 110 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SYS_MOD) 111 | ldr sp,=_SYS_STACK 112 | 113 | _clear_bss: 114 | ldr r1,_bss_start_ 115 | ldr r3,_bss_end_ 116 | mov r2,#0x0 117 | 1: 118 | cmp r1,r3 119 | beq _main 120 | str r2,[r1],#0x4 121 | b 1b 122 | /*jump to plat_boot function in boot.c*/ 123 | _main: 124 | b plat_boot 125 | 126 | _bss_start_:.word __bss_start__ 127 | _bss_end_:.word __bss_end__ 128 | 129 | .section .startup 130 | .code 32 131 | .align 0 132 | _start: 133 | 134 | ldr pc,_vector_reset 135 | ldr pc,_vector_undefined 136 | ldr pc,_vector_swi 137 | ldr pc,_vector_prefetch_abort 138 | ldr pc,_vector_data_abort 139 | ldr pc,_vector_reserved 140 | ldr pc,_vector_irq 141 | ldr pc,_vector_fiq 142 | 143 | .align 4 144 | 145 | _vector_reset: .word __vector_reset 146 | _vector_undefined: .word __vector_undefined 147 | _vector_swi: .word __vector_swi 148 | _vector_prefetch_abort: .word __vector_prefetch_abort 149 | _vector_data_abort: .word __vector_data_abort 150 | _vector_reserved: .word __vector_reserved 151 | _vector_irq: .word __vector_irq 152 | _vector_fiq: .word __vector_fiq 153 | 154 | 155 | -------------------------------------------------------------------------------- /labMMU/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = arm-none-eabi- 2 | CC = $(CROSS_COMPILE)gcc 3 | OBJCOPY = $(CROSS_COMPILE)objcopy 4 | LD = $(CROSS_COMPILE)ld 5 | ARCH = $(CROSS_COMPILE)ar 6 | IMAGE = boot 7 | 8 | 9 | 10 | 11 | CFLAGS = \ 12 | -fno-builtin \ 13 | -O0 -g -fomit-frame-pointer -fno-strict-aliasing 14 | 15 | LDSCRIPT := ld-scr.lds 16 | LDFLAGS = \ 17 | -nostdlib -static -nostartfiles \ 18 | -T $(LDSCRIPT) 19 | 20 | OBJCOPYFLAGS = \ 21 | -O binary \ 22 | -S 23 | 24 | C_SRC = ./boot.c ./mmu.c \ 25 | ./lib/print.c 26 | ASM_SRC = ./start.S 27 | 28 | 29 | C_OBJ = $(C_SRC:.c=.o) 30 | HW_DEP_ASM_OBJ = $(ASM_SRC:.S=.o) 31 | 32 | 33 | $(IMAGE).bin: $(IMAGE).elf 34 | $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ 35 | 36 | $(IMAGE).elf: $(C_OBJ) $(HW_DEP_ASM_OBJ) 37 | $(CC) $(LDFLAGS) -o $(IMAGE).elf \ 38 | $(C_OBJ) $(HW_DEP_ASM_OBJ) -lgcc 39 | 40 | $(C_OBJ) : %.o : %.c 41 | $(CC) -c $(CFLAGS) $< -o $@ 42 | 43 | 44 | $(HW_DEP_ASM_OBJ) : %.o : %.S 45 | $(CC) -c $(CFLAGS) $< -o $@ 46 | 47 | 48 | 49 | 50 | clean: 51 | rm -f ./*.o \ 52 | ./lib/*.o \ 53 | $(IMAGE).bin $(IMAGE).elf \ 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /labMMU/README: -------------------------------------------------------------------------------- 1 | 2 | MMU initialization example 3 | 4 | 5 | check my blog for details 6 | http://karosesblog.blogspot.tw/ 7 | 8 | Reference: 9 | https://github.com/dwelch67/raspberrypi 10 | http://stackoverflow.com/questions/3439708/how-to-enable-arm1136jfs-arm-v6-mmu-to-have-one-to-one-mapping-between-physica 11 | -------------------------------------------------------------------------------- /labMMU/RESULT: -------------------------------------------------------------------------------- 1 | HelloWorld 2 | PRINTK TEST 3 | page_table[2560]addr=0x16800, section=0x20000412 4 | page_table[2561]addr=0x16804, section=0x20100412 5 | page_table[2562]addr=0x16808, section=0x20200412 6 | page_table[2563]addr=0x1680c, section=0x20300412 7 | page_table[2564]addr=0x16810, section=0x20400412 8 | page_table[2565]addr=0x16814, section=0x20500412 9 | page_table[2566]addr=0x16818, section=0x20600412 10 | page_table[2567]addr=0x1681c, section=0x20700412 11 | page_table[2568]addr=0x16820, section=0x20800412 12 | page_table[2569]addr=0x16824, section=0x20900412 13 | page_table[2570]addr=0x16828, section=0x20a00412 14 | page_table[2571]addr=0x1682c, section=0x20b00412 15 | page_table[2572]addr=0x16830, section=0x20c00412 16 | page_table[2573]addr=0x16834, section=0x20d00412 17 | page_table[2574]addr=0x16838, section=0x20e00412 18 | page_table[2575]addr=0x1683c, section=0x20f00412 19 | page_table[2576]addr=0x16840, section=0x21000412 20 | page_talble base=0x14000 page_table409=0x17ffc 21 | test_mmu 22 | Finish TEST 23 | 24 | -------------------------------------------------------------------------------- /labMMU/boot.c: -------------------------------------------------------------------------------- 1 | /* 2 | boot.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Hzu Hang modifed. 19 | */ 20 | 21 | 22 | 23 | 24 | typedef void (*init_func)(void); 25 | 26 | #define UFCON0 ((volatile unsigned int *)(0x20201000)) 27 | 28 | void helloworld(void){ 29 | const char *p="HelloWorld\n"; 30 | while(*p){ 31 | *UFCON0=*p++; 32 | }; 33 | } 34 | 35 | void test_mmu(void){ 36 | const char *p="test_mmu\n"; 37 | while(*p){ 38 | *(volatile unsigned int *)0xa0201000=*p++; 39 | }; 40 | } 41 | 42 | 43 | static init_func init[]={ 44 | helloworld, 45 | 0, 46 | }; 47 | 48 | 49 | 50 | void plat_boot(void){ 51 | int i; 52 | for(i=0;init[i];i++){ 53 | init[i](); 54 | } 55 | 56 | printk("PRINTK TEST\n"); 57 | enable_mmu2(); 58 | test_mmu(); 59 | 60 | printk("Finish TEST\n"); 61 | while(1); 62 | } 63 | -------------------------------------------------------------------------------- /labMMU/ld-scr.lds: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | SECTIONS 6 | { 7 | . = 0x00010000; 8 | .text : 9 | { 10 | *(.startup) 11 | *(.text) 12 | } 13 | . = ALIGN(32); 14 | 15 | .data : 16 | { 17 | *(.data) 18 | } 19 | 20 | . = ALIGN(32); 21 | __bss_start__ = .; 22 | .bss : 23 | { 24 | *(.bss) 25 | } 26 | __bss_end__ = .; 27 | } 28 | -------------------------------------------------------------------------------- /labMMU/lib/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | print.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | 20 | typedef char * va_list; 21 | #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 22 | #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 23 | #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 24 | #define va_end(ap) ( ap = (va_list)0 ) 25 | 26 | const char *digits="0123456789abcdef"; 27 | char numbers[68]; 28 | 29 | static char print_buf[1024]; 30 | 31 | #define FORMAT_TYPE_MASK 0xff00 32 | #define FORMAT_TYPE_SIGN_BIT 0x0100 33 | #define FORMAT_TYPE_NONE 0x000 34 | #define FORMAT_TYPE_CHAR 0x100 35 | #define FORMAT_TYPE_UCHAR 0x200 36 | #define FORMAT_TYPE_SHORT 0x300 37 | #define FORMAT_TYPE_USHORT 0x400 38 | #define FORMAT_TYPE_INT 0x500 39 | #define FORMAT_TYPE_UINT 0x600 40 | #define FORMAT_TYPE_LONG 0x700 41 | #define FORMAT_TYPE_ULONG 0x800 42 | #define FORMAT_TYPE_STR 0xd00 43 | #define FORMAT_TYPE_PTR 0x900 44 | #define FORMAT_TYPE_SIZE_T 0xb00 45 | 46 | #define FORMAT_TYPE(x) ((x)&FORMAT_TYPE_MASK) 47 | #define SET_FORMAT_TYPE(x,t) do{\ 48 | (x)&=~FORMAT_TYPE_MASK;(x)|=(t);\ 49 | }while(0) 50 | #define FORMAT_SIGNED(x) ((x)&FORMAT_TYPE_SIGN_BIT) 51 | 52 | #define FORMAT_FLAG_MASK 0xffff0000 53 | #define FORMAT_FLAG_SPACE 0x10000 54 | #define FORMAT_FLAG_ZEROPAD 0x20000 55 | #define FORMAT_FLAG_LEFT 0x40000 56 | #define FORMAT_FLAG_WIDTH 0x100000 57 | 58 | #define FORMAT_FLAG(x) ((x)&FORMAT_FLAG_MASK) 59 | #define SET_FORMAT_FLAG(x,f) ((x)|=(f)) 60 | 61 | #define FORMAT_BASE_MASK 0xff 62 | #define FORMAT_BASE_O 0x08 63 | #define FORMAT_BASE_X 0x10 64 | #define FORMAT_BASE_D 0x0a 65 | #define FORMAT_BASE_B 0x02 66 | 67 | #define FORMAT_BASE(x) (FORMAT_BASE_MASK&(x)) 68 | #define SET_FORMAT_BASE(x,t) do{(x)&=~FORMAT_BASE_MASK;(x)|=(t);}while(0) 69 | 70 | #define do_div(n,base) ({ \ 71 | int __res; \ 72 | __res = ((unsigned int) n) % (unsigned int) base; \ 73 | n = ((unsigned int) n) / (unsigned int) base; \ 74 | __res; }) 75 | 76 | void __put_char(char *p,int num){ 77 | while(*p&&num--){ 78 | *(volatile unsigned int *)0x20201000=*p++; 79 | }; 80 | } 81 | 82 | void * memcpy(void * dest,const void *src,unsigned int count) 83 | { 84 | char *tmp = (char *) dest, *s = (char *) src; 85 | while (count--) 86 | *tmp++ = *s++; 87 | return dest; 88 | } 89 | 90 | char *number(char *str, int num,int base,unsigned int flags){ 91 | int i=0; 92 | int sign=0; 93 | 94 | if(FORMAT_SIGNED(flags)&&(signed int)num<0){ 95 | sign=1; 96 | num=~num+1; 97 | } 98 | 99 | do{ 100 | numbers[i++]=digits[do_div(num,base)]; 101 | }while(num!=0); 102 | 103 | 104 | if(FORMAT_BASE(flags)==FORMAT_BASE_O){ 105 | numbers[i++]='0'; 106 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_X){ 107 | numbers[i++]='x'; 108 | numbers[i++]='0'; 109 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_B){ 110 | numbers[i++]='b'; 111 | numbers[i++]='0'; 112 | } 113 | if(sign) 114 | numbers[i++]='-'; 115 | 116 | while (i-- > 0) 117 | *str++ = numbers[i]; 118 | return str; 119 | } 120 | 121 | int format_decode(const char *fmt,unsigned int *flags){ 122 | const char *start = fmt; 123 | 124 | *flags &= ~FORMAT_TYPE_MASK; 125 | *flags |= FORMAT_TYPE_NONE; 126 | for (; *fmt ; ++fmt) { 127 | if (*fmt == '%') 128 | break; 129 | } 130 | 131 | if (fmt != start || !*fmt) 132 | return fmt - start; 133 | 134 | do{ 135 | fmt++; 136 | switch(*fmt){ 137 | case 'l': 138 | SET_FORMAT_FLAG(*flags,FORMAT_FLAG_WIDTH); 139 | break; 140 | default: 141 | break; 142 | } 143 | }while(0); 144 | 145 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 146 | switch (*fmt) { 147 | case 'c': 148 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_CHAR); 149 | break; 150 | 151 | case 's': 152 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_STR); 153 | break; 154 | 155 | case 'o': 156 | SET_FORMAT_BASE(*flags,FORMAT_BASE_O); 157 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 158 | break; 159 | 160 | case 'x': 161 | case 'X': 162 | SET_FORMAT_BASE(*flags,FORMAT_BASE_X); 163 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 164 | break; 165 | 166 | case 'd': 167 | case 'i': 168 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_INT); 169 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 170 | break; 171 | case 'u': 172 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 173 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 174 | break; 175 | 176 | default: 177 | break; 178 | } 179 | return ++fmt-start; 180 | } 181 | 182 | int vsnprintf(char *buf, int size, const char *fmt, va_list args){ 183 | int num; 184 | char *str, *end, c,*s; 185 | int read; 186 | unsigned int spec=0; 187 | 188 | str = buf; 189 | end = buf + size; 190 | 191 | if (end < buf) { 192 | end = ((void *)-1); 193 | size = end - buf; 194 | } 195 | 196 | while (*fmt) { 197 | const char *old_fmt = fmt; 198 | 199 | read = format_decode(fmt, &spec); 200 | fmt += read; 201 | 202 | if((FORMAT_TYPE(spec))==FORMAT_TYPE_NONE){ 203 | int copy = read; 204 | if (str < end) { 205 | if (copy > end - str) 206 | copy = end - str; 207 | memcpy(str, old_fmt, copy); 208 | } 209 | str += read; 210 | 211 | }else if(spec&FORMAT_FLAG_WIDTH){ 212 | //do nothing 213 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_CHAR){ 214 | c = (unsigned char) va_arg(args, int); 215 | if (str < end) 216 | *str = c; 217 | ++str; 218 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_STR){ 219 | s = (char *) va_arg(args, char *); 220 | while(str 0) { 243 | if (str < end) 244 | *str = '\0'; 245 | else 246 | end[-1] = '\0'; 247 | } 248 | return str-buf; 249 | } 250 | 251 | void printk(const char *fmt, ...) 252 | { 253 | va_list args; 254 | unsigned int i; 255 | 256 | va_start (args, fmt); 257 | i = vsnprintf (print_buf, sizeof(print_buf),fmt, args); 258 | va_end (args); 259 | 260 | __put_char (print_buf,i); 261 | } 262 | 263 | void test_printk(void){ 264 | char *p="this is %s test"; 265 | char c='H'; 266 | int d=-256; 267 | int k=0; 268 | printk("testing printk\n"); 269 | printk("test string ::: %s\ntest char ::: %c\ntest digit ::: %d\ntest X ::: %x\ntest unsigned ::: %u\ntest zero ::: %d\n",p,c,d,d,d,k); 270 | } 271 | -------------------------------------------------------------------------------- /labMMU/mmu.c: -------------------------------------------------------------------------------- 1 | #define NUM_PAGE_TABLE_ENTRIES 4096 /* 1 entry per 1MB, so this covers 4G address space */ 2 | #define CACHE_DISABLED 0x12 3 | #define SDRAM_START 0x80000000 4 | #define SDRAM_END 0x8fffffff 5 | #define CACHE_WRITEBACK 0x1e 6 | 7 | #define U32 unsigned int 8 | 9 | void enable_mmu2(void) 10 | { 11 | static unsigned int *page_table=(unsigned int *const)0x14000; 12 | 13 | int i; 14 | U32 reg; 15 | 16 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 17 | { 18 | /* map 0x20000000~0x210000000 to 0xa0000000~0xa1000000 */ 19 | if (i >= (0xa0000000 >> 20) && i <= ( 0xa1000000 >> 20)) 20 | { 21 | page_table[i] = (i-2048)<<20 | 0x0410 | 2; 22 | printk("page_table[%d]addr=%x, section=%x \n",i,&page_table[i],page_table[i]); 23 | } 24 | else 25 | /*not mapping yet*/ 26 | page_table[i]= i<<20| 0x0410|2 ; 27 | } 28 | printk("page_talble base=%x page_table409=%x \n",page_table,&page_table[4095]); 29 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 30 | /* Copy the page table address to cp15 */ 31 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 32 | : : "r" (page_table) : "memory"); 33 | /* Set the access control to all-supervisor */ 34 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 35 | 36 | /* Enable the MMU */ 37 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 38 | reg|=0x1; 39 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 40 | } 41 | 42 | void enable_mmu(void) 43 | { 44 | static U32 __attribute__((aligned(16384))) page_table[NUM_PAGE_TABLE_ENTRIES]; 45 | int i; 46 | U32 reg; 47 | 48 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 49 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 50 | page_table[i] = i << 20 | (3 << 10) | CACHE_DISABLED; 51 | /* Then, enable cacheable and bufferable for RAM only */ 52 | for (i = SDRAM_START >> 20; i < SDRAM_END >> 20; i++) 53 | { 54 | page_table[i] = i << 20 | (3 << 10) | CACHE_WRITEBACK; 55 | } 56 | 57 | /* Copy the page table address to cp15 */ 58 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 59 | : : "r" (page_table) : "memory"); 60 | /* Set the access control to all-supervisor */ 61 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 62 | 63 | /* Enable the MMU */ 64 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 65 | reg|=0x1; 66 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 67 | } 68 | -------------------------------------------------------------------------------- /labMMU/run_pi.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/qemu-system-arm -kernel boot.bin -cpu arm1176 -m 256 -M raspi -serial stdio 2 | -------------------------------------------------------------------------------- /labMMU/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | start.s: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | 20 | 21 | .global _start 22 | .global __vector_reset 23 | .global __vector_undefined 24 | .global __vector_swi 25 | .global __vector_prefetch_abort 26 | .global __vector_data_abort 27 | .global __vector_reserved 28 | .global __vector_irq 29 | .global __vector_fiq 30 | 31 | .equ DISABLE_IRQ, 0x80 /* when I bit is set, IRQ is disabled */ 32 | .equ DISABLE_FIQ, 0x40 /* when F bit is set, FIQ is disabled */ 33 | .equ SYS_MOD, 0x1f /* System Mode */ 34 | .equ IRQ_MOD, 0x12 /* IRQ Mode */ 35 | .equ FIQ_MOD, 0x11 /* FIQ Mode */ 36 | .equ SVC_MOD, 0x13 /* Supervisor Mode */ 37 | .equ ABT_MOD, 0x17 /* Abort Mode */ 38 | .equ UND_MOD, 0x1b /* Undefined Mode */ 39 | 40 | .equ MEM_SIZE, 0x7A00000 41 | .equ TEXT_BASE, 0x00010000 42 | 43 | .equ _SVC_STACK, (TEXT_BASE+MEM_SIZE-4) 44 | .equ _IRQ_STACK, (_SVC_STACK-0x400) 45 | .equ _FIQ_STACK, (_IRQ_STACK-0x400) 46 | .equ _ABT_STACK, (_FIQ_STACK-0x400) 47 | .equ _UND_STACK, (_ABT_STACK-0x400) 48 | .equ _SYS_STACK, (_UND_STACK-0x400) 49 | 50 | .text 51 | .code 32 52 | 53 | __vector_undefined: 54 | nop 55 | __vector_swi: 56 | nop 57 | __vector_prefetch_abort: 58 | nop 59 | __vector_data_abort: 60 | nop 61 | __vector_reserved: 62 | nop 63 | __vector_irq: 64 | nop 65 | __vector_fiq: 66 | nop 67 | 68 | 69 | 70 | .extern plat_boot 71 | .extern __bss_start__ 72 | .extern __bss_end__ 73 | 74 | /*set stack*/ 75 | __vector_reset: 76 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SVC_MOD) 77 | ldr sp,=_SVC_STACK 78 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|IRQ_MOD) 79 | ldr sp,=_IRQ_STACK 80 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|FIQ_MOD) 81 | ldr sp,=_FIQ_STACK 82 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|ABT_MOD) 83 | ldr sp,=_ABT_STACK 84 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|UND_MOD) 85 | ldr sp,=_UND_STACK 86 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SYS_MOD) 87 | ldr sp,=_SYS_STACK 88 | 89 | _clear_bss: 90 | ldr r1,_bss_start_ 91 | ldr r3,_bss_end_ 92 | mov r2,#0x0 93 | 1: 94 | cmp r1,r3 95 | beq _main 96 | str r2,[r1],#0x4 97 | b 1b 98 | /*jump to plat_boot function in boot.c*/ 99 | _main: 100 | b plat_boot 101 | 102 | _bss_start_:.word __bss_start__ 103 | _bss_end_:.word __bss_end__ 104 | 105 | .section .startup 106 | .code 32 107 | .align 0 108 | _start: 109 | 110 | ldr pc,_vector_reset 111 | ldr pc,_vector_undefined 112 | ldr pc,_vector_swi 113 | ldr pc,_vector_prefetch_abort 114 | ldr pc,_vector_data_abort 115 | ldr pc,_vector_reserved 116 | ldr pc,_vector_irq 117 | ldr pc,_vector_fiq 118 | 119 | .align 4 120 | 121 | _vector_reset: .word __vector_reset 122 | _vector_undefined: .word __vector_undefined 123 | _vector_swi: .word __vector_swi 124 | _vector_prefetch_abort: .word __vector_prefetch_abort 125 | _vector_data_abort: .word __vector_data_abort 126 | _vector_reserved: .word __vector_reserved 127 | _vector_irq: .word __vector_irq 128 | _vector_fiq: .word __vector_fiq 129 | 130 | 131 | -------------------------------------------------------------------------------- /labMem/.boot.c.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tzuCarlos/RaspberryPi/de08cc43e94b891d68b245373e88471c2fa09531/labMem/.boot.c.swp -------------------------------------------------------------------------------- /labMem/.mem.c.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tzuCarlos/RaspberryPi/de08cc43e94b891d68b245373e88471c2fa09531/labMem/.mem.c.swp -------------------------------------------------------------------------------- /labMem/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = arm-none-eabi- 2 | CC = $(CROSS_COMPILE)gcc 3 | OBJCOPY = $(CROSS_COMPILE)objcopy 4 | LD = $(CROSS_COMPILE)ld 5 | ARCH = $(CROSS_COMPILE)ar 6 | IMAGE = boot 7 | 8 | 9 | 10 | 11 | CFLAGS = \ 12 | -fno-builtin \ 13 | -O0 -g -fomit-frame-pointer -fno-strict-aliasing -mcpu=arm1176jzf-s 14 | 15 | LDSCRIPT := ld-scr.lds 16 | LDFLAGS = \ 17 | -nostdlib -static -nostartfiles \ 18 | -T $(LDSCRIPT) 19 | 20 | OBJCOPYFLAGS = \ 21 | -O binary \ 22 | -S 23 | 24 | C_SRC = ./boot.c ./mmu.c ./interrupt.c ./mem.c\ 25 | ./lib/print.c 26 | ASM_SRC = ./start.S 27 | 28 | 29 | C_OBJ = $(C_SRC:.c=.o) 30 | HW_DEP_ASM_OBJ = $(ASM_SRC:.S=.o) 31 | 32 | 33 | $(IMAGE).bin: $(IMAGE).elf 34 | $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ 35 | 36 | $(IMAGE).elf: $(C_OBJ) $(HW_DEP_ASM_OBJ) 37 | $(CC) $(LDFLAGS) -o $(IMAGE).elf \ 38 | $(C_OBJ) $(HW_DEP_ASM_OBJ) -lgcc 39 | 40 | $(C_OBJ) : %.o : %.c 41 | $(CC) -c $(CFLAGS) $< -o $@ 42 | 43 | 44 | $(HW_DEP_ASM_OBJ) : %.o : %.S 45 | $(CC) -c $(CFLAGS) $< -o $@ 46 | 47 | 48 | 49 | 50 | clean: 51 | rm -f ./*.o \ 52 | ./lib/*.o \ 53 | $(IMAGE).bin $(IMAGE).elf \ 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /labMem/README: -------------------------------------------------------------------------------- 1 | 2 | Raspberry Pi (ARMv6) Buddy memory allocation example 3 | 4 | 5 | check my blog for details 6 | http://karosesblog.blogspot.tw/ 7 | 8 | Reference: 9 | leeos http://www.leeos.org 10 | brianwiddas https://github.com/brianwiddas/pi-baremetal 11 | -------------------------------------------------------------------------------- /labMem/RESULT: -------------------------------------------------------------------------------- 1 | HelloWorld 2 | PRINTK TEST 3 | page_table[2560]addr=0x16800, section=0x20000412 4 | page_table[2561]addr=0x16804, section=0x20100412 5 | page_table[2562]addr=0x16808, section=0x20200412 6 | page_table[2563]addr=0x1680c, section=0x20300412 7 | page_table[2564]addr=0x16810, section=0x20400412 8 | page_table[2565]addr=0x16814, section=0x20500412 9 | page_table[2566]addr=0x16818, section=0x20600412 10 | page_table[2567]addr=0x1681c, section=0x20700412 11 | page_table[2568]addr=0x16820, section=0x20800412 12 | page_table[2569]addr=0x16824, section=0x20900412 13 | page_table[2570]addr=0x16828, section=0x20a00412 14 | page_table[2571]addr=0x1682c, section=0x20b00412 15 | page_table[2572]addr=0x16830, section=0x20c00412 16 | page_table[2573]addr=0x16834, section=0x20d00412 17 | page_table[2574]addr=0x16838, section=0x20e00412 18 | page_table[2575]addr=0x1683c, section=0x20f00412 19 | page_table[2576]addr=0x16840, section=0x21000412 20 | page_talble base=0x14000 page_table409=0x17ffc 21 | test_mmu 22 | Finish TEST 23 | IRQ_handler 24 | IRQ_handler 25 | IRQ_handler 26 | 27 | -------------------------------------------------------------------------------- /labMem/boot.c: -------------------------------------------------------------------------------- 1 | /* 2 | boot.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Hzu Hang modifed. 19 | */ 20 | 21 | 22 | 23 | 24 | typedef void (*init_func)(void); 25 | 26 | #define UFCON0 ((volatile unsigned int *)(0x20201000)) 27 | 28 | void helloworld(void){ 29 | const char *p="HelloWorld\n"; 30 | while(*p){ 31 | *UFCON0=*p++; 32 | }; 33 | } 34 | 35 | void test_mmu(void){ 36 | const char *p="test_mmu\n"; 37 | while(*p){ 38 | *(volatile unsigned int *)0xa0201000=*p++; 39 | }; 40 | } 41 | 42 | 43 | static init_func init[]={ 44 | helloworld, 45 | 0, 46 | }; 47 | 48 | 49 | 50 | void plat_boot(void){ 51 | int i; 52 | for(i=0;init[i];i++){ 53 | init[i](); 54 | } 55 | 56 | printk("PRINTK TEST\n"); 57 | enable_mmu2(); 58 | test_mmu(); 59 | // IRQ_init(); 60 | init_page_map(); 61 | char *p1,*p2,*p3,*p4; 62 | p1=(char *)get_free_pages(0,6); 63 | printk("the return address of get_free_pages %x\n",p1); 64 | p2=(char *)get_free_pages(0,6); 65 | printk("the return address of get_free_pages %x\n",p2); 66 | put_free_pages(p2,6); 67 | put_free_pages(p1,6); 68 | p3=(char *)get_free_pages(0,7); 69 | printk("the return address of get_free_pages %x\n",p3); 70 | p4=(char *)get_free_pages(0,7); 71 | printk("the return address of get_free_pages %x\n",p4); 72 | 73 | while(1); 74 | } 75 | -------------------------------------------------------------------------------- /labMem/interrupt.c: -------------------------------------------------------------------------------- 1 | /* 2 | interrupt.s 3 | Carlos Hsu 4 | 5 | reference:brianwiddas https://github.com/brianwiddas/pi-baremetal 6 | tnishinaga book:"BareMetalで遊ぶ Raspberry Pi" 7 | */ 8 | static volatile unsigned int *irqEnable1 = (unsigned int *)0x2000b210; 9 | static volatile unsigned int *irqEnable2 = (unsigned int *) 0x2000b214; 10 | static volatile unsigned int *irqEnableBasic = (unsigned int *) 0x2000b218; 11 | 12 | static volatile unsigned int *armTimerLoad = (unsigned int *) 0x2000b400; 13 | static volatile unsigned int *armTimerValue = (unsigned int *) 0x2000b404; 14 | static volatile unsigned int *armTimerControl = (unsigned int *) 0x2000b408; 15 | static volatile unsigned int *armTimerIRQClear = (unsigned int *) 0x2000b40c; 16 | 17 | 18 | __attribute__ ((naked, aligned(32))) static void interrupt_vectors(void) 19 | { 20 | asm volatile("b __vector_reset\n" /* RESET */ 21 | "b __vector_undefined\n" /* UNDEF */ 22 | "b __vector_swi\n" 23 | "b __vector_prefetch_abort \n" 24 | "b __vector_data_abort \n" 25 | "b __vector_reserved;\n" /* Unused vector */ 26 | "b __vector_irq \n" /*IRQ*/ 27 | "b __vector_fiq\n" /* FIQ */ 28 | ); 29 | } 30 | 31 | 32 | void IRQ_handler() 33 | { 34 | disable_IRQ(); 35 | printk("IRQ_handler\n"); 36 | 37 | /*reset timer*/ 38 | *armTimerIRQClear = 0; 39 | 40 | enable_IRQ(); 41 | } 42 | 43 | void IRQ_init() 44 | { 45 | 46 | /* Set interrupt base register */ 47 | asm volatile("mcr p15, 0, %[addr], c12, c0, 0" : : [addr] "r" (&interrupt_vectors)); 48 | 49 | /* Turn on interrupts */ 50 | asm volatile("cpsie i"); 51 | printk("irq init \n"); 52 | 53 | /* Use the ARM timer - BCM 2832 peripherals doc, p.196 */ 54 | /* Enable ARM timer IRQ */ 55 | *irqEnableBasic = 0x00000001; 56 | 57 | /* Interrupt every 1024 * 256 (prescaler) timer ticks */ 58 | *armTimerLoad = 0x00000400; 59 | 60 | /* Timer enabled, interrupt enabled, prescale=256, "23 bit" counter 61 | * (did they mean 32 bit?) 62 | */ 63 | *armTimerControl = 0x000000aa; 64 | } 65 | -------------------------------------------------------------------------------- /labMem/ld-scr.lds: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | SECTIONS 6 | { 7 | . = 0x00010000; 8 | .text : 9 | { 10 | *(.startup) 11 | *(.text) 12 | } 13 | . = ALIGN(32); 14 | 15 | .data : 16 | { 17 | *(.data) 18 | } 19 | 20 | . = ALIGN(32); 21 | __bss_start__ = .; 22 | .bss : 23 | { 24 | *(.bss) 25 | } 26 | __bss_end__ = .; 27 | } 28 | -------------------------------------------------------------------------------- /labMem/lib/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | print.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | 20 | typedef char * va_list; 21 | #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 22 | #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 23 | #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 24 | #define va_end(ap) ( ap = (va_list)0 ) 25 | 26 | const char *digits="0123456789abcdef"; 27 | char numbers[68]; 28 | 29 | static char print_buf[1024]; 30 | 31 | #define FORMAT_TYPE_MASK 0xff00 32 | #define FORMAT_TYPE_SIGN_BIT 0x0100 33 | #define FORMAT_TYPE_NONE 0x000 34 | #define FORMAT_TYPE_CHAR 0x100 35 | #define FORMAT_TYPE_UCHAR 0x200 36 | #define FORMAT_TYPE_SHORT 0x300 37 | #define FORMAT_TYPE_USHORT 0x400 38 | #define FORMAT_TYPE_INT 0x500 39 | #define FORMAT_TYPE_UINT 0x600 40 | #define FORMAT_TYPE_LONG 0x700 41 | #define FORMAT_TYPE_ULONG 0x800 42 | #define FORMAT_TYPE_STR 0xd00 43 | #define FORMAT_TYPE_PTR 0x900 44 | #define FORMAT_TYPE_SIZE_T 0xb00 45 | 46 | #define FORMAT_TYPE(x) ((x)&FORMAT_TYPE_MASK) 47 | #define SET_FORMAT_TYPE(x,t) do{\ 48 | (x)&=~FORMAT_TYPE_MASK;(x)|=(t);\ 49 | }while(0) 50 | #define FORMAT_SIGNED(x) ((x)&FORMAT_TYPE_SIGN_BIT) 51 | 52 | #define FORMAT_FLAG_MASK 0xffff0000 53 | #define FORMAT_FLAG_SPACE 0x10000 54 | #define FORMAT_FLAG_ZEROPAD 0x20000 55 | #define FORMAT_FLAG_LEFT 0x40000 56 | #define FORMAT_FLAG_WIDTH 0x100000 57 | 58 | #define FORMAT_FLAG(x) ((x)&FORMAT_FLAG_MASK) 59 | #define SET_FORMAT_FLAG(x,f) ((x)|=(f)) 60 | 61 | #define FORMAT_BASE_MASK 0xff 62 | #define FORMAT_BASE_O 0x08 63 | #define FORMAT_BASE_X 0x10 64 | #define FORMAT_BASE_D 0x0a 65 | #define FORMAT_BASE_B 0x02 66 | 67 | #define FORMAT_BASE(x) (FORMAT_BASE_MASK&(x)) 68 | #define SET_FORMAT_BASE(x,t) do{(x)&=~FORMAT_BASE_MASK;(x)|=(t);}while(0) 69 | 70 | #define do_div(n,base) ({ \ 71 | int __res; \ 72 | __res = ((unsigned int) n) % (unsigned int) base; \ 73 | n = ((unsigned int) n) / (unsigned int) base; \ 74 | __res; }) 75 | 76 | void __put_char(char *p,int num){ 77 | while(*p&&num--){ 78 | *(volatile unsigned int *)0x20201000=*p++; 79 | }; 80 | } 81 | 82 | void * memcpy(void * dest,const void *src,unsigned int count) 83 | { 84 | char *tmp = (char *) dest, *s = (char *) src; 85 | while (count--) 86 | *tmp++ = *s++; 87 | return dest; 88 | } 89 | 90 | char *number(char *str, int num,int base,unsigned int flags){ 91 | int i=0; 92 | int sign=0; 93 | 94 | if(FORMAT_SIGNED(flags)&&(signed int)num<0){ 95 | sign=1; 96 | num=~num+1; 97 | } 98 | 99 | do{ 100 | numbers[i++]=digits[do_div(num,base)]; 101 | }while(num!=0); 102 | 103 | 104 | if(FORMAT_BASE(flags)==FORMAT_BASE_O){ 105 | numbers[i++]='0'; 106 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_X){ 107 | numbers[i++]='x'; 108 | numbers[i++]='0'; 109 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_B){ 110 | numbers[i++]='b'; 111 | numbers[i++]='0'; 112 | } 113 | if(sign) 114 | numbers[i++]='-'; 115 | 116 | while (i-- > 0) 117 | *str++ = numbers[i]; 118 | return str; 119 | } 120 | 121 | int format_decode(const char *fmt,unsigned int *flags){ 122 | const char *start = fmt; 123 | 124 | *flags &= ~FORMAT_TYPE_MASK; 125 | *flags |= FORMAT_TYPE_NONE; 126 | for (; *fmt ; ++fmt) { 127 | if (*fmt == '%') 128 | break; 129 | } 130 | 131 | if (fmt != start || !*fmt) 132 | return fmt - start; 133 | 134 | do{ 135 | fmt++; 136 | switch(*fmt){ 137 | case 'l': 138 | SET_FORMAT_FLAG(*flags,FORMAT_FLAG_WIDTH); 139 | break; 140 | default: 141 | break; 142 | } 143 | }while(0); 144 | 145 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 146 | switch (*fmt) { 147 | case 'c': 148 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_CHAR); 149 | break; 150 | 151 | case 's': 152 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_STR); 153 | break; 154 | 155 | case 'o': 156 | SET_FORMAT_BASE(*flags,FORMAT_BASE_O); 157 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 158 | break; 159 | 160 | case 'x': 161 | case 'X': 162 | SET_FORMAT_BASE(*flags,FORMAT_BASE_X); 163 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 164 | break; 165 | 166 | case 'd': 167 | case 'i': 168 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_INT); 169 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 170 | break; 171 | case 'u': 172 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 173 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 174 | break; 175 | 176 | default: 177 | break; 178 | } 179 | return ++fmt-start; 180 | } 181 | 182 | int vsnprintf(char *buf, int size, const char *fmt, va_list args){ 183 | int num; 184 | char *str, *end, c,*s; 185 | int read; 186 | unsigned int spec=0; 187 | 188 | str = buf; 189 | end = buf + size; 190 | 191 | if (end < buf) { 192 | end = ((void *)-1); 193 | size = end - buf; 194 | } 195 | 196 | while (*fmt) { 197 | const char *old_fmt = fmt; 198 | 199 | read = format_decode(fmt, &spec); 200 | fmt += read; 201 | 202 | if((FORMAT_TYPE(spec))==FORMAT_TYPE_NONE){ 203 | int copy = read; 204 | if (str < end) { 205 | if (copy > end - str) 206 | copy = end - str; 207 | memcpy(str, old_fmt, copy); 208 | } 209 | str += read; 210 | 211 | }else if(spec&FORMAT_FLAG_WIDTH){ 212 | //do nothing 213 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_CHAR){ 214 | c = (unsigned char) va_arg(args, int); 215 | if (str < end) 216 | *str = c; 217 | ++str; 218 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_STR){ 219 | s = (char *) va_arg(args, char *); 220 | while(str 0) { 243 | if (str < end) 244 | *str = '\0'; 245 | else 246 | end[-1] = '\0'; 247 | } 248 | return str-buf; 249 | } 250 | 251 | void printk(const char *fmt, ...) 252 | { 253 | va_list args; 254 | unsigned int i; 255 | 256 | va_start (args, fmt); 257 | i = vsnprintf (print_buf, sizeof(print_buf),fmt, args); 258 | va_end (args); 259 | 260 | __put_char (print_buf,i); 261 | } 262 | 263 | void test_printk(void){ 264 | char *p="this is %s test"; 265 | char c='H'; 266 | int d=-256; 267 | int k=0; 268 | printk("testing printk\n"); 269 | printk("test string ::: %s\ntest char ::: %c\ntest digit ::: %d\ntest X ::: %x\ntest unsigned ::: %u\ntest zero ::: %d\n",p,c,d,d,d,k); 270 | } 271 | -------------------------------------------------------------------------------- /labMem/mem.c: -------------------------------------------------------------------------------- 1 | /* 2 | mem.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #define NULL ((void *)0) 20 | 21 | struct list_head { 22 | struct list_head *next, *prev; 23 | }; 24 | 25 | 26 | static inline void INIT_LIST_HEAD(struct list_head *list) 27 | { 28 | list->next = list; 29 | list->prev = list; 30 | } 31 | 32 | static inline void __list_add(struct list_head *new_lst, 33 | struct list_head *prev, 34 | struct list_head *next) 35 | { 36 | next->prev = new_lst; 37 | new_lst->next = next; 38 | new_lst->prev = prev; 39 | prev->next = new_lst; 40 | } 41 | 42 | static inline void list_add(struct list_head *new_lst, struct list_head *head) 43 | { 44 | __list_add(new_lst, head, head->next); 45 | } 46 | 47 | static inline void list_add_tail(struct list_head *new_lst, struct list_head *head) 48 | { 49 | __list_add(new_lst, head->prev, head); 50 | } 51 | 52 | static inline void __list_del(struct list_head * prev, struct list_head * next) 53 | { 54 | next->prev = prev; 55 | prev->next = next; 56 | } 57 | 58 | static inline void list_del(struct list_head * entry) 59 | { 60 | __list_del(entry->prev,entry->next); 61 | } 62 | 63 | 64 | static inline void list_remove_chain(struct list_head *ch,struct list_head *ct){ 65 | ch->prev->next=ct->next; 66 | ct->next->prev=ch->prev; 67 | } 68 | 69 | static inline void list_add_chain(struct list_head *ch,struct list_head *ct,struct list_head *head){ 70 | ch->prev=head; 71 | ct->next=head->next; 72 | head->next->prev=ct; 73 | head->next=ch; 74 | } 75 | 76 | static inline void list_add_chain_tail(struct list_head *ch,struct list_head *ct,struct list_head *head){ 77 | ch->prev=head->prev; 78 | head->prev->next=ch; 79 | head->prev=ct; 80 | ct->next=head; 81 | } 82 | 83 | 84 | static inline int list_empty(const struct list_head *head) 85 | { 86 | return head->next == head; 87 | } 88 | 89 | 90 | 91 | #define offsetof(TYPE, MEMBER) ((unsigned int) &((TYPE *)0)->MEMBER) 92 | 93 | #define container_of(ptr, type, member) ({ \ 94 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 95 | (type *)( (char *)__mptr - offsetof(type,member) );}) 96 | 97 | 98 | #define list_entry(ptr,type,member) \ 99 | container_of(ptr, type, member) 100 | 101 | 102 | 103 | #define list_for_each(pos, head) \ 104 | for (pos = (head)->next; pos != (head); pos = pos->next) 105 | 106 | 107 | 108 | /*memory for dynamic allocation 8MB from 0x00010000 ~ 0x00810000*/ 109 | #define _MEM_END 0x00810000 110 | #define _MEM_START 0x00010000 111 | 112 | /*left-shift 1 12bits is 0x10000=4096bytes=4KB*/ 113 | #define PAGE_SHIFT (12) 114 | #define PAGE_SIZE (1< 1~256 * 4k => from 4k to 1MB 155 | */ 156 | #define MAX_BUDDY_PAGE_NUM (9) 157 | 158 | #define AVERAGE_PAGE_NUM_PER_BUDDY (KERNEL_PAGE_NUM/MAX_BUDDY_PAGE_NUM) 159 | #define PAGE_NUM_FOR_MAX_BUDDY ((1<>PAGE_SHIFT; 168 | if(i>KERNEL_PAGE_NUM) 169 | return NULL; 170 | return (struct page *)KERNEL_PAGE_START+i; 171 | } 172 | 173 | void init_page_buddy(void){ 174 | int i; 175 | printk("init_page_buddy\n"); 176 | for(i=0;ivaddr=KERNEL_PAGING_START+i*PAGE_SIZE; 192 | pg->flags=PAGE_AVAILABLE; 193 | pg->counter=0; 194 | INIT_LIST_HEAD(&(pg->list)); 195 | 196 | 197 | /*make the memory max buddy as possible*/ 198 | if(i<(KERNEL_PAGE_NUM&(~PAGE_NUM_FOR_MAX_BUDDY))){ 199 | /*the following code should be dealt carefully,we would change the order field of a head struct page to the corresponding order,and change others to -1*/ 200 | if((i&PAGE_NUM_FOR_MAX_BUDDY)==0){ 201 | pg->order=MAX_BUDDY_PAGE_NUM-1; 202 | }else{ 203 | pg->order=-1; 204 | } 205 | list_add_tail(&(pg->list),&page_buddy[MAX_BUDDY_PAGE_NUM-1]); 206 | /*the remainder not enough to merge into a max buddy is done as min buddy*/ 207 | }else{ 208 | pg->order=0; 209 | list_add_tail(&(pg->list),&page_buddy[0]); 210 | } 211 | 212 | } 213 | 214 | } 215 | 216 | 217 | /*we can do these all because the page structure that represents one page aera is continuous*/ 218 | #define BUDDY_END(x,order) ((x)+(1<<(order))-1) 219 | #define NEXT_BUDDY_START(x,order) ((x)+(1<<(order))) 220 | #define PREV_BUDDY_START(x,order) ((x)-(1<<(order))) 221 | 222 | /*the logic of this function seems good,no bug reported yet*/ 223 | struct page *get_pages_from_list(int order){ 224 | unsigned int vaddr; 225 | int neworder=order; 226 | struct page *pg,*ret; 227 | struct list_head *tlst,*tlst1; 228 | for(;neworderlist); 234 | tlst->next->prev=&page_buddy[neworder]; 235 | page_buddy[neworder].next=tlst->next; 236 | goto OUT_OK; 237 | } 238 | } 239 | return NULL; 240 | 241 | OUT_OK: 242 | for(neworder--;neworder>=order;neworder--){ 243 | 244 | tlst1=&(BUDDY_END(pg,neworder)->list); 245 | tlst=&(pg->list); 246 | 247 | pg=NEXT_BUDDY_START(pg,neworder); 248 | list_entry(tlst,struct page,list)->order=neworder; 249 | 250 | list_add_chain_tail(tlst,tlst1,&page_buddy[neworder]); 251 | } 252 | pg->flags|=PAGE_BUDDY_BUSY; 253 | pg->order=order; 254 | return pg; 255 | } 256 | 257 | 258 | 259 | void put_pages_to_list(struct page *pg,int order){ 260 | struct page *tprev,*tnext; 261 | if(!(pg->flags&PAGE_BUDDY_BUSY)){ 262 | printk("something must be wrong when you see this message,that probably means you are forcing to release a page that was not alloc at all\n"); 263 | return; 264 | } 265 | pg->flags&=~(PAGE_BUDDY_BUSY); 266 | 267 | for(;orderflags&PAGE_BUDDY_BUSY))&&(tnext->order==order)){ 271 | pg->order++; 272 | tnext->order=-1; 273 | list_remove_chain(&(tnext->list),&(BUDDY_END(tnext,order)->list)); 274 | BUDDY_END(pg,order)->list.next=&(tnext->list); 275 | tnext->list.prev=&(BUDDY_END(pg,order)->list); 276 | continue; 277 | }else if((!(tprev->flags&PAGE_BUDDY_BUSY))&&(tprev->order==order)){ 278 | pg->order=-1; 279 | 280 | list_remove_chain(&(pg->list),&(BUDDY_END(pg,order)->list)); 281 | BUDDY_END(tprev,order)->list.next=&(pg->list); 282 | pg->list.prev=&(BUDDY_END(tprev,order)->list); 283 | 284 | pg=tprev; 285 | pg->order++; 286 | continue; 287 | }else{ 288 | break; 289 | } 290 | } 291 | 292 | list_add_chain(&(pg->list),&((tnext-1)->list),&page_buddy[order]); 293 | } 294 | 295 | 296 | 297 | void *page_address(struct page *pg){ 298 | return (void *)(pg->vaddr); 299 | } 300 | 301 | struct page *alloc_pages(unsigned int flag,int order){ 302 | struct page *pg; 303 | int i; 304 | pg=get_pages_from_list(order); 305 | if(pg==NULL) 306 | return NULL; 307 | for(i=0;i<(1<flags|=PAGE_DIRTY; 309 | } 310 | return pg; 311 | } 312 | 313 | void free_pages(struct page *pg,int order){ 314 | int i; 315 | for(i=0;i<(1<flags&=~PAGE_DIRTY; 317 | } 318 | put_pages_to_list(pg,order); 319 | } 320 | 321 | void *get_free_pages(unsigned int flag,int order){ 322 | struct page * page; 323 | page = alloc_pages(flag, order); 324 | if (!page) 325 | return NULL; 326 | return page_address(page); 327 | } 328 | 329 | void put_free_pages(void *addr,int order){ 330 | free_pages(virt_to_page((unsigned int)addr),order); 331 | } 332 | 333 | -------------------------------------------------------------------------------- /labMem/mmu.c: -------------------------------------------------------------------------------- 1 | #define NUM_PAGE_TABLE_ENTRIES 4096 /* 1 entry per 1MB, so this covers 4G address space */ 2 | #define CACHE_DISABLED 0x12 3 | #define SDRAM_START 0x80000000 4 | #define SDRAM_END 0x8fffffff 5 | #define CACHE_WRITEBACK 0x1e 6 | 7 | #define U32 unsigned int 8 | 9 | void enable_mmu2(void) 10 | { 11 | static unsigned int *page_table=(unsigned int *const)0x14000; 12 | 13 | int i; 14 | U32 reg; 15 | 16 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 17 | { 18 | /* map 0x20000000~0x210000000 to 0xa0000000~0xa1000000 */ 19 | if (i >= (0xa0000000 >> 20) && i <= ( 0xa1000000 >> 20)) 20 | { 21 | page_table[i] = (i-2048)<<20 | 0x0410 | 2; 22 | printk("page_table[%d]addr=%x, section=%x \n",i,&page_table[i],page_table[i]); 23 | } 24 | else 25 | /*not mapping yet*/ 26 | page_table[i]= i<<20| 0x0410|2 ; 27 | } 28 | printk("page_talble base=%x page_table409=%x \n",page_table,&page_table[4095]); 29 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 30 | /* Copy the page table address to cp15 */ 31 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 32 | : : "r" (page_table) : "memory"); 33 | /* Set the access control to all-supervisor */ 34 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 35 | 36 | /* Enable the MMU */ 37 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 38 | reg|=0x1; 39 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 40 | } 41 | 42 | void enable_mmu(void) 43 | { 44 | static U32 __attribute__((aligned(16384))) page_table[NUM_PAGE_TABLE_ENTRIES]; 45 | int i; 46 | U32 reg; 47 | 48 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 49 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 50 | page_table[i] = i << 20 | (3 << 10) | CACHE_DISABLED; 51 | /* Then, enable cacheable and bufferable for RAM only */ 52 | for (i = SDRAM_START >> 20; i < SDRAM_END >> 20; i++) 53 | { 54 | page_table[i] = i << 20 | (3 << 10) | CACHE_WRITEBACK; 55 | } 56 | 57 | /* Copy the page table address to cp15 */ 58 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 59 | : : "r" (page_table) : "memory"); 60 | /* Set the access control to all-supervisor */ 61 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 62 | 63 | /* Enable the MMU */ 64 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 65 | reg|=0x1; 66 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 67 | } 68 | -------------------------------------------------------------------------------- /labMem/run_pi.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/qemu-system-arm -kernel boot.bin -cpu arm1176 -m 256 -M raspi -serial stdio 2 | -------------------------------------------------------------------------------- /labMem/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | start.s: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Modified by Carlos Hsu 19 | */ 20 | 21 | 22 | 23 | .global _start 24 | .global __vector_reset 25 | .global __vector_undefined 26 | .global __vector_swi 27 | .global __vector_prefetch_abort 28 | .global __vector_data_abort 29 | .global __vector_reserved 30 | .global __vector_irq 31 | .global __vector_fiq 32 | 33 | .equ DISABLE_IRQ, 0x80 /* when I bit is set, IRQ is disabled */ 34 | .equ DISABLE_FIQ, 0x40 /* when F bit is set, FIQ is disabled */ 35 | .equ SYS_MOD, 0x1f /* System Mode */ 36 | .equ IRQ_MOD, 0x12 /* IRQ Mode */ 37 | .equ FIQ_MOD, 0x11 /* FIQ Mode */ 38 | .equ SVC_MOD, 0x13 /* Supervisor Mode */ 39 | .equ ABT_MOD, 0x17 /* Abort Mode */ 40 | .equ UND_MOD, 0x1b /* Undefined Mode */ 41 | 42 | .equ MEM_SIZE, 0x7A00000 43 | .equ TEXT_BASE, 0x0008000 44 | 45 | .equ _SVC_STACK, (TEXT_BASE+MEM_SIZE-4) 46 | .equ _IRQ_STACK, (_SVC_STACK-0x400) 47 | .equ _FIQ_STACK, (_IRQ_STACK-0x400) 48 | .equ _ABT_STACK, (_FIQ_STACK-0x400) 49 | .equ _UND_STACK, (_ABT_STACK-0x400) 50 | .equ _SYS_STACK, (_UND_STACK-0x400) 51 | 52 | .text 53 | .code 32 54 | 55 | __vector_undefined: 56 | nop 57 | __vector_swi: 58 | nop 59 | __vector_prefetch_abort: 60 | nop 61 | __vector_data_abort: 62 | nop 63 | __vector_reserved: 64 | nop 65 | __vector_irq: 66 | // save registers 67 | stmfd r13!, {r0-r12,lr} 68 | // call interrupt handler 69 | bl IRQ_handler 70 | // restore registers 71 | ldmfd r13!, {r0-r12,lr} 72 | // return address(IRQ lr-4) 73 | subs pc,lr, #4 74 | __vector_fiq: 75 | nop 76 | 77 | // IRQ enable set CPSR 78 | .global enable_IRQ 79 | enable_IRQ: 80 | mrs r0, cpsr 81 | bic r0, r0, #0x80 82 | msr cpsr_c,r0 83 | bx lr 84 | 85 | // IRQ disable set CPSR 86 | .global disable_IRQ 87 | disable_IRQ: 88 | mrs r0, cpsr 89 | ldr r1, =0x80 90 | orr r0, r0, r1 91 | msr cpsr_c, r0 92 | bx lr 93 | 94 | .extern plat_boot 95 | .extern __bss_start__ 96 | .extern __bss_end__ 97 | 98 | /*set stack*/ 99 | __vector_reset: 100 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SVC_MOD) 101 | ldr sp,=_SVC_STACK 102 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|IRQ_MOD) 103 | ldr sp,=_IRQ_STACK 104 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|FIQ_MOD) 105 | ldr sp,=_FIQ_STACK 106 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|ABT_MOD) 107 | ldr sp,=_ABT_STACK 108 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|UND_MOD) 109 | ldr sp,=_UND_STACK 110 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SYS_MOD) 111 | ldr sp,=_SYS_STACK 112 | 113 | _clear_bss: 114 | ldr r1,_bss_start_ 115 | ldr r3,_bss_end_ 116 | mov r2,#0x0 117 | 1: 118 | cmp r1,r3 119 | beq _main 120 | str r2,[r1],#0x4 121 | b 1b 122 | /*jump to plat_boot function in boot.c*/ 123 | _main: 124 | b plat_boot 125 | 126 | _bss_start_:.word __bss_start__ 127 | _bss_end_:.word __bss_end__ 128 | 129 | .section .startup 130 | .code 32 131 | .align 0 132 | _start: 133 | 134 | ldr pc,_vector_reset 135 | ldr pc,_vector_undefined 136 | ldr pc,_vector_swi 137 | ldr pc,_vector_prefetch_abort 138 | ldr pc,_vector_data_abort 139 | ldr pc,_vector_reserved 140 | ldr pc,_vector_irq 141 | ldr pc,_vector_fiq 142 | 143 | .align 4 144 | 145 | _vector_reset: .word __vector_reset 146 | _vector_undefined: .word __vector_undefined 147 | _vector_swi: .word __vector_swi 148 | _vector_prefetch_abort: .word __vector_prefetch_abort 149 | _vector_data_abort: .word __vector_data_abort 150 | _vector_reserved: .word __vector_reserved 151 | _vector_irq: .word __vector_irq 152 | _vector_fiq: .word __vector_fiq 153 | 154 | 155 | -------------------------------------------------------------------------------- /mimiOS/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE = arm-none-eabi- 2 | CC = $(CROSS_COMPILE)gcc 3 | OBJCOPY = $(CROSS_COMPILE)objcopy 4 | LD = $(CROSS_COMPILE)ld 5 | ARCH = $(CROSS_COMPILE)ar 6 | IMAGE = boot 7 | 8 | 9 | 10 | 11 | CFLAGS = \ 12 | -fno-builtin \ 13 | -O0 -g -fomit-frame-pointer -fno-strict-aliasing -mcpu=arm1176jzf-s 14 | 15 | LDSCRIPT := ld-scr.lds 16 | LDFLAGS = \ 17 | -nostdlib -static -nostartfiles \ 18 | -T $(LDSCRIPT) 19 | 20 | OBJCOPYFLAGS = \ 21 | -O binary \ 22 | -S 23 | 24 | C_SRC = ./boot.c ./mmu.c ./interrupt.c ./mem.c \ 25 | ./lib/print.c ./process.c ./syscall.c ./scheduler.c 26 | ASM_SRC = ./start.S 27 | 28 | 29 | C_OBJ = $(C_SRC:.c=.o) 30 | HW_DEP_ASM_OBJ = $(ASM_SRC:.S=.o) 31 | 32 | 33 | $(IMAGE).bin: $(IMAGE).elf 34 | $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ 35 | 36 | $(IMAGE).elf: $(C_OBJ) $(HW_DEP_ASM_OBJ) 37 | $(CC) $(LDFLAGS) -o $(IMAGE).elf \ 38 | $(C_OBJ) $(HW_DEP_ASM_OBJ) -lgcc 39 | 40 | $(C_OBJ) : %.o : %.c 41 | $(CC) -c $(CFLAGS) $< -o $@ 42 | 43 | 44 | $(HW_DEP_ASM_OBJ) : %.o : %.S 45 | $(CC) -c $(CFLAGS) $< -o $@ 46 | 47 | 48 | 49 | 50 | clean: 51 | rm -f ./*.o \ 52 | ./lib/*.o \ 53 | $(IMAGE).bin $(IMAGE).elf \ 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /mimiOS/README: -------------------------------------------------------------------------------- 1 | 2 | MimiOS - A tiny OS on Raspberry Pi ARMv6 board. 3 | 4 | 5 | Reference sources: 6 | 1. Daniel Santos Bathke , PIqueno 7 | 2. brianwiddas, https://github.com/brianwiddas/pi-baremetal 8 | 3. David Welch , https://github.com/dwelch67/raspberrypi 9 | 4. david leels , http://leeosorg.appspot.com 10 | 11 | check my blog for details 12 | http://karosesblog.blogspot.tw/ 13 | 14 | 15 | -------------------------------------------------------------------------------- /mimiOS/RESULT: -------------------------------------------------------------------------------- 1 | HelloWorld 2 | PRINTK TEST 3 | page_table[2560]addr=0x16800, section=0x20000412 4 | page_table[2561]addr=0x16804, section=0x20100412 5 | page_table[2562]addr=0x16808, section=0x20200412 6 | page_table[2563]addr=0x1680c, section=0x20300412 7 | page_table[2564]addr=0x16810, section=0x20400412 8 | page_table[2565]addr=0x16814, section=0x20500412 9 | page_table[2566]addr=0x16818, section=0x20600412 10 | page_table[2567]addr=0x1681c, section=0x20700412 11 | page_table[2568]addr=0x16820, section=0x20800412 12 | page_table[2569]addr=0x16824, section=0x20900412 13 | page_table[2570]addr=0x16828, section=0x20a00412 14 | page_table[2571]addr=0x1682c, section=0x20b00412 15 | page_table[2572]addr=0x16830, section=0x20c00412 16 | page_table[2573]addr=0x16834, section=0x20d00412 17 | page_table[2574]addr=0x16838, section=0x20e00412 18 | page_table[2575]addr=0x1683c, section=0x20f00412 19 | page_table[2576]addr=0x16840, section=0x21000412 20 | page_talble base=0x14000 page_table409=0x17ffc 21 | test_mmu 22 | init_page_map 23 | KERNE_FROM:0x10000 to 0x802000 24 | KERNEL_PAGE_STRUCT start:0x802188 25 | init_page_buddy 26 | the return address of get_free_pages 0xd0000 27 | the return address of get_free_pages 0x90000 28 | the return address of get_free_pages 0x10000 29 | the return address of get_free_pages 0x90000 30 | Main stack is 0x0x7a06bb4 31 | Forked stack is 0x0x7a06fb4 32 | Forked stack is 0x0x7a073b4 33 | Forked stack is 0x0x7a077b4 34 | irq init 35 | 36 | 37 | Schedule timeout. Current active pid is 0 with name Main. Switching to next process. 38 | Saving stack... stack saved, was 0x0x7a06b9c 39 | Saving pc... pc saved, was 0x0x104ac 40 | Restoring stack 0x0x7a06fb4 41 | Restoring pc 0x0x11a54 42 | Starting process 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 43 | Handling syscall: 0 44 | Invoking syscall terminate_process() 45 | Turning interrupt on again 46 | 47 | 48 | Schedule timeout. Current active pid is 1 with name Sample process 1. Switching to next process. 49 | Saving stack... stack saved, was 0x0x7a06f4c 50 | Saving pc... pc saved, was 0x0x104ac 51 | Restoring stack 0x0x7a073b4 52 | Restoring pc 0x0x11af4 53 | Starting process 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 54 | Handling syscall: 0 55 | Invoking syscall terminate_process() 56 | Turning interrupt on again 57 | 58 | 59 | Schedule timeout. Current active pid is 2 with name Sample process 2. Switching to next process. 60 | Saving stack... stack saved, was 0x0x7a0734c 61 | Saving pc... pc saved, was 0x0x104ac 62 | Restoring stack 0x0x7a077b4 63 | Restoring pc 0x0x11af4 64 | Starting process 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 65 | Handling syscall: 0 66 | Invoking syscall terminate_process() 67 | Turning interrupt on again 68 | 69 | 70 | Schedule timeout. Current active pid is 3 with name Sample process 3. Switching to next process. 71 | Saving stack... stack saved, was 0x0x7a0774c 72 | Saving pc... pc saved, was 0x0x104ac 73 | No more waiting processes, halting. -------------------------------------------------------------------------------- /mimiOS/boot.c: -------------------------------------------------------------------------------- 1 | /* 2 | boot.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Tzu Hang modifed to miniOS 19 | */ 20 | 21 | #include "process.h" 22 | #include "scheduler.h" 23 | 24 | 25 | 26 | typedef void (*init_func)(void); 27 | 28 | #define UFCON0 ((volatile unsigned int *)(0x20201000)) 29 | 30 | void helloworld(void){ 31 | const char *p="HelloWorld\n"; 32 | while(*p){ 33 | *UFCON0=*p++; 34 | }; 35 | } 36 | 37 | void test_mmu(void){ 38 | const char *p="test_mmu\n"; 39 | while(*p){ 40 | *(volatile unsigned int *)0xa0201000=*p++; 41 | }; 42 | } 43 | 44 | 45 | static init_func init[]={ 46 | helloworld, 47 | 0, 48 | }; 49 | 50 | void main_endloop(void) 51 | { 52 | printk("\nPrefetch abort done"); 53 | 54 | /* Repeatedly halt the CPU and wait for interrupt */ 55 | while(1) 56 | asm volatile("mcr p15,0,r0,c7,c0,4" : : : "r0"); 57 | 58 | } 59 | 60 | 61 | 62 | void plat_boot(void){ 63 | int i; 64 | for(i=0;init[i];i++){ 65 | init[i](); 66 | } 67 | 68 | printk("PRINTK TEST\n"); 69 | 70 | enable_mmu2(); 71 | test_mmu(); 72 | 73 | //Timer interrupt init. 74 | //IRQ_init(); 75 | 76 | //memory management Buddy system 77 | init_page_map(); 78 | char *p1,*p2,*p3,*p4; 79 | p1=(char *)get_free_pages(0,6); 80 | printk("the return address of get_free_pages %x\n",p1); 81 | p2=(char *)get_free_pages(0,6); 82 | printk("the return address of get_free_pages %x\n",p2); 83 | put_free_pages(p2,6); 84 | put_free_pages(p1,6); 85 | p3=(char *)get_free_pages(0,7); 86 | printk("the return address of get_free_pages %x\n",p3); 87 | p4=(char *)get_free_pages(0,7); 88 | printk("the return address of get_free_pages %x\n",p4); 89 | 90 | 91 | create_main_process(); 92 | 93 | // Create three sample processes with name and address of function 94 | fork("Sample process 1", &sample_process_1); 95 | fork("Sample process 2", &sample_process_2); 96 | fork("Sample process 3", &sample_process_2); 97 | 98 | IRQ_init(); 99 | while(1); 100 | } 101 | -------------------------------------------------------------------------------- /mimiOS/interrupt.c: -------------------------------------------------------------------------------- 1 | /* 2 | interrupt.s 3 | Tzu Hang 4 | 5 | reference:brianwiddas https://github.com/brianwiddas/pi-baremetal 6 | tnishinaga book:"BareMetalで遊ぶ Raspberry Pi" 7 | */ 8 | static volatile unsigned int *irqEnable1 = (unsigned int *)0x2000b210; 9 | static volatile unsigned int *irqEnable2 = (unsigned int *) 0x2000b214; 10 | static volatile unsigned int *irqEnableBasic = (unsigned int *) 0x2000b218; 11 | 12 | static volatile unsigned int *armTimerLoad = (unsigned int *) 0x2000b400; 13 | static volatile unsigned int *armTimerValue = (unsigned int *) 0x2000b404; 14 | static volatile unsigned int *armTimerControl = (unsigned int *) 0x2000b408; 15 | static volatile unsigned int *armTimerIRQClear = (unsigned int *) 0x2000b40c; 16 | 17 | 18 | __attribute__ ((naked, aligned(32))) static void interrupt_vectors(void) 19 | { 20 | asm volatile("b __vector_reset\n" /* RESET */ 21 | "b __vector_undefined\n" /* UNDEF */ 22 | "b __vector_swi\n" 23 | "b __vector_prefetch_abort \n" 24 | "b __vector_data_abort \n" 25 | "b __vector_reserved;\n" /* Unused vector */ 26 | "b __vector_irq \n" /*IRQ*/ 27 | "b __vector_fiq\n" /* FIQ */ 28 | ); 29 | } 30 | 31 | 32 | 33 | void IRQ_handler() 34 | { 35 | 36 | disable_IRQ(); 37 | // This function starts on IRQ mode 38 | 39 | // Push all registers into the IRQ mode stack (R13) 40 | asm volatile("push {R0-R12}"); 41 | 42 | // Put LR register of IRQ mode (PC of interrupted process) on R0 43 | asm volatile("MOV R0, LR"); 44 | 45 | 46 | // Change to system mode 47 | asm volatile("cps #0x1f"); 48 | 49 | // Push R0 (interrupted PC) to the system mode stack 50 | asm volatile("push {R0}"); 51 | 52 | 53 | // Return to IRQ mode 54 | asm volatile("cps #0x12"); 55 | 56 | // Pop all registers again 57 | asm volatile("pop {R0-R12}"); 58 | 59 | 60 | // Return to system mode 61 | asm volatile("cps #0x1f"); 62 | 63 | // Push all registers into the system mode stack 64 | asm volatile("push {R0-R12}"); 65 | 66 | // Push the interrupted LR to system mode stack 67 | asm volatile("push {LR}"); 68 | 69 | // Copy the processor status to R0 70 | asm volatile("MRS R0, SPSR"); 71 | 72 | // Push the processor status to system mode stack 73 | asm volatile("push {R0}"); 74 | 75 | 76 | // Return to IRQ mode 77 | asm volatile("cps #0x12"); 78 | 79 | // Copy LR to R0 80 | asm volatile("MOV R0, LR"); 81 | 82 | // Back to system mode 83 | asm volatile("cps #0x1f"); 84 | 85 | unsigned long pc; 86 | 87 | unsigned long stack_pointer; 88 | 89 | // Getting pc and stack just to debug 90 | asm volatile ("MOV %0, R0\n\t" : "=r" (pc) ); 91 | asm volatile ("MOV %0, SP\n\t" : "=r" (stack_pointer) ); 92 | 93 | 94 | // Jump to scheduler to do the context switch 95 | schedule_timeout(stack_pointer, pc); 96 | 97 | 98 | 99 | } 100 | 101 | void timer_reset(void) 102 | { 103 | *armTimerIRQClear = 0; 104 | } 105 | 106 | 107 | void IRQ_init() 108 | { 109 | 110 | /* Set interrupt base register */ 111 | asm volatile("mcr p15, 0, %[addr], c12, c0, 0" : : [addr] "r" (&interrupt_vectors)); 112 | 113 | /* Turn on interrupts */ 114 | asm volatile("cpsie i"); 115 | printk("irq init \n"); 116 | 117 | /* Use the ARM timer - BCM 2832 peripherals doc, p.196 */ 118 | /* Enable ARM timer IRQ */ 119 | *irqEnableBasic = 0x00000001; 120 | 121 | /* Interrupt every 1024 * 256 (prescaler) timer ticks */ 122 | *armTimerLoad = 0x00000400; 123 | 124 | /* Timer enabled, interrupt enabled, prescale=256, "23 bit" counter 125 | * (did they mean 32 bit?) 126 | */ 127 | *armTimerControl = 0x000000aa; 128 | } 129 | -------------------------------------------------------------------------------- /mimiOS/ld-scr.lds: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | SECTIONS 6 | { 7 | . = 0x00010000; 8 | .text : 9 | { 10 | *(.startup) 11 | *(.text) 12 | } 13 | . = ALIGN(32); 14 | 15 | .data : 16 | { 17 | *(.data) 18 | } 19 | 20 | . = ALIGN(32); 21 | __bss_start__ = .; 22 | .bss : 23 | { 24 | *(.bss) 25 | } 26 | __bss_end__ = .; 27 | } 28 | -------------------------------------------------------------------------------- /mimiOS/lib/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | print.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | 20 | typedef char * va_list; 21 | #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 22 | #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 23 | #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 24 | #define va_end(ap) ( ap = (va_list)0 ) 25 | 26 | const char *digits="0123456789abcdef"; 27 | char numbers[68]; 28 | 29 | static char print_buf[1024]; 30 | 31 | #define FORMAT_TYPE_MASK 0xff00 32 | #define FORMAT_TYPE_SIGN_BIT 0x0100 33 | #define FORMAT_TYPE_NONE 0x000 34 | #define FORMAT_TYPE_CHAR 0x100 35 | #define FORMAT_TYPE_UCHAR 0x200 36 | #define FORMAT_TYPE_SHORT 0x300 37 | #define FORMAT_TYPE_USHORT 0x400 38 | #define FORMAT_TYPE_INT 0x500 39 | #define FORMAT_TYPE_UINT 0x600 40 | #define FORMAT_TYPE_LONG 0x700 41 | #define FORMAT_TYPE_ULONG 0x800 42 | #define FORMAT_TYPE_STR 0xd00 43 | #define FORMAT_TYPE_PTR 0x900 44 | #define FORMAT_TYPE_SIZE_T 0xb00 45 | 46 | #define FORMAT_TYPE(x) ((x)&FORMAT_TYPE_MASK) 47 | #define SET_FORMAT_TYPE(x,t) do{\ 48 | (x)&=~FORMAT_TYPE_MASK;(x)|=(t);\ 49 | }while(0) 50 | #define FORMAT_SIGNED(x) ((x)&FORMAT_TYPE_SIGN_BIT) 51 | 52 | #define FORMAT_FLAG_MASK 0xffff0000 53 | #define FORMAT_FLAG_SPACE 0x10000 54 | #define FORMAT_FLAG_ZEROPAD 0x20000 55 | #define FORMAT_FLAG_LEFT 0x40000 56 | #define FORMAT_FLAG_WIDTH 0x100000 57 | 58 | #define FORMAT_FLAG(x) ((x)&FORMAT_FLAG_MASK) 59 | #define SET_FORMAT_FLAG(x,f) ((x)|=(f)) 60 | 61 | #define FORMAT_BASE_MASK 0xff 62 | #define FORMAT_BASE_O 0x08 63 | #define FORMAT_BASE_X 0x10 64 | #define FORMAT_BASE_D 0x0a 65 | #define FORMAT_BASE_B 0x02 66 | 67 | #define FORMAT_BASE(x) (FORMAT_BASE_MASK&(x)) 68 | #define SET_FORMAT_BASE(x,t) do{(x)&=~FORMAT_BASE_MASK;(x)|=(t);}while(0) 69 | 70 | #define do_div(n,base) ({ \ 71 | int __res; \ 72 | __res = ((unsigned int) n) % (unsigned int) base; \ 73 | n = ((unsigned int) n) / (unsigned int) base; \ 74 | __res; }) 75 | 76 | void __put_char(char *p,int num){ 77 | while(*p&&num--){ 78 | *(volatile unsigned int *)0x20201000=*p++; 79 | }; 80 | } 81 | 82 | void * memcpy(void * dest,const void *src,unsigned int count) 83 | { 84 | char *tmp = (char *) dest, *s = (char *) src; 85 | while (count--) 86 | *tmp++ = *s++; 87 | return dest; 88 | } 89 | 90 | char *number(char *str, int num,int base,unsigned int flags){ 91 | int i=0; 92 | int sign=0; 93 | 94 | if(FORMAT_SIGNED(flags)&&(signed int)num<0){ 95 | sign=1; 96 | num=~num+1; 97 | } 98 | 99 | do{ 100 | numbers[i++]=digits[do_div(num,base)]; 101 | }while(num!=0); 102 | 103 | 104 | if(FORMAT_BASE(flags)==FORMAT_BASE_O){ 105 | numbers[i++]='0'; 106 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_X){ 107 | numbers[i++]='x'; 108 | numbers[i++]='0'; 109 | }else if(FORMAT_BASE(flags)==FORMAT_BASE_B){ 110 | numbers[i++]='b'; 111 | numbers[i++]='0'; 112 | } 113 | if(sign) 114 | numbers[i++]='-'; 115 | 116 | while (i-- > 0) 117 | *str++ = numbers[i]; 118 | return str; 119 | } 120 | 121 | int format_decode(const char *fmt,unsigned int *flags){ 122 | const char *start = fmt; 123 | 124 | *flags &= ~FORMAT_TYPE_MASK; 125 | *flags |= FORMAT_TYPE_NONE; 126 | for (; *fmt ; ++fmt) { 127 | if (*fmt == '%') 128 | break; 129 | } 130 | 131 | if (fmt != start || !*fmt) 132 | return fmt - start; 133 | 134 | do{ 135 | fmt++; 136 | switch(*fmt){ 137 | case 'l': 138 | SET_FORMAT_FLAG(*flags,FORMAT_FLAG_WIDTH); 139 | break; 140 | default: 141 | break; 142 | } 143 | }while(0); 144 | 145 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 146 | switch (*fmt) { 147 | case 'c': 148 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_CHAR); 149 | break; 150 | 151 | case 's': 152 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_STR); 153 | break; 154 | 155 | case 'o': 156 | SET_FORMAT_BASE(*flags,FORMAT_BASE_O); 157 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 158 | break; 159 | 160 | case 'x': 161 | case 'X': 162 | SET_FORMAT_BASE(*flags,FORMAT_BASE_X); 163 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 164 | break; 165 | 166 | case 'd': 167 | case 'i': 168 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_INT); 169 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 170 | break; 171 | case 'u': 172 | SET_FORMAT_TYPE(*flags,FORMAT_TYPE_UINT); 173 | SET_FORMAT_BASE(*flags,FORMAT_BASE_D); 174 | break; 175 | 176 | default: 177 | break; 178 | } 179 | return ++fmt-start; 180 | } 181 | 182 | int vsnprintf(char *buf, int size, const char *fmt, va_list args){ 183 | int num; 184 | char *str, *end, c,*s; 185 | int read; 186 | unsigned int spec=0; 187 | 188 | str = buf; 189 | end = buf + size; 190 | 191 | if (end < buf) { 192 | end = ((void *)-1); 193 | size = end - buf; 194 | } 195 | 196 | while (*fmt) { 197 | const char *old_fmt = fmt; 198 | 199 | read = format_decode(fmt, &spec); 200 | fmt += read; 201 | 202 | if((FORMAT_TYPE(spec))==FORMAT_TYPE_NONE){ 203 | int copy = read; 204 | if (str < end) { 205 | if (copy > end - str) 206 | copy = end - str; 207 | memcpy(str, old_fmt, copy); 208 | } 209 | str += read; 210 | 211 | }else if(spec&FORMAT_FLAG_WIDTH){ 212 | //do nothing 213 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_CHAR){ 214 | c = (unsigned char) va_arg(args, int); 215 | if (str < end) 216 | *str = c; 217 | ++str; 218 | }else if(FORMAT_TYPE(spec)==FORMAT_TYPE_STR){ 219 | s = (char *) va_arg(args, char *); 220 | while(str 0) { 243 | if (str < end) 244 | *str = '\0'; 245 | else 246 | end[-1] = '\0'; 247 | } 248 | return str-buf; 249 | } 250 | 251 | void printk(const char *fmt, ...) 252 | { 253 | va_list args; 254 | unsigned int i; 255 | 256 | va_start (args, fmt); 257 | i = vsnprintf (print_buf, sizeof(print_buf),fmt, args); 258 | va_end (args); 259 | 260 | __put_char (print_buf,i); 261 | } 262 | 263 | void test_printk(void){ 264 | char *p="this is %s test"; 265 | char c='H'; 266 | int d=-256; 267 | int k=0; 268 | printk("testing printk\n"); 269 | printk("test string ::: %s\ntest char ::: %c\ntest digit ::: %d\ntest X ::: %x\ntest unsigned ::: %u\ntest zero ::: %d\n",p,c,d,d,d,k); 270 | } 271 | -------------------------------------------------------------------------------- /mimiOS/mem.c: -------------------------------------------------------------------------------- 1 | /* 2 | mem.c: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #define NULL ((void *)0) 20 | 21 | struct list_head { 22 | struct list_head *next, *prev; 23 | }; 24 | 25 | 26 | static inline void INIT_LIST_HEAD(struct list_head *list) 27 | { 28 | list->next = list; 29 | list->prev = list; 30 | } 31 | 32 | static inline void __list_add(struct list_head *new_lst, 33 | struct list_head *prev, 34 | struct list_head *next) 35 | { 36 | next->prev = new_lst; 37 | new_lst->next = next; 38 | new_lst->prev = prev; 39 | prev->next = new_lst; 40 | } 41 | 42 | static inline void list_add(struct list_head *new_lst, struct list_head *head) 43 | { 44 | __list_add(new_lst, head, head->next); 45 | } 46 | 47 | static inline void list_add_tail(struct list_head *new_lst, struct list_head *head) 48 | { 49 | __list_add(new_lst, head->prev, head); 50 | } 51 | 52 | static inline void __list_del(struct list_head * prev, struct list_head * next) 53 | { 54 | next->prev = prev; 55 | prev->next = next; 56 | } 57 | 58 | static inline void list_del(struct list_head * entry) 59 | { 60 | __list_del(entry->prev,entry->next); 61 | } 62 | 63 | 64 | static inline void list_remove_chain(struct list_head *ch,struct list_head *ct){ 65 | ch->prev->next=ct->next; 66 | ct->next->prev=ch->prev; 67 | } 68 | 69 | static inline void list_add_chain(struct list_head *ch,struct list_head *ct,struct list_head *head){ 70 | ch->prev=head; 71 | ct->next=head->next; 72 | head->next->prev=ct; 73 | head->next=ch; 74 | } 75 | 76 | static inline void list_add_chain_tail(struct list_head *ch,struct list_head *ct,struct list_head *head){ 77 | ch->prev=head->prev; 78 | head->prev->next=ch; 79 | head->prev=ct; 80 | ct->next=head; 81 | } 82 | 83 | 84 | static inline int list_empty(const struct list_head *head) 85 | { 86 | return head->next == head; 87 | } 88 | 89 | 90 | 91 | #define offsetof(TYPE, MEMBER) ((unsigned int) &((TYPE *)0)->MEMBER) 92 | 93 | #define container_of(ptr, type, member) ({ \ 94 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 95 | (type *)( (char *)__mptr - offsetof(type,member) );}) 96 | 97 | 98 | #define list_entry(ptr,type,member) \ 99 | container_of(ptr, type, member) 100 | 101 | 102 | 103 | #define list_for_each(pos, head) \ 104 | for (pos = (head)->next; pos != (head); pos = pos->next) 105 | 106 | 107 | 108 | /*memory for dynamic allocation 8MB from 0x00010000 ~ 0x00810000*/ 109 | #define _MEM_END 0x00810000 110 | #define _MEM_START 0x00010000 111 | 112 | /*left-shift 1 12bits is 0x10000=4096bytes=4KB*/ 113 | #define PAGE_SHIFT (12) 114 | #define PAGE_SIZE (1< 1~256 * 4k => from 4k to 1MB 155 | */ 156 | #define MAX_BUDDY_PAGE_NUM (9) 157 | 158 | #define AVERAGE_PAGE_NUM_PER_BUDDY (KERNEL_PAGE_NUM/MAX_BUDDY_PAGE_NUM) 159 | #define PAGE_NUM_FOR_MAX_BUDDY ((1<>PAGE_SHIFT; 168 | if(i>KERNEL_PAGE_NUM) 169 | return NULL; 170 | return (struct page *)KERNEL_PAGE_START+i; 171 | } 172 | 173 | void init_page_buddy(void){ 174 | int i; 175 | printk("init_page_buddy\n"); 176 | for(i=0;ivaddr=KERNEL_PAGING_START+i*PAGE_SIZE; 192 | pg->flags=PAGE_AVAILABLE; 193 | pg->counter=0; 194 | INIT_LIST_HEAD(&(pg->list)); 195 | 196 | 197 | /*make the memory max buddy as possible*/ 198 | if(i<(KERNEL_PAGE_NUM&(~PAGE_NUM_FOR_MAX_BUDDY))){ 199 | /*the following code should be dealt carefully,we would change the order field of a head struct page to the corresponding order,and change others to -1*/ 200 | if((i&PAGE_NUM_FOR_MAX_BUDDY)==0){ 201 | pg->order=MAX_BUDDY_PAGE_NUM-1; 202 | }else{ 203 | pg->order=-1; 204 | } 205 | list_add_tail(&(pg->list),&page_buddy[MAX_BUDDY_PAGE_NUM-1]); 206 | /*the remainder not enough to merge into a max buddy is done as min buddy*/ 207 | }else{ 208 | pg->order=0; 209 | list_add_tail(&(pg->list),&page_buddy[0]); 210 | } 211 | 212 | } 213 | 214 | } 215 | 216 | 217 | /*we can do these all because the page structure that represents one page aera is continuous*/ 218 | #define BUDDY_END(x,order) ((x)+(1<<(order))-1) 219 | #define NEXT_BUDDY_START(x,order) ((x)+(1<<(order))) 220 | #define PREV_BUDDY_START(x,order) ((x)-(1<<(order))) 221 | 222 | /*the logic of this function seems good,no bug reported yet*/ 223 | struct page *get_pages_from_list(int order){ 224 | unsigned int vaddr; 225 | int neworder=order; 226 | struct page *pg,*ret; 227 | struct list_head *tlst,*tlst1; 228 | for(;neworderlist); 234 | tlst->next->prev=&page_buddy[neworder]; 235 | page_buddy[neworder].next=tlst->next; 236 | goto OUT_OK; 237 | } 238 | } 239 | return NULL; 240 | 241 | OUT_OK: 242 | for(neworder--;neworder>=order;neworder--){ 243 | 244 | tlst1=&(BUDDY_END(pg,neworder)->list); 245 | tlst=&(pg->list); 246 | 247 | pg=NEXT_BUDDY_START(pg,neworder); 248 | list_entry(tlst,struct page,list)->order=neworder; 249 | 250 | list_add_chain_tail(tlst,tlst1,&page_buddy[neworder]); 251 | } 252 | pg->flags|=PAGE_BUDDY_BUSY; 253 | pg->order=order; 254 | return pg; 255 | } 256 | 257 | 258 | 259 | void put_pages_to_list(struct page *pg,int order){ 260 | struct page *tprev,*tnext; 261 | if(!(pg->flags&PAGE_BUDDY_BUSY)){ 262 | printk("something must be wrong when you see this message,that probably means you are forcing to release a page that was not alloc at all\n"); 263 | return; 264 | } 265 | pg->flags&=~(PAGE_BUDDY_BUSY); 266 | 267 | for(;orderflags&PAGE_BUDDY_BUSY))&&(tnext->order==order)){ 271 | pg->order++; 272 | tnext->order=-1; 273 | list_remove_chain(&(tnext->list),&(BUDDY_END(tnext,order)->list)); 274 | BUDDY_END(pg,order)->list.next=&(tnext->list); 275 | tnext->list.prev=&(BUDDY_END(pg,order)->list); 276 | continue; 277 | }else if((!(tprev->flags&PAGE_BUDDY_BUSY))&&(tprev->order==order)){ 278 | pg->order=-1; 279 | 280 | list_remove_chain(&(pg->list),&(BUDDY_END(pg,order)->list)); 281 | BUDDY_END(tprev,order)->list.next=&(pg->list); 282 | pg->list.prev=&(BUDDY_END(tprev,order)->list); 283 | 284 | pg=tprev; 285 | pg->order++; 286 | continue; 287 | }else{ 288 | break; 289 | } 290 | } 291 | 292 | list_add_chain(&(pg->list),&((tnext-1)->list),&page_buddy[order]); 293 | } 294 | 295 | 296 | 297 | void *page_address(struct page *pg){ 298 | return (void *)(pg->vaddr); 299 | } 300 | 301 | struct page *alloc_pages(unsigned int flag,int order){ 302 | struct page *pg; 303 | int i; 304 | pg=get_pages_from_list(order); 305 | if(pg==NULL) 306 | return NULL; 307 | for(i=0;i<(1<flags|=PAGE_DIRTY; 309 | } 310 | return pg; 311 | } 312 | 313 | void free_pages(struct page *pg,int order){ 314 | int i; 315 | for(i=0;i<(1<flags&=~PAGE_DIRTY; 317 | } 318 | put_pages_to_list(pg,order); 319 | } 320 | 321 | void *get_free_pages(unsigned int flag,int order){ 322 | struct page * page; 323 | page = alloc_pages(flag, order); 324 | if (!page) 325 | return NULL; 326 | return page_address(page); 327 | } 328 | 329 | void put_free_pages(void *addr,int order){ 330 | free_pages(virt_to_page((unsigned int)addr),order); 331 | } 332 | 333 | -------------------------------------------------------------------------------- /mimiOS/mmu.c: -------------------------------------------------------------------------------- 1 | /* 2 | Author Tzu Hang 3 | */ 4 | 5 | #define NUM_PAGE_TABLE_ENTRIES 4096 /* 1 entry per 1MB, so this covers 4G address space */ 6 | #define CACHE_DISABLED 0x12 7 | #define SDRAM_START 0x80000000 8 | #define SDRAM_END 0x8fffffff 9 | #define CACHE_WRITEBACK 0x1e 10 | 11 | #define U32 unsigned int 12 | 13 | void enable_mmu2(void) 14 | { 15 | static unsigned int *page_table=(unsigned int *const)0x14000; 16 | 17 | int i; 18 | U32 reg; 19 | 20 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 21 | { 22 | /* map 0x20000000~0x210000000 to 0xa0000000~0xa1000000 */ 23 | if (i >= (0xa0000000 >> 20) && i <= ( 0xa1000000 >> 20)) 24 | { 25 | page_table[i] = (i-2048)<<20 | 0x0410 | 2; 26 | printk("page_table[%d]addr=%x, section=%x \n",i,&page_table[i],page_table[i]); 27 | } 28 | else 29 | /*not mapping yet*/ 30 | page_table[i]= i<<20| 0x0410|2 ; 31 | } 32 | printk("page_talble base=%x page_table409=%x \n",page_table,&page_table[4095]); 33 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 34 | /* Copy the page table address to cp15 */ 35 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 36 | : : "r" (page_table) : "memory"); 37 | /* Set the access control to all-supervisor */ 38 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 39 | 40 | /* Enable the MMU */ 41 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 42 | reg|=0x1; 43 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 44 | } 45 | 46 | void enable_mmu(void) 47 | { 48 | static U32 __attribute__((aligned(16384))) page_table[NUM_PAGE_TABLE_ENTRIES]; 49 | int i; 50 | U32 reg; 51 | 52 | /* Set up an identity-mapping for all 4GB, rw for everyone */ 53 | for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 54 | page_table[i] = i << 20 | (3 << 10) | CACHE_DISABLED; 55 | /* Then, enable cacheable and bufferable for RAM only */ 56 | for (i = SDRAM_START >> 20; i < SDRAM_END >> 20; i++) 57 | { 58 | page_table[i] = i << 20 | (3 << 10) | CACHE_WRITEBACK; 59 | } 60 | 61 | /* Copy the page table address to cp15 */ 62 | asm volatile("mcr p15, 0, %0, c2, c0, 0" 63 | : : "r" (page_table) : "memory"); 64 | /* Set the access control to all-supervisor */ 65 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 66 | 67 | /* Enable the MMU */ 68 | asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 69 | reg|=0x1; 70 | asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 71 | } 72 | -------------------------------------------------------------------------------- /mimiOS/process.c: -------------------------------------------------------------------------------- 1 | /* 2 | This process and round-robin scheduler are from PIqueno 3 | Tzu Hang modified it to mimiOS 4 | */ 5 | 6 | 7 | #include "scheduler.h" 8 | 9 | // Just some counting for easy debug on the screen. Simulate user process. 10 | void sample_process_1() { 11 | 12 | printk("Starting process 1 "); 13 | 14 | int to = 100; 15 | 16 | int i, j; 17 | for (i=0; i 4 | */ 5 | 6 | #include "process.h" 7 | 8 | 9 | static process process_list[1024]; 10 | static unsigned int stack_base; 11 | static unsigned int process_count = 0; 12 | static unsigned int active_process_index; 13 | 14 | extern void main_endloop(); 15 | extern void timer_reset(); 16 | 17 | static int debug_counter=0; 18 | 19 | void terminate_process() { 20 | // Set it to terminated status, so the scheduler will ignore it 21 | process_list[active_process_index].status = PROCESS_STATUS_TERMINATED; 22 | } 23 | 24 | // Function to create the main process 25 | void create_main_process() { 26 | 27 | // Creating process 28 | process main_process; 29 | 30 | main_process.id = process_count; 31 | main_process.name = "Main"; 32 | main_process.pc = &main_endloop; 33 | main_process.times_loaded = 1; 34 | main_process.status = PROCESS_STATUS_ZOMBIE; 35 | 36 | // Gets the actual stack address 37 | unsigned int stack_pointer; 38 | asm volatile ("MOV %0, SP\n\t" : "=r" (stack_pointer) ); 39 | 40 | // Use it as base address processes stack pointer 41 | stack_base = stack_pointer; 42 | 43 | // Output the stack address 44 | printk("Main stack is 0x"); 45 | printk("%x",stack_pointer); 46 | printk("\n"); 47 | 48 | // Saving the process in the process table 49 | process_list[process_count] = main_process; 50 | 51 | // Set it as the current active process 52 | active_process_index = process_count; 53 | 54 | // Increments the process counter 55 | process_count++; 56 | } 57 | 58 | /* 59 | * Procedure to fork this process, creating a new one, pointing the pc 60 | * to the memory address of the desired procedure 61 | */ 62 | void fork(char * name, unsigned long * pc) { 63 | 64 | process fork_process; 65 | 66 | // Basic memory organization to get new stack addr. just add 1024 bytes from the main stack 67 | unsigned int * forked_stack_pointer = stack_base + (process_count * 1024); 68 | 69 | printk("Forked stack is 0x"); 70 | printk("%x",forked_stack_pointer); 71 | printk("\n"); 72 | 73 | fork_process.id = process_count; 74 | fork_process.name = name; 75 | fork_process.pc = pc; 76 | fork_process.parent = active_process_index; 77 | fork_process.times_loaded = 0; 78 | fork_process.stack_pointer = forked_stack_pointer; 79 | fork_process.status = PROCESS_STATUS_WAITING; 80 | 81 | process_list[process_count] = fork_process; 82 | 83 | process_count++; 84 | } 85 | 86 | /* 87 | * Function to get the next ready process in the list 88 | */ 89 | int next_waiting_process_index() { 90 | 91 | // Start in the active index 92 | int next_process_index = active_process_index; 93 | 94 | // Do this while the actual process isnt in the waiting status 95 | // and not reach the actual running process 96 | do { 97 | next_process_index++; 98 | 99 | // Just rewind the list 100 | if (next_process_index == process_count) { 101 | next_process_index = 0; 102 | } 103 | 104 | } while ((process_list[next_process_index].status != PROCESS_STATUS_WAITING) && (next_process_index != active_process_index)); 105 | 106 | // If the found process isnt waiting 107 | if (process_list[next_process_index].status != PROCESS_STATUS_WAITING) { 108 | return -1; 109 | } 110 | 111 | return next_process_index; 112 | } 113 | 114 | /* 115 | * Just keep the processor busy 116 | */ 117 | void halt() { 118 | while(1); 119 | } 120 | 121 | /* 122 | * Procedure coming from the IRQ interrupt, to change the running process 123 | */ 124 | void schedule_timeout(unsigned long stack_pointer, unsigned long pc) { 125 | 126 | // Saving stack and pc 127 | process_list[active_process_index].stack_pointer = stack_pointer; 128 | process_list[active_process_index].pc = pc; 129 | 130 | // Updating process status to waiting 131 | if (process_list[active_process_index].status == PROCESS_STATUS_RUNNING) { 132 | process_list[active_process_index].status = PROCESS_STATUS_WAITING; 133 | } 134 | 135 | //halt system to check debug messages. 136 | // debug_counter++; 137 | if(debug_counter >3) 138 | { 139 | printk("debug.... halting. \n"); 140 | halt(); 141 | } 142 | 143 | 144 | printk("\n"); 145 | printk("\n"); 146 | printk("Schedule timeout. Current active pid is "); 147 | printk("%d",process_list[active_process_index].id); 148 | printk(" with name "); 149 | printk(process_list[active_process_index].name); 150 | printk(". Switching to next process.\n"); 151 | 152 | printk("Saving stack..."); 153 | printk(" stack saved, was 0x"); 154 | printk("%x",process_list[active_process_index].stack_pointer); 155 | printk("\n"); 156 | 157 | printk("Saving pc..."); 158 | printk(" pc saved, was 0x"); 159 | printk("%x",process_list[active_process_index].pc); 160 | printk("\n"); 161 | 162 | // Get next process id 163 | int next_process = next_waiting_process_index(); 164 | 165 | // If -1, halt 166 | if (next_process < 0) { 167 | printk("No more waiting processes, halting."); 168 | halt(); 169 | } 170 | 171 | // Updating next running process 172 | active_process_index = next_process; 173 | 174 | // Increasing statistics, updating status to running 175 | process_list[active_process_index].times_loaded++; 176 | process_list[active_process_index].status = PROCESS_STATUS_RUNNING; 177 | 178 | printk("Restoring stack 0x"); 179 | printk("%x",process_list[active_process_index].stack_pointer); 180 | printk("\n"); 181 | 182 | printk("Restoring pc 0x"); 183 | printk("%x",process_list[active_process_index].pc); 184 | printk("\n"); 185 | 186 | // Assembly to load the sp with the new process stack address 187 | asm volatile("MOV SP, %[addr]" : : [addr] "r" ((unsigned long )(process_list[active_process_index].stack_pointer)) ); 188 | 189 | // If its is not the first time 190 | if (process_list[active_process_index].times_loaded > 1) { 191 | 192 | timer_reset(); 193 | 194 | // Pops registers from the stack 195 | asm volatile("pop {R0}"); 196 | asm volatile("MSR SPSR_cxsf, R0"); 197 | asm volatile("pop {LR}"); 198 | asm volatile("pop {R0 - R12}"); 199 | 200 | // Turn on interrupt again 201 | asm volatile("cpsie i"); 202 | 203 | // Pops the last register into PC to resume processing 204 | asm volatile("pop {PC}"); 205 | 206 | } else { 207 | 208 | // Push the first pc address into the stack 209 | unsigned long addr = (unsigned long )(process_list[active_process_index].pc); 210 | asm volatile("MOV R0, %[addr]" : : [addr] "r" (addr) ); 211 | asm volatile("push {R0}"); 212 | 213 | timer_reset(); 214 | 215 | // Turn on interrupt again 216 | asm volatile("cpsie i"); 217 | 218 | // Pops the last register into PC to resume processing 219 | asm volatile("pop {PC}"); 220 | 221 | } 222 | 223 | 224 | 225 | 226 | } 227 | -------------------------------------------------------------------------------- /mimiOS/scheduler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SCHEDULER_H 3 | #define SCHEDULER_H 4 | 5 | #include "process.h" 6 | 7 | void create_main_process(); 8 | void fork(char * name, unsigned long addr); 9 | void schedule_timeout(unsigned long stack_pointer, unsigned long pc); 10 | void terminate_process(); 11 | void halt(); 12 | 13 | #endif /* SCHEDULER_H */ 14 | 15 | -------------------------------------------------------------------------------- /mimiOS/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | start.s: 3 | Copyright (C) 2009 david leels 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | Modified by Carlos Hsu 19 | */ 20 | 21 | 22 | 23 | .global _start 24 | .global __vector_reset 25 | .global __vector_undefined 26 | .global __vector_swi 27 | .global __vector_prefetch_abort 28 | .global __vector_data_abort 29 | .global __vector_reserved 30 | .global __vector_irq 31 | .global __vector_fiq 32 | 33 | .equ DISABLE_IRQ, 0x80 /* when I bit is set, IRQ is disabled */ 34 | .equ DISABLE_FIQ, 0x40 /* when F bit is set, FIQ is disabled */ 35 | .equ SYS_MOD, 0x1f /* System Mode */ 36 | .equ IRQ_MOD, 0x12 /* IRQ Mode */ 37 | .equ FIQ_MOD, 0x11 /* FIQ Mode */ 38 | .equ SVC_MOD, 0x13 /* Supervisor Mode */ 39 | .equ ABT_MOD, 0x17 /* Abort Mode */ 40 | .equ UND_MOD, 0x1b /* Undefined Mode */ 41 | 42 | .equ MEM_SIZE, 0x7A00000 43 | .equ TEXT_BASE, 0x0008000 44 | 45 | .equ _SVC_STACK, (TEXT_BASE+MEM_SIZE-4) 46 | .equ _IRQ_STACK, (_SVC_STACK-0x400) 47 | .equ _FIQ_STACK, (_IRQ_STACK-0x400) 48 | .equ _ABT_STACK, (_FIQ_STACK-0x400) 49 | .equ _UND_STACK, (_ABT_STACK-0x400) 50 | .equ _SYS_STACK, (_UND_STACK-0x400) 51 | 52 | .text 53 | .code 32 54 | 55 | __vector_undefined: 56 | nop 57 | __vector_swi: 58 | ldr r0,[lr,#-4] 59 | mov r1,#0x00FFFFFF 60 | and r0, r0, r1 61 | cps #0x1f 62 | bl syscall 63 | __vector_prefetch_abort: 64 | nop 65 | __vector_data_abort: 66 | nop 67 | __vector_reserved: 68 | nop 69 | __vector_irq: 70 | // save registers 71 | // stmfd r13!, {r0-r12,lr} 72 | // call interrupt handler 73 | bl IRQ_handler 74 | // restore registers 75 | // ldmfd r13!, {r0-r12,lr} 76 | // return address(IRQ lr-4) 77 | // subs pc,lr, #4 78 | __vector_fiq: 79 | nop 80 | 81 | // IRQ enable set CPSR 82 | .global enable_IRQ 83 | enable_IRQ: 84 | mrs r0, cpsr 85 | bic r0, r0, #0x80 86 | msr cpsr_c,r0 87 | bx lr 88 | 89 | // IRQ disable set CPSR 90 | .global disable_IRQ 91 | disable_IRQ: 92 | mrs r0, cpsr 93 | ldr r1, =0x80 94 | orr r0, r0, r1 95 | msr cpsr_c, r0 96 | bx lr 97 | 98 | .extern plat_boot 99 | .extern __bss_start__ 100 | .extern __bss_end__ 101 | 102 | /*set stack*/ 103 | __vector_reset: 104 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SVC_MOD) 105 | ldr sp,=_SVC_STACK 106 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|IRQ_MOD) 107 | ldr sp,=_IRQ_STACK 108 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|FIQ_MOD) 109 | ldr sp,=_FIQ_STACK 110 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|ABT_MOD) 111 | ldr sp,=_ABT_STACK 112 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|UND_MOD) 113 | ldr sp,=_UND_STACK 114 | msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SYS_MOD) 115 | ldr sp,=_SYS_STACK 116 | 117 | _clear_bss: 118 | ldr r1,_bss_start_ 119 | ldr r3,_bss_end_ 120 | mov r2,#0x0 121 | 1: 122 | cmp r1,r3 123 | beq _main 124 | str r2,[r1],#0x4 125 | b 1b 126 | /*jump to plat_boot function in boot.c*/ 127 | _main: 128 | b plat_boot 129 | 130 | _bss_start_:.word __bss_start__ 131 | _bss_end_:.word __bss_end__ 132 | 133 | .section .startup 134 | .code 32 135 | .align 0 136 | _start: 137 | 138 | ldr pc,_vector_reset 139 | ldr pc,_vector_undefined 140 | ldr pc,_vector_swi 141 | ldr pc,_vector_prefetch_abort 142 | ldr pc,_vector_data_abort 143 | ldr pc,_vector_reserved 144 | ldr pc,_vector_irq 145 | ldr pc,_vector_fiq 146 | 147 | .align 4 148 | 149 | _vector_reset: .word __vector_reset 150 | _vector_undefined: .word __vector_undefined 151 | _vector_swi: .word __vector_swi 152 | _vector_prefetch_abort: .word __vector_prefetch_abort 153 | _vector_data_abort: .word __vector_data_abort 154 | _vector_reserved: .word __vector_reserved 155 | _vector_irq: .word __vector_irq 156 | _vector_fiq: .word __vector_fiq 157 | 158 | 159 | -------------------------------------------------------------------------------- /mimiOS/syscall.c: -------------------------------------------------------------------------------- 1 | /* 2 | This process and round-robin scheduler are from PIqueno 3 | Tzu Hang modified it to mimiOS 4 | */ 5 | 6 | #include "scheduler.h" 7 | #include "syscall.h" 8 | 9 | 10 | /* 11 | * Procedure to handle software interrupts 12 | */ 13 | void syscall(unsigned int swi) { 14 | 15 | printk("\nHandling syscall: "); 16 | printk("%d",swi); 17 | printk("\n"); 18 | 19 | switch (swi) { 20 | 21 | case SYSCALL_TERMINATE_PROCESS: 22 | printk("Invoking syscall terminate_process()"); 23 | printk("\n"); 24 | 25 | // Calling the right intra-kernel procedure 26 | terminate_process(); 27 | break; 28 | } 29 | 30 | printk("Turning interrupt on again"); 31 | printk("\n"); 32 | 33 | // Turn on interrupt again 34 | asm volatile("cpsie i"); 35 | 36 | // Wait for timer interrupt. Probably not the best thing to do. 37 | halt(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /mimiOS/syscall.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SYSCALL_H 3 | #define SYSCALL_H 4 | 5 | #define SYSCALL_TERMINATE_PROCESS 0 6 | 7 | void syscall(unsigned int swi); 8 | 9 | #endif /* SYSCALL_H */ 10 | 11 | -------------------------------------------------------------------------------- /pi-baremetal/COPYING: -------------------------------------------------------------------------------- 1 | Licence 2 | ======= 3 | 4 | (such as it is) 5 | 6 | This code is me experimenting with bare-metal programming on the Raspberry 7 | Pi. I hope it's useful. Please feel free to pinch bits if so. 8 | 9 | This file is mostly here to separate my code from the GPLv3-licensed 10 | libgcc.a (see rpi-libgcc/COPYING3) for that. 11 | -------------------------------------------------------------------------------- /pi-baremetal/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # These values should work for any Linux where the arm-linux-gnueabihf gcc 3 | # suite is installed, including Raspbian 4 | # 5 | # If they don't, you'll need to manually add the paths for gcc, ld, as and 6 | # objcopy 7 | #CC:=arm-linux-gnueabihf-gcc 8 | CC:=arm-none-eabi-gcc 9 | LD:=$(shell $(CC) -print-prog-name=ld) 10 | AS:=$(shell $(CC) -print-prog-name=as) 11 | OBJCOPY:=$(shell $(CC) -print-prog-name=objcopy) 12 | 13 | # Location of libgcc.a (contains ARM AEABI functions such as numeric 14 | # division) 15 | # 16 | # The standard libgcc.a in some (cross-compiling) versions of gcc appears to 17 | # contain Thumb2 instructions, which don't exist on the ARM1176. This causes 18 | # undefined instruction exceptions. If the code is being compiled on a 19 | # Raspberry Pi, it ought to be fine. Otherwise, you may need to use a 20 | # different libgcc.a to the one which comes with your compiler 21 | # 22 | # If compiling on a Broadcom 2708 (a Raspberry Pi), use the libgcc.a 23 | # provided by the compiler. Otherwise, use rpi-libgcc/libgcc.a (this won't 24 | # definitely work on anything other than arm-linux-gnueabihf-gcc 4.6, but 25 | # is likely to) 26 | 27 | # If LOCALLIBGCC is set, use the libgcc.a supplied with the compiler 28 | ifdef LOCALLIBGCC 29 | LIBGCC:=$(shell $(CC) -print-libgcc-file-name) 30 | endif 31 | 32 | # If this is a Raspberry Pi (specifically, a Broadcom 2708 SoC), use the 33 | # libgcc.a supplied with the compiler, unless an alternative is set in 34 | # $(LIBGCC) 35 | ifneq ($(shell grep BCM2708 /proc/cpuinfo 2>/dev/null),) 36 | LIBGCC ?= $(shell $(CC) -print-libgcc-file-name) 37 | endif 38 | 39 | # If no alternative is set in $(LIBGCC) by this point, use rpi-libgcc/libgcc.a 40 | LIBGCC ?= rpi-libgcc/libgcc.a 41 | 42 | 43 | # Assembler options: 44 | # -mcpu=arm1176jzf-s will cause the assembler to error on ARM opcodes which are 45 | # not valid for that specific processor 46 | ASOPT=--warn -mcpu=arm1176jzf-s 47 | 48 | # Compiler options: 49 | # -marm prevents gcc building Thumb code 50 | # -mcpu sets the exact CPU in the RPi, for optimised code 51 | # -nostdinc so as not to use any system #include locations 52 | # -ffreestanding to tell the compiler the usual system libraries aren't 53 | # available 54 | CCOPT=-Wall -O6 -nostdinc -ffreestanding -g -marm -mcpu=arm1176jzf-s 55 | 56 | # Object files built from C 57 | COBJS=atags.o divby0.o framebuffer.o initsys.o interrupts.o led.o mailbox.o \ 58 | main.o memory.o memutils.o textutils.o scheduler.o process.o syscall.o 59 | 60 | # Object files build from assembler 61 | ASOBJS=start.o 62 | 63 | all: make.dep kernel.img 64 | 65 | clean: 66 | rm -f make.dep *.o kernel.elf kernel.img 67 | 68 | .PHONY: all clean 69 | 70 | # Build the list of dependencies included at the bottom 71 | make.dep: *.c *.h 72 | gcc -M $(COBJS:.o=.c) >make.dep 73 | 74 | # If gcc -M fails, delete make.dep rather than allowing a half-finished file 75 | # to sit around for the next build 76 | .DELETE_ON_ERROR: make.dep 77 | 78 | # Build the assembler bits 79 | start.o: start.s 80 | 81 | $(ASOBJS): 82 | $(AS) $(ASOPT) -o $@ $< 83 | 84 | # Make an ELF kernel which loads at 0x8000 (RPi default) from all the object 85 | # files 86 | kernel.elf: linkscript $(ASOBJS) $(COBJS) 87 | $(LD) -T linkscript -nostdlib -nostartfiles -gc-sections \ 88 | -o kernel.elf \ 89 | $(ASOBJS) $(COBJS) $(LIBGCC) 90 | 91 | # Turn the ELF kernel into a binary file. This could be combined with the 92 | # step above, but it's easier to disassemble the ELF version to see why 93 | # something's not working 94 | kernel.img: kernel.elf 95 | $(OBJCOPY) kernel.elf -O binary kernel.img 96 | 97 | # Generic builder for C files 98 | $(COBJS): 99 | $(CC) $(CCOPT) -c -o $@ $< 100 | 101 | # Include the auto-generated make.dep file. The hyphen before "include" 102 | # stops it complaining that the file isn't there. 103 | -include make.dep 104 | -------------------------------------------------------------------------------- /pi-baremetal/README: -------------------------------------------------------------------------------- 1 | Raspberry Pi bare metal experiments 2 | =================================== 3 | 4 | Building 5 | -------- 6 | 7 | The code is known to build on Linux Mint 12 using the arm-linux-gnueabihf 8 | versions of the gcc compiler chain (apt-get install 9 | arm-linux-gnueabihf-gcc). This is the same version which exists on the 10 | Raspbian "Wheezy" distribution, and the code builds on the Rasperry Pi. 11 | 12 | To build, type "make". make will build a list of dependencies (in make.dep) 13 | by examining each of the .c files, then build the object files before 14 | linking them into kernel.elf, and turning that into a binary version 15 | (kernel.img). 16 | 17 | 18 | IF YOU'RE NOT BUILDING ON A RASPBERRY PI, there is a copy of libgcc.a from 19 | gcc 4.6 from the Raspberry Pi in rpi-libgcc. Make will use this by default. 20 | If you know the libgcc.a on your compiler is ok (ie, it only contains ARMv6 21 | instructions), you can set "LOCALLIBGCC=1" in the Makefile, or run "make 22 | LOCALLIBGCC=1" instead of "make". 23 | 24 | When building on a Raspberry Pi (specifically, any device with a processor 25 | type of "BCM2708"), make will use the libgcc.a which comes with gcc. 26 | 27 | In both cases, you can override the libgcc filename by running 28 | "make LIBGCC=[filename]". However, the default make will probably work just 29 | fine. 30 | 31 | 32 | Installing 33 | ---------- 34 | 35 | kernel.img should be copied onto an SD card. The usual Videocore firmware 36 | files are also needed (start.elf, bootcode.bin, fixup.dat and config.txt). 37 | Optionally, cmdline.txt can be used to set the kernel command line. At the 38 | moment, this is just displayed on the screen rather then being used for 39 | anything. 40 | 41 | As the kernel takes up minimal space and has no filesystem requirement, 42 | almost any old SD card will do 43 | 44 | A recent firmware version is required. If the kernel doesn't boot, try the 45 | latest firmware files from 46 | https://github.com/raspberrypi/firmware/tree/master/boot 47 | 48 | 49 | Code overview 50 | ------------- 51 | 52 | The kernel is loaded into memory at 0x8000 and starts running from that 53 | location, at _start in start.s, which sets up a stack, turns on unaligned 54 | memory accesses (it makes the memory routines simpler) and calls initsys(). 55 | 56 | initsys() sets up the memory management unit (MMU) and remaps the kernel to 57 | 0xf0000000, its data to 0xc0000000, and maps the physical memory and 58 | peripherals to 0x80000000. It then jumps to main() at its new address. 59 | 60 | main() further initialises memory, along with the led (GPIO16) and 61 | framebuffer. 62 | 63 | If the framebuffer initialisation fails for any reason, an error code is 64 | flashed on the LED in a permanent loop (long pause, 2 short flashes in quick 65 | succession, then 8 bits. Short flash = 0, long flash = 1. Least significant 66 | bit first. See framebuffer.c for the meaning of the errors). 67 | 68 | The framebuffer is initialised using tag mailbox calls to VideoCore. First, 69 | a call is made to read the physical framebuffer size, then a call is made to 70 | set the size (physical and virtual) and depth (bits per pixel) and allocate 71 | a framebuffer. Finally, the framebuffer's pitch (bytes per pixel line) is 72 | read. 73 | 74 | It appears to be necessary to set the virtual size before allocating the 75 | framebuffer, but reading the physical size of the framebuffer returns an 76 | apparently sensible value (unless something silly has been set in 77 | config.txt). On boot, the virtual size is set to 2x2. If a framebuffer is 78 | allocated without reconfiguring the virtual size, the screen will consist of 79 | four very large virtual pixels. Coloured red, green, yellow and blue, they 80 | produce the "rainbow" startup screen. 81 | 82 | A very basic text console has been added. This uses the SAA5050 teletext 83 | character set (taken from the datasheet: 84 | http://www-uxsup.csx.cam.ac.uk/~bjh21/BBCdata/SAA5050.pdf), partly because 85 | it looks quite nice and is a neat link to the BBC Micro, and partly because 86 | I already have the data from another project. 87 | 88 | The SAA5050 character set isn't totally ideal. The # [ { ^ } ] ` _ | and \ 89 | characters appear as other symbols (pound sign, left arrow, 1/4, up arrow, 90 | 3/4, right arrow, long dash, #, double vertical line and 1/2, respectively). 91 | 92 | Having set up the framebuffer, the kernel then reads the ATAGs data set up 93 | by the bootloader and displays it on screen. The ATAGs format is documented 94 | here: 95 | http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html#d0e428 96 | 97 | The ATAGs code will display most of the tags defined on that page, even 98 | where they are not obviously relevant to the Raspberry Pi. In practice, it 99 | seems the bootloader only sets up a handful of tags. It is possible to 100 | configure the bootloader to not set up ATAGs (disable_commandline_tags=1 in 101 | config.txt), but doing so will change the kernel's load address, and it will 102 | no longer work. 103 | 104 | Next, the kernel uses the tag mailbox to get various bits of data from 105 | Videocore to display on the screen, along with displaying the kernel code 106 | and data addresses. 107 | 108 | The kernel sets up interrupt vectors and enables the ARM timer 109 | interrupt. This interrupt is used to flash the OK LED. 110 | 111 | The kernel checks that it can't write to its own code area, before 112 | attempting to jump to 0x02100000, which resuts in a prefetch abort. Finally, 113 | in the prefetch abort routine, the kernel enters an infinite sleep loop. 114 | 115 | Files overview: 116 | * Makefile Controls the build process 117 | * linkscript Controls the linker - defines what order 118 | code appears in the final kernel, and what 119 | address it should expect to be loaded 120 | * start.s Assembly code to handle kernel entry point, 121 | set up a stack and jump to initsys() 122 | * initsys.c Set up MMU, remap kernel addresses and jump 123 | to main() 124 | * barrier.h Contains asm macros for data memory/sync 125 | barriers, and full cache flush 126 | * main.c Contains main() and tag mailbox examples 127 | * atags.c Read and display ATAGs 128 | * led.c GPIO/OK LED control 129 | * mailbox.c Read/write the mailboxes 130 | * framebuffer.c Framebuffer initialisation and text console 131 | * teletext.h SAA5050 character set 132 | * textutils.c Couple of small routines to convert numbers 133 | into text 134 | * memutils.c Routines to copy and clear memory areas 135 | * divby0.c If a division function in libgcc.a (which 136 | might be called by a divide operation 137 | somewhere in the code) attempts to divide by 138 | zero, the function will call raise(), which 139 | is defined in this file 140 | * interrupts.c Interrupt handling routines 141 | * memory.c Memory management 142 | -------------------------------------------------------------------------------- /pi-baremetal/atags.c: -------------------------------------------------------------------------------- 1 | #include "atags.h" 2 | 3 | #include "framebuffer.h" 4 | #include "memory.h" 5 | #include "textutils.h" 6 | 7 | static void print_atag_core(struct atag_core *data) 8 | { 9 | if(data->header.size == 5) 10 | { 11 | console_write(" Flags: 0x"); 12 | console_write(tohex(data->flags, 4)); 13 | console_write(", pagesize: 0x"); 14 | console_write(tohex(data->pagesize, 4)); 15 | console_write(", root device: 0x"); 16 | console_write(tohex(data->rootdevice, 4)); 17 | console_write("\n"); 18 | } 19 | else 20 | console_write(" No additional data\n"); 21 | } 22 | 23 | static void print_atag_mem(struct atag_mem *data) 24 | { 25 | console_write(" Address: 0x"); 26 | console_write(tohex(data->address, 4)); 27 | console_write(" - 0x"); 28 | console_write(tohex(data->address+data->size-1, 4)); 29 | console_write(" ("); 30 | console_write(todec(data->size, 0)); 31 | console_write(" bytes)\n"); 32 | } 33 | 34 | static void print_atag_ramdisk(struct atag_ramdisk *data) 35 | { 36 | console_write(" Flags: 0x"); 37 | console_write(tohex(data->flags, 4)); 38 | console_write(", size: 0x"); 39 | console_write(tohex(data->size, 4)); 40 | console_write(", start block: 0x"); 41 | console_write(tohex(data->start, 4)); 42 | console_write("\n"); 43 | } 44 | 45 | static void print_atag_initrd2(struct atag_initrd2 *data) 46 | { 47 | console_write(" Address: 0x"); 48 | console_write(tohex(data->address, 4)); 49 | console_write(" - 0x"); 50 | console_write(tohex(data->address+data->size-1, 4)); 51 | console_write(" ("); 52 | console_write(todec(data->size, 0)); 53 | console_write(" bytes)\n"); 54 | } 55 | 56 | static void print_atag_serial(struct atag_serial *data) 57 | { 58 | console_write(" Serial number: 0x"); 59 | console_write(tohex(data->high, 4)); 60 | console_write(tohex(data->low, 4)); 61 | console_write("\n"); 62 | } 63 | 64 | static void print_atag_revision(struct atag_revision *data) 65 | { 66 | console_write(" Board revision: "); 67 | console_write(todec(data->revision, 0)); 68 | console_write("\n"); 69 | } 70 | 71 | static void print_atag_videolfb(struct atag_videolfb *data) 72 | { 73 | console_write(" Size: "); 74 | console_write(todec(data->width, 0)); 75 | console_write("x"); 76 | console_write(todec(data->height, 0)); 77 | console_write(", depth: "); 78 | console_write(todec(data->depth, 0)); 79 | console_write("bpp, linelength: "); 80 | console_write(todec(data->linelength, 0)); 81 | 82 | console_write("\n Address: 0x"); 83 | console_write(tohex(data->address, 4)); 84 | console_write(" - 0x"); 85 | console_write(tohex(data->address+data->size-1, 4)); 86 | console_write(" ("); 87 | console_write(todec(data->size, 0)); 88 | console_write(" bytes)\n"); 89 | 90 | console_write(" Pos/size: R "); 91 | console_write(todec(data->redpos, 0)); 92 | console_write("/"); 93 | console_write(todec(data->redsize, 0)); 94 | 95 | console_write(", G "); 96 | console_write(todec(data->greenpos, 0)); 97 | console_write("/"); 98 | console_write(todec(data->greensize, 0)); 99 | 100 | console_write(", B "); 101 | console_write(todec(data->bluepos, 0)); 102 | console_write("/"); 103 | console_write(todec(data->bluesize, 0)); 104 | 105 | console_write(", reserved "); 106 | console_write(todec(data->reservedpos, 0)); 107 | console_write("/"); 108 | console_write(todec(data->reservedsize, 0)); 109 | 110 | console_write("\n"); 111 | } 112 | 113 | static void print_atag_cmdline(struct atag_cmdline *data) 114 | { 115 | console_write(" \""); 116 | console_write(&data->commandline); 117 | console_write("\"\n"); 118 | } 119 | 120 | void print_atags(unsigned int address) 121 | { 122 | /* Use virtual mapped physical memory to access the ATAGs */ 123 | struct atag_header *atags = (struct atag_header *) mem_p2v(address); 124 | unsigned int tag; 125 | 126 | console_write(COLOUR_PUSH BG_GREEN BG_HALF "Reading ATAGs\n\n" COLOUR_POP); 127 | 128 | do 129 | { 130 | tag = atags->tag; 131 | console_write("ATAG at address 0x"); 132 | console_write(tohex((unsigned int) atags, 4)); 133 | console_write(" is 0x"); 134 | console_write(tohex(tag, 4)); 135 | 136 | switch(tag) 137 | { 138 | case 0: 139 | console_write(" (ATAG_NONE)\n\n"); 140 | break; 141 | case ATAG_CORE: 142 | console_write(" (ATAG_CORE)\n"); 143 | print_atag_core((struct atag_core *)atags); 144 | break; 145 | case ATAG_MEM: 146 | console_write(" (ATAG_MEM)\n"); 147 | print_atag_mem((struct atag_mem *)atags); 148 | break; 149 | case ATAG_VIDEOTEXT: 150 | console_write(" (ATAG_VIDEOTEXT)\n"); 151 | break; 152 | case ATAG_RAMDISK: 153 | console_write(" (ATAG_RAMDISK)\n"); 154 | print_atag_ramdisk((struct atag_ramdisk *)atags); 155 | break; 156 | case ATAG_INITRD2: 157 | console_write(" (ATAG_INITRD2)\n"); 158 | print_atag_initrd2((struct atag_initrd2 *)atags); 159 | break; 160 | case ATAG_SERIAL: 161 | console_write(" (ATAG_SERIAL)\n"); 162 | print_atag_serial((struct atag_serial *)atags); 163 | break; 164 | case ATAG_REVISION: 165 | console_write(" (ATAG_REVISION)\n"); 166 | print_atag_revision((struct atag_revision *)atags); 167 | break; 168 | case ATAG_VIDEOLFB: 169 | console_write(" (ATAG_VIDEOLFB)\n"); 170 | print_atag_videolfb((struct atag_videolfb *)atags); 171 | break; 172 | case ATAG_CMDLINE: 173 | console_write(" (ATAG_CMDLINE)\n"); 174 | print_atag_cmdline((struct atag_cmdline *)atags); 175 | break; 176 | default: 177 | console_write(" (UNKNOWN)\n"); 178 | return; 179 | } 180 | 181 | atags = (struct atag_header *)((unsigned int)atags + (atags->size * 4)); 182 | } while(tag); 183 | } 184 | -------------------------------------------------------------------------------- /pi-baremetal/atags.h: -------------------------------------------------------------------------------- 1 | #ifndef ATAGS_H 2 | #define ATAGS_H 3 | 4 | extern void print_atags(unsigned int address); 5 | 6 | #define ATAG_NONE 0 7 | #define ATAG_CORE 0x54410001 8 | #define ATAG_MEM 0x54410002 9 | #define ATAG_VIDEOTEXT 0x54410003 10 | #define ATAG_RAMDISK 0x54410004 11 | #define ATAG_INITRD2 0x54420005 12 | #define ATAG_SERIAL 0x54410006 13 | #define ATAG_REVISION 0x54410007 14 | #define ATAG_VIDEOLFB 0x54410008 15 | #define ATAG_CMDLINE 0x54410009 16 | 17 | struct atag_header 18 | { 19 | unsigned int size; /* Size in words of this tag */ 20 | unsigned int tag; /* Tag value */ 21 | }; 22 | 23 | /* ATAG_NONE ends the list of ATAGs */ 24 | struct atag_none 25 | { 26 | struct atag_header header; 27 | /* No further data in this ATAG */ 28 | }; 29 | 30 | /* ATAG_CORE begins the list of ATAGs */ 31 | struct atag_core 32 | { 33 | struct atag_header header; 34 | /* Optional entries below */ 35 | unsigned int flags; /* Bit 0 - read only. Others unused */ 36 | unsigned int pagesize; /* Page size */ 37 | unsigned int rootdevice; /* Root device number */ 38 | }; 39 | 40 | /* ATAG_MEM defines a physical memory region */ 41 | struct atag_mem 42 | { 43 | struct atag_header header; 44 | unsigned int size; /* Size of region */ 45 | unsigned int address; /* Address of start of region */ 46 | }; 47 | 48 | /* ATAG_VIDEOTEXT defines a VGA text screen. Not relevant to a Raspberry Pi */ 49 | 50 | /* ATAG_RAMDISK defines an initial ramdisk - floppy images only? */ 51 | struct atag_ramdisk 52 | { 53 | struct atag_header header; 54 | unsigned int flags; /* Bit 0 = load, bit 1 = prompt */ 55 | unsigned int size; /* Decompressed size in KB */ 56 | unsigned int start; /* Start block of ram disk */ 57 | }; 58 | 59 | /* ATAG_INITRD2 - define physical location of ramdisk image */ 60 | struct atag_initrd2 61 | { 62 | struct atag_header header; 63 | unsigned int address; /* Address of ramdisk image */ 64 | unsigned int size; /* Size of compressed(?) image */ 65 | }; 66 | 67 | /* ATAG_SERIAL has the 64-bit serial number */ 68 | struct atag_serial 69 | { 70 | struct atag_header header; 71 | unsigned int low; 72 | unsigned int high; 73 | }; 74 | 75 | /* ATAG_REVISION - board revision number */ 76 | struct atag_revision 77 | { 78 | struct atag_header header; 79 | unsigned int revision; 80 | }; 81 | 82 | /* ATAG_VIDEOLFB - describes a framebuffer */ 83 | struct atag_videolfb 84 | { 85 | struct atag_header header; 86 | unsigned short int width; /* Width of buffer */ 87 | unsigned short int height; /* Height */ 88 | unsigned short int depth; /* Bits/pixel */ 89 | unsigned short int linelength; // ? 90 | unsigned int address; /* Base address of buffer */ 91 | unsigned int size; /* Size of buffer */ 92 | unsigned char redsize; /* Number of red bits in each pixel */ 93 | unsigned char redpos; /* Position of red bits in pixel */ 94 | unsigned char greensize; 95 | unsigned char greenpos; 96 | unsigned char bluesize; 97 | unsigned char bluepos; 98 | unsigned char reservedsize; /* Number of reserved bits/pixel */ 99 | unsigned char reservedpos; /* Position of reserved bits */ 100 | }; 101 | 102 | /* ATAG_CMDLINE - kernel command line */ 103 | struct atag_cmdline 104 | { 105 | struct atag_header header; 106 | char commandline; /* Multiple characters from here */ 107 | }; 108 | 109 | #endif /* ATAGS_H */ 110 | -------------------------------------------------------------------------------- /pi-baremetal/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef BARRIER_H 2 | #define BARRIER_H 3 | 4 | /* 5 | * Data memory barrier 6 | * No memory access after the DMB can run until all memory accesses before it 7 | * have completed 8 | */ 9 | #define dmb() asm volatile \ 10 | ("mcr p15, #0, %[zero], c7, c10, #5" : : [zero] "r" (0) ) 11 | 12 | 13 | /* 14 | * Data synchronisation barrier 15 | * No instruction after the DSB can run until all instructions before it have 16 | * completed 17 | */ 18 | #define dsb() asm volatile \ 19 | ("mcr p15, #0, %[zero], c7, c10, #4" : : [zero] "r" (0) ) 20 | 21 | 22 | /* 23 | * Clean and invalidate entire cache 24 | * Flush pending writes to main memory 25 | * Remove all data in data cache 26 | */ 27 | #define flushcache() asm volatile \ 28 | ("mcr p15, #0, %[zero], c7, c14, #0" : : [zero] "r" (0) ) 29 | 30 | #endif /* BARRIER_H */ 31 | -------------------------------------------------------------------------------- /pi-baremetal/divby0.c: -------------------------------------------------------------------------------- 1 | #include "framebuffer.h" 2 | #include "textutils.h" 3 | 4 | /* This function is called by libgcc.a's division functions when an attempt 5 | * is made to divide by zero. If this has happened, something has probably 6 | * gone wrong, so print an error and stop 7 | */ 8 | void raise(void) 9 | { 10 | console_write(FG_RED "Error: division by zero attempted\n"); 11 | console_write("STOPPED\n"); 12 | 13 | while(1); 14 | } 15 | -------------------------------------------------------------------------------- /pi-baremetal/framebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef FRAMEBUFFER_H 2 | #define FRAMEBUFFER_H 3 | 4 | extern void fb_init(void); 5 | extern void console_write(char *text); 6 | 7 | /* Control characters for the console */ 8 | #define FG_RED "\001" 9 | #define FG_GREEN "\002" 10 | #define FG_BLUE "\003" 11 | #define FG_YELLOW "\004" 12 | #define FG_MAGENTA "\005" 13 | #define FG_CYAN "\006" 14 | #define FG_WHITE "\007" 15 | #define FG_BLACK "\010" 16 | #define FG_HALF "\011" 17 | 18 | #define COLOUR_PUSH "\013" 19 | #define COLOUR_POP "\014" 20 | 21 | #define BG_RED "\021" 22 | #define BG_GREEN "\022" 23 | #define BG_BLUE "\023" 24 | #define BG_YELLOW "\024" 25 | #define BG_MAGENTA "\025" 26 | #define BG_CYAN "\026" 27 | #define BG_WHITE "\027" 28 | #define BG_BLACK "\030" 29 | #define BG_HALF "\031" 30 | 31 | #endif /* FRAMEBUFFER_H */ 32 | -------------------------------------------------------------------------------- /pi-baremetal/initsys.c: -------------------------------------------------------------------------------- 1 | /* Virtual memory layout 2 | * 3 | * 0x00000000 - 0x7fffffff (0-2GB) = user process memory 4 | * 0x80000000 - 0xa0ffffff (2GB) = physical memory 5 | * includes peripherals at 0x20000000 - 0x20ffffff 6 | * 0xc0000000 - 0xefffffff = kernel heap/stack 7 | * 0xf0000000 - 0xffffffff = kernel code 8 | * 9 | * Memory from 0x80000000 upwards won't be accessible to user processes 10 | */ 11 | 12 | static unsigned int *initpagetable = (unsigned int * const)0x4000; /* 16K */ 13 | static unsigned int *kerneldatatable = (unsigned int * const)0x3c00; /* 1K */ 14 | 15 | /* initsys calls main() when it's finished, so we need to tell the compiler 16 | * it's an external symbol 17 | */ 18 | extern void main(void); 19 | 20 | /* Memory locations. Defined in linkscript, set during linking */ 21 | extern unsigned int _physdatastart, _physbssstart, _physbssend; 22 | extern unsigned int _kstart, _kend; 23 | 24 | #define UFCON0 ((volatile unsigned int *)(0x20201000)) 25 | 26 | void helloworld(void){ 27 | const char *p="helloworld\n"; 28 | while(*p){ 29 | *UFCON0=*p++; 30 | }; 31 | } 32 | 33 | __attribute__((naked)) void initsys(void) 34 | { 35 | register unsigned int x; 36 | register unsigned int pt_addr; 37 | register unsigned int control; 38 | register unsigned int *bss; 39 | 40 | helloworld(); 41 | /* Save r0-r2 as they contain the start values used by the kernel */ 42 | asm volatile("push {r0, r1, r2}"); 43 | 44 | /* The MMU has two translation tables. Table 0 covers the bottom 45 | * of the address space, from 0x00000000, and deals with between 46 | * 32MB to 4GB of the virtual address space. 47 | * Translation table 1 covers the rest of the memory. For now, 48 | * both tables are set to the same thing, and, by default, table 49 | * 0 manages the entire virtual address space. Later on, the 50 | * table 0 register will be pointed to process-specific tables for 51 | * each process's virtual memory 52 | */ 53 | 54 | /* Set up translation table 55 | * ARM1176JZF-S manual, 6-39 56 | * 57 | * The memory is divided in to 4096 1MB sections. Most of these are 58 | * unmapped (resulting in prefetch/data aborts), except 59 | * 0x8000000-0xa1000000, which are mapped to 0x00000000-0x2a000000 60 | * (physical memory and peripherals), and the kernel code and data 61 | * 62 | * Memory privilege is set by APX/AP bits (3 bits in total) 63 | * APX is at bit 15 of the sector definition, while AP are at bits 64 | * 10 and 11. 65 | * 66 | * APX AP Privileged Unprivileged 67 | * 1 11 (0x8c00) = read-only read-only 68 | * 1 01 (0x8400) = read-only no access 69 | * 0 10 (0x0800) = read-write read-only 70 | * 0 01 (0x0400) = read-write no-access 71 | * 72 | * eXecute Never (XN) is at bit 4 (0x10) - sections with this flag 73 | * cannot be executes, even by privileged processor modes 74 | * 75 | * Bits 0 and 1 identify the table entry type 76 | * 0 or 3 = translation fault (3 is reserved and shouldn't be used) 77 | * 1 = course page table 78 | * 2 = section or supersection 79 | */ 80 | for(x=0; x<4096; x++) 81 | { 82 | if((x >= (0x80000000>>20)) && (x < (0xa1000000>>20))) 83 | { 84 | /* Map physical memory to virtual 85 | * Read/write for priviledged modes, no execute 86 | */ 87 | initpagetable[x] = (x-2048)<<20 | 0x0410 | 2; 88 | } 89 | else 90 | { 91 | /* No entry in table; translation fault */ 92 | initpagetable[x] = 0; 93 | } 94 | } 95 | 96 | /* Map 0x00000000-0x000fffff into virtual memory at the same address. 97 | * This is temporary: it's where the code is currently running. Once 98 | * initsys has branched tothe kernel at 0xf0000000, it will be removed 99 | * 100 | * Read/write for privileged mode only 101 | */ 102 | initpagetable[0] = 0<<20 | 0x0400 | 2; 103 | 104 | /* Map 1MB at 0xf00000000-0xf00fffff to the kernel code in memory. 105 | * Typically, this is loaded at 0x9000, and appears in virtual memory 106 | * from 0xf0009000. This means we can use a single 1MB entry to 107 | * cover it all (as long as the kernel doesn't get above 1MB...), 108 | * reducing the number of TLB entries 109 | * 110 | * Map as read-only for privileged modes only 111 | * 112 | * It will also map any free memory surrounding the kernel code (eg. 113 | * 0x00000000-0x8fffffff, kernel data). However, as this mapping is 114 | * read-only and only available to the kernel, the potential for harm 115 | * is minimal 116 | */ 117 | initpagetable[3840] = 0<<20 | 0x8400 | 2; 118 | 119 | /* 0xc0000000-0xc00fffff is mapped to physical memory by a course 120 | * page table 121 | * 122 | * This maps the kernel data from where it has been loaded in memory 123 | * (after the kernel code, eg. at 0x0001f000) to 0xc0000000 124 | * Only memory in use is mapped (to the next 4K). The rest of the 125 | * table is unmapped. 126 | */ 127 | initpagetable[3072] = 1 | (unsigned int)kerneldatatable; 128 | 129 | /* Populate kerneldatatable - see ARM1176JZF-S manual, 6-40 130 | * 131 | * APX/AP bits for a page table entry are at bits 9 and 4&5. The 132 | * meaning is the same as for a section entry. 133 | * 0 01 (0x0010) = read-write privileded modes, no access otherwise 134 | * 135 | * bits 0 and 1 determine the page type: 136 | * 0 = unmapped, translation fault 137 | * 1 = large page (64K) (XN is bit 15) 138 | * 2 = small page (4K), executable (XN is bit 0) 139 | * 3 = small page (4K), not-executable (XN is bit 0) 140 | * 141 | * 256 entries, one for each 4KB in the 1MB covered by the table 142 | */ 143 | for(x=0; x<256; x++) 144 | { 145 | /* &_physbssend is the physical address of the end of the 146 | * kernel data - somewhere between 0x00009000 and 1MB (any 147 | * more than that and this code will need rewriting...) 148 | */ 149 | if(x <= ((unsigned int)&_physbssend >> 12)) 150 | kerneldatatable[x] = ((unsigned int)&_physdatastart + (x<<12)) | 0x0010 | 2; 151 | else 152 | kerneldatatable[x] = 0; 153 | } 154 | 155 | /* The .bss section is allocated in physical memory, but its contents 156 | * (all zeroes) are not loaded in with the kernel. 157 | * It needs to be zeroed before it can be used 158 | */ 159 | bss = &_physbssstart; 160 | while(bss<&_physbssend) 161 | { 162 | *bss = 0; 163 | bss++; 164 | } 165 | 166 | pt_addr = (unsigned int) initpagetable; 167 | 168 | /* Translation table 0 - ARM1176JZF-S manual, 3-57 */ 169 | asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt_addr)); 170 | /* Translation table 1 */ 171 | asm volatile("mcr p15, 0, %[addr], c2, c0, 1" : : [addr] "r" (pt_addr)); 172 | /* Use translation table 0 for everything, for now */ 173 | asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (0)); 174 | 175 | /* Set Domain 0 ACL to "Client", enforcing memory permissions 176 | * See ARM1176JZF-S manual, 3-64 177 | * Every mapped section/page is in domain 0 178 | */ 179 | asm volatile("mcr p15, 0, %[r], c3, c0, 0" : : [r] "r" (0x1)); 180 | 181 | /* Read control register */ 182 | asm volatile("mrc p15, 0, %[control], c1, c0, 0" : [control] "=r" (control)); 183 | /* Turn on MMU */ 184 | control |= 1; 185 | /* Enable ARMv6 MMU features (disable sub-page AP) */ 186 | control |= (1<<23); 187 | /* Write value back to control register */ 188 | asm volatile("mcr p15, 0, %[control], c1, c0, 0" : : [control] "r" (control)); 189 | 190 | /* Set the LR (R14) to the address of main(), then pop off r0-r2 191 | * before exiting this function (which doesn't store anything else 192 | * on the stack). The "mov lr" comes first as it's impossible to 193 | * guarantee the compiler wouldn't use one of r0-r2 for %[main] 194 | */ 195 | asm volatile("mov lr, %[main]" : : [main] "r" ((unsigned int)&main) ); 196 | asm volatile("pop {r0, r1, r2}"); 197 | asm volatile("bx lr"); 198 | } 199 | -------------------------------------------------------------------------------- /pi-baremetal/interrupts.c: -------------------------------------------------------------------------------- 1 | #include "interrupts.h" 2 | 3 | #include "framebuffer.h" 4 | #include "led.h" 5 | #include "memory.h" 6 | #include "textutils.h" 7 | #include "scheduler.h" 8 | #include "syscall.h" 9 | 10 | static volatile unsigned int *irqEnable1 = (unsigned int *) mem_p2v(0x2000b210); 11 | static volatile unsigned int *irqEnable2 = (unsigned int *) mem_p2v(0x2000b214); 12 | static volatile unsigned int *irqEnableBasic = (unsigned int *) mem_p2v(0x2000b218); 13 | 14 | static volatile unsigned int *armTimerLoad = (unsigned int *) mem_p2v(0x2000b400); 15 | static volatile unsigned int *armTimerValue = (unsigned int *) mem_p2v(0x2000b404); 16 | static volatile unsigned int *armTimerControl = (unsigned int *) mem_p2v(0x2000b408); 17 | static volatile unsigned int *armTimerIRQClear = (unsigned int *) mem_p2v(0x2000b40c); 18 | 19 | /* Interrupt vectors called by the CPU. Needs to be aligned to 32 bits as the 20 | * bottom 5 bits of the vector address as set in the control coprocessor must 21 | * be zero 22 | * 23 | * The RESET vector is set to bad_exception. On CPU reset the interrupt vectors 24 | * are set back to 0x00000000, so it won't be used. Any attempt to call this 25 | * vector is clearly an error. Also, resetting the Pi will reset VideoCore, 26 | * and reboot. 27 | */ 28 | __attribute__ ((naked, aligned(32))) static void interrupt_vectors(void) 29 | { 30 | asm volatile("b bad_exception\n" /* RESET */ 31 | "b bad_exception\n" /* UNDEF */ 32 | "b interrupt_swi\n" 33 | "b interrupt_prefetch_abort \n" 34 | "b interrupt_data_abort \n" 35 | "b bad_exception;\n" /* Unused vector */ 36 | "b interrupt_irq \n" 37 | "b bad_exception\n" /* FIQ */ 38 | ); 39 | } 40 | 41 | /* Unhandled exceptions - hang the machine */ 42 | __attribute__ ((naked)) void bad_exception(void) 43 | { 44 | while(1); 45 | } 46 | 47 | __attribute__ ((interrupt ("SWI"))) void interrupt_swi(void) 48 | { 49 | register unsigned int addr; 50 | register unsigned int swi_no; 51 | /* Read link register into addr - contains the address of the 52 | * instruction after the SWI 53 | */ 54 | asm volatile("mov %[addr], lr" : [addr] "=r" (addr) ); 55 | 56 | addr -= 4; 57 | /* Bottom 24 bits of the SWI instruction are the SWI number */ 58 | swi_no = *((unsigned int *)addr) & 0x00ffffff; 59 | 60 | console_write(COLOUR_PUSH FG_GREEN "SWI call. Address: 0x"); 61 | console_write(tohex(addr, 4)); 62 | console_write(" SWI number "); 63 | console_write(todec(swi_no, 0)); 64 | console_write(COLOUR_POP "\n"); 65 | 66 | //change processor mode 67 | asm volatile("cps #0x1f"); 68 | 69 | //Handle syscall 70 | syscall(swi_no); 71 | } 72 | 73 | /* IRQs flash the OK LED */ 74 | __attribute__ ((interrupt ("IRQ"))) void interrupt_irq(void) 75 | { 76 | // This function starts on IRQ mode 77 | 78 | // Push all registers into the IRQ mode stack (R13) 79 | asm volatile("push {R0-R12}"); 80 | 81 | // Put LR register of IRQ mode (PC of interrupted process) on R0 82 | asm volatile("MOV R0, LR"); 83 | 84 | 85 | // Change to system mode 86 | asm volatile("cps #0x1f"); 87 | 88 | // Push R0 (interrupted PC) to the system mode stack 89 | asm volatile("push {R0}"); 90 | 91 | 92 | // Return to IRQ mode 93 | asm volatile("cps #0x12"); 94 | 95 | // Pop all registers again 96 | asm volatile("pop {R0-R12}"); 97 | 98 | 99 | // Return to system mode 100 | asm volatile("cps #0x1f"); 101 | 102 | // Push all registers into the system mode stack 103 | asm volatile("push {R0-R12}"); 104 | 105 | // Push the interrupted LR to system mode stack 106 | asm volatile("push {LR}"); 107 | 108 | // Copy the processor status to R0 109 | asm volatile("MRS R0, SPSR"); 110 | 111 | // Push the processor status to system mode stack 112 | asm volatile("push {R0}"); 113 | 114 | 115 | // Return to IRQ mode 116 | asm volatile("cps #0x12"); 117 | 118 | // Copy LR to R0 119 | asm volatile("MOV R0, LR"); 120 | 121 | // Back to system mode 122 | asm volatile("cps #0x1f"); 123 | 124 | unsigned long pc; 125 | 126 | unsigned long stack_pointer; 127 | 128 | // Getting pc and stack just to debug 129 | asm volatile ("MOV %0, R0\n\t" : "=r" (pc) ); 130 | asm volatile ("MOV %0, SP\n\t" : "=r" (stack_pointer) ); 131 | 132 | // Invert led to inform context switch activity 133 | led_invert(); 134 | 135 | // Jump to scheduler to do the context switch 136 | schedule_timeout(stack_pointer, pc); 137 | } 138 | 139 | __attribute__ ((interrupt ("ABORT"))) void interrupt_data_abort(void) 140 | { 141 | register unsigned int addr, far; 142 | asm volatile("mov %[addr], lr" : [addr] "=r" (addr) ); 143 | /* Read fault address register */ 144 | asm volatile("mrc p15, 0, %[addr], c6, c0, 0": [addr] "=r" (far) ); 145 | 146 | 147 | console_write("Data abort!\n"); 148 | console_write("Instruction address: 0x"); 149 | /* addr = lr, but the very start of the abort routine does 150 | * sub lr, lr, #4 151 | * lr = address of aborted instruction, plus 8 152 | */ 153 | console_write(tohex(addr-4, 4)); 154 | 155 | console_write(" fault address: 0x"); 156 | console_write(tohex(far, 4)); 157 | console_write("\n"); 158 | 159 | /* Routine terminates by returning to LR-4, which is the instruction 160 | * after the aborted one 161 | * GCC doesn't properly deal with data aborts in its interrupt 162 | * handling - no option to return to the failed instruction 163 | */ 164 | } 165 | 166 | /* Return to this function after a prefetch abort */ 167 | extern void main_endloop(void); 168 | 169 | __attribute__ ((interrupt ("ABORT"))) void interrupt_prefetch_abort(void) 170 | { 171 | register unsigned int addr; 172 | asm volatile("mov %[addr], lr" : [addr] "=r" (addr) ); 173 | 174 | console_write("Prefetch abort!\n"); 175 | console_write("Instruction address: 0x"); 176 | /* lr = address of aborted instruction, plus 4 177 | * addr = lr, but the very start of the abort routine does 178 | * sub lr, lr, #4 179 | */ 180 | console_write(tohex(addr, 4)); 181 | console_write("\n"); 182 | 183 | /* Set the return address to be the function main_endloop(), by 184 | * putting its address into the program counter 185 | * 186 | * THIS IS JUST A TEST - you can't normally do this as it doesn't 187 | * restore the registers or put the stack pointer back where it was, 188 | * so repeated aborts will overflow the stack. 189 | */ 190 | asm volatile("movs pc, %[addr]" : : 191 | [addr] "r" ((unsigned int)(&main_endloop)) ); 192 | 193 | /* Doesn't reach this point */ 194 | } 195 | 196 | /* Initialise the interrupts 197 | * 198 | * Enable the ARM timer interrupt 199 | */ 200 | void interrupts_init(void) 201 | { 202 | /* Set interrupt base register */ 203 | asm volatile("mcr p15, 0, %[addr], c12, c0, 0" : : [addr] "r" (&interrupt_vectors)); 204 | /* Turn on interrupts */ 205 | asm volatile("cpsie i"); 206 | 207 | /* Use the ARM timer - BCM 2832 peripherals doc, p.196 */ 208 | /* Enable ARM timer IRQ */ 209 | *irqEnableBasic = 0x00000001; 210 | 211 | /* Interrupt every 1024 * 256 (prescaler) timer ticks */ 212 | *armTimerLoad = 0x00000400; 213 | 214 | /* Timer enabled, interrupt enabled, prescale=256, "23 bit" counter 215 | * (did they mean 32 bit?) 216 | */ 217 | *armTimerControl = 0x000000aa; 218 | } 219 | 220 | void timer_reset(void) 221 | { 222 | *armTimerIRQClear = 0; 223 | } 224 | -------------------------------------------------------------------------------- /pi-baremetal/interrupts.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTS_H 2 | #define INTERRUPTS_H 3 | 4 | extern void interrupts_init(void); 5 | 6 | #endif /* INTERRUPTS_H */ 7 | -------------------------------------------------------------------------------- /pi-baremetal/led.c: -------------------------------------------------------------------------------- 1 | #include "led.h" 2 | #include "memory.h" 3 | 4 | /* Addresses of ARM GPIO devices (with conversion to virtual addresses) 5 | * See BCM2835 peripherals guide 6 | */ 7 | static volatile unsigned int *gpioGPFSEL1 = (unsigned int *) mem_p2v(0x20200004); 8 | static volatile unsigned int *gpioGPSET0 = (unsigned int *) mem_p2v(0x2020001c); 9 | static volatile unsigned int *gpioGPCLR0 = (unsigned int *) mem_p2v(0x20200028); 10 | static volatile unsigned int *gpioGPLEV0 = (unsigned int *) mem_p2v(0x20200034); 11 | 12 | static volatile unsigned int *gpioGPPUD = (unsigned int *) mem_p2v(0x20200094); 13 | static volatile unsigned int *gpioPUDCLK0 = (unsigned int *) mem_p2v(0x20200098); 14 | static volatile unsigned int *gpioPUDCLK1 = (unsigned int *) mem_p2v(0x2020009c); 15 | 16 | /* Short delay loop */ 17 | static void delay(void) 18 | { 19 | unsigned int timer=150; 20 | 21 | while(timer--) 22 | asm ("mov r0, r0"); /* No-op */ 23 | } 24 | 25 | void led_init(void) 26 | { 27 | unsigned int var; 28 | 29 | /* Each GPIO has 3 bits which determine its function 30 | * GPIO 14 and 16 are in GPFSEL1 31 | */ 32 | /* Read current value of GPFSEL1 */ 33 | var = *gpioGPFSEL1; 34 | 35 | /* GPIO 16 = 001 - output */ 36 | var&=~(7<<18); 37 | var|=1<<18; 38 | /* GPIO 14 = 000 - input */ 39 | var&=~(7<<12); 40 | 41 | /* Write back updated value */ 42 | *gpioGPFSEL1 = var; 43 | 44 | /* Set up pull-up on GPIO14 */ 45 | /* Enable pull-up control, then wait at least 150 cycles 46 | * The delay loop actually waits longer than that 47 | */ 48 | *gpioGPPUD = 2; 49 | delay(); 50 | 51 | /* Set the pull up/down clock for pin 14*/ 52 | *gpioPUDCLK0 = 1<<14; 53 | *gpioPUDCLK1 = 0; 54 | delay(); 55 | 56 | /* Disable pull-up control and reset the clock registers */ 57 | *gpioGPPUD = 0; 58 | *gpioPUDCLK0 = 0; 59 | *gpioPUDCLK1 = 0; 60 | } 61 | 62 | static unsigned int led_status = 0; 63 | 64 | void led_invert(void) 65 | { 66 | led_status = !led_status; 67 | 68 | if(led_status) 69 | *gpioGPCLR0 = 1<<16; /* on */ 70 | else 71 | *gpioGPSET0 = 1<<16; /* off */ 72 | } 73 | 74 | 75 | /* Shortish delay loop */ 76 | static void shortdelay(void) 77 | { 78 | unsigned int timer = 3000000; 79 | 80 | while(timer--) 81 | asm("mov r0, r0"); /* No-op */ 82 | } 83 | /* Massively long delay loop */ 84 | static void longdelay(void) 85 | { 86 | unsigned int timer = 10000000; 87 | 88 | while(timer--) 89 | asm("mov r0, r0"); /* No-op */ 90 | } 91 | 92 | static void output_n(unsigned int num, unsigned int count) 93 | { 94 | 95 | longdelay(); 96 | longdelay(); 97 | longdelay(); 98 | longdelay(); 99 | 100 | /* Flash quickly to indicate start */ 101 | *gpioGPCLR0 = 1<<16; 102 | shortdelay(); 103 | *gpioGPSET0 = 1<<16; 104 | shortdelay(); 105 | *gpioGPCLR0 = 1<<16; 106 | shortdelay(); 107 | *gpioGPSET0 = 1<<16; 108 | longdelay(); 109 | longdelay(); 110 | 111 | while(count--) 112 | { 113 | *gpioGPCLR0 = 1<<16; 114 | 115 | if(num & 1) 116 | longdelay(); 117 | else 118 | shortdelay(); 119 | 120 | *gpioGPSET0 = 1<<16; 121 | longdelay(); 122 | 123 | num = num >> 1; 124 | } 125 | } 126 | 127 | void output32(unsigned int num) 128 | { 129 | output_n(num, 32); 130 | } 131 | 132 | void output(unsigned int num) 133 | { 134 | output_n(num, 8); 135 | } 136 | -------------------------------------------------------------------------------- /pi-baremetal/led.h: -------------------------------------------------------------------------------- 1 | #ifndef LED_H 2 | #define LED_H 3 | 4 | void led_init(void); 5 | void led_invert(void); 6 | void output32(unsigned int num); 7 | void output(unsigned int num); 8 | 9 | #endif /* LED_H */ 10 | -------------------------------------------------------------------------------- /pi-baremetal/linkscript: -------------------------------------------------------------------------------- 1 | /* Linker script for kernel */ 2 | 3 | /* Define the kernel entry point. Needed to prevent ld's -gc-sections option 4 | * getting rid of everything 5 | */ 6 | ENTRY(_start) 7 | 8 | /* Define the memory as starting at 0x8000, and being a megabyte long 9 | * (shouldn't need to be more than this) 10 | * "kernel" is where the majority of the kernel is run - it is linked at 11 | * this address, but loaded into memory after initsys at 0x9000 (probably, 12 | * as long as initsys is less than 4K) 13 | */ 14 | 15 | MEMORY 16 | { 17 | initsys : org = 0x8000, len = 1M 18 | kernel : org = 0xf0000000, len = 1M 19 | data : org = 0xc0000000, len = 1M 20 | } 21 | 22 | /* Output kernel code (.text) and read-only data (.rodata) into kernel 23 | * code space (0xf0000000), read/write data (.data) and initialised-to-zero 24 | * data (.bss) into kernel data space (0xc0000000), and the initial 25 | * start-up code/data (in start.s/initsys.c) at 0x8000 26 | * 27 | * Make sure start.o comes first, so the entry point is at the start of the 28 | * file 29 | * 30 | * The file ends up looking something like this: 31 | * 32 | * File offset Load address Remapped to 33 | * 0x00000000 0x00008000 0x00008000 start.o/initsys.o 34 | * 0x00001000 0x00009000 0xf0009000 .text, .rodata 35 | * 0x00010000 0x00018000 0xc0000000 .data 36 | * n/a 0x00020000 0xc0008000 .bss 37 | * 38 | * Various pointers are calculated to help initsys map the kernel's virtual 39 | * memory, and clear .bss 40 | */ 41 | 42 | SECTIONS 43 | { 44 | /* Initial section, loads/runs at 0x8000 */ 45 | .init : { 46 | start.o(.text* .data* .bss* .rodata*) 47 | initsys.o (.text* .data* .bss* .rodata*) 48 | } >initsys 49 | 50 | _highkernelload = ALIGN(4k); 51 | 52 | /* Main kernel text/data. Loads at 0x9000, is remapped to 53 | * 0xf0009000 by initsys 54 | */ 55 | .text (_highkernelload + 0xf0000000) : AT(_highkernelload) { 56 | _kstart = ABSOLUTE(.); /* Address of the kernel */ 57 | *(.text*) 58 | } >kernel 59 | .rodata : { 60 | /* Where the kernel code ends and read-only data begins */ 61 | _krodata = ABSOLUTE(.); 62 | 63 | *(.rodata*) 64 | } >kernel 65 | 66 | _kend = .; /* Address of the end of the kernel (RO data) */ 67 | _data_kmem = ALIGN(4k); 68 | 69 | /* Kernel read/write data */ 70 | .data : AT(_data_kmem - 0xf0000000) { 71 | _datastart = ABSOLUTE(.) ; 72 | *(.data) } 73 | >data 74 | 75 | /* Kernel read/write memory - needs to be zeroed by the kernel before 76 | * being used 77 | */ 78 | .bss : { 79 | _bssstart = ABSOLUTE(.) ; 80 | *(.bss) 81 | *(COMMON) 82 | _bssend = ABSOLUTE(.) ; 83 | } >data 84 | 85 | /* Calculate physical addresses of data memory for the kernel */ 86 | _physdatastart = _data_kmem - 0xf0000000; 87 | _physbssstart = _physdatastart + (_bssstart - _datastart); 88 | _physbssend = _physdatastart + (_bssend - _datastart); 89 | } 90 | -------------------------------------------------------------------------------- /pi-baremetal/mailbox.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Access system mailboxes 3 | */ 4 | #include "mailbox.h" 5 | 6 | #include "barrier.h" 7 | #include "memory.h" 8 | 9 | /* Mailbox memory addresses */ 10 | static volatile unsigned int *MAILBOX0READ = (unsigned int *) mem_p2v(0x2000b880); 11 | static volatile unsigned int *MAILBOX0STATUS = (unsigned int *) mem_p2v(0x2000b898); 12 | static volatile unsigned int *MAILBOX0WRITE = (unsigned int *) mem_p2v(0x2000b8a0); 13 | 14 | /* Bit 31 set in status register if the write mailbox is full */ 15 | #define MAILBOX_FULL 0x80000000 16 | 17 | /* Bit 30 set in status register if the read mailbox is empty */ 18 | #define MAILBOX_EMPTY 0x40000000 19 | 20 | unsigned int readmailbox(unsigned int channel) 21 | { 22 | unsigned int count = 0; 23 | unsigned int data; 24 | 25 | /* Loop until something is received from channel 26 | * If nothing recieved, it eventually give up and returns 0xffffffff 27 | */ 28 | while(1) 29 | { 30 | while (*MAILBOX0STATUS & MAILBOX_EMPTY) 31 | { 32 | /* Need to check if this is the right thing to do */ 33 | flushcache(); 34 | 35 | /* This is an arbritarily large number */ 36 | if(count++ >(1<<25)) 37 | { 38 | return 0xffffffff; 39 | } 40 | } 41 | /* Read the data 42 | * Data memory barriers as we've switched peripheral 43 | */ 44 | dmb(); 45 | data = *MAILBOX0READ; 46 | dmb(); 47 | 48 | if ((data & 15) == channel) 49 | return data; 50 | } 51 | } 52 | 53 | void writemailbox(unsigned int channel, unsigned int data) 54 | { 55 | /* Wait for mailbox to be not full */ 56 | while (*MAILBOX0STATUS & MAILBOX_FULL) 57 | { 58 | /* Need to check if this is the right thing to do */ 59 | flushcache(); 60 | } 61 | 62 | dmb(); 63 | *MAILBOX0WRITE = (data | channel); 64 | } 65 | -------------------------------------------------------------------------------- /pi-baremetal/mailbox.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MAILBOX_H 3 | #define MAILBOX_H 4 | 5 | extern unsigned int readmailbox(unsigned int channel); 6 | extern void writemailbox(unsigned int channel, unsigned int data); 7 | 8 | #endif /* MAILBOX_H */ 9 | -------------------------------------------------------------------------------- /pi-baremetal/main.c: -------------------------------------------------------------------------------- 1 | #include "led.h" 2 | #include "atags.h" 3 | #include "barrier.h" 4 | #include "framebuffer.h" 5 | #include "interrupts.h" 6 | #include "mailbox.h" 7 | #include "memory.h" 8 | #include "memutils.h" 9 | #include "textutils.h" 10 | #include "process.h" 11 | #include "scheduler.h" 12 | 13 | /* Pull various bits of information from the VideoCore and display it on 14 | * screen 15 | */ 16 | void mailboxtest(void) 17 | { 18 | /* 1kb buffer on the stack for passing data to/from VideoCore */ 19 | volatile unsigned int buffer[256] __attribute__((aligned (16))); 20 | unsigned int count, var; 21 | unsigned int mem, size; 22 | 23 | console_write(BG_GREEN BG_HALF "Reading from tag mailbox\n\n" BG_BLACK); 24 | 25 | buffer[0] = 8 * 4; // Total size 26 | buffer[1] = 0; // Request 27 | 28 | buffer[2] = 0x40003; // Display size 29 | buffer[3] = 8; // Buffer size 30 | buffer[4] = 0; // Request size 31 | buffer[5] = 0; 32 | buffer[6] = 0; 33 | 34 | buffer[7] = 0; 35 | 36 | writemailbox(8, mem_v2p((unsigned int)buffer)); 37 | 38 | var = readmailbox(8); 39 | 40 | console_write(COLOUR_PUSH FG_CYAN "Display resolution: " BG_WHITE BG_HALF BG_HALF); 41 | console_write(todec(buffer[5], 0)); 42 | console_write("x"); 43 | console_write(todec(buffer[6], 0)); 44 | console_write(COLOUR_POP "\n"); 45 | 46 | buffer[0] = 8 * 4; // Total size 47 | buffer[1] = 0; // Request 48 | 49 | buffer[2] = 0x40008; // Display size 50 | buffer[3] = 8; // Buffer size 51 | buffer[4] = 0; // Request size 52 | buffer[5] = 0; 53 | buffer[6] = 0; 54 | 55 | buffer[7] = 0; 56 | 57 | writemailbox(8, mem_v2p((unsigned int)buffer)); 58 | 59 | var = readmailbox(8); 60 | 61 | console_write(COLOUR_PUSH FG_CYAN "Pitch: " BG_WHITE BG_HALF BG_HALF); 62 | console_write(todec(buffer[5], 0)); 63 | console_write(" bytes" COLOUR_POP "\n"); 64 | 65 | buffer[0] = 200 * 4; // Total size 66 | buffer[1] = 0; // Request 67 | 68 | buffer[2] = 0x50001; // Command line 69 | buffer[3] = 195*4; // Buffer size 70 | buffer[4] = 0; // Request size 71 | 72 | for(count=5; count<200; count++) 73 | buffer[count] = 0; 74 | 75 | writemailbox(8, mem_v2p((unsigned int)buffer)); 76 | 77 | var = readmailbox(8); 78 | 79 | console_write("\n" COLOUR_PUSH FG_RED "Kernel command line: " COLOUR_PUSH BG_RED BG_HALF BG_HALF); 80 | console_write((char *)(&buffer[5])); 81 | console_write(COLOUR_POP COLOUR_POP "\n\n"); 82 | 83 | 84 | buffer[0] = 13 * 4; // Total size 85 | buffer[1] = 0; // Request 86 | 87 | buffer[2] = 0x10005; // ARM memory 88 | buffer[3] = 8; // Buffer size 89 | buffer[4] = 0; // Request size 90 | buffer[5] = 0; 91 | buffer[6] = 0; 92 | 93 | buffer[7] = 0x10006; // VideoCore memory 94 | buffer[8] = 8; // Buffer size 95 | buffer[9] = 0; // Request size 96 | buffer[10] = 0; 97 | buffer[11] = 0; 98 | 99 | buffer[12] = 0; 100 | 101 | writemailbox(8, mem_v2p((unsigned int)buffer)); 102 | 103 | var = readmailbox(8); 104 | 105 | mem = buffer[5]; 106 | size = buffer[6]; 107 | var = size / (1024*1024); 108 | 109 | console_write(COLOUR_PUSH FG_YELLOW "ARM memory: " BG_YELLOW BG_HALF BG_HALF "0x"); 110 | console_write(tohex(mem, 4)); 111 | console_write(" - 0x"); 112 | console_write(tohex(mem+size-1, 4)); 113 | console_write(" ("); 114 | console_write(todec(size, 0)); 115 | /* ] appears as an arrow in the SAA5050 character set */ 116 | console_write(" bytes ] "); 117 | console_write(todec(var, 0)); 118 | console_write(" megabytes)" COLOUR_POP "\n"); 119 | 120 | mem = buffer[10]; 121 | size = buffer[11]; 122 | var = size / (1024*1024); 123 | console_write(COLOUR_PUSH FG_YELLOW "VC memory: " BG_YELLOW BG_HALF BG_HALF "0x"); 124 | console_write(tohex(mem, 4)); 125 | console_write(" - 0x"); 126 | console_write(tohex(mem+size-1, 4)); 127 | console_write(" ("); 128 | console_write(todec(size, 0)); 129 | console_write(" bytes ] "); 130 | console_write(todec(var, 0)); 131 | console_write(" megabytes)" COLOUR_POP "\n"); 132 | } 133 | 134 | /* Call non-existent code at 33MB - should cause a prefetch abort */ 135 | static void(*deliberate_prefetch_abort)(void) = (void(*)(void))0x02100000; 136 | 137 | /* Location of the initial page table in RAM */ 138 | static unsigned int *initpagetable = (unsigned int *) mem_p2v(0x4000); 139 | 140 | /* Data/bss locations in physical RAM */ 141 | extern unsigned int _physdatastart, _physbssstart, _physbssend; 142 | extern unsigned int _datastart, _bssstart, _bssend; 143 | extern unsigned int _kstart, _krodata, _kend; 144 | 145 | 146 | void testmmu(unsigned int *UFCON0){ 147 | const char *p="helloworld MMU\n"; 148 | while(*p){ 149 | *UFCON0=*p++; 150 | }; 151 | } 152 | 153 | /* Main high memory kernel routine - called directly from initsys.c 154 | * Begins by completing the memory management work of initsys; removing the 155 | * virtual memory page that initsys was running in. 156 | * 157 | * ARM procedure call standard says the first 3 parameters of a function 158 | * are r0, r1, r2. These registers are untouched by _start/initsys, so will be 159 | * exactly as the bootloader set them 160 | * r0 should be 0 161 | * r1 should be the machine type - 0x0c42 = Raspberry Pi 162 | * r2 should be the ATAGs structure address (probably 0x100) 163 | */ 164 | void main(unsigned int r0, unsigned int machtype, unsigned int atagsaddr) 165 | { 166 | /* No further need to access kernel code at 0x00000000 - 0x000fffff */ 167 | initpagetable[0] = 0; 168 | /* Flush it out of the TLB */ 169 | asm volatile("mcr p15, 0, %[data], c8, c7, 1" : : [data] "r" (0x00000000)); 170 | 171 | /* Initialise stuff */ 172 | mem_init(); 173 | 174 | unsigned int VCADDR = mem_p2v(0x20201000); 175 | static volatile unsigned int *gpioGPSET0 = (unsigned int *) mem_p2v(0x20201000); 176 | testmmu(gpioGPSET0); 177 | testmmu(0xA0203000); 178 | led_init(); 179 | fb_init(); 180 | 181 | create_main_process(); 182 | 183 | // Create three sample processes with name and address of function 184 | fork("Sample process 1", &sample_process_1); 185 | fork("Sample process 2", &sample_process_2); 186 | fork("Sample process 3", &sample_process_2); 187 | 188 | interrupts_init(); 189 | 190 | 191 | /* Say hello */ 192 | console_write("Pi-Baremetal booted\n\n"); 193 | 194 | console_write(FG_RED "Machine type is 0x"); 195 | console_write(tohex(machtype, 4)); 196 | 197 | if(machtype == 0xc42) 198 | console_write(", a Broadcom BCM2708 (Raspberry Pi)\n\n" FG_WHITE); 199 | else 200 | console_write(". Unknown machine type. Good luck!\n\n" FG_WHITE); 201 | 202 | /* Read in ATAGS */ 203 | print_atags(atagsaddr); 204 | 205 | /* Read in some system data */ 206 | mailboxtest(); 207 | 208 | /* Test interrupt */ 209 | console_write("\nTest SWI: "); 210 | asm volatile("swi #1234"); 211 | 212 | console_write(FG_YELLOW "\nKernel starts: 0x"); 213 | console_write(tohex((unsigned int)&_kstart, 4)); 214 | console_write(FG_YELLOW "\nKernel read-only data: 0x"); 215 | console_write(tohex((unsigned int)&_krodata, 4)); 216 | console_write(FG_YELLOW "\nKernel ends: 0x"); 217 | console_write(tohex((unsigned int)&_kend, 4)); 218 | 219 | console_write(FG_YELLOW"\n\nUART MMU ADDRESS: 0x"); 220 | console_write(tohex((unsigned int)VCADDR,4)); 221 | 222 | console_write(FG_MAGENTA "\n\nKernel data: 0x"); 223 | console_write(tohex((unsigned int)&_physdatastart, 4)); 224 | console_write(" - 0x"); 225 | console_write(tohex((unsigned int)&_physbssstart, 4)); 226 | console_write(" (physical), 0x"); 227 | console_write(tohex((unsigned int)&_datastart, 4)); 228 | console_write(" - 0x"); 229 | console_write(tohex((unsigned int)&_bssstart, 4)); 230 | console_write(" (virtual)\nKernel bss: 0x"); 231 | console_write(tohex((unsigned int)&_physbssstart, 4)); 232 | console_write(" - 0x"); 233 | console_write(tohex((unsigned int)&_physbssend, 4)); 234 | console_write(" (physical), 0x"); 235 | console_write(tohex((unsigned int)&_bssstart, 4)); 236 | console_write(" - 0x"); 237 | console_write(tohex((unsigned int)&_bssend, 4)); 238 | console_write(" (virtual)\n"); 239 | 240 | console_write(BG_WHITE BG_HALF BG_HALF FG_CYAN 241 | "\nKernel code should be read-only, even to privileged CPU modes: " 242 | "attempting write to 0x"); 243 | console_write(tohex((unsigned int)&_kstart, 4)); 244 | console_write("\n" FG_RED); 245 | _kstart = 1234; 246 | 247 | console_write(FG_WHITE BG_GREEN BG_HALF "\nOK LED flashing under interrupt"); 248 | 249 | console_write(BG_BLACK FG_YELLOW 250 | "\n\nPerforming deliberate prefetch abort (calling non-existent code at 0x02100000): " 251 | FG_RED BG_RED BG_HALF); 252 | deliberate_prefetch_abort(); 253 | 254 | /* Prefetch abort doesn't return, so it won't get past this point */ 255 | 256 | console_write(FG_WHITE BG_RED BG_HALF "\ndeliberate_prefetch_abort() didn't abort!"); 257 | 258 | while(1); 259 | } 260 | 261 | void main_endloop(void) 262 | { 263 | console_write(FG_WHITE BG_GREEN BG_HALF "\nPrefetch abort done"); 264 | 265 | /* Repeatedly halt the CPU and wait for interrupt */ 266 | while(1) 267 | asm volatile("mcr p15,0,r0,c7,c0,4" : : : "r0"); 268 | 269 | } 270 | -------------------------------------------------------------------------------- /pi-baremetal/memory.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | 3 | /* Virtual memory layout 4 | * 5 | * 0x00000000 - 0x7fffffff (0-2GB) = user process memory 6 | * 0x80000000 - 0xa0ffffff = physical memory 7 | * includes peripherals at 0x20000000 - 0x20ffffff 8 | * 0xc0000000 - 0xefffffff = kernel data 9 | * 0xf0000000 - 0xffffffff = kernel code 10 | */ 11 | 12 | /* Need to access the page table, etc as physical memory */ 13 | static unsigned int *pagetable = (unsigned int * const) mem_p2v(0x4000); /* 16k */ 14 | 15 | /* Last used location in physical RAM */ 16 | extern unsigned int _physbssend; 17 | /* Start of kernel in physical RAM */ 18 | extern unsigned int _highkernelload; 19 | 20 | /* Convert a virtual address to a physical one by following the page tables 21 | * Returns physical address, or 0xffffffff if the virtual address does not map 22 | * See ARM1176-TZJS technical reference manual, page 6-39 (6.11.2) 23 | */ 24 | unsigned int mem_v2p(unsigned int virtualaddr) 25 | { 26 | unsigned int pt_data = pagetable[virtualaddr >> 20]; 27 | unsigned int cpt_data, physaddr; 28 | 29 | if((pt_data & 3)==0 || (pt_data & 3)==3) 30 | { 31 | /* Nothing mapped */ 32 | return 0xffffffff; 33 | } 34 | 35 | if((pt_data & 3)==2) 36 | { 37 | /* (Super)Section */ 38 | 39 | physaddr = pt_data & 0xfff00000; 40 | 41 | if(pt_data & (1<<18)) 42 | { 43 | /* 16MB Supersection */ 44 | physaddr += virtualaddr & 0x00ffffff; 45 | } 46 | else 47 | { 48 | /* 1MB Section */ 49 | physaddr += virtualaddr & 0x000fffff; 50 | } 51 | 52 | return physaddr; 53 | } 54 | 55 | /* Coarse page table */ 56 | cpt_data = ((unsigned int *)(0x80000000 + (pt_data & 0xfffffc00)))[(virtualaddr>>12)&0xff] ; 57 | 58 | if((cpt_data & 3) == 0) 59 | { 60 | /* Nothing mapped */ 61 | return 0xffffffff; 62 | } 63 | 64 | if(cpt_data & 2) 65 | { 66 | /* Small (4k) page */ 67 | return (cpt_data & 0xfffff000) + (virtualaddr & 0xfff); 68 | } 69 | 70 | /* Large (64k) page */ 71 | return (cpt_data & 0xffff0000) + (virtualaddr & 0xffff); 72 | } 73 | 74 | /* mem_p2v is a simple macro defined in memory.h which adds 0x80000000 to an 75 | * address, to put the physical memory address (0x00000000-0x20ffffff) into 76 | * the corresponding mapped area of virtual memory (0x80000000-0xa0ffffff) 77 | */ 78 | 79 | /* Translation table 0 - covers the first 64 MB, for now 80 | * Needs to be aligned to its size (ie 64*4 bytes) 81 | */ 82 | unsigned int pagetable0[64] __attribute__ ((aligned (256))); 83 | 84 | /* Initialise memory - actually, there's not much to do now, since initsys 85 | * covers most of it. It just sets up a pagetable for the first 64MB of RAM 86 | * (all unmapped) 87 | */ 88 | void mem_init(void) 89 | { 90 | unsigned int x; 91 | unsigned int pt0_addr; 92 | 93 | /* Translation table 0 - covers the first 64 MB, for now 94 | * Currently nothing mapped in it. 95 | */ 96 | for(x=0; x<64; x++) 97 | { 98 | pagetable0[x] = 0; 99 | } 100 | 101 | /* Get physical address of pagetable0 */ 102 | pt0_addr = mem_v2p((unsigned int) &pagetable0); 103 | 104 | /* Use translation table 0 up to 64MB */ 105 | asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (6)); 106 | /* Translation table 0 - ARM1176JZF-S manual, 3-57 */ 107 | asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt0_addr)); 108 | /* Invalidate the translation lookaside buffer (TLB) 109 | * ARM1176JZF-S manual, p. 3-86 110 | */ 111 | asm volatile("mcr p15, 0, %[data], c8, c7, 0" : : [data] "r" (0)); 112 | } 113 | -------------------------------------------------------------------------------- /pi-baremetal/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_H 2 | #define MEMORY_H 3 | 4 | /* Convert a virtual address to a physical one by following the page tables 5 | * Returns physical address, or 0xffffffff if the virtual address does not map 6 | */ 7 | extern unsigned int mem_v2p(unsigned int); 8 | 9 | /* Convert a physical address to a virtual one - essentially, just add 10 | * 0x80000000 to it 11 | */ 12 | #define mem_p2v(X) (X+0x80000000) 13 | 14 | extern void mem_init(void); 15 | 16 | #endif /* MEMORY_H */ 17 | -------------------------------------------------------------------------------- /pi-baremetal/memutils.c: -------------------------------------------------------------------------------- 1 | /* Various memory utilities */ 2 | 3 | #include "memutils.h" 4 | 5 | /* Clear (set to 0) length bytes of memory starting at address 6 | */ 7 | void memclr(void *address, unsigned int length) 8 | { 9 | register unsigned int addr = (unsigned int)address; 10 | 11 | /* If the start address is unaligned, fill in the first 1-3 bytes 12 | * until it is 13 | */ 14 | while((addr & 3) && length) 15 | { 16 | *((unsigned char *)addr) = 0; 17 | addr++; 18 | length--; 19 | } 20 | 21 | /* Fill in the remaining 32-bit word-aligned memory locations */ 22 | while(length & 0xfffffffc) 23 | { 24 | *((unsigned int *)addr) = 0; 25 | addr+=4; 26 | length-=4; 27 | } 28 | 29 | /* Deal with the remaining 1-3 bytes, if any */ 30 | while(length) 31 | { 32 | addr++; 33 | length--; 34 | *((unsigned char *)addr) = 0; 35 | } 36 | } 37 | 38 | /* Move length bytes from src to dest. Memory areas may overlap 39 | * Four possibilities: 40 | * ..[...src...]..[...dest...].. -- non-overlapping 41 | * ..[...dest...]..[...src...].. -- non-overlapping 42 | * ..[...src..[.]..dest...].. -- overlapping 43 | * ..[...dest..[.]..src...].. -- overlapping 44 | * The first two can be dealt with by copying from either end of the source 45 | * block 46 | * The third (overlapping, source first) by copying from the end of the block 47 | * back to the start 48 | * The fourth (overlapping, destination first) by copying from the start of the 49 | * source block to the end 50 | * 51 | * Returns the address of the destination memory area 52 | */ 53 | void *memmove(void *dest, const void *src, unsigned int length) 54 | { 55 | /* Turn destination and source pointers into integers for easier 56 | * calculations 57 | */ 58 | register unsigned int d = (unsigned int)dest; 59 | register unsigned int s = (unsigned int)src; 60 | 61 | if(!length) 62 | return dest; 63 | 64 | /* Assume the memory blocks are word aligned. Most will be, and the 65 | * CPU can deal with unaligned accesses if necessary (as long as it 66 | * is configured to do so) 67 | */ 68 | if(d>s && d<(s+length)) 69 | { 70 | /* Destination starts inside source area - work backwards */ 71 | /* If length isn't a multiple of 4 bytes, copy the last 1-3 72 | * bytes first 73 | */ 74 | while(length & 3) 75 | { 76 | length--; 77 | ((unsigned char *)d)[length] = ((unsigned char *)s)[length]; 78 | } 79 | 80 | /* Copy everything else as 32-bit words. If one or both of the 81 | * memory areas aren't aligned, this will cause unaligned 82 | * reads. Inefficient, but less so than doing everything as 83 | * a series of bytes 84 | */ 85 | while(length) 86 | { 87 | length-=4; 88 | *((unsigned int *)d+length) = *((unsigned int *)s+length); 89 | } 90 | } 91 | else 92 | { 93 | /* Source starts inside destination area - working forwards 94 | * is fine - or two areas don't overlap (or they overlap 95 | * exactly, but that's an unlikely edge case) 96 | * 97 | * Copy as much as possible as 32-bit words. See above for 98 | * alignment issues 99 | */ 100 | while(length & 0xfffffffc) 101 | { 102 | *((unsigned int *)d) = *((unsigned int *)s); 103 | d+=4; 104 | s+=4; 105 | length-=4; 106 | } 107 | 108 | /* Deal with 1-3 remaining bytes, if applicable */ 109 | while(length) 110 | { 111 | *((unsigned char *)d) = *((unsigned char *)s); 112 | d++; 113 | s++; 114 | length--; 115 | } 116 | } 117 | 118 | return dest; 119 | } 120 | -------------------------------------------------------------------------------- /pi-baremetal/memutils.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMUTILS_H 2 | #define MEMUTILS_H 3 | 4 | /* Clear length bytes of memory (set to 0) starting at address */ 5 | extern void memclr(void *address, unsigned int length); 6 | 7 | /* Move length bytes from src to dest. Memory areas may overlap */ 8 | extern void *memmove(void *dest, const void *src, unsigned int length); 9 | 10 | #endif /* MEMUTILS_H */ 11 | -------------------------------------------------------------------------------- /pi-baremetal/process.c: -------------------------------------------------------------------------------- 1 | 2 | #include "textutils.h" 3 | #include "framebuffer.h" 4 | #include "scheduler.h" 5 | 6 | // Just some counting for easy debug on the screen. Simulate user process. 7 | void sample_process_1() { 8 | 9 | console_write("Starting process 1 "); 10 | 11 | int to = 300; 12 | 13 | int i, j; 14 | for (i=0; i 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this 8 | license document, but changing it is not allowed. 9 | 10 | This GCC Runtime Library Exception ("Exception") is an additional 11 | permission under section 7 of the GNU General Public License, version 12 | 3 ("GPLv3"). It applies to a given file (the "Runtime Library") that 13 | bears a notice placed by the copyright holder of the file stating that 14 | the file is governed by GPLv3 along with this Exception. 15 | 16 | When you use GCC to compile a program, GCC may combine portions of 17 | certain GCC header files and runtime libraries with the compiled 18 | program. The purpose of this Exception is to allow compilation of 19 | non-GPL (including proprietary) programs to use, in this way, the 20 | header files and runtime libraries covered by this Exception. 21 | 22 | 0. Definitions. 23 | 24 | A file is an "Independent Module" if it either requires the Runtime 25 | Library for execution after a Compilation Process, or makes use of an 26 | interface provided by the Runtime Library, but is not otherwise based 27 | on the Runtime Library. 28 | 29 | "GCC" means a version of the GNU Compiler Collection, with or without 30 | modifications, governed by version 3 (or a specified later version) of 31 | the GNU General Public License (GPL) with the option of using any 32 | subsequent versions published by the FSF. 33 | 34 | "GPL-compatible Software" is software whose conditions of propagation, 35 | modification and use would permit combination with GCC in accord with 36 | the license of GCC. 37 | 38 | "Target Code" refers to output from any compiler for a real or virtual 39 | target processor architecture, in executable form or suitable for 40 | input to an assembler, loader, linker and/or execution 41 | phase. Notwithstanding that, Target Code does not include data in any 42 | format that is used as a compiler intermediate representation, or used 43 | for producing a compiler intermediate representation. 44 | 45 | The "Compilation Process" transforms code entirely represented in 46 | non-intermediate languages designed for human-written code, and/or in 47 | Java Virtual Machine byte code, into Target Code. Thus, for example, 48 | use of source code generators and preprocessors need not be considered 49 | part of the Compilation Process, since the Compilation Process can be 50 | understood as starting with the output of the generators or 51 | preprocessors. 52 | 53 | A Compilation Process is "Eligible" if it is done using GCC, alone or 54 | with other GPL-compatible software, or if it is done without using any 55 | work based on GCC. For example, using non-GPL-compatible Software to 56 | optimize any GCC intermediate representations would not qualify as an 57 | Eligible Compilation Process. 58 | 59 | 1. Grant of Additional Permission. 60 | 61 | You have permission to propagate a work of Target Code formed by 62 | combining the Runtime Library with Independent Modules, even if such 63 | propagation would otherwise violate the terms of GPLv3, provided that 64 | all Target Code was generated by Eligible Compilation Processes. You 65 | may then convey such a combination under terms of your choice, 66 | consistent with the licensing of the Independent Modules. 67 | 68 | 2. No Weakening of GCC Copyleft. 69 | 70 | The availability of this Exception does not imply any general 71 | presumption that third-party software is unaffected by the copyleft 72 | requirements of the license of GCC. 73 | 74 | -------------------------------------------------------------------------------- /pi-baremetal/rpi-libgcc/README: -------------------------------------------------------------------------------- 1 | libgcc.a for Raspberry Pi 2 | ========================= 3 | 4 | The libgcc.a file in this directory is taken from gcc in the Raspbian Wheezy 5 | distribution and in subject to the GPL, version 3, with the runtime 6 | exception (see the files COPYING3 and COPYING.RUNTIME). 7 | 8 | A copy of the source code can be found at 9 | https://github.com/mirrors/gcc/tree/master/libgcc 10 | -------------------------------------------------------------------------------- /pi-baremetal/rpi-libgcc/libgcc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tzuCarlos/RaspberryPi/de08cc43e94b891d68b245373e88471c2fa09531/pi-baremetal/rpi-libgcc/libgcc.a -------------------------------------------------------------------------------- /pi-baremetal/run_pi.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/qemu-system-arm -kernel kernel.elf -cpu arm1176 -m 256 -M raspi -serial stdio 2 | -------------------------------------------------------------------------------- /pi-baremetal/scheduler.c: -------------------------------------------------------------------------------- 1 | 2 | #include "process.h" 3 | #include "framebuffer.h" 4 | #include "textutils.h" 5 | #include "interrupts.h" 6 | 7 | static process process_list[1024]; 8 | static unsigned int stack_base; 9 | static unsigned int process_count = 0; 10 | static unsigned int active_process_index; 11 | 12 | extern void main_endloop(); 13 | extern void timer_reset(); 14 | 15 | void terminate_process() { 16 | // Set it to terminated status, so the scheduler will ignore it 17 | process_list[active_process_index].status = PROCESS_STATUS_TERMINATED; 18 | } 19 | 20 | // Function to create the main process 21 | void create_main_process() { 22 | 23 | // Creating process 24 | process main_process; 25 | 26 | main_process.id = process_count; 27 | main_process.name = "Main"; 28 | main_process.pc = &main_endloop; 29 | main_process.times_loaded = 1; 30 | main_process.status = PROCESS_STATUS_ZOMBIE; 31 | 32 | // Gets the actual stack address 33 | unsigned int stack_pointer; 34 | asm volatile ("MOV %0, SP\n\t" : "=r" (stack_pointer) ); 35 | 36 | // Use it as base address processes stack pointer 37 | stack_base = stack_pointer; 38 | 39 | // Output the stack address 40 | console_write("Main stack is 0x"); 41 | console_write(tohex(stack_pointer, 4)); 42 | console_write("\n"); 43 | 44 | // Saving the process in the process table 45 | process_list[process_count] = main_process; 46 | 47 | // Set it as the current active process 48 | active_process_index = process_count; 49 | 50 | // Increments the process counter 51 | process_count++; 52 | } 53 | 54 | /* 55 | * Procedure to fork this process, creating a new one, pointing the pc 56 | * to the memory address of the desired procedure 57 | */ 58 | void fork(char * name, unsigned long * pc) { 59 | 60 | process fork_process; 61 | 62 | // Basic memory organization to get new stack addr. just add 1024 bytes from the main stack 63 | unsigned int * forked_stack_pointer = stack_base + (process_count * 1024); 64 | 65 | console_write("Forked stack is 0x"); 66 | console_write(tohex(forked_stack_pointer, 4)); 67 | console_write("\n"); 68 | 69 | fork_process.id = process_count; 70 | fork_process.name = name; 71 | fork_process.pc = pc; 72 | fork_process.parent = active_process_index; 73 | fork_process.times_loaded = 0; 74 | fork_process.stack_pointer = forked_stack_pointer; 75 | fork_process.status = PROCESS_STATUS_WAITING; 76 | 77 | process_list[process_count] = fork_process; 78 | 79 | process_count++; 80 | } 81 | 82 | /* 83 | * Function to get the next ready process in the list 84 | */ 85 | int next_waiting_process_index() { 86 | 87 | // Start in the active index 88 | int next_process_index = active_process_index; 89 | 90 | // Do this while the actual process isnt in the waiting status and not reach the actual running process 91 | do { 92 | next_process_index++; 93 | 94 | // Just rewind the list 95 | if (next_process_index == process_count) { 96 | next_process_index = 0; 97 | } 98 | 99 | } while ((process_list[next_process_index].status != PROCESS_STATUS_WAITING) && (next_process_index != active_process_index)); 100 | 101 | // If the found process isnt waiting 102 | if (process_list[next_process_index].status != PROCESS_STATUS_WAITING) { 103 | return -1; 104 | } 105 | 106 | return next_process_index; 107 | } 108 | 109 | /* 110 | * Just keep the processor busy 111 | */ 112 | void halt() { 113 | while(1); 114 | } 115 | 116 | /* 117 | * Procedure coming from the IRQ interrupt, to change the running process 118 | */ 119 | void schedule_timeout(unsigned long stack_pointer, unsigned long pc) { 120 | 121 | // Saving stack and pc 122 | process_list[active_process_index].stack_pointer = stack_pointer; 123 | process_list[active_process_index].pc = pc; 124 | 125 | // Updating process status to waiting 126 | if (process_list[active_process_index].status == PROCESS_STATUS_RUNNING) { 127 | process_list[active_process_index].status = PROCESS_STATUS_WAITING; 128 | } 129 | 130 | console_write("\n"); 131 | console_write("\n"); 132 | console_write("Schedule timeout. Current active pid is "); 133 | console_write(todec(process_list[active_process_index].id, 0)); 134 | console_write(" with name "); 135 | console_write(process_list[active_process_index].name); 136 | console_write(". Switching to next process.\n"); 137 | 138 | console_write("Saving stack..."); 139 | console_write(" stack saved, was 0x"); 140 | console_write(tohex(process_list[active_process_index].stack_pointer, 4)); 141 | console_write("\n"); 142 | 143 | console_write("Saving pc..."); 144 | console_write(" pc saved, was 0x"); 145 | console_write(tohex(process_list[active_process_index].pc, 4)); 146 | console_write("\n"); 147 | 148 | // Get next process id 149 | int next_process = next_waiting_process_index(); 150 | 151 | // If -1, halt 152 | if (next_process < 0) { 153 | console_write("No more waiting processes, halting."); 154 | halt(); 155 | } 156 | 157 | // Updating next running process 158 | active_process_index = next_process; 159 | 160 | // Increasing statistics, updating status to running 161 | process_list[active_process_index].times_loaded++; 162 | process_list[active_process_index].status = PROCESS_STATUS_RUNNING; 163 | 164 | console_write("Restoring stack 0x"); 165 | console_write(tohex(process_list[active_process_index].stack_pointer, 4)); 166 | console_write("\n"); 167 | 168 | console_write("Restoring pc 0x"); 169 | console_write(tohex(process_list[active_process_index].pc, 4)); 170 | console_write("\n"); 171 | 172 | // Assembly to load the sp with the new process stack address 173 | asm volatile("MOV SP, %[addr]" : : [addr] "r" ((unsigned long )(process_list[active_process_index].stack_pointer)) ); 174 | 175 | // If its is not the first time 176 | if (process_list[active_process_index].times_loaded > 1) { 177 | 178 | timer_reset(); 179 | 180 | // Pops registers from the stack 181 | asm volatile("pop {R0}"); 182 | asm volatile("MSR SPSR_cxsf, R0"); 183 | asm volatile("pop {LR}"); 184 | asm volatile("pop {R0 - R12}"); 185 | 186 | // Turn on interrupt again 187 | asm volatile("cpsie i"); 188 | 189 | // Pops the last register into PC to resume processing 190 | asm volatile("pop {PC}"); 191 | 192 | } else { 193 | 194 | // Push the first pc address into the stack 195 | unsigned long addr = (unsigned long )(process_list[active_process_index].pc); 196 | asm volatile("MOV R0, %[addr]" : : [addr] "r" (addr) ); 197 | asm volatile("push {R0}"); 198 | 199 | timer_reset(); 200 | 201 | // Turn on interrupt again 202 | asm volatile("cpsie i"); 203 | 204 | // Pops the last register into PC to resume processing 205 | asm volatile("pop {PC}"); 206 | 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /pi-baremetal/scheduler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SCHEDULER_H 3 | #define SCHEDULER_H 4 | 5 | #include "process.h" 6 | 7 | void create_main_process(); 8 | void fork(char * name, unsigned long addr); 9 | void schedule_timeout(unsigned long stack_pointer, unsigned long pc); 10 | void terminate_process(); 11 | void halt(); 12 | 13 | #endif /* SCHEDULER_H */ 14 | 15 | -------------------------------------------------------------------------------- /pi-baremetal/start.s: -------------------------------------------------------------------------------- 1 | /* Set up stacks and jump to C code */ 2 | 3 | .global _start 4 | 5 | _start: 6 | /* Leave r0-r2 alone as main() is expecting to use the values in 7 | * them 8 | */ 9 | 10 | /* kernel.img is loaded at 0x8000 11 | * Below that, 0x4000-0x7fff is the 1MB memory page table, then 12 | * 0x3c00-0x3fff is the kernel data coarse page table (see initsys.c) 13 | * 14 | * Stacks go below it, as follows: 15 | * 16 | * 0x2c00 - 0x3c00 User/system stack 17 | * 0x2800 - 0x2c00 IRQ stack 18 | * 0x2400 - 0x2800 Abort stack 19 | * 0x2000 - 0x2400 Supervisor (SWI/SVC) stack 20 | * 21 | * All stacks grow down; decrement then store 22 | * 23 | * Stack addresses are stored in the stack pointers as 24 | * 0x80000000+address, as this means the stack pointer doesn't have 25 | * to change when the MMU is turned on (before the MMU is on, accesses 26 | * to 0x80000000 go to 0x00000000, and so on). Eventually, the stacks 27 | * will be given a proper home 28 | */ 29 | 30 | mov r4, #0x80000000 31 | 32 | /* SVC stack (for SWIs) at 0x2000 */ 33 | /* The processor appears to start in this mode, but change to it 34 | * anyway 35 | */ 36 | cps #0x13 /* Change to supervisor (SVC) mode */ 37 | add sp, r4, #0x2400 38 | 39 | /* ABORT stack at 0x2400 */ 40 | cps #0x17 /* Change to Abort mode */ 41 | add sp, r4, #0x2800 42 | 43 | /* IRQ stack at 0x2800 */ 44 | cps #0x12 /* Change to IRQ mode */ 45 | add sp, r4, #0x2c00 46 | 47 | /* System stack at 0x2c00 */ 48 | cps #0x1f /* Change to system mode */ 49 | add sp, r4, #0x3c00 50 | 51 | /* Stay in system mode from now on */ 52 | 53 | /* Turn on unaligned memory access */ 54 | mrc p15, #0, r4, c1, c0, #0 55 | orr r4, #0x400000 /* 1<22 */ 56 | mcr p15, #0, r4, c1, c0, #0 57 | 58 | /* Jump to memory map initialisation code */ 59 | b initsys 60 | 61 | -------------------------------------------------------------------------------- /pi-baremetal/syscall.c: -------------------------------------------------------------------------------- 1 | 2 | #include "scheduler.h" 3 | #include "syscall.h" 4 | #include "framebuffer.h" 5 | #include "textutils.h" 6 | 7 | /* 8 | * Procedure to handle software interrupts 9 | */ 10 | void syscall(unsigned int swi) { 11 | 12 | console_write("Handling syscall: "); 13 | console_write(todec(swi, 0)); 14 | console_write("\n"); 15 | 16 | switch (swi) { 17 | 18 | case SYSCALL_TERMINATE_PROCESS: 19 | console_write("Invoking syscall terminate_process()"); 20 | console_write("\n"); 21 | 22 | // Calling the right intra-kernel procedure 23 | terminate_process(); 24 | break; 25 | } 26 | 27 | console_write("Turning interrupt on again"); 28 | console_write("\n"); 29 | 30 | // Turn on interrupt again 31 | asm volatile("cpsie i"); 32 | 33 | // Wait for timer interrupt. Probably not the best thing to do. 34 | halt(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /pi-baremetal/syscall.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SYSCALL_H 3 | #define SYSCALL_H 4 | 5 | #define SYSCALL_TERMINATE_PROCESS 0 6 | 7 | void syscall(unsigned int swi); 8 | 9 | #endif /* SYSCALL_H */ 10 | 11 | -------------------------------------------------------------------------------- /pi-baremetal/teletext.h: -------------------------------------------------------------------------------- 1 | // Character definitions from SAA5050 datasheet 2 | // Each character is a 5x9 bit matrix 3 | // 9 rows of 5-bit numbers 4 | static unsigned char teletext[][9] = { 5 | { 0,0,0,0,0,0,0,0,0 }, // space 6 | { 4,4,4,4,4,0,4,0,0 }, // ! 7 | { 10,10,10,0,0,0,0,0,0 }, // " 8 | { 6,9,8,28,8,8,31,0,0 }, // £ # in ASCII 9 | { 14,21,20,14,5,21,14,0,0 }, // $ 10 | { 24,25,2,4,8,19,3,0,0 }, // % 11 | { 8,20,20,8,21,18,13,0,0 }, // & 12 | { 4,4,4,0,0,0,0,0,0 }, // ' 13 | { 2,4,8,8,8,4,2,0,0 }, // ( 14 | { 8,4,2,2,2,4,8,0,0 }, // ) 15 | { 4,21,14,4,14,21,4,0,0 }, // * 16 | { 0,4,4,31,4,4,0,0,0 }, // + 17 | { 0,0,0,0,0,4,4,8,0 }, // , 18 | { 0,0,0,14,0,0,0,0,0 }, // - 19 | { 0,0,0,0,0,0,4,0,0 }, // . 20 | { 0,1,2,4,8,16,0,0,0 }, // / 21 | { 4,10,17,17,17,10,4,0,0 }, // 0 22 | { 4,12,4,4,4,4,14,0,0 }, // 1 23 | { 14,17,1,6,8,16,31,0,0 }, // 2 24 | { 31,1,2,6,1,17,14,0,0 }, // 3 25 | { 2,6,10,18,31,2,2,0,0 }, // 4 26 | { 31,16,30,1,1,17,14,0,0 }, // 5 27 | { 6,8,16,30,17,17,14,0,0 }, // 6 28 | { 31,1,2,4,8,8,8,0,0 }, // 7 29 | { 14,17,17,14,17,17,14,0,0 }, // 8 30 | { 14,17,17,15,1,2,12,0,0 }, // 9 31 | { 0,0,4,0,0,0,4,0,0 }, // : 32 | { 0,0,4,0,0,4,4,8,0 }, // ; 33 | { 2,4,8,16,8,4,2,0,0 }, // < 34 | { 0,0,31,0,31,0,0,0,0 }, // = 35 | { 8,4,2,1,2,4,8,0,0 }, // > 36 | { 14,17,2,4,4,0,4,0,0 }, // ? 37 | { 14,17,23,21,23,16,14,0,0 }, // @ 38 | { 4,10,17,17,31,17,17,0,0 }, // A 39 | { 30,17,17,30,17,17,30,0,0 }, // B 40 | { 14,17,16,16,16,17,14,0,0 }, // C 41 | { 30,17,17,17,17,17,30,0,0 }, // D 42 | { 31,16,16,30,16,16,31,0,0 }, // E 43 | { 31,16,16,30,16,16,16,0,0 }, // F 44 | { 14,17,16,16,19,17,15,0,0 }, // G 45 | { 17,17,17,31,17,17,17,0,0 }, // H 46 | { 14,4,4,4,4,4,14,0,0 }, // I 47 | { 1,1,1,1,1,17,14,0,0 }, // J 48 | { 17,18,20,24,20,18,17,0,0 }, // K 49 | { 16,16,16,16,16,16,31,0,0 }, // L 50 | { 17,27,21,21,17,17,17,0,0 }, // M 51 | { 17,17,25,21,19,17,17,0,0 }, // N 52 | { 14,17,17,17,17,17,14,0,0 }, // O 53 | { 30,17,17,30,16,16,16,0,0 }, // P 54 | { 14,17,17,17,21,18,13,0,0 }, // Q 55 | { 30,17,17,30,20,18,17,0,0 }, // R 56 | { 14,17,16,14,1,17,14,0,0 }, // S 57 | { 31,4,4,4,4,4,4,0,0 }, // T 58 | { 17,17,17,17,17,17,14,0,0 }, // U 59 | { 17,17,17,10,10,4,4,0,0 }, // V 60 | { 17,17,17,21,21,21,10,0,0 }, // W 61 | { 17,17,10,4,10,17,17,0,0 }, // X 62 | { 17,17,10,4,4,4,4,0,0 }, // Y 63 | { 31,1,2,4,8,16,31,0,0 }, // Z 64 | { 0,4,8,31,8,4,0,0,0 }, // left arrow [ in ASCII 65 | { 16,16,16,16,22,1,2,4,7 }, // 1/2 \ in ASCII 66 | { 0,4,2,31,2,4,0,0,0 }, // right arrow ] in ASCII 67 | { 0,4,14,21,4,4,0,0,0 }, // up arrow ^ in ASCII 68 | { 10,10,31,10,31,10,10,0,0 }, // # _ in ASCII 69 | { 0,0,0,31,0,0,0,0,0 }, // dash ` in ASCII 70 | { 0,0,14,1,15,17,15,0,0 }, // a 71 | { 16,16,30,17,17,17,30,0,0 }, // b 72 | { 0,0,15,16,16,16,15,0,0 }, // c 73 | { 1,1,15,17,17,17,15,0,0 }, // d 74 | { 0,0,14,17,31,16,14,0,0 }, // e 75 | { 2,4,4,14,4,4,4,0,0 }, // f 76 | { 0,0,15,17,17,17,15,1,14 }, // g 77 | { 16,16,30,17,17,17,17,0,0 }, // h 78 | { 4,0,12,4,4,4,14,0,0 }, // i 79 | { 4,0,4,4,4,4,4,4,8 }, // j 80 | { 8,8,9,10,12,10,9,0,0 }, // k 81 | { 12,4,4,4,4,4,14,0,0 }, // l 82 | { 0,0,26,21,21,21,21,0,0 }, // m 83 | { 0,0,30,17,17,17,17,0,0 }, // n 84 | { 0,0,14,17,17,17,14,0,0 }, // o 85 | { 0,0,30,17,17,17,30,16,16 }, // p 86 | { 0,0,15,17,17,17,15,1,1 }, // q 87 | { 0,0,11,12,8,8,8,0,0 }, // r 88 | { 0,0,15,16,14,1,30,0,0 }, // s 89 | { 4,4,14,4,4,4,2,0,0 }, // t 90 | { 0,0,17,17,17,17,15,0,0 }, // u 91 | { 0,0,17,17,10,10,4,0,0 }, // v 92 | { 0,0,17,17,21,21,10,0,0 }, // w 93 | { 0,0,17,10,4,10,17,0,0 }, // x 94 | { 0,0,17,17,17,17,15,1,14 }, // y 95 | { 0,0,31,2,4,8,31,0,0 }, // z 96 | { 8,8,8,8,9,3,5,7,1 }, // 1/4 { in ASCII 97 | { 10,10,10,10,10,10,10,0,0 }, // || | in ASCII 98 | { 24,4,24,4,25,3,5,7,1 }, // 3/4 } in ASCII 99 | { 0,4,0,31,0,4,0,0,0 }, // divide sign ~ in ASCII 100 | { 31,31,31,31,31,31,31,0,0 } // character-sized block 101 | // not defined in ASCII 102 | }; 103 | -------------------------------------------------------------------------------- /pi-baremetal/textutils.c: -------------------------------------------------------------------------------- 1 | #include "textutils.h" 2 | 3 | /* Convert an unsigned value to hex (without the trailing "0x") 4 | * size = size in bytes (only 1, 2 or 4 permitted) 5 | */ 6 | char *tohex(unsigned int value, unsigned int size) 7 | { 8 | static char buffer[9]; 9 | 10 | unsigned int offset; 11 | unsigned char ch; 12 | 13 | if(size!=1 && size!=2 && size!=4) 14 | return "error"; 15 | 16 | offset=size*2; 17 | 18 | buffer[offset] = 0; 19 | 20 | while(offset--) 21 | { 22 | ch = 48 + (value & 15); 23 | if(ch>=58) 24 | ch+=7; 25 | 26 | buffer[offset] = ch; 27 | value = value >> 4; 28 | } 29 | 30 | return buffer; 31 | } 32 | 33 | /* Convert unsigned value to decimal 34 | * leading = 0 - no leading spaces/zeroes 35 | * leading >0 - number of leading zeroes 36 | * leading <0 - number (when +ve) of leading spaces 37 | */ 38 | char *todec(unsigned int value, int leading) 39 | { 40 | /* Biggest number is 4294967295 (10 digits) */ 41 | static char buffer[11]; 42 | static char leadchar; 43 | 44 | unsigned int offset = 10; 45 | unsigned char ch; 46 | 47 | if(leading <0) 48 | { 49 | leading = -leading; 50 | leadchar = ' '; 51 | } 52 | else 53 | { 54 | leadchar = '0'; 55 | } 56 | 57 | if(leading>10) 58 | return "error"; 59 | 60 | buffer[offset] = 0; 61 | 62 | while(value || (offset == 10)) 63 | { 64 | offset--; 65 | leading--; 66 | ch = 48 + (value % 10); 67 | buffer[offset] = ch; 68 | 69 | value = value/10; 70 | } 71 | 72 | while(leading>0) 73 | { 74 | offset--; 75 | leading--; 76 | buffer[offset] = leadchar; 77 | } 78 | 79 | return &buffer[offset]; 80 | } 81 | -------------------------------------------------------------------------------- /pi-baremetal/textutils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TEXTUTILS_H 3 | #define TEXTUTILS_H 4 | 5 | extern char *tohex(unsigned int value, unsigned int size); 6 | extern char *todec(unsigned int value, int leading); 7 | 8 | #endif /* TEXTUTILS_H */ 9 | --------------------------------------------------------------------------------