diff --git a/README.md b/README.md new file mode 100644 index 000000000..b72a6271d --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Operating Systems Capstone 2022 + +## Author + +| Student ID | GitHub account name | My name | +| --- | ----------- | --- | +|`A111120`| `Chang-Tiger` | `Teng-Wu Chang` | + + +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 diff --git a/lab1/Makefile b/lab1/Makefile new file mode 100644 index 000000000..a8597cc4b --- /dev/null +++ b/lab1/Makefile @@ -0,0 +1,43 @@ +# debug use CFLAGS='-g' ASMFLAGS='-g' + +ARMGNU ?= aarch64-linux-gnu + +COPS = $(CFLAGS) -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG #-D__DEBUG_MM #-D__DEBUG_MM_ALLOC #-D__DEBUG_MM_SCHED +ASMOPS = $(ASMFLAGS) -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -g -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy -g $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio + +run_debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -s -S + +connect_raspi: + sudo screen /dev/ttyUSB0 115200 + diff --git a/lab1/build/kernel8.elf b/lab1/build/kernel8.elf new file mode 100644 index 000000000..c04aba63a Binary files /dev/null and b/lab1/build/kernel8.elf differ diff --git a/lab1/build/main_c.d b/lab1/build/main_c.d new file mode 100644 index 000000000..6b34d6149 --- /dev/null +++ b/lab1/build/main_c.d @@ -0,0 +1,2 @@ +build/main_c.o: src/main.c include/uart.h include/mbox.h include/shell.h \ + include/string.h diff --git a/lab1/build/main_c.o b/lab1/build/main_c.o new file mode 100644 index 000000000..09dae7daa Binary files /dev/null and b/lab1/build/main_c.o differ diff --git a/lab1/build/mbox_c.d b/lab1/build/mbox_c.d new file mode 100644 index 000000000..775d28e6c --- /dev/null +++ b/lab1/build/mbox_c.d @@ -0,0 +1 @@ +build/mbox_c.o: src/mbox.c include/gpio.h diff --git a/lab1/build/mbox_c.o b/lab1/build/mbox_c.o new file mode 100644 index 000000000..3b6e85aa9 Binary files /dev/null and b/lab1/build/mbox_c.o differ diff --git a/lab1/build/shell_c.d b/lab1/build/shell_c.d new file mode 100644 index 000000000..f31e638e0 --- /dev/null +++ b/lab1/build/shell_c.d @@ -0,0 +1,2 @@ +build/shell_c.o: src/shell.c include/uart.h include/string.h \ + include/shell.h include/mbox.h include/system.h diff --git a/lab1/build/shell_c.o b/lab1/build/shell_c.o new file mode 100644 index 000000000..eb29ff026 Binary files /dev/null and b/lab1/build/shell_c.o differ diff --git a/lab1/build/start_s.d b/lab1/build/start_s.d new file mode 100644 index 000000000..afcb7e88c --- /dev/null +++ b/lab1/build/start_s.d @@ -0,0 +1 @@ +build/start_s.o: src/start.S diff --git a/lab1/build/start_s.o b/lab1/build/start_s.o new file mode 100644 index 000000000..b8ad155a6 Binary files /dev/null and b/lab1/build/start_s.o differ diff --git a/lab1/build/string_c.d b/lab1/build/string_c.d new file mode 100644 index 000000000..9c2847ac5 --- /dev/null +++ b/lab1/build/string_c.d @@ -0,0 +1 @@ +build/string_c.o: src/string.c include/string.h diff --git a/lab1/build/string_c.o b/lab1/build/string_c.o new file mode 100644 index 000000000..50a041687 Binary files /dev/null and b/lab1/build/string_c.o differ diff --git a/lab1/build/system_c.d b/lab1/build/system_c.d new file mode 100644 index 000000000..869c7c11f --- /dev/null +++ b/lab1/build/system_c.d @@ -0,0 +1,2 @@ +build/system_c.o: src/system.c include/system.h include/uart.h \ + include/mbox.h diff --git a/lab1/build/system_c.o b/lab1/build/system_c.o new file mode 100644 index 000000000..6c7a32bfe Binary files /dev/null and b/lab1/build/system_c.o differ diff --git a/lab1/build/uart_c.d b/lab1/build/uart_c.d new file mode 100644 index 000000000..b59c7761e --- /dev/null +++ b/lab1/build/uart_c.d @@ -0,0 +1 @@ +build/uart_c.o: src/uart.c include/gpio.h include/uart.h diff --git a/lab1/build/uart_c.o b/lab1/build/uart_c.o new file mode 100644 index 000000000..30fb90b6e Binary files /dev/null and b/lab1/build/uart_c.o differ diff --git a/lab1/include/gpio.h b/lab1/include/gpio.h new file mode 100644 index 000000000..399ae80f2 --- /dev/null +++ b/lab1/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#define MMIO_BASE 0x3F000000 + +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) + +#endif diff --git a/lab1/include/mbox.h b/lab1/include/mbox.h new file mode 100644 index 000000000..46160f821 --- /dev/null +++ b/lab1/include/mbox.h @@ -0,0 +1,26 @@ +/* a properly aligned buffer */ +/* use this buffer(global variable) directly and the mbox_call will use it after call*/ +/* mbox format https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ +/* mbox address need to be aligned to 16 bytes */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define GET_BOARD_REVISION 0x10002 +#define MBOX_TAG_GETSERIAL 0x10004 +#define GET_ARM_MEMORY 0x10005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); \ No newline at end of file diff --git a/lab1/include/shell.h b/lab1/include/shell.h new file mode 100644 index 000000000..74bd0aa42 --- /dev/null +++ b/lab1/include/shell.h @@ -0,0 +1,8 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); +void do_cmd(char* cmd); +void print_system_messages(); + +#endif \ No newline at end of file diff --git a/lab1/include/string.h b/lab1/include/string.h new file mode 100644 index 000000000..8123bc2d4 --- /dev/null +++ b/lab1/include/string.h @@ -0,0 +1,9 @@ +#ifndef STRING_H +#define STRING_H + +int strcmp (const char * s1, const char * s2 ); +char* strcat (char *dest, const char *src); +unsigned long long strlen(const char *str); +char* strcpy (char *dest, const char *src); +char* memcpy (void *dest, const void *src, unsigned long long len); +#endif \ No newline at end of file diff --git a/lab1/include/system.h b/lab1/include/system.h new file mode 100644 index 000000000..97cb9ab7c --- /dev/null +++ b/lab1/include/system.h @@ -0,0 +1,6 @@ +int get_board_revision(unsigned int* board_revision); +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size); +void set(long addr, unsigned int value); +void reboot(); +void reset(int tick); +void cancel_reset(); \ No newline at end of file diff --git a/lab1/include/uart.h b/lab1/include/uart.h new file mode 100644 index 000000000..1c6bde5de --- /dev/null +++ b/lab1/include/uart.h @@ -0,0 +1,15 @@ +#ifndef UART_H +#define UART_H + +#define MAX_BUF_SIZE 0x100 + +void uart_init(); +void uart_putc(char c); +char uart_getc(); +int uart_puts(char *s); +char* uart_gets(char *buf); +int uart_printf(char *s); +void uart_hex(unsigned int d); +void disable_uart(); + +#endif diff --git a/lab1/kernel8.img b/lab1/kernel8.img new file mode 100644 index 000000000..85e666bf8 Binary files /dev/null and b/lab1/kernel8.img differ diff --git a/lab1/linker.ld b/lab1/linker.ld new file mode 100644 index 000000000..066df7b90 --- /dev/null +++ b/lab1/linker.ld @@ -0,0 +1,19 @@ +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/lab1/src/main.c b/lab1/src/main.c new file mode 100644 index 000000000..87f8e7f37 --- /dev/null +++ b/lab1/src/main.c @@ -0,0 +1,12 @@ +#include "uart.h" +#include "mbox.h" +#include "shell.h" +#include "string.h" + +void main() +{ + // set up serial console + uart_init(); + + shell(); +} diff --git a/lab1/src/mbox.c b/lab1/src/mbox.c new file mode 100644 index 000000000..a0b4c4412 --- /dev/null +++ b/lab1/src/mbox.c @@ -0,0 +1,37 @@ +#include "gpio.h" + +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mbox[36]; + +#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) +#define MBOX_RESPONSE 0x80000000 // mbox[1] = 0x80000000 -> request successful +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) // Mailbox 0 define several channels, but we only use channel 8 (CPU->GPU) for communication. +{ + unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); + //wait until we can write to the mailbox + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + //write the address of our message to the mailbox with channel identifier + *MBOX_WRITE = r; + //now wait for the response + while(1) { + //is there a response?wait until empty flag unset + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + //is it a response to our message? + if(r == *MBOX_READ) + //is it a valid successful response? + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} diff --git a/lab1/src/shell.c b/lab1/src/shell.c new file mode 100644 index 000000000..076a6b9a3 --- /dev/null +++ b/lab1/src/shell.c @@ -0,0 +1,58 @@ +#include "uart.h" +#include "string.h" +#include "shell.h" +#include "mbox.h" +#include "system.h" + +void shell() +{ + char cmd[MAX_BUF_SIZE]; + print_system_messages(); + while(1) + { + uart_printf("# "); + uart_gets(cmd); + do_cmd(cmd); + } +} + +void do_cmd(char* cmd) +{ + if(strcmp(cmd,"help")==0) + { + uart_puts("help : print this help menu"); + uart_puts("hello : print Hello World!"); + uart_puts("reboot : reboot the device"); + } + else if((strcmp(cmd,"hello")==0)) + { + uart_puts("Hello World!"); + } + else if((strcmp(cmd,"reboot")==0)) + { + reboot(); + }else + { + uart_puts("Unknown command! again"); + } +} + +void print_system_messages() +{ + unsigned int board_revision; + get_board_revision(&board_revision); + uart_printf("Board revision is : 0x"); + uart_hex(board_revision); + uart_puts(""); + + unsigned int arm_mem_base_addr; + unsigned int arm_mem_size; + + get_arm_memory_info(&arm_mem_base_addr,&arm_mem_size); + uart_printf("ARM memory base address in bytes : 0x"); + uart_hex(arm_mem_base_addr); + uart_puts(""); + uart_printf("ARM memory size in bytes : 0x"); + uart_hex(arm_mem_size); + uart_puts(""); +} diff --git a/lab1/src/start.S b/lab1/src/start.S new file mode 100644 index 000000000..ffd92918f --- /dev/null +++ b/lab1/src/start.S @@ -0,0 +1,26 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f +1: wfe + b 1b +2: // cpu id == 0 + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b diff --git a/lab1/src/string.c b/lab1/src/string.c new file mode 100644 index 000000000..de4783cae --- /dev/null +++ b/lab1/src/string.c @@ -0,0 +1,45 @@ +#include "string.h" +#include + +int strcmp (const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } + while (c1 == c2); + return c1 - c2; +} + +char* strcat (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} + +char* strcpy (char *dest, const char *src) +{ + return memcpy (dest, src, strlen (src) + 1); +} + +unsigned long long strlen(const char *str) +{ + size_t count = 0; + while((unsigned char)*str++)count++; + return count; +} + +char* memcpy (void *dest, const void *src, unsigned long long len) +{ + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} \ No newline at end of file diff --git a/lab1/src/system.c b/lab1/src/system.c new file mode 100644 index 000000000..7c4201bdc --- /dev/null +++ b/lab1/src/system.c @@ -0,0 +1,79 @@ +#include "system.h" +#include "uart.h" +#include "mbox.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +//For all return 0 -> success , -1 failure + +int get_board_revision(unsigned int* board_revision) +{ + mbox[0] = 7*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_BOARD_REVISION; // tag identifier + mbox[3] = 4; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer + mbox[6] = MBOX_TAG_LAST; // end tag + // send the message to the GPU and receive answer if success + if (mbox_call(MBOX_CH_PROP)) { + *board_revision = mbox[5]; + return 0; + } else { + uart_puts("Unable to query serial!"); + *board_revision = mbox[5] = -1; + return -1; + } +} + +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size) +{ + /* + GET arm_memory address and size + */ + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_ARM_MEMORY; // tag identifier + mbox[3] = 8; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer ( u32: base address in bytes ) + mbox[6] = 0; // clear output buffer ( u32: size in bytes ) + mbox[7] = MBOX_TAG_LAST; // end tag + + // send the message to the GPU and receive answer if success + if (mbox_call(MBOX_CH_PROP)) { + *base_addr = mbox[5]; + *size = mbox[6]; + return 0; + } else { + uart_puts("Unable to query serial!"); + return -1; + } +} + +void set(long addr, unsigned int value) +{ + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reboot() +{ + //disable_uart(); + reset(1); // timeout = 1/16th of a second? +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + while(1); // hang until reboot +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab1/src/uart.c b/lab1/src/uart.c new file mode 100644 index 000000000..27752e0e2 --- /dev/null +++ b/lab1/src/uart.c @@ -0,0 +1,176 @@ +#include "gpio.h" +#include "uart.h" + +/* Auxilary mini UART registers */ +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // Set AUXENB register to enable mini UART. Then mini UART register can be accessed. + *AUX_MU_CNTL = 0; // Set AUX_MU_CNTL_REG to 0. Disable transmitter and receiver during configuration. + *AUX_MU_IER = 0; // Set AUX_MU_IER_REG to 0. Disable interrupt because currently you don’t need interrupt. + *AUX_MU_LCR = 3; // Set AUX_MU_LCR_REG to 3. Set the data size to 8 bit. + *AUX_MU_MCR = 0; // Set AUX_MU_MCR_REG to 0. Don’t need auto flow control. + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 (disable pull up/down) + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx + + while((*AUX_MU_LSR&0x01))*AUX_MU_IO; //clean rx data +} + + +void disable_uart() +{ + register unsigned int r; + *AUX_ENABLE &= ~(unsigned int)1; + *AUX_MU_CNTL = 0; + r=*GPFSEL1; + r|=((7<<12)|(7<<15)); // gpio14, gpio15 + r&=~(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 2; // enable pins 14 and 15 (pull down) + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup +} + +/** + * Send a character + */ +void uart_putc(char c) { + unsigned int intc = c; + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=intc; +} + +/** + * Receive a character + */ +char uart_getc() { + char r; + // wait until something is in the buffer + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + // read it and return + r = (char)(*AUX_MU_IO);//get input words from mini uart receive buffer + + /* + echo back + */ + if(r == '\r')//input enter + { + uart_puts("\r"); + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x40)); //wait for output success Transmitter idle + }else if(r == '\x7f') // backspace -> get del + { + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + }else + { + uart_putc(r); + } + //convert carrige return to newline + return r=='\r'?'\n':r; +} + +/** + * Display a string with newline + */ +int uart_puts(char *s) { + int i=0; + + while(*s) { + uart_putc(*s++); + i++; + } + uart_putc('\r'); + uart_putc('\n'); + + return i+2; +} + +/** + * get a string + */ +char* uart_gets(char *buf) +{ + int count; + char c; + char *s; + for (s = buf,count = 0; (c = uart_getc()) != '\n' && count!=MAX_BUF_SIZE-1 ;count++) + { + *s = c; + if(*s=='\x7f') + { + count--; + if(count==-1) + { + uart_putc(' '); // prevent back over command line # + continue; + } + s--; + count--; + continue; + } + s++; + } + *s = '\0'; + return buf; +} + +/** + * printf (TODO) + */ +int uart_printf(char *s) { + int i = 0; + while(*s) { + uart_putc(*s++); + i++; + } + return i; +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_putc(n); + } +} diff --git a/lab2/Makefile b/lab2/Makefile new file mode 100644 index 000000000..f036f3fb7 --- /dev/null +++ b/lab2/Makefile @@ -0,0 +1,48 @@ +# debug use CFLAGS='-g -O3' ASMFLAGS='-g -O3' +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = $(CFLAGS) -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG #-D__DEBUG_MM #-D__DEBUG_MM_ALLOC #-D__DEBUG_MM_SCHED +ASMOPS = $(ASMFLAGS) -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img bootloader/bootloader.img + +clean : + rm -rf $(BUILD_DIR) *.img + make -C bootloader clean + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -g -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy -g $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run_debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -s -S -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +connect_raspi: + sudo screen /dev/ttyUSB0 115200 + +bootloader/bootloader.img: + make -C bootloader + diff --git a/lab2/bcm2710-rpi-3-b-plus.dtb b/lab2/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab2/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab2/bootloader/Makefile b/lab2/bootloader/Makefile new file mode 100644 index 000000000..40e6c597f --- /dev/null +++ b/lab2/bootloader/Makefile @@ -0,0 +1,50 @@ +# debug use CFLAGS='-g' ASMFLAGS='-g' +# Modify from +# https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile +ARMGNU ?= aarch64-linux-gnu + +COPS = $(CFLAGS) -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude #-ggdb #-D__FS_DEBUG #-D__DEBUG #-D__DEBUG_MM #-D__DEBUG_MM_ALLOC #-D__DEBUG_MM_SCHED +ASMOPS = $(ASMFLAGS) -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : bootloader.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +bootloader.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -g -T linker.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy -g $(BUILD_DIR)/bootloader.elf -O binary bootloader.img + +run: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial stdio + +run_pty: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial pty -initrd ../initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb + +run_debug: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial stdio -dtb ../bcm2710-rpi-3-b-plus.dtb -s -S + +run_debug_pty: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial pty -s -S + +connect_raspi: + sudo screen /dev/ttyUSB0 115200 + diff --git a/lab2/bootloader/bootloader.img b/lab2/bootloader/bootloader.img new file mode 100644 index 000000000..755a793d2 Binary files /dev/null and b/lab2/bootloader/bootloader.img differ diff --git a/lab2/bootloader/build/bootloader.elf b/lab2/bootloader/build/bootloader.elf new file mode 100644 index 000000000..5b91b206a Binary files /dev/null and b/lab2/bootloader/build/bootloader.elf differ diff --git a/lab2/bootloader/build/main_c.d b/lab2/bootloader/build/main_c.d new file mode 100644 index 000000000..385a1351c --- /dev/null +++ b/lab2/bootloader/build/main_c.d @@ -0,0 +1,2 @@ +build/main_c.o: src/main.c include/uart.h include/mbox.h include/shell.h \ + include/string.h include/system.h diff --git a/lab2/bootloader/build/main_c.o b/lab2/bootloader/build/main_c.o new file mode 100644 index 000000000..3494369e6 Binary files /dev/null and b/lab2/bootloader/build/main_c.o differ diff --git a/lab2/bootloader/build/mbox_c.d b/lab2/bootloader/build/mbox_c.d new file mode 100644 index 000000000..775d28e6c --- /dev/null +++ b/lab2/bootloader/build/mbox_c.d @@ -0,0 +1 @@ +build/mbox_c.o: src/mbox.c include/gpio.h diff --git a/lab2/bootloader/build/mbox_c.o b/lab2/bootloader/build/mbox_c.o new file mode 100644 index 000000000..3b6e85aa9 Binary files /dev/null and b/lab2/bootloader/build/mbox_c.o differ diff --git a/lab2/bootloader/build/shell_c.d b/lab2/bootloader/build/shell_c.d new file mode 100644 index 000000000..f31e638e0 --- /dev/null +++ b/lab2/bootloader/build/shell_c.d @@ -0,0 +1,2 @@ +build/shell_c.o: src/shell.c include/uart.h include/string.h \ + include/shell.h include/mbox.h include/system.h diff --git a/lab2/bootloader/build/shell_c.o b/lab2/bootloader/build/shell_c.o new file mode 100644 index 000000000..a0e097b73 Binary files /dev/null and b/lab2/bootloader/build/shell_c.o differ diff --git a/lab2/bootloader/build/start_s.d b/lab2/bootloader/build/start_s.d new file mode 100644 index 000000000..afcb7e88c --- /dev/null +++ b/lab2/bootloader/build/start_s.d @@ -0,0 +1 @@ +build/start_s.o: src/start.S diff --git a/lab2/bootloader/build/start_s.o b/lab2/bootloader/build/start_s.o new file mode 100644 index 000000000..b8ad155a6 Binary files /dev/null and b/lab2/bootloader/build/start_s.o differ diff --git a/lab2/bootloader/build/string_c.d b/lab2/bootloader/build/string_c.d new file mode 100644 index 000000000..9c2847ac5 --- /dev/null +++ b/lab2/bootloader/build/string_c.d @@ -0,0 +1 @@ +build/string_c.o: src/string.c include/string.h diff --git a/lab2/bootloader/build/string_c.o b/lab2/bootloader/build/string_c.o new file mode 100644 index 000000000..50a041687 Binary files /dev/null and b/lab2/bootloader/build/string_c.o differ diff --git a/lab2/bootloader/build/system_c.d b/lab2/bootloader/build/system_c.d new file mode 100644 index 000000000..869c7c11f --- /dev/null +++ b/lab2/bootloader/build/system_c.d @@ -0,0 +1,2 @@ +build/system_c.o: src/system.c include/system.h include/uart.h \ + include/mbox.h diff --git a/lab2/bootloader/build/system_c.o b/lab2/bootloader/build/system_c.o new file mode 100644 index 000000000..0d2f6a3a9 Binary files /dev/null and b/lab2/bootloader/build/system_c.o differ diff --git a/lab2/bootloader/build/uart_c.d b/lab2/bootloader/build/uart_c.d new file mode 100644 index 000000000..b59c7761e --- /dev/null +++ b/lab2/bootloader/build/uart_c.d @@ -0,0 +1 @@ +build/uart_c.o: src/uart.c include/gpio.h include/uart.h diff --git a/lab2/bootloader/build/uart_c.o b/lab2/bootloader/build/uart_c.o new file mode 100644 index 000000000..a53731260 Binary files /dev/null and b/lab2/bootloader/build/uart_c.o differ diff --git a/lab2/bootloader/include/gpio.h b/lab2/bootloader/include/gpio.h new file mode 100644 index 000000000..399ae80f2 --- /dev/null +++ b/lab2/bootloader/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#define MMIO_BASE 0x3F000000 + +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) + +#endif diff --git a/lab2/bootloader/include/mbox.h b/lab2/bootloader/include/mbox.h new file mode 100644 index 000000000..46160f821 --- /dev/null +++ b/lab2/bootloader/include/mbox.h @@ -0,0 +1,26 @@ +/* a properly aligned buffer */ +/* use this buffer(global variable) directly and the mbox_call will use it after call*/ +/* mbox format https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ +/* mbox address need to be aligned to 16 bytes */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define GET_BOARD_REVISION 0x10002 +#define MBOX_TAG_GETSERIAL 0x10004 +#define GET_ARM_MEMORY 0x10005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); \ No newline at end of file diff --git a/lab2/bootloader/include/shell.h b/lab2/bootloader/include/shell.h new file mode 100644 index 000000000..74bd0aa42 --- /dev/null +++ b/lab2/bootloader/include/shell.h @@ -0,0 +1,8 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); +void do_cmd(char* cmd); +void print_system_messages(); + +#endif \ No newline at end of file diff --git a/lab2/bootloader/include/string.h b/lab2/bootloader/include/string.h new file mode 100644 index 000000000..8123bc2d4 --- /dev/null +++ b/lab2/bootloader/include/string.h @@ -0,0 +1,9 @@ +#ifndef STRING_H +#define STRING_H + +int strcmp (const char * s1, const char * s2 ); +char* strcat (char *dest, const char *src); +unsigned long long strlen(const char *str); +char* strcpy (char *dest, const char *src); +char* memcpy (void *dest, const void *src, unsigned long long len); +#endif \ No newline at end of file diff --git a/lab2/bootloader/include/system.h b/lab2/bootloader/include/system.h new file mode 100644 index 000000000..79410c43e --- /dev/null +++ b/lab2/bootloader/include/system.h @@ -0,0 +1,14 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + +extern char* _dtb; + +int get_board_revision(unsigned int* board_revision); +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size); +void set(long addr, unsigned int value); +void reboot(); +void reset(int tick); +void cancel_reset(); +void load_kernel(); + +#endif \ No newline at end of file diff --git a/lab2/bootloader/include/uart.h b/lab2/bootloader/include/uart.h new file mode 100644 index 000000000..e226d69aa --- /dev/null +++ b/lab2/bootloader/include/uart.h @@ -0,0 +1,16 @@ +#ifndef UART_H +#define UART_H + +#define MAX_BUF_SIZE 0x100 + +void uart_init(); +void uart_putc(char c); +char uart_getc(); +int uart_puts(char *s); +char* uart_gets(char *buf); +int uart_printf(char *s); +void uart_hex(unsigned int d); +void disable_uart(); +char uart_getc_pure(); + +#endif diff --git a/lab2/bootloader/linker.ld b/lab2/bootloader/linker.ld new file mode 100644 index 000000000..3d0a0f5d1 --- /dev/null +++ b/lab2/bootloader/linker.ld @@ -0,0 +1,22 @@ +SECTIONS +{ + . = 0x70000; + _code_relocate_place = .; + /*bootloader on 0x80000, kernel on 0x80000 need to self relocate bootloader to other place*/ + . = 0x80000; + PROVIDE(_start = .); + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; +__code_size = (_end - _start); diff --git a/lab2/bootloader/src/main.c b/lab2/bootloader/src/main.c new file mode 100644 index 000000000..b56ee1741 --- /dev/null +++ b/lab2/bootloader/src/main.c @@ -0,0 +1,44 @@ +#include "uart.h" +#include "mbox.h" +#include "shell.h" +#include "string.h" +#include "system.h" + +extern char* _code_relocate_place; +extern unsigned long long __code_size; +extern unsigned long long _start; +extern char* _dtb; + +void code_relocate(char * addr); + +int relocate=1; + +void main(char* arg) +{ + _dtb = arg; + char* reloc_place = (char*)&_code_relocate_place; + + if(relocate) // only do relocate once + { + relocate = 0; + code_relocate(reloc_place); + } + + // set up serial console + uart_init(); + + shell(); +} + +// relocate code and jump to there +void code_relocate(char * addr) +{ + unsigned long long size = (unsigned long long)&__code_size; + char* start = (char *)&_start; + for(unsigned long long i=0;i request successful +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) // Mailbox 0 define several channels, but we only use channel 8 (CPU->GPU) for communication. +{ + unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) + /* is it a valid successful response? */ + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} \ No newline at end of file diff --git a/lab2/bootloader/src/shell.c b/lab2/bootloader/src/shell.c new file mode 100644 index 000000000..e0f1766d1 --- /dev/null +++ b/lab2/bootloader/src/shell.c @@ -0,0 +1,63 @@ +#include "uart.h" +#include "string.h" +#include "shell.h" +#include "mbox.h" +#include "system.h" + +void shell() +{ + char cmd[MAX_BUF_SIZE]; + print_system_messages(); + uart_puts("Welcome, this is bootloader. Try to load kernel with uart with protocol in system.c(load_kernel)"); + while(1) + { + uart_printf("# "); + uart_gets(cmd); + do_cmd(cmd); + } +} + +void do_cmd(char* cmd) +{ + if(strcmp(cmd,"help")==0) + { + uart_puts("help : print this help menu"); + uart_puts("hello : print Hello World!"); + uart_puts("reboot : reboot the device"); + uart_puts("load_kernel : load kernel code from uart to 0x80000 and jump to it!"); + } + else if(strcmp(cmd,"hello")==0) + { + uart_puts("Hello World!"); + } + else if(strcmp(cmd,"reboot")==0) + { + reboot(); + }else if(strcmp(cmd,"load_kernel")==0) + { + load_kernel(); + }else + { + uart_puts("Unknown command!"); + } +} + +void print_system_messages() +{ + unsigned int board_revision; + get_board_revision(&board_revision); + uart_printf("Board revision is : 0x"); + uart_hex(board_revision); + uart_puts(""); + + unsigned int arm_mem_base_addr; + unsigned int arm_mem_size; + + get_arm_memory_info(&arm_mem_base_addr,&arm_mem_size); + uart_printf("ARM memory base address in bytes : 0x"); + uart_hex(arm_mem_base_addr); + uart_puts(""); + uart_printf("ARM memory size in bytes : 0x"); + uart_hex(arm_mem_size); + uart_puts(""); +} \ No newline at end of file diff --git a/lab2/bootloader/src/start.S b/lab2/bootloader/src/start.S new file mode 100644 index 000000000..446a11244 --- /dev/null +++ b/lab2/bootloader/src/start.S @@ -0,0 +1,33 @@ +.section ".text.boot" + +.global _start + +//avoid use x0 which stored dtb place +_start: + + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + +4: + // jump to C code, should not return + bl main + // for failsafe, halt this core too + b 1b diff --git a/lab2/bootloader/src/string.c b/lab2/bootloader/src/string.c new file mode 100644 index 000000000..de4783cae --- /dev/null +++ b/lab2/bootloader/src/string.c @@ -0,0 +1,45 @@ +#include "string.h" +#include + +int strcmp (const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } + while (c1 == c2); + return c1 - c2; +} + +char* strcat (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} + +char* strcpy (char *dest, const char *src) +{ + return memcpy (dest, src, strlen (src) + 1); +} + +unsigned long long strlen(const char *str) +{ + size_t count = 0; + while((unsigned char)*str++)count++; + return count; +} + +char* memcpy (void *dest, const void *src, unsigned long long len) +{ + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} \ No newline at end of file diff --git a/lab2/bootloader/src/system.c b/lab2/bootloader/src/system.c new file mode 100644 index 000000000..b6435e662 --- /dev/null +++ b/lab2/bootloader/src/system.c @@ -0,0 +1,121 @@ +#include "system.h" +#include "uart.h" +#include "mbox.h" + +extern char _start[]; //bootloader load kernel to here +char* _dtb; + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +/* For all return 0 -> success , -1 failure*/ + +int get_board_revision(unsigned int* board_revision) +{ + /* + GET_BOARD_REVISION + */ + mbox[0] = 7*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_BOARD_REVISION; // tag identifier + mbox[3] = 4; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer + mbox[6] = MBOX_TAG_LAST; // end tag + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *board_revision = mbox[5]; + return 0; + } else { + uart_puts("Unable to query serial!"); + *board_revision = mbox[5] = -1; + return -1; + } +} + +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size) +{ + /* + GET arm_memory address and size + */ + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_ARM_MEMORY; // tag identifier + mbox[3] = 8; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer ( u32: base address in bytes ) + mbox[6] = 0; // clear output buffer ( u32: size in bytes ) + mbox[7] = MBOX_TAG_LAST; // end tag + + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *base_addr = mbox[5]; + *size = mbox[6]; + return 0; + } else { + uart_puts("Unable to query serial!"); + return -1; + } +} + +void set(long addr, unsigned int value) +{ + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reboot() +{ + //disable_uart(); + reset(1); // timeout = 1/16th of a second? (whatever) +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + while(1); // wati for clock +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} + + +//編譯器不要優化這段 +#pragma GCC push_options +#pragma GCC optimize ("O0") + +void load_kernel() +{ + // prevent dtb been rewrited by kernel + char* temp_dtb = _dtb; + char c; + unsigned long long kernel_size=0; + char* kernel_start = (char*) (&_start); + + uart_puts("kernel size:"); + for(int i=0;i<8;i++) //protocol : use little endian to get kernel size + { + c = uart_getc_pure(); + kernel_size += c<<(i*8); + } + + + for(int i=0;i get del + { + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + }else + { + uart_putc(r); + } + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string with newline + */ +int uart_puts(char *s) { + int i=0; + + while(*s) { + uart_putc(*s++); + i++; + } + uart_putc('\r'); + uart_putc('\n'); + + return i+2; +} + +/** + * get a string + */ +char* uart_gets(char *buf) +{ + int count; + char c; + char *s; + for (s = buf,count = 0; (c = uart_getc()) != '\n' && count!=MAX_BUF_SIZE-1 ;count++) + { + *s = c; + if(*s=='\x7f') + { + count--; + if(count==-1) + { + uart_putc(' '); // prevent back over command line # + continue; + } + s--; + count--; + continue; + } + s++; + } + *s = '\0'; + return buf; +} + +/** + * printf (TODO) + */ +int uart_printf(char *s) { + int i = 0; + while(*s) { + uart_putc(*s++); + i++; + } + return i; +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_putc(n); + } +} + + +/** + * Receive a character without echo and any translation + */ +char uart_getc_pure() { + char r; + /* wait until something is in the buffer */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + return r; +} diff --git a/lab2/build/cpio_c.d b/lab2/build/cpio_c.d new file mode 100644 index 000000000..f3c9e5145 --- /dev/null +++ b/lab2/build/cpio_c.d @@ -0,0 +1 @@ +build/cpio_c.o: src/cpio.c include/cpio.h include/string.h include/uart.h diff --git a/lab2/build/cpio_c.o b/lab2/build/cpio_c.o new file mode 100644 index 000000000..3ef5a8ff0 Binary files /dev/null and b/lab2/build/cpio_c.o differ diff --git a/lab2/build/dtb_c.d b/lab2/build/dtb_c.d new file mode 100644 index 000000000..daaf671fe --- /dev/null +++ b/lab2/build/dtb_c.d @@ -0,0 +1,2 @@ +build/dtb_c.o: src/dtb.c include/dtb.h include/uart.h include/string.h \ + include/cpio.h diff --git a/lab2/build/dtb_c.o b/lab2/build/dtb_c.o new file mode 100644 index 000000000..21f4252e6 Binary files /dev/null and b/lab2/build/dtb_c.o differ diff --git a/lab2/build/filesystem_c.d b/lab2/build/filesystem_c.d new file mode 100644 index 000000000..993f919da --- /dev/null +++ b/lab2/build/filesystem_c.d @@ -0,0 +1,2 @@ +build/filesystem_c.o: src/filesystem.c include/cpio.h \ + include/filesystem.h include/uart.h include/string.h diff --git a/lab2/build/filesystem_c.o b/lab2/build/filesystem_c.o new file mode 100644 index 000000000..c3fcfd9ef Binary files /dev/null and b/lab2/build/filesystem_c.o differ diff --git a/lab2/build/kernel8.elf b/lab2/build/kernel8.elf new file mode 100644 index 000000000..d218f7882 Binary files /dev/null and b/lab2/build/kernel8.elf differ diff --git a/lab2/build/main_c.d b/lab2/build/main_c.d new file mode 100644 index 000000000..80042f4e5 --- /dev/null +++ b/lab2/build/main_c.d @@ -0,0 +1,2 @@ +build/main_c.o: src/main.c include/uart.h include/mbox.h include/shell.h \ + include/string.h include/malloc.h include/dtb.h include/cpio.h diff --git a/lab2/build/main_c.o b/lab2/build/main_c.o new file mode 100644 index 000000000..e2c5c9c9d Binary files /dev/null and b/lab2/build/main_c.o differ diff --git a/lab2/build/malloc_c.d b/lab2/build/malloc_c.d new file mode 100644 index 000000000..9f050d18e --- /dev/null +++ b/lab2/build/malloc_c.d @@ -0,0 +1 @@ +build/malloc_c.o: src/malloc.c include/malloc.h diff --git a/lab2/build/malloc_c.o b/lab2/build/malloc_c.o new file mode 100644 index 000000000..86615c865 Binary files /dev/null and b/lab2/build/malloc_c.o differ diff --git a/lab2/build/mbox_c.d b/lab2/build/mbox_c.d new file mode 100644 index 000000000..775d28e6c --- /dev/null +++ b/lab2/build/mbox_c.d @@ -0,0 +1 @@ +build/mbox_c.o: src/mbox.c include/gpio.h diff --git a/lab2/build/mbox_c.o b/lab2/build/mbox_c.o new file mode 100644 index 000000000..3b6e85aa9 Binary files /dev/null and b/lab2/build/mbox_c.o differ diff --git a/lab2/build/shell_c.d b/lab2/build/shell_c.d new file mode 100644 index 000000000..9e9c83605 --- /dev/null +++ b/lab2/build/shell_c.d @@ -0,0 +1,3 @@ +build/shell_c.o: src/shell.c include/uart.h include/string.h \ + include/shell.h include/mbox.h include/system.h include/filesystem.h \ + include/dtb.h diff --git a/lab2/build/shell_c.o b/lab2/build/shell_c.o new file mode 100644 index 000000000..ad46b8142 Binary files /dev/null and b/lab2/build/shell_c.o differ diff --git a/lab2/build/sprintf_c.d b/lab2/build/sprintf_c.d new file mode 100644 index 000000000..1a092c7a0 --- /dev/null +++ b/lab2/build/sprintf_c.d @@ -0,0 +1 @@ +build/sprintf_c.o: src/sprintf.c include/uart.h diff --git a/lab2/build/sprintf_c.o b/lab2/build/sprintf_c.o new file mode 100644 index 000000000..7d45cb40e Binary files /dev/null and b/lab2/build/sprintf_c.o differ diff --git a/lab2/build/start_s.d b/lab2/build/start_s.d new file mode 100644 index 000000000..afcb7e88c --- /dev/null +++ b/lab2/build/start_s.d @@ -0,0 +1 @@ +build/start_s.o: src/start.S diff --git a/lab2/build/start_s.o b/lab2/build/start_s.o new file mode 100644 index 000000000..b8ad155a6 Binary files /dev/null and b/lab2/build/start_s.o differ diff --git a/lab2/build/string_c.d b/lab2/build/string_c.d new file mode 100644 index 000000000..9c2847ac5 --- /dev/null +++ b/lab2/build/string_c.d @@ -0,0 +1 @@ +build/string_c.o: src/string.c include/string.h diff --git a/lab2/build/string_c.o b/lab2/build/string_c.o new file mode 100644 index 000000000..20cdb4516 Binary files /dev/null and b/lab2/build/string_c.o differ diff --git a/lab2/build/system_c.d b/lab2/build/system_c.d new file mode 100644 index 000000000..869c7c11f --- /dev/null +++ b/lab2/build/system_c.d @@ -0,0 +1,2 @@ +build/system_c.o: src/system.c include/system.h include/uart.h \ + include/mbox.h diff --git a/lab2/build/system_c.o b/lab2/build/system_c.o new file mode 100644 index 000000000..6c7a32bfe Binary files /dev/null and b/lab2/build/system_c.o differ diff --git a/lab2/build/uart_c.d b/lab2/build/uart_c.d new file mode 100644 index 000000000..44a8b59d5 --- /dev/null +++ b/lab2/build/uart_c.d @@ -0,0 +1,2 @@ +build/uart_c.o: src/uart.c include/gpio.h include/uart.h \ + include/sprintf.h diff --git a/lab2/build/uart_c.o b/lab2/build/uart_c.o new file mode 100644 index 000000000..bea120f20 Binary files /dev/null and b/lab2/build/uart_c.o differ diff --git a/lab2/config.txt b/lab2/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/lab2/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/lab2/include/cpio.h b/lab2/include/cpio.h new file mode 100644 index 000000000..2cc4d66d9 --- /dev/null +++ b/lab2/include/cpio.h @@ -0,0 +1,39 @@ +#ifndef CPIO_H +#define CPIO_H + + +/* + cpio format : https://www.freebsd.org/cgi/man.cgi?query=cpio&sektion=5 + header,file path,file data,header ...... + header+file path (padding 4 bytes) + file data (padding 4 bytes) (max size 4gb) +*/ + +#define CPIO_NEWC_HEADER_MAGIC "070701" // big endian + +void* CPIO_DEFAULT_PLACE; // init in main + +struct cpio_newc_header +{ + char c_magic[6]; //magic The string "070701". + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; //check This field is always set to zero by writers and ignored by readers. +}; + +/* write pathname,data,next header into corresponding parameter*/ +int cpio_newc_parse_header(struct cpio_newc_header *this_header_pointer, + char **pathname, unsigned int *filesize, char **data, + struct cpio_newc_header **next_header_pointer); + +#endif \ No newline at end of file diff --git a/lab2/include/dtb.h b/lab2/include/dtb.h new file mode 100644 index 000000000..0c2329ba9 --- /dev/null +++ b/lab2/include/dtb.h @@ -0,0 +1,22 @@ +#ifndef DTB_H +#define DTB_H + +#define uint32_t unsigned int + +// manipulate device tree with dtb file format +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +char* dtb_place; +extern void* CPIO_DEFAULT_PLACE; // initialize by callback dtb_callback_initramfs in main 本來是寫死的 +typedef void (*dtb_callback)(uint32_t node_type, char *name, void *value, uint32_t name_size); + +uint32_t uint32_endian_big2lttle(uint32_t data); +void traverse_device_tree(void *base,dtb_callback callback); //traverse dtb tree +void dtb_callback_show_tree(uint32_t node_type, char *name, void *value, uint32_t name_size); +void dtb_callback_initramfs(uint32_t node_type, char *name, void *value, uint32_t name_size); + +#endif \ No newline at end of file diff --git a/lab2/include/filesystem.h b/lab2/include/filesystem.h new file mode 100644 index 000000000..a9600057e --- /dev/null +++ b/lab2/include/filesystem.h @@ -0,0 +1,9 @@ +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +extern void* CPIO_DEFAULT_PLACE; + +int ls(char* working_dir); +int cat(char* thefilepath); + +#endif \ No newline at end of file diff --git a/lab2/include/gpio.h b/lab2/include/gpio.h new file mode 100644 index 000000000..399ae80f2 --- /dev/null +++ b/lab2/include/gpio.h @@ -0,0 +1,25 @@ +#ifndef GPIO_H +#define GPIO_H + +#define MMIO_BASE 0x3F000000 + +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) + +#endif diff --git a/lab2/include/malloc.h b/lab2/include/malloc.h new file mode 100644 index 000000000..1fc290936 --- /dev/null +++ b/lab2/include/malloc.h @@ -0,0 +1,5 @@ +#ifndef MALLOC_H +#define MALLOC_H +void* malloc(unsigned int size); + +#endif \ No newline at end of file diff --git a/lab2/include/mbox.h b/lab2/include/mbox.h new file mode 100644 index 000000000..b224f4ba1 --- /dev/null +++ b/lab2/include/mbox.h @@ -0,0 +1,31 @@ +#ifndef MBOX_H +#define MBOX_H + +/* a properly aligned buffer */ +/* use this buffer(global variable) directly and the mbox_call will use it after call*/ +/* mbox format https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ +/* mbox address need to be aligned to 16 bytes */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define GET_BOARD_REVISION 0x10002 +#define MBOX_TAG_GETSERIAL 0x10004 +#define GET_ARM_MEMORY 0x10005 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); + +#endif \ No newline at end of file diff --git a/lab2/include/shell.h b/lab2/include/shell.h new file mode 100644 index 000000000..74bd0aa42 --- /dev/null +++ b/lab2/include/shell.h @@ -0,0 +1,8 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); +void do_cmd(char* cmd); +void print_system_messages(); + +#endif \ No newline at end of file diff --git a/lab2/include/sprintf.h b/lab2/include/sprintf.h new file mode 100644 index 000000000..101e564e3 --- /dev/null +++ b/lab2/include/sprintf.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); \ No newline at end of file diff --git a/lab2/include/string.h b/lab2/include/string.h new file mode 100644 index 000000000..bea076572 --- /dev/null +++ b/lab2/include/string.h @@ -0,0 +1,11 @@ +#ifndef STRING_H +#define STRING_H + +int strcmp (const char * s1, const char * s2 ); +int strncmp (const char *s1, const char *s2, unsigned long long n); +char* strcat (char *dest, const char *src); +unsigned long long strlen(const char *str); +char* strcpy (char *dest, const char *src); +char* memcpy (void *dest, const void *src, unsigned long long len); + +#endif \ No newline at end of file diff --git a/lab2/include/system.h b/lab2/include/system.h new file mode 100644 index 000000000..34bee2bd0 --- /dev/null +++ b/lab2/include/system.h @@ -0,0 +1,11 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + +int get_board_revision(unsigned int* board_revision); +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size); +void set(long addr, unsigned int value); +void reboot(); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab2/include/uart.h b/lab2/include/uart.h new file mode 100644 index 000000000..ba9d1bdec --- /dev/null +++ b/lab2/include/uart.h @@ -0,0 +1,15 @@ +#ifndef UART_H +#define UART_H + +#define MAX_BUF_SIZE 0x100 + +void uart_init(); +void uart_putc(char c); +char uart_getc(); +int uart_puts(char *s); +char* uart_gets(char *buf); +int uart_printf(char *fmt, ...); +void uart_hex(unsigned int d); +void disable_uart(); + +#endif diff --git a/lab2/initramfs.cpio b/lab2/initramfs.cpio new file mode 100644 index 000000000..488aa207f Binary files /dev/null and b/lab2/initramfs.cpio differ diff --git a/lab2/kernel8.img b/lab2/kernel8.img new file mode 100644 index 000000000..9f17fb9eb Binary files /dev/null and b/lab2/kernel8.img differ diff --git a/lab2/linker.ld b/lab2/linker.ld new file mode 100644 index 000000000..7d7a4bc42 --- /dev/null +++ b/lab2/linker.ld @@ -0,0 +1,20 @@ +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _heap_start = .; + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/lab2/rootfs/testfile1 b/lab2/rootfs/testfile1 new file mode 100644 index 000000000..734d5d5db --- /dev/null +++ b/lab2/rootfs/testfile1 @@ -0,0 +1,2 @@ +1 +1111111111111111111111111111 diff --git a/lab2/rootfs/testfile112345 b/lab2/rootfs/testfile112345 new file mode 100644 index 000000000..539a7773b --- /dev/null +++ b/lab2/rootfs/testfile112345 @@ -0,0 +1 @@ +1111111111111111111111 diff --git a/lab2/rootfs/testfile2222 b/lab2/rootfs/testfile2222 new file mode 100644 index 000000000..876c79950 --- /dev/null +++ b/lab2/rootfs/testfile2222 @@ -0,0 +1 @@ +222222 diff --git a/lab2/send_kernel_to_bootloader.py b/lab2/send_kernel_to_bootloader.py new file mode 100644 index 000000000..b922e86c4 --- /dev/null +++ b/lab2/send_kernel_to_bootloader.py @@ -0,0 +1,31 @@ +from serial import Serial +from pwn import * +import argparse + +parser = argparse.ArgumentParser(description='NYCU OSC kernel sender') +parser.add_argument('--filename', metavar='PATH', default='kernel8.img', type=str, help='path to kernel8.img') +parser.add_argument('--device', metavar='TTY',default='/dev/ttyUSB0', type=str, help='path to UART device') +parser.add_argument('--baud', metavar='Hz',default=115200, type=int, help='baud rate') +args = parser.parse_args() + +with open(args.filename,'rb') as fd: + with Serial(args.device, args.baud) as ser: + + kernel_raw = fd.read() + length = len(kernel_raw) + + print("Kernel image size : ", hex(length)) + for i in range(8): + ser.write(p64(length)[i:i+1]) + ser.flush() + + print("Start sending kernel img by uart...") + for i in range(length): + # Use kernel_raw[i: i+1] is byte type. Instead of using kernel_raw[i] it will retrieve int type then cause error + ser.write(kernel_raw[i: i+1]) + ser.flush() + if i % 100 == 0: + print("{:>6}/{:>6} bytes".format(i, length)) + print("{:>6}/{:>6} bytes".format(length, length)) + print("Transfer finished!") + \ No newline at end of file diff --git a/lab2/src/cpio.c b/lab2/src/cpio.c new file mode 100644 index 000000000..0f354b5fd --- /dev/null +++ b/lab2/src/cpio.c @@ -0,0 +1,64 @@ +#include "cpio.h" +#include "string.h" +#include "uart.h" + + +/* Parse an ASCII hex string into an integer. (big endian)*/ +static unsigned int parse_hex_str(char *s, unsigned int max_len) +{ + unsigned int r = 0; + + for (unsigned int i = 0; i < max_len; i++) { + r *= 16; + if (s[i] >= '0' && s[i] <= '9') { + r += s[i] - '0'; + } else if (s[i] >= 'a' && s[i] <= 'f') { + r += s[i] - 'a' + 10; + } else if (s[i] >= 'A' && s[i] <= 'F') { + r += s[i] - 'A' + 10; + } else { + return r; + } + } + return r; +} + + +/* write pathname,data,next header into corresponding parameter */ +/* if no next header, next_header_pointer = 0 */ +/* return -1 if parse error*/ +int cpio_newc_parse_header(struct cpio_newc_header *this_header_pointer, char **pathname, unsigned int *filesize, char **data, struct cpio_newc_header **next_header_pointer) +{ + /* Ensure magic header exists. */ + if (strncmp(this_header_pointer->c_magic, CPIO_NEWC_HEADER_MAGIC,sizeof(this_header_pointer->c_magic)) != 0)return -1; + + //transfer big endian 8 byte hex string to unsinged int and store into *filesize + *filesize = parse_hex_str(this_header_pointer->c_filesize,8); + + // end of header is the pathname + *pathname = ((char *)this_header_pointer) + sizeof(struct cpio_newc_header); + + // get file data, file data is just after pathname + unsigned int pathname_length = parse_hex_str(this_header_pointer->c_namesize,8); + unsigned int offset = pathname_length+sizeof(struct cpio_newc_header); + offset = offset%4==0?offset:(offset+4-offset%4); //padding + *data = (char *)this_header_pointer+offset; + + //get next header pointer + if(*filesize==0) + { + *next_header_pointer = (struct cpio_newc_header*)*data; + }else + { + offset = *filesize; + *next_header_pointer = (struct cpio_newc_header*)(*data + (offset%4==0?offset:(offset+4-offset%4))); + } + + // if filepath is TRAILER!!! means there is no more files. + if(strncmp(*pathname,"TRAILER!!!",sizeof("TRAILER!!!"))==0) + { + *next_header_pointer = 0; + } + + return 0; +} \ No newline at end of file diff --git a/lab2/src/dtb.c b/lab2/src/dtb.c new file mode 100644 index 000000000..0bb88c2c6 --- /dev/null +++ b/lab2/src/dtb.c @@ -0,0 +1,103 @@ +#include "dtb.h" +#include "uart.h" +#include "string.h" +#include "cpio.h" + +//stored as big endian +struct fdt_header { + uint32_t magic; + uint32_t totalsize; + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +}; + +uint32_t uint32_endian_big2lttle(uint32_t data) +{ + char* r = (char*)&data; + return (r[3]<<0) | (r[2]<<8) | (r[1]<<16) | (r[0]<<24); +} + +void traverse_device_tree(void *dtb_ptr,dtb_callback callback) +{ + struct fdt_header* header = dtb_ptr; + if(uint32_endian_big2lttle(header->magic) != 0xD00DFEED) + { + uart_puts("traverse_device_tree : wrong magic in traverse_device_tree"); + return; + } + + uint32_t struct_size = uint32_endian_big2lttle(header->size_dt_struct); + char* dt_struct_ptr = (char*)((char*)header + uint32_endian_big2lttle(header->off_dt_struct)); + char* dt_strings_ptr = (char*)((char*)header + uint32_endian_big2lttle(header->off_dt_strings)); + + char* end = (char*)dt_struct_ptr + struct_size; + char* pointer = dt_struct_ptr; + + while(pointer < end) + { + uint32_t token_type = uint32_endian_big2lttle(*(uint32_t*)pointer); + + pointer += 4; + if(token_type == FDT_BEGIN_NODE) + { + callback(token_type,pointer,0,0); + pointer += strlen(pointer); + pointer += 4 - (unsigned long long)pointer%4; //alignment 4 byte + }else if(token_type == FDT_END_NODE) + { + callback(token_type,0,0,0); + }else if(token_type == FDT_PROP) + { + uint32_t len = uint32_endian_big2lttle(*(uint32_t*)pointer); + pointer += 4; + char* name = (char*)dt_strings_ptr + uint32_endian_big2lttle(*(uint32_t*)pointer); + pointer += 4; + callback(token_type,name,pointer,len); + pointer += len; + if((unsigned long long)pointer % 4 !=0)pointer += 4 - (unsigned long long)pointer%4; //alignment 4 byte + }else if(token_type == FDT_NOP) + { + callback(token_type,0,0,0); + }else if(token_type == FDT_END) + { + callback(token_type,0,0,0); + }else + { + uart_printf("error type:%x\n",token_type); + return; + } + } +} + +void dtb_callback_show_tree(uint32_t node_type, char *name, void *data, uint32_t name_size) +{ + static int level = 0; + if(node_type==FDT_BEGIN_NODE) + { + for(int i=0;i request successful +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mbox_call(unsigned char ch) // Mailbox 0 define several channels, but we only use channel 8 (CPU->GPU) for communication. +{ + unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + *MBOX_WRITE = r; + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) + /* is it a valid successful response? */ + return mbox[1]==MBOX_RESPONSE; + } + return 0; +} \ No newline at end of file diff --git a/lab2/src/shell.c b/lab2/src/shell.c new file mode 100644 index 000000000..59bb42213 --- /dev/null +++ b/lab2/src/shell.c @@ -0,0 +1,76 @@ +#include "uart.h" +#include "string.h" +#include "shell.h" +#include "mbox.h" +#include "system.h" +#include "filesystem.h" +#include "dtb.h" + +void shell() +{ + char cmd[MAX_BUF_SIZE]; + print_system_messages(); + while(1) + { + uart_printf("# "); + uart_gets(cmd); + do_cmd(cmd); + } +} + +void do_cmd(char* cmd) +{ + if(strcmp(cmd,"help")==0) + { + uart_puts("help : print this help menu"); + uart_puts("hello : print Hello World!"); + uart_puts("reboot : reboot the device"); + uart_puts("ls : list current directory"); + uart_puts("cat : print content of a file"); + uart_puts("show_device_tree : show device tree"); + } + else if(strcmp(cmd,"hello")==0) + { + uart_puts("Hello World!"); + } + else if(strcmp(cmd,"reboot")==0) + { + reboot(); + }else if(strcmp(cmd,"cat")==0) + { + uart_printf("Filename: "); + char filepath[MAX_BUF_SIZE]; + uart_gets(filepath); + cat(filepath); + + }else if(strcmp(cmd,"ls")==0) + { + ls("."); + }else if(strcmp(cmd,"show_device_tree")==0) + { + traverse_device_tree(dtb_place,dtb_callback_show_tree); + }else + { + uart_puts("Unknown command!"); + } +} + +void print_system_messages() +{ + unsigned int board_revision; + get_board_revision(&board_revision); + uart_printf("Board revision is : 0x"); + uart_hex(board_revision); + uart_puts(""); + + unsigned int arm_mem_base_addr; + unsigned int arm_mem_size; + + get_arm_memory_info(&arm_mem_base_addr,&arm_mem_size); + uart_printf("ARM memory base address in bytes : 0x"); + uart_hex(arm_mem_base_addr); + uart_puts(""); + uart_printf("ARM memory size in bytes : 0x"); + uart_hex(arm_mem_size); + uart_puts(""); +} \ No newline at end of file diff --git a/lab2/src/sprintf.c b/lab2/src/sprintf.c new file mode 100644 index 000000000..650b4ab8b --- /dev/null +++ b/lab2/src/sprintf.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ + +#include "uart.h" + +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + if(dst-orig > MAX_BUF_SIZE-0x10) + { + uart_puts("Error!!! format string too long!!!!"); + return -1; + } + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + unsigned int r = vsprintf(dst,fmt,args); + __builtin_va_end(args); + return r; +} \ No newline at end of file diff --git a/lab2/src/start.S b/lab2/src/start.S new file mode 100644 index 000000000..e28b48ab5 --- /dev/null +++ b/lab2/src/start.S @@ -0,0 +1,30 @@ +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b diff --git a/lab2/src/string.c b/lab2/src/string.c new file mode 100644 index 000000000..c8e4eed7c --- /dev/null +++ b/lab2/src/string.c @@ -0,0 +1,84 @@ +#include "string.h" +#include + +int strcmp (const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } + while (c1 == c2); + return c1 - c2; +} + +int strncmp (const char *s1, const char *s2, unsigned long long n) +{ + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + if (n >= 4) + { + size_t n4 = n >> 2; + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + } while (--n4 > 0); + n &= 3; + } + while (n > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + n--; + } + return c1 - c2; +} + +char* strcat (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} + +char* strcpy (char *dest, const char *src) +{ + return memcpy (dest, src, strlen (src) + 1); +} + +unsigned long long strlen(const char *str) +{ + size_t count = 0; + while((unsigned char)*str++)count++; + return count; +} + +char* memcpy (void *dest, const void *src, unsigned long long len) +{ + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} \ No newline at end of file diff --git a/lab2/src/system.c b/lab2/src/system.c new file mode 100644 index 000000000..a1bd53864 --- /dev/null +++ b/lab2/src/system.c @@ -0,0 +1,82 @@ +#include "system.h" +#include "uart.h" +#include "mbox.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +/* For all return 0 -> success , -1 failure*/ + +int get_board_revision(unsigned int* board_revision) +{ + /* + GET_BOARD_REVISION + */ + mbox[0] = 7*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_BOARD_REVISION; // tag identifier + mbox[3] = 4; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer + mbox[6] = MBOX_TAG_LAST; // end tag + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *board_revision = mbox[5]; + return 0; + } else { + uart_puts("Unable to query serial!"); + *board_revision = mbox[5] = -1; + return -1; + } +} + +int get_arm_memory_info(unsigned int* base_addr,unsigned int* size) +{ + /* + GET arm_memory address and size + */ + mbox[0] = 8*4; // length of the message + mbox[1] = MBOX_REQUEST; // request code + mbox[2] = GET_ARM_MEMORY; // tag identifier + mbox[3] = 8; // value buffer size in bytes + mbox[4] = 0; // request codes : b31 clear, b30-b0 reversed + mbox[5] = 0; // clear output buffer ( u32: base address in bytes ) + mbox[6] = 0; // clear output buffer ( u32: size in bytes ) + mbox[7] = MBOX_TAG_LAST; // end tag + + // send the message to the GPU and receive answer + if (mbox_call(MBOX_CH_PROP)) { + *base_addr = mbox[5]; + *size = mbox[6]; + return 0; + } else { + uart_puts("Unable to query serial!"); + return -1; + } +} + +void set(long addr, unsigned int value) +{ + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reboot() +{ + //disable_uart(); + reset(1); // timeout = 1/16th of a second? (whatever) +} + +void reset(int tick) +{ // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick + while(1); +} + +void cancel_reset() +{ + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab2/src/uart.c b/lab2/src/uart.c new file mode 100644 index 000000000..7ceeac441 --- /dev/null +++ b/lab2/src/uart.c @@ -0,0 +1,192 @@ +#include "gpio.h" +#include "uart.h" +#include "sprintf.h" + +/* Auxilary mini UART registers */ +#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) + +// get address from linker +extern volatile unsigned char _end; + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // Set AUXENB register to enable mini UART. Then mini UART register can be accessed. + *AUX_MU_CNTL = 0; // Set AUX_MU_CNTL_REG to 0. Disable transmitter and receiver during configuration. + *AUX_MU_IER = 0; // Set AUX_MU_IER_REG to 0. Disable interrupt because currently you don’t need interrupt. + *AUX_MU_LCR = 3; // Set AUX_MU_LCR_REG to 3. Set the data size to 8 bit. + *AUX_MU_MCR = 0; // Set AUX_MU_MCR_REG to 0. Don’t need auto flow control. + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 (disable pull up/down) + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx + + while((*AUX_MU_LSR&0x01))*AUX_MU_IO; //clean rx data +} + +// maybe don't do so many step +void disable_uart() +{ + register unsigned int r; + *AUX_ENABLE &= ~(unsigned int)1; + *AUX_MU_CNTL = 0; + r=*GPFSEL1; + r|=((7<<12)|(7<<15)); // gpio14, gpio15 + r&=~(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 2; // enable pins 14 and 15 (pull down) + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup +} + +/** + * Send a character + */ +void uart_putc(char c) { + unsigned int intc = c; + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=intc; +} + +/** + * Receive a character + */ +char uart_getc() { + char r; + /* wait until something is in the buffer */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + + /* + echo back + */ + if(r == '\r') + { + uart_puts("\r"); + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x40)); //wait for output success Transmitter idle + }else if(r == '\x7f') // backspace -> get del + { + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + }else + { + uart_putc(r); + } + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string with newline + */ +int uart_puts(char *s) { + int i=0; + + while(*s) { + uart_putc(*s++); + i++; + } + uart_putc('\r'); + uart_putc('\n'); + + return i+2; +} + +/** + * get a string + */ +char* uart_gets(char *buf) +{ + int count; + char c; + char *s; + for (s = buf,count = 0; (c = uart_getc()) != '\n' && count!=MAX_BUF_SIZE-1 ;count++) + { + *s = c; + if(*s=='\x7f') + { + count--; + if(count==-1) + { + uart_putc(' '); // prevent back over command line # + continue; + } + s--; + count--; + continue; + } + s++; + } + *s = '\0'; + return buf; +} + +/** + * printf (from https://github.com/bztsrc/raspi3-tutorial/tree/master/12_printf) + initial printf from github dont use any va_end, and it is also can run. (in assembly there is nothing compiled from __builtin_va_end) + */ +int uart_printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + char buf[MAX_BUF_SIZE]; + // we don't have memory allocation yet, so we + // simply place our string after our code + char *s = (char*)buf; + // use sprintf to format our string + int count = vsprintf(s,fmt,args); + // print out as usual + while(*s) { + /* convert newline to carrige return + newline */ + if(*s=='\n') + uart_putc('\r'); + uart_putc(*s++); + } + __builtin_va_end(args); + return count; +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_putc(n); + } +}