From b59f5bded1ff069fbebac141431c6399ff9fd43e Mon Sep 17 00:00:00 2001 From: hsu Date: Thu, 13 Jun 2024 19:08:05 +0800 Subject: [PATCH 1/2] lab2 finish --- Makefile => Lab1/kernel code/Makefile | 0 Lab1/kernel code/README.md | 3 + gpio.h => Lab1/kernel code/gpio.h | 0 kernel8.img => Lab1/kernel code/kernel8.img | Bin link.ld => Lab1/kernel code/link.ld | 0 main.c => Lab1/kernel code/main.c | 0 mbox.c => Lab1/kernel code/mbox.c | 0 mbox.h => Lab1/kernel code/mbox.h | 0 shell.c => Lab1/kernel code/shell.c | 0 shell.h => Lab1/kernel code/shell.h | 0 start.S => Lab1/kernel code/start.S | 2 +- string.c => Lab1/kernel code/string.c | 0 string.h => Lab1/kernel code/string.h | 0 uart.c => Lab1/kernel code/uart.c | 0 uart.h => Lab1/kernel code/uart.h | 0 Lab2/Makefile | 34 +++++ Lab2/bash_send_kernel.sh | 25 ++++ Lab2/bootloader/Makefile | 33 +++++ Lab2/bootloader/include/gpio.h | 25 ++++ Lab2/bootloader/include/stdint.h | 16 +++ Lab2/bootloader/include/uart.h | 41 ++++++ Lab2/bootloader/src/link.ld | 21 ++++ Lab2/bootloader/src/main.c | 58 +++++++++ Lab2/bootloader/src/start.S | 40 ++++++ Lab2/bootloader/src/uart.c | 124 ++++++++++++++++++ Lab2/include/command.h | 31 +++++ Lab2/include/cpio_parser.h | 29 +++++ Lab2/include/gpio.h | 25 ++++ Lab2/include/my_stddef.h | 8 ++ Lab2/include/my_stdint.h | 23 ++++ Lab2/include/my_stdio.h | 6 + Lab2/include/my_stdlib.h | 17 +++ Lab2/include/my_string.h | 15 +++ Lab2/include/shell.h | 17 +++ Lab2/include/uart.h | 39 ++++++ Lab2/initramfs.cpio | Bin 0 -> 512 bytes Lab2/rootfs/file1.txt | 1 + Lab2/rootfs/file2.txt | 1 + Lab2/screen.sh | 17 +++ Lab2/send_kernel.py | 72 +++++++++++ Lab2/src/command.c | 103 +++++++++++++++ Lab2/src/cpio_parser.c | 112 +++++++++++++++++ Lab2/src/link.ld | 18 +++ Lab2/src/main.c | 15 +++ Lab2/src/my_stdlib.c | 35 ++++++ Lab2/src/my_string.c | 88 +++++++++++++ Lab2/src/shell.c | 75 +++++++++++ Lab2/src/start.S | 32 +++++ Lab2/src/uart.c | 131 ++++++++++++++++++++ 49 files changed, 1331 insertions(+), 1 deletion(-) rename Makefile => Lab1/kernel code/Makefile (100%) create mode 100755 Lab1/kernel code/README.md rename gpio.h => Lab1/kernel code/gpio.h (100%) rename kernel8.img => Lab1/kernel code/kernel8.img (100%) rename link.ld => Lab1/kernel code/link.ld (100%) rename main.c => Lab1/kernel code/main.c (100%) rename mbox.c => Lab1/kernel code/mbox.c (100%) rename mbox.h => Lab1/kernel code/mbox.h (100%) rename shell.c => Lab1/kernel code/shell.c (100%) rename shell.h => Lab1/kernel code/shell.h (100%) rename start.S => Lab1/kernel code/start.S (90%) rename string.c => Lab1/kernel code/string.c (100%) rename string.h => Lab1/kernel code/string.h (100%) rename uart.c => Lab1/kernel code/uart.c (100%) rename uart.h => Lab1/kernel code/uart.h (100%) create mode 100755 Lab2/Makefile create mode 100755 Lab2/bash_send_kernel.sh create mode 100755 Lab2/bootloader/Makefile create mode 100755 Lab2/bootloader/include/gpio.h create mode 100755 Lab2/bootloader/include/stdint.h create mode 100755 Lab2/bootloader/include/uart.h create mode 100755 Lab2/bootloader/src/link.ld create mode 100755 Lab2/bootloader/src/main.c create mode 100755 Lab2/bootloader/src/start.S create mode 100755 Lab2/bootloader/src/uart.c create mode 100755 Lab2/include/command.h create mode 100755 Lab2/include/cpio_parser.h create mode 100755 Lab2/include/gpio.h create mode 100755 Lab2/include/my_stddef.h create mode 100755 Lab2/include/my_stdint.h create mode 100755 Lab2/include/my_stdio.h create mode 100755 Lab2/include/my_stdlib.h create mode 100755 Lab2/include/my_string.h create mode 100755 Lab2/include/shell.h create mode 100755 Lab2/include/uart.h create mode 100755 Lab2/initramfs.cpio create mode 100755 Lab2/rootfs/file1.txt create mode 100755 Lab2/rootfs/file2.txt create mode 100755 Lab2/screen.sh create mode 100755 Lab2/send_kernel.py create mode 100755 Lab2/src/command.c create mode 100755 Lab2/src/cpio_parser.c create mode 100755 Lab2/src/link.ld create mode 100755 Lab2/src/main.c create mode 100755 Lab2/src/my_stdlib.c create mode 100755 Lab2/src/my_string.c create mode 100755 Lab2/src/shell.c create mode 100755 Lab2/src/start.S create mode 100755 Lab2/src/uart.c diff --git a/Makefile b/Lab1/kernel code/Makefile similarity index 100% rename from Makefile rename to Lab1/kernel code/Makefile diff --git a/Lab1/kernel code/README.md b/Lab1/kernel code/README.md new file mode 100755 index 000000000..3a6b50ddc --- /dev/null +++ b/Lab1/kernel code/README.md @@ -0,0 +1,3 @@ +| Github Account | Student ID | Name | +|----------------|------------|---------------| +|Hsu0208 | 311551158 | Wei Ling Hsu | diff --git a/gpio.h b/Lab1/kernel code/gpio.h similarity index 100% rename from gpio.h rename to Lab1/kernel code/gpio.h diff --git a/kernel8.img b/Lab1/kernel code/kernel8.img similarity index 100% rename from kernel8.img rename to Lab1/kernel code/kernel8.img diff --git a/link.ld b/Lab1/kernel code/link.ld similarity index 100% rename from link.ld rename to Lab1/kernel code/link.ld diff --git a/main.c b/Lab1/kernel code/main.c similarity index 100% rename from main.c rename to Lab1/kernel code/main.c diff --git a/mbox.c b/Lab1/kernel code/mbox.c similarity index 100% rename from mbox.c rename to Lab1/kernel code/mbox.c diff --git a/mbox.h b/Lab1/kernel code/mbox.h similarity index 100% rename from mbox.h rename to Lab1/kernel code/mbox.h diff --git a/shell.c b/Lab1/kernel code/shell.c similarity index 100% rename from shell.c rename to Lab1/kernel code/shell.c diff --git a/shell.h b/Lab1/kernel code/shell.h similarity index 100% rename from shell.h rename to Lab1/kernel code/shell.h diff --git a/start.S b/Lab1/kernel code/start.S similarity index 90% rename from start.S rename to Lab1/kernel code/start.S index 17db9b5b2..e83b58227 100755 --- a/start.S +++ b/Lab1/kernel code/start.S @@ -9,7 +9,7 @@ _start: cbz x1, 2f // cpu id > 0, stop 1: wfe - b 1b + b 1b // b uncinditional branch 1-label b- backward 2: // cpu id == 0 // set stack before our code diff --git a/string.c b/Lab1/kernel code/string.c similarity index 100% rename from string.c rename to Lab1/kernel code/string.c diff --git a/string.h b/Lab1/kernel code/string.h similarity index 100% rename from string.h rename to Lab1/kernel code/string.h diff --git a/uart.c b/Lab1/kernel code/uart.c similarity index 100% rename from uart.c rename to Lab1/kernel code/uart.c diff --git a/uart.h b/Lab1/kernel code/uart.h similarity index 100% rename from uart.h rename to Lab1/kernel code/uart.h diff --git a/Lab2/Makefile b/Lab2/Makefile new file mode 100755 index 000000000..b111770f7 --- /dev/null +++ b/Lab2/Makefile @@ -0,0 +1,34 @@ +ARMGNU = aarch64-linux-gnu + +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +ASMFLAGS = -Iinclude +QEMUFLAGS = -M raspi3b -display none -serial null -serial pty + +BUILD_DIR = build +SRC_DIR = src + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%.o) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMFLAGS) -c $< -o $@ + +all: clean kernel8.img + +kernel8.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +clean: + rm -rf $(BUILD_DIR) *.img *.elf *.o + +qemu: kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -initrd initramfs.cpio + diff --git a/Lab2/bash_send_kernel.sh b/Lab2/bash_send_kernel.sh new file mode 100755 index 000000000..5eb4ea73d --- /dev/null +++ b/Lab2/bash_send_kernel.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +## rapspi -> bash send_kernel.sh +## qemu -> bash send_kernel.sh i + +## Construct the device path +if [ $# -eq 0 ]; then + device="/dev/ttyUSB0" +else + index="$1" + device="/dev/pts/$index" +fi + +# Check if the device file exists +if [ ! -c "$device" ]; then + echo "Device not found: $device" + exit 1 +fi + +# Change permissions of the device file +echo chmod a+rw "$device" +sudo chmod a+rw "$device" + +# Execute send_kernel.py with the appropriate argument +python3 send_kernel.py $1 diff --git a/Lab2/bootloader/Makefile b/Lab2/bootloader/Makefile new file mode 100755 index 000000000..b345a8bcf --- /dev/null +++ b/Lab2/bootloader/Makefile @@ -0,0 +1,33 @@ +ARMGNU = aarch64-linux-gnu + +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles +ASMFLAGS = -Iinclude +QEMUFLAGS = -M raspi3b -display none -serial null -serial pty + +BUILD_DIR = build +SRC_DIR = src + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%.o) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMFLAGS) -c $< -o $@ + +all: bootloader.img + +bootloader.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/bootloader.elf -O binary bootloader.img + +clean: + rm -rf $(BUILD_DIR) *.img *.elf *.o + +qemu: bootloader.img + qemu-system-aarch64 $(QEMUFLAGS) -kernel bootloader.img -initrd ../initramfs.cpio \ No newline at end of file diff --git a/Lab2/bootloader/include/gpio.h b/Lab2/bootloader/include/gpio.h new file mode 100755 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/stdint.h b/Lab2/bootloader/include/stdint.h new file mode 100755 index 000000000..c54cccf50 --- /dev/null +++ b/Lab2/bootloader/include/stdint.h @@ -0,0 +1,16 @@ +#ifndef _STDINT_H +#define _STDINT_H + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef unsigned int size_t; + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/Lab2/bootloader/include/uart.h b/Lab2/bootloader/include/uart.h new file mode 100755 index 000000000..2772882f8 --- /dev/null +++ b/Lab2/bootloader/include/uart.h @@ -0,0 +1,41 @@ +#include "../include/stdint.h" + +#ifndef UART_H +#define 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(); + + +/** + * Receive a character + */ +char uart_getc(); + +/** + * Display a string + */ +void uart_puts(char *s); + + +char uart_recv(); + +void itos(uint32_t value, char *str); +#endif diff --git a/Lab2/bootloader/src/link.ld b/Lab2/bootloader/src/link.ld new file mode 100755 index 000000000..10513d40b --- /dev/null +++ b/Lab2/bootloader/src/link.ld @@ -0,0 +1,21 @@ +SECTIONS +{ + . = 0x60000; + __bootloader_start = .; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + __bootloader_end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; +__bootloader_size = (__bootloader_end - __bootloader_start) >> 3; \ No newline at end of file diff --git a/Lab2/bootloader/src/main.c b/Lab2/bootloader/src/main.c new file mode 100755 index 000000000..54c40858b --- /dev/null +++ b/Lab2/bootloader/src/main.c @@ -0,0 +1,58 @@ +#include "../include/uart.h" +#include "../include/stdint.h" + +void main() +{ + // set up serial console + uart_init(); + uart_puts("bootloader is coming~\n"); + + uint32_t file_size = 0; + size_t index = 0; + // Buffer to store received data + uint8_t byte; + + while(1) { + if(uart_recv() == ((uint8_t)77)) break; + } + uart_puts("ready for receiving kernel size.\n"); + + + // Receive the file size as a 4-byte integer in little-endian format + for (int i = 0; i < 4; i++) { + byte = uart_recv(); + file_size |= ((uint32_t)byte) << (8 * i); + } + + char file_size_str[32]; // Adjust the buffer size as needed + itos(file_size, file_size_str); + + uart_puts("kernel size :"); + uart_puts(file_size_str); + uart_puts(" bytes.\n"); + + while(1) { + uart_puts("ready for receiving kernel.\n"); + if(uart_recv() == ((uint8_t)77)) break; + } + + + char *kernel = (char *)0x80000; + while (index < file_size) { + // Receive a byte + byte = uart_recv(); + // Write the byte to memory + *(kernel + index) = byte; + // Increment the index + index++; + } + + uart_puts("finished loading kernel~\n"); + + + // restore arguments and jump to the new kernel. + asm volatile ( + "mov x30, 0x80000;" // Move the immediate value 0x80000 to the link register (x30) + "ret;" // Return from subroutine (this will jump to the address in x30) + ); +} \ No newline at end of file diff --git a/Lab2/bootloader/src/start.S b/Lab2/bootloader/src/start.S new file mode 100755 index 000000000..6c61831dc --- /dev/null +++ b/Lab2/bootloader/src/start.S @@ -0,0 +1,40 @@ +.section ".text.boot" + +.global _start + +_start: + /* relocate bootloader */ + ldr x1, =0x80000 //address for relocation. + ldr x2, =__bootloader_start + ldr w3, =__bootloader_size + +relocate: + ldr x4, [x1], #8 + str x4, [x2], #8 + sub w3, w3, #1 + cbnz w3, relocate + + /* set stack pointer */ + ldr x1, =_start + mov sp, x1 + + +bss_init: + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_memory: + cbz w2, jump_to_main + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_memory + +// jump to C code, should not return +jump_to_main: + bl main-0x20000 + // for failsafe, halt this core too + b halt + +halt: + b halt diff --git a/Lab2/bootloader/src/uart.c b/Lab2/bootloader/src/uart.c new file mode 100755 index 000000000..ad9b63c17 --- /dev/null +++ b/Lab2/bootloader/src/uart.c @@ -0,0 +1,124 @@ +#include "../include/gpio.h" +#include "../include/uart.h" +#include "../include/stdint.h" + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int reg; + + /* initialize UART */ + *AUX_ENABLE |= 1; /* enable mini UART */ + *AUX_MU_CNTL = 0; /* Disable transmitter and receiver during configuration. */ + + *AUX_MU_IER = 0; /* Disable interrupt */ + *AUX_MU_LCR = 3; /* Set the data size to 8 bit. */ + *AUX_MU_MCR = 0; /* Don’t need auto flow control. */ + *AUX_MU_BAUD = 270; /* 115200 baud */ + *AUX_MU_IIR = 6; /* No FIFO */ + // *AUX_MU_IIR = 0xc6; /* No FIFO */ + + /* map UART1 to GPIO pins */ + // GPFSEL1 register controls the function of GPIO pins + reg = *GPFSEL1; + reg &= ~((7<<12)|(7<<15)); /* address of gpio 14, 15 */ + reg |= (2<<12)|(2<<15); /* set to alt5 */ + + *GPFSEL1 = reg; + + // ensures that GPIO pins are not affected by internal resistors + *GPPUD = 0; /* Disable pull-up/down */ + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + *GPPUDCLK0 = (1<<14)|(1<<15); + + //Stabilizing the Signal to ensure Proper Configuration + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + // ensures that GPIO pins are returned to a neutral state + *GPPUDCLK0 = 0; /* flush GPIO setup */ + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver. + *AUX_MU_IER = 3; // Enable the interrupt. +} + +/** + * Send a character + */ +void uart_send(unsigned int c) +{ + /* Wait until UART transmitter is ready to accept new data. */ + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + /* write the character to the buffer */ + *AUX_MU_IO = c; + + // ensure proper line termination + if ( c == '\n' ) + { + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + //*AUX_MU_IO = '\r'; + } +} + + +/** + * Display a string + */ +void uart_puts(char *s) +{ + while( *s ) + { + + uart_send(*s++); + + } +} + +/** + * Display a binary value in hexadecimal + */ + +char uart_recv ( void ) +{ + while(! ( *AUX_MU_LSR&0x01 ) ){ + asm volatile("nop"); + } + return(*AUX_MU_IO&0xFF); +} + +void itos(uint32_t value, char *str) { + int i = 0; + do { + str[i++] = value % 10 + '0'; + value /= 10; + } while (value != 0); + str[i] = '\0'; + + // Reverse the string + int len = i; + for (int j = 0; j < len / 2; j++) { + char temp = str[j]; + str[j] = str[len - j - 1]; + str[len - j - 1] = temp; + } +} \ No newline at end of file diff --git a/Lab2/include/command.h b/Lab2/include/command.h new file mode 100755 index 000000000..aecb7a431 --- /dev/null +++ b/Lab2/include/command.h @@ -0,0 +1,31 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include "../include/my_stddef.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +#define TMP_BUFFER_LEN 32 + +typedef void (*command_handler_t)(void); + +typedef struct { + const char *command; + const char *description; + command_handler_t handler; +} command_t; + +extern command_t commands[]; + +void set(long addr, unsigned int value); +char *get_string(void); +void cmd_help(void); +void cmd_hello(void); +void cmd_reboot(void); +void cmd_ls(void); +void cmd_cat(void); +void cmd_malloc(void); + +#endif \ No newline at end of file diff --git a/Lab2/include/cpio_parser.h b/Lab2/include/cpio_parser.h new file mode 100755 index 000000000..becbb1959 --- /dev/null +++ b/Lab2/include/cpio_parser.h @@ -0,0 +1,29 @@ +#ifndef MY_CPIO_PARSER_H +#define MY_CPIO_PARSER_H + +#define CPIO_NEWC_MAGIC "070701" +#define HEADER_SIZE sizeof(struct cpio_newc_header) +#define MAX_ARCHIVE_SIZE (1024 * 1024 * 1024) // 1 GB +#define RAPSPI_CPIO_ADDRESS 0x20000000 + +struct cpio_newc_header { + char c_magic[6]; + 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]; +}; + +void cpio_ls(char *cpio_archive_start); +void cpio_cat(char *cpio_archive_start, const char *filename); + +#endif \ No newline at end of file diff --git a/Lab2/include/gpio.h b/Lab2/include/gpio.h new file mode 100755 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/my_stddef.h b/Lab2/include/my_stddef.h new file mode 100755 index 000000000..efa35140a --- /dev/null +++ b/Lab2/include/my_stddef.h @@ -0,0 +1,8 @@ +#ifndef MY_STDDEF_H +#define MY_STDDEF_H + +#define NULL ((void *)0) + +typedef unsigned int size_t; + +#endif \ No newline at end of file diff --git a/Lab2/include/my_stdint.h b/Lab2/include/my_stdint.h new file mode 100755 index 000000000..34506dafa --- /dev/null +++ b/Lab2/include/my_stdint.h @@ -0,0 +1,23 @@ +#ifndef MY_STDINT_H +#define MY_STDINT_H + +#define __LP64__ 1 // Define __LP64__ macro to indicate a 64-bit system + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +// Define uintptr_t based on the size of a pointer +#if defined(__LP64__) || defined(_LP64) +typedef unsigned long int uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/Lab2/include/my_stdio.h b/Lab2/include/my_stdio.h new file mode 100755 index 000000000..e17a409a5 --- /dev/null +++ b/Lab2/include/my_stdio.h @@ -0,0 +1,6 @@ +#ifndef MY_STDIO_H +#define MY_STDIO_H + +#define EOF (-1) + +#endif \ No newline at end of file diff --git a/Lab2/include/my_stdlib.h b/Lab2/include/my_stdlib.h new file mode 100755 index 000000000..e79f01bc9 --- /dev/null +++ b/Lab2/include/my_stdlib.h @@ -0,0 +1,17 @@ +#ifndef MY_STDLIB_H +#define MY_STDLIB_H + +#include "../include/my_stddef.h" + +extern int __bss_end; +//have tried 1GB but kernel dead +#define HEAP_SIZE (1024) // 1 KB +#define HEAP_START (&__bss_end) +#define HEAP_END ((void *)((uintptr_t)HEAP_START + HEAP_SIZE)) + + +void* alignas(size_t alignment, void* ptr); +void initialize_heap(void); +void* simple_malloc(size_t size); + +#endif \ No newline at end of file diff --git a/Lab2/include/my_string.h b/Lab2/include/my_string.h new file mode 100755 index 000000000..fb6804417 --- /dev/null +++ b/Lab2/include/my_string.h @@ -0,0 +1,15 @@ +#ifndef MY_STRING_H +#define MY_STRING_H + +#include "../include/my_stddef.h" + +#define HEX_DIGIT_TO_INT(c) ((c >= '0' && c <= '9') ? (c - '0') : ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : (c - 'A' + 10))) + +void strset( char * s1, int c, int size ); +int strlen( char * s ); +int strncmp(const char *s1, const char *s2, size_t n); +int strcmp(const char *s1, const char *s2); +void itoa(int num, char *str, int base); +unsigned int hex_to_uint(char *hex); + +#endif diff --git a/Lab2/include/shell.h b/Lab2/include/shell.h new file mode 100755 index 000000000..75764af22 --- /dev/null +++ b/Lab2/include/shell.h @@ -0,0 +1,17 @@ +#ifndef MYSHELL_H +#define MYSHELL_H + +#include "../include/my_stddef.h" + +#define MAX_BUFFER_LEN 64 +#define NEW_LINE 1001 +#define LINE_FEED 10 +#define CRRIAGE_RETURN 13 +#define BACKSPACE 8 + + +void shell_start(); +void command_controller(char c, char buffer[], int *counter); +void execute_command(char *buffer); + +#endif diff --git a/Lab2/include/uart.h b/Lab2/include/uart.h new file mode 100755 index 000000000..2bfa7678a --- /dev/null +++ b/Lab2/include/uart.h @@ -0,0 +1,39 @@ +#ifndef UART_H +#define 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(); + +/** + * Send a character + */ +void uart_send(unsigned int c); +/** + * Receive a character + */ +char uart_getc(); + +/** + * Display a string + */ +void uart_puts(const char *s); + +void uart_hex(unsigned int d); +#endif diff --git a/Lab2/initramfs.cpio b/Lab2/initramfs.cpio new file mode 100755 index 0000000000000000000000000000000000000000..6a66947746ff0c36f414be5ef150dbfefebb01b7 GIT binary patch literal 512 zcmXpoH!wFaGynlZOH&YKV(4Z8q7lHt63R9-Gcz-Eb#`_^$RV?gkvYh0BN#`I0cab- zK68+`1ws2p!~g&Q literal 0 HcmV?d00001 diff --git a/Lab2/rootfs/file1.txt b/Lab2/rootfs/file1.txt new file mode 100755 index 000000000..c0e3b6139 --- /dev/null +++ b/Lab2/rootfs/file1.txt @@ -0,0 +1 @@ +this is file1 \ No newline at end of file diff --git a/Lab2/rootfs/file2.txt b/Lab2/rootfs/file2.txt new file mode 100755 index 000000000..5040297ea --- /dev/null +++ b/Lab2/rootfs/file2.txt @@ -0,0 +1 @@ +this is file2 \ No newline at end of file diff --git a/Lab2/screen.sh b/Lab2/screen.sh new file mode 100755 index 000000000..4704fdd9a --- /dev/null +++ b/Lab2/screen.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ $# -eq 0 ]; then + device="/dev/ttyUSB0" +else + index="$1" + device="/dev/pts/$index" +fi + +if [ ! -c "$device" ]; then + echo "Device not found: $device" + exit 1 +fi + +echo "screen device : $device" +sudo screen "$device" 115200 + diff --git a/Lab2/send_kernel.py b/Lab2/send_kernel.py new file mode 100755 index 000000000..13490b2ba --- /dev/null +++ b/Lab2/send_kernel.py @@ -0,0 +1,72 @@ +import time +import serial +import sys +import os +import struct + +baud_rate = 115200 # Baud rate for the serial connection +timeout = 5 # Timeout for serial read operations in seconds +kernel_img_path = './kernel8.img' + +def send_file(serial_port, file_path, baud_rate, timeout): + # Check if the file exists + if not os.path.exists(file_path): + print(f"File {file_path} does not exist.") + return + + try: + # Open the serial port + with serial.Serial(serial_port, baud_rate, timeout=timeout) as ser: + print(f"Opened serial port {serial_port} at {baud_rate} baud.") + + # Get the size of the file + file_size = os.path.getsize(file_path) + print(f"File size: {file_size} bytes.") + + #call bootloader to start + + #time.sleep(2) + # Wait for Raspberry Pi + ser.write((77).to_bytes(1, byteorder='little')) + while(1): + rasp_response = ser.readline().decode() + print("Raspberry Pi :",repr(rasp_response)) + if rasp_response == "ready for receiving kernel size.\n": + break + + print("start sending kernel size.") + # Send the file size as a 4-byte integer in little-endian format + ser.write(file_size.to_bytes(4, byteorder='little')) + #time.sleep(10) + # Wait for Raspberry Pi + + #time.sleep(2) + ser.write((77).to_bytes(1, byteorder='little')) + while(1): + rasp_response = ser.readline().decode() + print("Raspberry Pi :",repr(rasp_response)) + + if rasp_response == "ready for receiving kernel.\n": + break + + # Read the file and send it over the serial connection + print("start sending kernel.") + with open(file_path, 'rb') as f: + ser.write(f.read()) + + print(f"Successfully sent {file_path} to {serial_port}.") + ser.close() + + except serial.SerialException as e: + print(f"Error opening or using serial port {serial_port}: {e}") + except Exception as e: + print(f"Error: {e}") + +if __name__ == '__main__': + if len(sys.argv)>1: + serial_port = f"/dev/pts/{sys.argv[1]}" + else: + serial_port = "/dev/ttyUSB0" + + send_file(serial_port, kernel_img_path, baud_rate, timeout) + diff --git a/Lab2/src/command.c b/Lab2/src/command.c new file mode 100755 index 000000000..94e1c1052 --- /dev/null +++ b/Lab2/src/command.c @@ -0,0 +1,103 @@ +#include "../include/command.h" +#include "../include/uart.h" +#include "../include/cpio_parser.h" +#include "../include/shell.h" +#include "../include/my_stddef.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +char *get_string(void){ + int buffer_counter = 0; + char input_char; + static char buffer[TMP_BUFFER_LEN]; + strset(buffer, 0, TMP_BUFFER_LEN); + while (1) { + input_char = uart_getc(); + if (!(input_char < 128 && input_char >= 0)) { + uart_puts("Invalid character received\n"); + return NULL; + } else if (input_char == LINE_FEED || input_char == CRRIAGE_RETURN) { + uart_send(input_char); + buffer[buffer_counter] = '\0'; + return buffer; + }else { + uart_send(input_char); + + if (buffer_counter < TMP_BUFFER_LEN) { + buffer[buffer_counter] = input_char; + buffer_counter++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + buffer_counter = 0; + strset(buffer, 0, TMP_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } + } +} + +void cmd_help(void) { + uart_puts("help : print this help menu\n"); + uart_puts("hello : print Hello World!\n"); + uart_puts("reboot : reboot the device\n"); + uart_puts("ls : show file in rootfs\n"); + uart_puts("cat : show file content\n"); + uart_puts("malloc : malloc demp\n"); +} + +void cmd_hello(void) { + uart_puts("Hello World!\n"); +} + +void cmd_reboot(void) { + uart_puts("Start rebooting...\n"); + set(PM_RSTC, PM_PASSWORD | 0x20); +} + +void cmd_ls(void) { + char *cpio_archive_start = (char *)RAPSPI_CPIO_ADDRESS; + cpio_ls(cpio_archive_start); +} + +void cmd_cat(void){ + uart_puts("Filename: "); + char *filename = get_string(); + if (filename == NULL) { + uart_puts("Error: Invalid filename\n"); + return; + } + char *cpio_archive_start = (char *)RAPSPI_CPIO_ADDRESS; + cpio_cat(cpio_archive_start,filename); +} + +void cmd_malloc(void) { + char *ptr1 = simple_malloc(7); + ptr1[0]='M'; + ptr1[1]='A'; + ptr1[2]='L'; + ptr1[3]='L'; + ptr1[4]='O'; + ptr1[5]='C'; + ptr1[6]='\0'; + uart_puts(ptr1); + uart_puts("\n"); +} + + +command_t commands[] = { + {"help", "print this help menu", cmd_help}, + {"hello", "print Hello World!", cmd_hello}, + {"reboot", "reboot the device", cmd_reboot}, + {"ls", "show file in rootfs", cmd_ls}, + {"cat", "show file content", cmd_cat}, + {"malloc", "malloc demo", cmd_malloc}, + {NULL, NULL, NULL} // Sentinel value to mark the end of the array +}; \ No newline at end of file diff --git a/Lab2/src/cpio_parser.c b/Lab2/src/cpio_parser.c new file mode 100755 index 000000000..b2ae2f908 --- /dev/null +++ b/Lab2/src/cpio_parser.c @@ -0,0 +1,112 @@ +#include "../include/uart.h" +#include "../include/cpio_parser.h" +#include "../include/my_stddef.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" +#include "../include/my_stdint.h" + +void cpio_ls(char *cpio_archive_start) { + char *ptr = cpio_archive_start; + + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + break; + } + + //The "new" ASCII format uses 8-byte hexadecimal fields for all numbers + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + /*Each file system object in a cpio archive comprises a header record + with basic numeric metadata followed by the full pathname of the entry and the file data.*/ + ptr += HEADER_SIZE; + char *filename = ptr; + ptr += namesize; + + //allign to 4 byte + //the filedata is padded to a multiple of four bytes.. + ptr = alignas(4, ptr); + + if (strcmp(filename, "TRAILER!!!") == 0) { + break; + } + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + + uart_puts(filename); + uart_puts("\n"); + + } +} + +void cpio_cat(char *cpio_archive_start, const char *filename) { + char *ptr = cpio_archive_start; + int file_exist=0; + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + return; + } + + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + ptr += HEADER_SIZE; + char *current_filename = ptr; + ptr += namesize; + + // Align to 4 bytes + ptr = alignas(4, ptr); + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + + char *content = ptr; + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + if (strcmp(current_filename, filename) == 0) { + // Print file content + uart_puts(content); + uart_puts("\n"); + return; + } + + // Check if we've reached the end of the archive + if (strcmp(current_filename, "TRAILER!!!") == 0) { + uart_puts("File not found\n"); + uart_puts("\n"); + return; + } + } + if (file_exist==0){ + uart_puts("Can't find :"); + uart_puts(filename); + uart_puts("Please check if the file name is correct!"); + } + +} \ No newline at end of file diff --git a/Lab2/src/link.ld b/Lab2/src/link.ld new file mode 100755 index 000000000..31993e853 --- /dev/null +++ b/Lab2/src/link.ld @@ -0,0 +1,18 @@ +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .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/Lab2/src/main.c b/Lab2/src/main.c new file mode 100755 index 000000000..87e2ad487 --- /dev/null +++ b/Lab2/src/main.c @@ -0,0 +1,15 @@ +#include "../include/uart.h" +#include "../include/shell.h" +#include "../include/my_stdlib.h" + +int main(){ + // set up serial console + uart_init(); + + initialize_heap(); + + // start shell + shell_start(); + + return 0; +} diff --git a/Lab2/src/my_stdlib.c b/Lab2/src/my_stdlib.c new file mode 100755 index 000000000..0129f586c --- /dev/null +++ b/Lab2/src/my_stdlib.c @@ -0,0 +1,35 @@ +#include "../include/my_stdlib.h" +#include "../include/my_stddef.h" +#include "../include/my_stdint.h" +#include "../include/uart.h" + + +static uintptr_t heap_index = (uintptr_t)HEAP_START; + +void* alignas(size_t alignment, void* ptr) { + uintptr_t ptr_value = (uintptr_t)ptr; + uintptr_t mask = alignment - 1; + return (void*)((ptr_value + mask) & ~mask); +} + +void initialize_heap() { + // Initialize heap index + heap_index = (uintptr_t)HEAP_START; + +} + +void *simple_malloc(size_t size) { + // Align size to multiple of 8 + size = (size + 7) & ~7; + + // Check if there's enough space in the heap + if (heap_index + size > (uintptr_t)HEAP_END) { + uart_puts("Error: Insufficient space in the heap\n"); + return NULL; // Out of memory + } + + // Allocate memory from the heap + void *ptr = (void *)heap_index; + heap_index += size; + return ptr; +} \ No newline at end of file diff --git a/Lab2/src/my_string.c b/Lab2/src/my_string.c new file mode 100755 index 000000000..8bfeecf8b --- /dev/null +++ b/Lab2/src/my_string.c @@ -0,0 +1,88 @@ +#include "../include/my_string.h" + + +void strset (char * s1, int c, int size ) +{ + int i; + + for ( i = 0; i < size; i ++) + s1[i] = c; +} + +int strlen ( char * s ) +{ + int i = 0; + while ( 1 ) + { + if ( *(s+i) == '\0' ) + break; + i++; + } + + return i; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (n-- > 0) { + if (*s1 != *s2) return *(unsigned char *)s1 - *(unsigned char *)s2; + if (*s1 == '\0') return 0; + s1++; + s2++; + } + return 0; +} + +// Custom strcmp function +int strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +// Custom itoa function +void itoa(int num, char *str, int base) { + int i = 0; + int is_negative = 0; + + if (num == 0) { + str[i++] = '0'; + str[i] = '\0'; + return; + } + + if (num < 0 && base == 10) { + is_negative = 1; + num = -num; + } + + while (num != 0) { + int rem = num % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + num = num / base; + } + + if (is_negative) str[i++] = '-'; + + str[i] = '\0'; + + int start = 0; + int end = i - 1; + while (start < end) { + char temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} + + +unsigned int hex_to_uint(char *hex) { + unsigned int result = 0; + for (int i = 0; i < 8; i++) { // Assuming each field contains 8 hexadecimal characters + result = (result << 4) | HEX_DIGIT_TO_INT(hex[i]); + } + return result; +} diff --git a/Lab2/src/shell.c b/Lab2/src/shell.c new file mode 100755 index 000000000..9df297e3f --- /dev/null +++ b/Lab2/src/shell.c @@ -0,0 +1,75 @@ +#include "../include/my_string.h" +#include "../include/shell.h" +#include "../include/uart.h" +#include "../include/command.h" + +void shell_start(void) { + int buffer_counter = 0; + char input_char; + char buffer[MAX_BUFFER_LEN]; + + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + + // Read input + while (1) { + input_char = uart_getc(); + command_controller(input_char, buffer, &buffer_counter); + } +} + +void command_controller(char c, char buffer[], int *counter) { + if (!(c < 128 && c >= 0)) { + uart_puts("Invalid character received\n"); + return; + } else if (c == LINE_FEED || c == CRRIAGE_RETURN) { + uart_send(c); + + buffer[*counter] = '\0'; + execute_command(buffer); + + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } else if (c == BACKSPACE) { ///not working + uart_puts("Error: Command not found\n"); + if (*counter > 0) { + uart_send('h'); + uart_send('\b'); // Send Backspace to move cursor back + uart_send(' '); // Send space to clear the character on the screen + uart_send('\b'); // Send Backspace again to move cursor back + (*counter)--; // Decrement counter to remove the last character from the buffer + } + }else { + uart_send(c); + + if (*counter < MAX_BUFFER_LEN) { + buffer[*counter] = c; + (*counter)++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } +} + +void execute_command(char *buffer) { + for (command_t *cmd = commands; cmd->command != NULL; cmd++) { + if (strcmp(buffer, cmd->command) == 0) { + cmd->handler(); + return; + } + } + + uart_puts("Error: Command not found\n"); + uart_puts("Try command: help\n"); +} \ No newline at end of file diff --git a/Lab2/src/start.S b/Lab2/src/start.S new file mode 100755 index 000000000..6fc2f03d8 --- /dev/null +++ b/Lab2/src/start.S @@ -0,0 +1,32 @@ +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, bss_init + // cpu id > 0, stop + +halt: + wfe + b halt + +// cpu id == 0 +bss_init: + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_memory: + cbz w2, jump_to_main + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_memory + +// jump to C code, should not return +jump_to_main: + bl main + // for failsafe, halt this core too + b halt diff --git a/Lab2/src/uart.c b/Lab2/src/uart.c new file mode 100755 index 000000000..17ff11d3d --- /dev/null +++ b/Lab2/src/uart.c @@ -0,0 +1,131 @@ +#include "../include/gpio.h" +#include "../include/uart.h" + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int reg; + + /* initialize UART */ + *AUX_ENABLE |= 1; /* enable mini UART */ + *AUX_MU_CNTL = 0; /* Disable transmitter and receiver during configuration. */ + + *AUX_MU_IER = 0; /* Disable interrupt */ + *AUX_MU_LCR = 3; /* Set the data size to 8 bit. */ + *AUX_MU_MCR = 0; /* Don’t need auto flow control. */ + *AUX_MU_BAUD = 270; /* 115200 baud */ + *AUX_MU_IIR = 6; /* No FIFO */ + // *AUX_MU_IIR = 0xc6; /* No FIFO */ + + /* map UART1 to GPIO pins */ + // GPFSEL1 register controls the function of GPIO pins + reg = *GPFSEL1; + reg &= ~((7<<12)|(7<<15)); /* address of gpio 14, 15 */ + reg |= (2<<12)|(2<<15); /* set to alt5 */ + + *GPFSEL1 = reg; + + // ensures that GPIO pins are not affected by internal resistors + *GPPUD = 0; /* Disable pull-up/down */ + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + *GPPUDCLK0 = (1<<14)|(1<<15); + + //Stabilizing the Signal to ensure Proper Configuration + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + // ensures that GPIO pins are returned to a neutral state + *GPPUDCLK0 = 0; /* flush GPIO setup */ + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver. + *AUX_MU_IER = 3; // Enable the interrupt. +} + +/** + * Send a character + */ +void uart_send(unsigned int c) +{ + /* Wait until UART transmitter is ready to accept new data. */ + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + /* write the character to the buffer */ + *AUX_MU_IO = c; + + // ensure proper line termination + if ( c == '\n' ) + { + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + *AUX_MU_IO = '\r'; + } +} + + +/** + * 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 the data*/ + r = ( char )( *AUX_MU_IO ); + + /* convert carrige return to newline */ + //standardize newline characters across different systems. + return r == '\r' ? '\n' : r; +} + +/** + * Display a string + */ +void uart_puts(const char *s) +{ + while( *s ) + { + + uart_send(*s++); + + } +} + +/** + * 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_send(n); + } +} From ec5db14545a5489b8495bbd8cb6f46b6e372b251 Mon Sep 17 00:00:00 2001 From: hsu Date: Thu, 27 Jun 2024 19:40:57 +0800 Subject: [PATCH 2/2] sadasdad --- demo/Makefile | 37 +++ demo/bash_send_kernel.sh | 25 ++ demo/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 34228 bytes demo/build/allocator.o | Bin 0 -> 52112 bytes demo/build/command.o | Bin 0 -> 31720 bytes demo/build/cpio_parser.o | Bin 0 -> 17816 bytes demo/build/dtb.o | Bin 0 -> 12496 bytes demo/build/exception.o | Bin 0 -> 17688 bytes demo/build/kernel8.elf | Bin 0 -> 182752 bytes demo/build/main.o | Bin 0 -> 7048 bytes demo/build/my_stdlib.o | Bin 0 -> 6688 bytes demo/build/my_string.o | Bin 0 -> 16712 bytes demo/build/shell.o | Bin 0 -> 13944 bytes demo/build/start.o | Bin 0 -> 8304 bytes demo/build/task.o | Bin 0 -> 9632 bytes demo/build/timer.o | Bin 0 -> 13496 bytes demo/build/uart.o | Bin 0 -> 18696 bytes demo/create_initramfs.sh | 2 + demo/include/allocator.h | 73 +++++ demo/include/command.h | 45 +++ demo/include/cpio_parser.h | 29 ++ demo/include/dtb.h | 36 +++ demo/include/exception.h | 22 ++ demo/include/gpio.h | 25 ++ demo/include/my_stddef.h | 8 + demo/include/my_stdint.h | 23 ++ demo/include/my_stdio.h | 6 + demo/include/my_stdlib.h | 31 ++ demo/include/my_string.h | 21 ++ demo/include/shell.h | 18 ++ demo/include/task.h | 32 ++ demo/include/timer.h | 30 ++ demo/include/uart.h | 63 ++++ demo/initramfs.cpio | Bin 0 -> 1024 bytes demo/kernel8.img | Bin 0 -> 24952 bytes demo/rootfs/file1.txt | 1 + demo/rootfs/file2.txt | 1 + demo/rootfs/userprogram.img | Bin 0 -> 24 bytes demo/src/allocator.c | 489 +++++++++++++++++++++++++++++ demo/src/command.c | 256 +++++++++++++++ demo/src/cpio_parser.c | 165 ++++++++++ demo/src/dtb.c | 137 ++++++++ demo/src/exception.c | 242 ++++++++++++++ demo/src/link.ld | 18 ++ demo/src/main.c | 38 +++ demo/src/my_stdlib.c | 38 +++ demo/src/my_string.c | 271 ++++++++++++++++ demo/src/shell.c | 103 ++++++ demo/src/start.S | 184 +++++++++++ demo/src/task.c | 110 +++++++ demo/src/timer.c | 154 +++++++++ demo/src/uart.c | 307 ++++++++++++++++++ demo/user_program/asm2img.sh | 3 + demo/user_program/user_program.S | 11 + demo/user_program/user_program.elf | Bin 0 -> 864 bytes demo/user_program/user_program.o | Bin 0 -> 736 bytes 56 files changed, 3054 insertions(+) create mode 100755 demo/Makefile create mode 100755 demo/bash_send_kernel.sh create mode 100755 demo/bcm2710-rpi-3-b-plus.dtb create mode 100755 demo/build/allocator.o create mode 100755 demo/build/command.o create mode 100755 demo/build/cpio_parser.o create mode 100755 demo/build/dtb.o create mode 100755 demo/build/exception.o create mode 100755 demo/build/kernel8.elf create mode 100755 demo/build/main.o create mode 100755 demo/build/my_stdlib.o create mode 100755 demo/build/my_string.o create mode 100755 demo/build/shell.o create mode 100755 demo/build/start.o create mode 100755 demo/build/task.o create mode 100755 demo/build/timer.o create mode 100755 demo/build/uart.o create mode 100755 demo/create_initramfs.sh create mode 100755 demo/include/allocator.h create mode 100755 demo/include/command.h create mode 100755 demo/include/cpio_parser.h create mode 100755 demo/include/dtb.h create mode 100755 demo/include/exception.h create mode 100755 demo/include/gpio.h create mode 100755 demo/include/my_stddef.h create mode 100755 demo/include/my_stdint.h create mode 100755 demo/include/my_stdio.h create mode 100755 demo/include/my_stdlib.h create mode 100755 demo/include/my_string.h create mode 100755 demo/include/shell.h create mode 100755 demo/include/task.h create mode 100755 demo/include/timer.h create mode 100755 demo/include/uart.h create mode 100755 demo/initramfs.cpio create mode 100755 demo/kernel8.img create mode 100755 demo/rootfs/file1.txt create mode 100755 demo/rootfs/file2.txt create mode 100755 demo/rootfs/userprogram.img create mode 100755 demo/src/allocator.c create mode 100755 demo/src/command.c create mode 100755 demo/src/cpio_parser.c create mode 100755 demo/src/dtb.c create mode 100755 demo/src/exception.c create mode 100755 demo/src/link.ld create mode 100755 demo/src/main.c create mode 100755 demo/src/my_stdlib.c create mode 100755 demo/src/my_string.c create mode 100755 demo/src/shell.c create mode 100755 demo/src/start.S create mode 100755 demo/src/task.c create mode 100755 demo/src/timer.c create mode 100755 demo/src/uart.c create mode 100755 demo/user_program/asm2img.sh create mode 100755 demo/user_program/user_program.S create mode 100755 demo/user_program/user_program.elf create mode 100755 demo/user_program/user_program.o diff --git a/demo/Makefile b/demo/Makefile new file mode 100755 index 000000000..631bbefab --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,37 @@ +ARMGNU = aarch64-linux-gnu + +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -Iinclude -mgeneral-regs-only -g +ASMFLAGS = -Iinclude +QEMUFLAGS = -M raspi3b -display none -serial null -serial pty + +BUILD_DIR = build +SRC_DIR = src + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%.o) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMFLAGS) -c $< -o $@ + +all: clean kernel8.img + +kernel8.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +clean: + rm -rf $(BUILD_DIR) *.img *.elf *.o + +qemu: clean kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +qemu_asm: clean kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -display none -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -d in_asm + diff --git a/demo/bash_send_kernel.sh b/demo/bash_send_kernel.sh new file mode 100755 index 000000000..5eb4ea73d --- /dev/null +++ b/demo/bash_send_kernel.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +## rapspi -> bash send_kernel.sh +## qemu -> bash send_kernel.sh i + +## Construct the device path +if [ $# -eq 0 ]; then + device="/dev/ttyUSB0" +else + index="$1" + device="/dev/pts/$index" +fi + +# Check if the device file exists +if [ ! -c "$device" ]; then + echo "Device not found: $device" + exit 1 +fi + +# Change permissions of the device file +echo chmod a+rw "$device" +sudo chmod a+rw "$device" + +# Execute send_kernel.py with the appropriate argument +python3 send_kernel.py $1 diff --git a/demo/bcm2710-rpi-3-b-plus.dtb b/demo/bcm2710-rpi-3-b-plus.dtb new file mode 100755 index 0000000000000000000000000000000000000000..60c45b9dc55470b5b5832d5743558b41435350ea GIT binary patch literal 34228 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 E0-3db>;M1& literal 0 HcmV?d00001 diff --git a/demo/build/allocator.o b/demo/build/allocator.o new file mode 100755 index 0000000000000000000000000000000000000000..031a2b3fbfe2deebd0ce6875758e8a92465d7c59 GIT binary patch literal 52112 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 literal 0 HcmV?d00001 diff --git a/demo/build/command.o b/demo/build/command.o new file mode 100755 index 0000000000000000000000000000000000000000..292844dea05c63bc89bc31a689a4d8d4c68f8b9a GIT binary patch literal 31720 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 literal 0 HcmV?d00001 diff --git a/demo/build/cpio_parser.o b/demo/build/cpio_parser.o new file mode 100755 index 0000000000000000000000000000000000000000..dd2776174c6fbaa31cf6f75ab20d0403632d219c GIT binary patch literal 17816 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 z zeC`w+epQQKmk18OfG;)lnCsXEOAqokY3TtzSV0d?=U@-!YmcP|_}&V7aDWRvgW}f# zOAqja74%@|!*BV_T}{2{W1N3}#=ooNf*(i$e^YSGDR3MV<3~085=W*q(8K!&E-Y{E zf;u%E;5_ar;V-oCZsB_@{1M@=v2gmiP*85O@OffX+QPHKZ?SN!YdbCc1Bt_43-1^H zI~G15{80;^D)u~K;qM8LJv`$4b-{mO$uAK-uUq(DvGW}Z|DN!5(hmL43P0Jx|4R6n zh5tnKTxj951z%<1TLr($!XFd7&%#~dZ?tgaAMU5H|6fJVm?i(1@H?bNeqvvV(@y9) zD01I5^zd)SIY+ttz``}E)FTGYvTLN_?+u*w92fj43qL0KPc8gM!vD;|VfU{LoX7nK z;a@j!9`{YjlQ%8=mxBL?f%BR$Dm-3CBR*oL`pA%H{aANCvGA|UdW1y*dcG}+>STPz zSx>%7H#AxJsNgLI&i-B@{2T*kJ;y|TzJ(tZ9QS?LvqC7Jfqb`z-tw;s4gc&j|mlh1W}*-?DID@Tkc=vkx1)jwJCF}cD1i-pe?{ACM2EBI>`{_ldHG;q%I zm&LFDGH||5kBdF@zg$6qodPRI@|1D*cbiPGXW?nVYYm*o#dXTZHC&+QV%bErS@;El z&o*%LI$dPoY|l=S@38Q%3VyzUvmRWh%M6_Lyesl6E&P<=`oCMW{j3M;WS=G9%gU(S zVBu>8{}aJ+9o;7LGGO6@f^WC*t%85w!uJdQoP{42{68)HNx>&bp2D8z1wYTiv7cFP z;7sCrUuWQaJy!D4t~|ZncP7iF83KY%i|bxpM~T3=lcfEB-VjP z4V?Ahe(OAR89$w>*Zbzt9LAUfmKAVOUPqAX)th3k*6e2CRz9~ z!RK0dhJHTHWub-NEckf_j=eg|FE((_XB7PN3$D|Ibh_M-XH#wxe3gN-9$fEN8#v2< zDDu}@_joIYT zT)&$QJjiod2ktU(mdEwGTX5uayXfCj0pDlg5@xl(0)EiK&xrm*74TygeznLyS^UM3BCL9=0{(l6E99}?m?`oewTmeMf^`TuV zkQ>t&q;d{@7`KMeN?E`vENhl862m(Gul@O)g>{}!pQ0lBf#XGB!G74m>nCVa^tkkY zMy?mM*|ICBfknAC%ZA0m$q^REk3(t4ua7WWC->YX_YJ)NW{it1%kNcejO9+t0`w{t zA_l40vLj_Mmiq-K29-`-h2M7n+o`3j|Cj47=+FN1eaZI!YlPW4xu+uw#_y~~iw*uc z-^RHAdwgI=1^aK!m5#NC8p_$fw~YN9O51*ZpT*UGQo@n|9x|06<_)@ZV5Y{e%`x4P+vD^vXt62^cX99F{EU_1^2xpA=L^=fw|ZIE{5 z-4zxAV{nLT2Pc6b+i^#ZXhUZVO($exPfU}x1Urq}*d5Q<#z|{3B+WE!oSC)*sbOrQ zo^#(hZ|`2MlK%LoccgdE`R+O2J@?%E?t6Q8AKiS{?H7{O5L^Gh-K8Z1WxbzrOFgr>>jg*tNyt+BH+0{vctVx@sDy#a|rS5jLY|&;9jZ z<~9nk`;cGs{^mZYZopz*@zD2wJJoy1tUnE* zjvHQ4d+2=lNVrNI3tu_#m0v(Swuqj^*juW^Lt&rjJ?@R3eWpVk`?)#yH2USC|Eog0 zc*q|;`%h+QMHp-*_Yede}Mywd?zS@B-!!b%^ySVo)DL9P0X5t9a-^7z_GgJNja~ z>W_9#f5z$WPE9pj-}hIiF2NXK9*^Q&guxzjd)f5Jd>j;F4f0*zcV6}#_e9UugDvtS zH;(m?M_?S|2cZpX?jL>72L8cCh^?7D@u76mzWugddpJIjPS}~z;l5O^5*wl1li8ig zKAf=&+1;rOfJ5ob=-8@sCSAxS+wz5YuHe{hMI=7lpSLAw$CJriDxbf_?iiB>mEuLO z5by`ZFBfQ)l$Faz5_SNO;X}dWv9L0|RytD<9>3Hii6_u}4;mPLH1K$4Vdb<`H)j#@ zO333^TI%LMi7gI9t`?@u=f~?Tza%pof)k)Qa-)=e{$~NHfPb;vTj}2ck;(*l1HlA> zj#4ERucK5;#qTIVsZ=@2Y^l^ZN{v+N9i>((jgC?$l?9Fxl8Wsp^-^hdhU;ypc>u!k z`IB%B9DqyJ_aGwYBGr#!gg*aaXsQmL1ljP;sxT465&jqTF$6BPL#Yff_sWO}tmDQ%gxR|lItUrt&C5nl$ml5sDO{`L zV0FJ^r8LW>j6{>rJck+47T6R!;f!sSJ2p%T7Gq*97}xeE3&L2{^d}A|ug=(3wc(s| zfo&69+8WV^i-X-Hr=}EJTL!y1xM7;_EdgA1TpC7%v7yAO5u4_Lo6}Wyom_fkFB^Xg zv+6W%X;SAxHvTI#HpmIMcb@9$IP5CHnvm7_bTg7T?eS)HBIi-Bm|o9exbE;g4%eNY z&q2d{Zu~Qd)iLYjYefbn*Qu&>Y;9y5fe@mM#I*F%HA2AE05=IQPx)aI(gA(jTfbmqo@aZdxX zHmMG&SKOJEY0E;Wdz$NS?ettviM+$ zA!`SVhAci&V#pc~&k$)f*m5!tpu-(N4~rYz?gm-pkZ}rn+yUHGG-Q!Ob_`kDUo>Qq zLv{>VD-M7k!sTL@m`yF5_W$=Y;1L@rI~F(OZtF$|XXHi9kjotjZ8MVcbj6@LU^WVEVibOrN0v^3$sONncNM?h{Xn&x=Kq z%vsQIotW)4S|Qy`Q-uw~G-tu(J&+yj}n0)k}QrBWQxQ4Cs{dJv}5rb z1XYO{ zSX|>m$p=XsDnk0gFhmc9sZ{W0EJjG*PxTU*N4^`RM0W$qa5u;b?gpOeum8{7^hp1k zy-_D_MdK6`gj}K;)+LKPVX(8YXirbi(IP|?Zsig0k<9)}M8V6ckrJf_Wk`*z%4`(A zazyUdRX~Y}oUIF?ayt%wqSRx8hd+nM3&Rlo?jXtt{CW$CVbM=!_&AyVE`!eqTq*P+ zS4w#Kh-bk?96?`EPf?F*VGubAEufght!Q*O=$i8U;BUR z_w=XlJ2Q=s?{zm&5`F;5HwB){c#RK()v#g9EgO0@^0|b7|Mp0vJ)KDmjV4oyICG0) zq==fm5XnMcBq5-m;k~hZAqj^nkwIJu@u8t?B3{VmK!ryNnhoOdf;7veGXoAj3dcQ; zgRmBh3TFwyD9pu%WrZxmH`lh-`8J}w&R1($zPrs)1H>lFzuLAz?=nXWv(_-PhFNb| zExxF=a)lMdmaw(d2PD2lAu9m2IcQkTKC{uV0=8A-Gdu2_YlVEl)`%7GnRk&vi!^Aq z(Wb%&AKQ?~Oc+*$xzLzvRRLkOuRUbdNud+^n{Cautrd%{b{mCipIK>JA;T9zzfTy@ zgV||Vwdga)td{y78^lU`16o9(&0J%IWT56Y)YcmHbLUv~J_F3c);e>{wjiE4%Yme` z9{6gk$Rg`T=)|^t=8)FYoj90*>4S;bmSJwRVK@~&^QA{4kXZ9aa7I%B3O4;nK+7~4 zvh*r6V06{^c^2GSfuec=VCDlLeadI9fDDB|sI@BEtxvUB6=ApnS=jOe@lx#Y21x$b zA2om_WM0IM!d7z|;O*gdh@;-BSZEoG;Ogstlc}88lgj1O*^C&9=L@k!c6cPl zNPaMzE7*8=SI8FPL;3V)QvwbgM^hpbA5LZa`vv^RhEv0_Tz=1Rd_;_b?fO_j)+2=+ zNO(6m>vkxc8L;IA3DGfGfMuK;O%z05HVa*kjHZ*Zk-@!r0Vg>ziY_sd&c^UO5@LWu zOxXlyl^CKEhC&5PJufgyqL%t-CZ8V2q>^@GFrI_fqFju~wZYJE5I3&IQLrbXBf0E| z>^uRtTVFh}8wV%zQ(|_<-S^m=I@j5q9g)?MPJ4C7>dubN&JMe6cp#NY<>Etaxzs?u zEt?tI3)oP)P#8+Jr83EMJOg^XFMaFK$l5h_+koBniPd&ne}68Of-_k#fb6yP$MbtL ziNRbplO4^sjbXMjYew+-0TVi-b z4mE}|j69e_B9bS}qCJ~WrrVRL;Vh;D6P3lO6S%#=q>VYk$Y>!iO8IFTX9-heLPL)wcEqJ#o&STSHr~@!1{1JGRi6U)3UyG8+l!2PQu1@bQR6K6bi- z+n=xeT1EGBp6+M8Up4P|#(LU!+xV>G{=IL%)pg;WO+UT(lXrg{6kvwU&w0>za}hl5 zAD{KK?-{GuxT*5(x4JL9a~sU=H}y`abt7kPcOdpHgpiU z%Ms9E=7LWyulSFtauz1;{AG%Xdw!W>Iw#B}E%5OI%1k`+e7?k9o>+^SaDH7Wae-*u z^VyOH(>aqb!B8=slld~Z)4SeaiYgtFx+$t>z~!;=v^G=JPQ#oY>zprFv{titj9t=V zI)~~d7)Da3zQATmI2O~N)(v^Ur#*zN+s7FVB2P}-!TJzAK;)HpRmS zG$Fv%)z(W(dya#gTbe;*aXCB-Wu$RA=E0*dxT@ZY91~T-mKaGLa}$hHGsZJq$1^XMM z7hr(H*8pze`C*1p<*6z_%FX?PdJg@wn*{WcJu zbDCWqoAA9F&Rfs{4c|pNe-vc?|0JH{n*HAs{-+ww`nNRPPsx5o!~cl%H#NM2>@RBg zO45I&;rmJFkJ=pn4+-~Dyo_%myjH`V=OKI>q2c_*SgGM(ARayrWc~|;Z`SO8N%~F= zUrqX#smArWfH<)FV+D7=kOLflRDgy1jZ@yfrPw1hPCD-=Y=2&Q3-Ol117A?Nd&IjM zPUeF54d!VhJ02h6$isPlU*oxzi2hx{F~>I%{-J^+&vS%NY5123pH1WDe(T6Cq~Srr z8wuxq;6=jMC^+s#eE)x3!BOP>ai@Z-`|zg~9L0Yj{?BOmM}+TFaOB~A@^QjB&o4n6 zmM<#yDAq_+h;J(Pn78|g|JxeAjqsNh9P?iw{S^gAo&}`;P{XT8e_g@(Ucr#wRdD3F zNcul&_#32OQgGzq`}%zaN1mhfiu-RG{w2b%C^+))J}{-=$nz7j=aY9{KkpLmr<(Ks z50tl%f+NpTdZ;#NxJ~#11;=<6Q5?$@9C=2`ex-(I3BOsxuMvK$hQC30w}Pv0!`l=b z(9>qz(6B4WA%~ji^@$gSpPAWLsZzG-;G<+-Jf3D!j!~4it4d;FARRu@> zXNc!D4gU(^ZxGJ=5`Ts9D-AyhTv(oE;~o$x0V9P?RAWKYe2k8AiR$^NS|;3qWvZn8f) z1O5#S=jY;?8F0=O<_Ayzx$u6>^T_yXBn-3>^U2R2#+mmd@i5NMcM-|&9ftEC zs0%r#9%Lz(8j42>sj-5HB;$p+i1g+2B9hCZg65r(^`N3rGSxRa5KCwJvtTOacwb*G zwTCr0MJln3=i-?GIB_Cl))X%IoneZbp(_!AW5wYVoT5cC*+MD;hh+HcLpYmq0!R(U z`r+q?DNft}y0*a+mpIQ86Gchj=P%=&U)J$m3#UHH0M&N0Bk+4bJ*e0ZEo;H&P)iA? z+thJ_>jrg_U3B_M44z#fr|usme?4CApD8;*z_?a3KsEb+M#I@3eXwkXf0iXcm($e$ z%XD9Gn{FG0hI086Esn>TN~gyB;T&=QoWCBxbWZf>qvyllX^omH@N<-oq5mqnSu50= zwv27I42J$U)#0`He&}e^`@;N|8~+*lz{&SFjvrH@j~_p$m5V<`{cqPAHC6sFSjT`; zyaYeM!t%G;I@E3P^I*C7FH!tFPZ&QwpY`~k2MjrRoFK|_fDUgSnW2A<;{~uT=l>yf zyqx&BVn43&b12JfgY{xQ2v9+gb=$uoObb&iC;vA!e;z->-v^;w{;pE~wvZv_52uv< zIjqSZ|=Rnd+zU?d+vSr-gnMjOG{>V&$UIbi18w7v*BSxF_%a zV>NF+_JJkZpE-FhXRb$xtx$if7cLX74$*!__(29@3*@cqw9SN6^kL#zmS7Vo#jqF0kX5=6Y)c<{W$^LVo|D&5b_J4T&;{9jW9o~n&KD+LD*X9%skwy?i~?XAZzfva?R>+u^q zTGMPhbZ^I}+I7+l&I~$!*^%^!ZIFLlZ^ucqY$jr3mzAcKq5ar4^x@fcKgjSOwnyZT z9NW;o>zI*y|1tE1=j3A_;207xhOURJ1+GJef3D+W7;}(c3f(oh#pH-vD{qg=}pB0M5tW^J+Xd(|3V5qh1NaU>m)C%>cq6w>KU?7#8 z?-W?cXt)7{mkcEm(Rj*=4u_+Iss4eu6^q^xjggcP%$FQYCc2`r=J{6BFftcVK{S>I zi>M;jo+|{*TM+#A6qs+Pm7gZ3)J8mBn0AEl_?^gr8xnGc&yGA2BhxGU<0%laa~=}$ z*cEIhPeD~Z$T{i4s!fn4KD)*Yv#|IVfZ3d8Q3a+cQ*3AaPRY3Z|AB&HCsPu52Qn2- zCRl--mdNpc4Prl*LW^XK?aLTsxxOFdW|fJ>O;#|NPCIsOkJ<5=M>DDDQxX7m=8 zV45;TcE+*7TdY{&9j92~Ey?YKDrm(xsB5eA20fV0@%O@S{$)_S84?98kT~ZUBBvD$ z17sT|rz`1;@{!HKXDaE7N7F{0oh}49VZ3M?j>#wS2ZFKtIgb!UcJd|LLpBUQ#o?iZ zFpdP#1sq^Wa)NC*B-`D}M~m#S#R4TS*@M8zx(r;+_=zkzI+g%q#(NTGA}8d)Q2Z9? zDK$ECVHu@R#tAG=FM_2Qg7L81*n=c%?DhkJ)7VGy(9;~sF;N^A#$$ylEQo5GOT~>e zc3%oqSYuaCS`A0{-EM^lsW5goK0orsmG1oive>QI5!Y;blJazRj62Te?N@4 zxzkk4ZE7)9e%x^cRg?a{2?{KO6vQyvtnW*1$sRy%D|7tAiCe7-J>g@{m8r(iDo{1T^s4*lbQM1H6 zaAfuj-8kj$kQkkCP?h8B%78jpi(x$yM&-D4EQ#3obSwtYBo%V|6Z+i_C){CIm9Gkp z_B>1C669DjInA0($yu&s^?4+3bS164H0@)!c|w+%knJ-X(`UkO19#dW9KCPxCjM8a z*nh9c{Y_o&si~u-I8UC+UKxvXpl8y#-Lai9LCkVwJsXu<4>_*N;Be;^uV~fQ zWug1Vr_+6xs%;WNpP$e&cyfYZjPn^zBHw3Jse>A7+rijfrQQIe@MIDYve`G9o->;E zPRMm}??gG8p6mm?#?-=Kz$~0pIL;`^DTYPHQzrs}g#f|sf|8)jJ6@QD^8=R!E)84> z-jYGXEDQu3zyQEkpp>`5a-UNKG$`sXGp0{Kkz6S-pN9poBWO`7ESj(Yx-s7{t_-4N zK@CVYf>2?Dv1kJ8ojw6gY_HhWVbc|<1fKHmb%5=~fce=i!_%S>(3ORuKdja%@I7~GvTqbx})WZb{32_V6T%imX7-B~TQ*Wl* zFTf^oAvVEN|M_i#Cce2U_CDYj_H)lsb1KLEHX zeh#qL_+w##Fd#q%E+d%;3%D8^8XEiK;n+|l`sXD7+^X5-g>X+=8sNcCh&5}wlBo!s zYc%xXSg;RqAPFr_g_5hC)KDma#n@_DDRNzJn_CS-$}(BvGvr0W<28H@GJvrmOYE%S zWG(6OO_5c;GFe?CYpP{!jjXDcWmU4ePL@^5s#02aasq_S8p|44n)XIuUveeAAWQBRBB}=Bt!YWxhUFP^O zTLCONmdy1nlnsz9Y=C4A>J;3%BTxm;hJEQJCPk^zXNuSHIP*pKzDl8umr zZO%%_m_rt211n`6v{nX#5EskfLa4P6)MM@0(r5nQ%aAHHp9AZQ48yYVQkiGS7N1%4 zd09{;TWaNG^R5M8OHGsX)6Kzk5XL$*j3E%G@g1Z6Q>Q`QEqtd-#MnzpuJjl2Z( z8*TEEYH8GfyUh*jKaU_>=+h!7mC#AK5PQH=UWiR-aygDEAC3YuZ-HzBw0eqcn{5Bi0(6S3 z1`PTIWUyt(f_+mbVOK7TeKTYbVlWHZ>@y!&59w0#Z2{xdR|a0FLgE`OB54E9n-!Lv z164rH99zvCRI^Y~13dXgRx%jU=c_(`%*q}EW~XpG)zzDb-Yy0c{R4^q)LJnF6T#e; zu9Qgj4J1+)9(Uq2Ao>%xcexWsS6?U|iA56v4`uCgr^226@!o+k#9{;SRhIpOe0PGP zXjjirZ!a(;qM=Ave>@T$?n;IFV}tjtsVgF#`$Ax;l8(khJ+UZgg)`~I&|pf8+UHh6L(vy=W<%4` zP{$6pvTH%4KdI5$HYP@GbX=N7cEuNNu$DB>vznV4W;Zljvzul&H#IjmS@mmHMdQ&# zC{~|{u1eMq#A9m#i}j~cv1olX9_bIoAs_1LZ;K7iZL#WCS@qY>w(5JKGo#5A^iDr` zyuLS-TpJJfB?jUHL&^G~IP_1XK802$h3%Di^iJEskx(k+cp=R?T(8_tht*=~a5TIE zMnjVN-0l%@5BA02Pzp!~hq`d2;9?iDcbuA(!qlcY2pSXguJ#>BP@EUOnFN`fIQJv`|0- z+T(r5?AY$vVcg)zpf28W@x~3Y11JxHu^Es)ga8E6-?Yc~kX*9eyTjb+*=6*-{@U?Z zQL7LwaJ`Fy5bTprRqt(ij^f3EG` zm+!Hk5#FugZxhasDr~10>_)x(NWyO!CIUWIduL|B=Vrn2IA<)Lv~7Rgu&9eT)2FgN z>1(k%quPtJI*F#O;`(Z=*2K9u+nPyhI!^G)B9djb#}y%C>CRkrVU^9c4;gzCqc1J$ z&LeYMF}emq2SZ?A&jY`gI*|R#X~f-AT`1vo19AH`8`ZJTb|H;8oE5skqExHKk8?W) z#8v)Q2exsQ|8oki@{bUXdfkI^z&0tk%D-8`Ri3Scqdh7QuT#36dlh+==aho0JiIpP zJPSY{2DIOOlLPs7!cktu4-g)N*k{*tehv~|rr}Q#J_%y(BdqZ>;mpJR`Yhqh!}y^r zJRfU3mSc|ilg7h1KBHsM?cw7}#N7jYkSiv6wv)$4DdB7<;}u!>D>WW&m!zNc5DoU2Q{8{8x>-A7M@2GTy5_@!kNFDcn)a%j2~2Z)c$=^+d9H?Yi?rQ0@2nBW=a_pS#=tve#;bW; zI>qp1mm|N9a9(Thz?L9e@*+iE-K{q%IO?5Fdgp0)0g)}#@IR9LQVstt<*(LoUc+wE z@Kux#Y4|TG&+`+vH%@wSe~p3h$%LD~nh_7mR4#{uP@O!Dff2-l!2!B+=d7gSg z!+%Bchcw(z_`hrT-%$RvhF?nZu;sP`xA*S|FVS$m2dXuk?VqLLZ2zSi&h{_UaJK(? z4d*AyRT|FY<30`lE!n?Q!-uH--_r06gnviFdA)f?!@o%UKh*HY34d9`TPS~mV!n^~ zIqf}7zK3}Jpy2pPC&A(q4JY$OAqikVqCDT9B^u8CSWY&WWjqi{3yu}WWhITIPW`ozl3^uZbX9~*5nTp{}T$1@;paB zPdMKf-?v*O#19pDOpXxF#?vZz7!c70APLI2L`P$$y*VJ+vNi zzwalUzouk+Zlm@VlRWnei3@%O$UMiWfL{qR{u9FID|&I9JVy9pji1jER%-G*&ch0h z{wXCpS7|uUM==FQy&UdTaOB~6XPt)Q{s;r_bFf|L=S~|H;yy)Q9sfHN9QoOw4{G== z#QzZC?B~;jKcUF0{Ld>m@^2*h7c~4H!jEYDUK$^-DL9U23oZ=qrvp$QMfv%M_cLr~ zCGq6aegkpjX+;tUK?O(A86?lIep#OHqehbFaX8av5n`^!!{zYF_qz`%^7gnT`TYux z_N*rSI~v|k_;)pa-Uq*=;OhSQWd%oyXK8%Aq2YsspC+99ix-}A3XXPeC3{Q>83;T- z{1xHO-vYo3e()ngTZq4kt?%5Nq4`5JzR@M{&lsy}a1aJ2I&vgbAp=XpP@ z@$pk;ArPB$j)apoS$Q#*ZBE4;S~kvdk*Nt zuN54rE$YA18qW9KS;EmyoDUBo34~m{`5|yW@~0prgtPofTMGJAljre2UBlTwEgH_B z*mNlT*uPg3|CO5jAo;CZlW!;a)e4S&K1cEc8h)1W^%~Cp*{I=DsDHO>_?3h|py5{# z{-}n>d7NlCuXBG-IQxGS*?CxzNB{6X?LQP8+q<3kU(xVwg#TRQ-%R}ftH`VTXA~Uy zdHy-8;r~edCVZ8Qf$iTy{1t@reZltEDme1l(h7{PVDaqifrV|A2y{=suGFk%sd* z-5UyyJl(|ewt^$YA>#Q&!BL){ll^|DBKIRdAC+l1&sX&t{wDEvC^+(uIJDww1xL|$ zNj{?Ce7<(Kh6@@G+Y}u6`JC;W3Xar%l7B+OxxbDO&g1iH+7G;};lCsMU)Oj#$^MTt zyqj=8J=ik;GQ#t-;H4VAi{vY^;FgAelkBX^g3r?MACY`h7Q9u%8_AvpS#azN4A@?B ziJdRDe@EvB%8FB2a6a>tz(Xo+$tIF#e1!6sYdAl54{JC-r|i~n?nhn^nVxgJbu3ZD)nn0XNIB_4R646+wA%)*(G}vFBH1s5sq9HMW85D1BXoV~aMWQ`J ztKdtW-T@G`)1jUo{6>Uwv4L=!WGE4euY#{zsF-sKm;G@O6@x0#5FS{w2L1q5G{gr| z(FXV+ryf3_fiFfJ1EPKKfmCQslv?@OBMYkHt;OSmnc6AA`vJyzyl@`R|GaRuGeGfR zt&`}Z`3&DXq8=W5yjPk=I86smCHUp%0T-YIa;RYzWRUZ-)^CQo$T=G>HL!jjk6gy~ zvmHyJfYU64aX#(mE~opE%XHaxC>YCsCuTY|_R&En`Vaev^|Sx315D?{nw_}lLf~^5 zCzmOU=S5@H_ftntMdOs9%ML)9j-hxxy=ZPy>S9ut{UTsvwST0|smS$_4)+Us`@amB z&WSZ|CHg)dJ_H+Gz zfy7w;JJRMz93nyVAKnUFpZ$vV=(@4WAiXT)_h8ta_#CO%$J literal 0 HcmV?d00001 diff --git a/demo/build/kernel8.elf b/demo/build/kernel8.elf new file mode 100755 index 0000000000000000000000000000000000000000..86bf4b39d3bd175745de003001c2952846231298 GIT binary patch literal 182752 zcmeFadwf;J)i*wSpG!{emy?9#B#@mDZjnHc00FU_gu7P=v05)BAqj%qlb}(l93Wa0 z+j2@2)F?rzlGOI06lZ0fHcE0V z9cDQp%xhznS*+_utGFpQ^Mi&OuSNPFT$BC>GLDFYfP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8fP;X8 zfP;X8fP;X8fP;X8fP=vQJpzAsiS{j`Rc&OIVywGhP%aF~u0QxK*Kd5w^^0%0{02HRj~m}dw7FYMj( z|Il7TgboXHfn>|!4+wx^k1=?^Rr^v)0$1O&LbWxFyw&tPkiAHC@ zvm&^msWaHUdY`c_m>uk%0GU?Qmm9Y`kPCf6XzPeylh3nml`q(FKE2DO74W?3?CsCC z5knni&bmanKXiUNOKUsj5(WRhPH(G%ZbRtnHhaa0D(Ii%3w0Q&`Z_=C7>#t)m0Iv` zw5`kKFF4%OvvF76>j76>u%q59l2;|{3gqqAvt|pitkPFHZWYR}943}kq0MHQwDwPD zmA3u+y0W&jx9{FYdkxs)0mjkjpTW>CV2`&;grf`*cC`jOIvZVO?z@s#2@@=pBM8)UTuC`m;V%hN+*dWBo z5+N?_Uf^yE;Qj$4J$&u%^e{0ben(wd1zoN_1vk4gVt)*La)kKT8Q@jv|L$$=Zc#A` z_J4}}DabvY_eOwisZR)YuhhlALMh+9?H-q?s7?rWH0x=xD}7=_Zck6eEeWEd%az%_ z+2#MJ6>a)BMl@GK=Brr56<47B1oJ7ujxUfGut{{Khu`~G>2ZY}P&0g25 zXL>4hV1Y52Qf9mn$XIzzEO7`WqP``;jvn2_B4efIFHH*G_H*F;xmV1530NKlK3y(X z!BuD@+b5tymUCsde_1~n{ri&aU(&5U|Gau)Tla!VZC@vs4Id!?By^v>{h78>;KcsX zlY$+@mYC76f@dZq6KAn~b%6asJjIGQzaKHHF(%mYR9FPFi$h}@-H`yScmT=?`c;KSHKUmF0QejNTBf}iCGeL*$!b~aY;>=dU* zSHo9V(pRAuSRJ6h=A%tN+t+{HD#)L`{SR$}&>nBx^8w;U?i- z_e0ot3ED%9eue7=NV3mGpKulWd=7krcv|=oJ7V^tS2QoO`OJ5f&#bd(@R^y4_GxUe z`|RzzWczZ&jAhf%h8JaDJ=Z4d3iS!ozR8ehJI>zzyp%nA`|oAEA&>pWIAExl!~WBz z1-rZZi|#GD_R+{Q6TN3P)f5D-zdN#8EPooU&{|vPA+i)M+puy)Ezl_R^ z@Bq}`tX9#N47`}-h0t!IWmpOYCbK|OfxkU9rr{Fv+Xm|VzKAqM;twsfIhL3`by z@|R`aUvNg++^79RnNKY^jXZobnf7;rX4;xs;O~DhFdz2T>*<$Zl4?H+JUJF>K%?*E zqHV;EcI6^A6r*0de|Pt%54^B#!&kk}DmYfHz8!@aISKLWGxWvhS)!YGaqJdL%$^UJ z3^_I}=>0OxG-%Y-X7RpB;U;r2Af+jAIi#EtfRo)zpi=MZzeag2y4GhVR1 zkr;pVx;Nb54R)XQh~_F>F`r^y3wCQkEzEjy@T?|BXdgX~exXkK_TSDj_WVw^hrana z+L0rYmfed!!uVg7Ff3ybot%yNYy7p>1;!rWt;j++!u=!uBe!c3!mBWIc97bGX9~VD)+3U^T z=0G>b;$}U4!MbSZk@Id=m}>|(FyJ^E3;Zyzl}lbQJN%VTG>?;h;cvf?cw-D70ZsBN zv%{a^K0}Vd^nxhG-wztcs7v+5KIA_~TQ=*N3w{AyH@n2LPZ5Vc>$5pf?t59 zL2iPY1GB;3tos+_V!msE4{jbVmT8C&mOohYx;gK^xNRNA5qWGE$EgSg!j`W*>l3Nx z@VZPMeTu&NH279bp`W17Pd4w$mU9Q=K;JjTqC+;gU@&< zCWS{@{8l4;mBnxENq1^E0tT!3Yud!dr#l9=wDqEQso&p}$KI<`ex99Gh+TGXU z8U4fXCDZoS{^9Ysrw?%K-YM4*h~FGPmHBcF!G32S7o!~`AWLjR@OiO!;|JpbW5HFp&PF_V^w+B&WGpb}i1dQ1&Rn+PH0HFw=xGb$uwOu1_KU8p zFl@ls^|z0qt)w9aoaNrymD+xxvi}J3lE?8cdFcf{#d}TW(+U_**seb!PrK8xFG_>| z{sr?zJYvA%J8s{QiMa6_%n8_^q&~eG`yW01BLi!e9as}@)-x8YI&k%EmjWZ=N?f?U z;$Dt;*1+#FF~*4_{oX2X&9@xGa*V6_pYdLe;r(0_aC~!J@M2VCZ10!j-WuDg+#kR{ zd%IjO0*e8%uRE;vcMS;t#<~v;3_oSv8-v2zt^3YF;a^zy!NK8n>%Mbv_zCO2a!7cq zb>B54yv4c?6@(wbJ=diYZ{vdSgRn>5i=p9-xHtX9vTvxgFN`uF7tR3SYvR}wpJ>6K z*I~WcVXbcs&Y@~7U5vBaNc&pN@~coDx|_R%*nvG$JLRPfs!XFSqipIL8eXn2>Ow!! zZ}+<3{~2QJV?)-KADh3ne9hf$bvR$>fN$M;lf6AytIw5X%k+DGGj%Fi<@w$B(APK4ghnAab?6<3bMzhmDJ z8g_4a&*x%n<>Ft|bzOux68nTdVju9?`yxCNahd+qdRzVJIlDyiu}{TVjJ5E3%mL=! zIlcX6=vb+zesol=Ywc@VmNotH*){_{LmcQ2VyU@~`8P2A9@a?QPhp+3o@=P!iePsI zXk1&7mP=You=`4LUDeJxavAO!f0oFrzkLyTz=Ig^Oa_NB@Zo3MWE@3(W-J!_>*ov$ zv(6`Ba|YI{*aK{&%r@kIkHmi9eo~00^5IxZ(5?i?+^ysu0q<8z?inRF0CKd|4Vjfl zSl8~S&JEz#KRPV@GbO)WUenq&=w662r;+NF-nHO8q~so#*HkGt2Qt)Ge{5LzW8B}U z{CkC$QuZ~Lkrfr`so_;5akSkHd5*4JF;vcE>bhf{5Sd;@f~#vFX`C0uEH39b#RgKc>4 zP5EW2c}A!F;g9eK6OW?s6=)x0pIYyOEQB?`TJx%$FM&Jz|8U+ItovMT*xT;UK>B>w zm~h7K0dg+R!aNl~o!EyKRK6v`eQ>|3Z0tJbL%`!Mo%Zx;=Uh$v|Ac&%p1JOQ@bg64 ztCX4O62?yY9GC5}jX*15L)SQ)!Hp}tx4RfF@CrZvK=R!Gi{F>_zJ3iPSw_CWJMn8QHoVY&8 z1V&?bj|t;kG4*xW37?eM>^Iw0u%)bc9os#@tna@Omsc&nK)d%MhDaajED66L z<4Q*RZWUKZH}M&J4nDs}dG>3^`Er=Y?D+r6s;6^o_}_A^*o)`a`I_`IV449OxmV*k z2Yrngd;vU-w?%jb?pKwKTgSa7@%#vLAb9P(FLn9X{S|q?@Y5ID>-Dr(O`K9C-Yc;# zybKr@K!>3d(^QG`K;*mNkEX9>N?%I`t@!t*uNk+SzD7K-x5xXRW5TydtOAiUaoKLU z4|+kKok=;!3t()<>;Jv1iT~JeEp$f80n4iYLmk4`c`e6t?|jp{US|90r}Ri(D) zN1z`j`ozqYjs5CMqi|-AGRJg0YXGKYIAd8oCAhN;wAnaEdLDBkvE6~b(6C2awJUdB zZXDJMr|$UaaoA%B%;%8Bvz28S;}sj+!H)ZjaGo#6dTM(;>OYM&7oUZ^kF{in4Sm&8pR0Wi^vSxRuNC`Tw(FG3)o!=Zh37Q?yI8=!V;{)%uox%T z!#aF-c0QhksQEoI7DD6B@$u7ck!sebwf|o2hw!`x^O)Grc%IuiPR_%hy7YFuAJQDc zyT-J`I{T=?{8Eg$M*4tpQJ8IA^@`{|hP6iMr==a2*~XY$v%xRkMxBrst77gskc)K~ z@$Bk}8f~r{#Ckk?THhb3tQqTjtk-fwI6s2iRLI?leAA|2_W2W^LZWjF+S-1D|Bia+6g{= zxC?9CRcssdvkdJslzr#W8~deLbo+Xdm^c42*u6nVa*G`t4}ZDRb%=8=p2u`Qr;Cr) zz*ZUSG2ioCw-4s<@8aq+V^TNef_M&Eg7ld#(7v>f_F}A5>7`irO*mYS^MVb!=zi*} zo~H$4LF+}~h3Hp#FUE)G%ll9{pQ+LZdr&{)t?3_o)ET^5lVE%n!?xaa?fCHb=p$Iy z)_<|`^<9?U(D?8y>mGH?z`Y;(u~s_3btcy#)X%km<%1UXtlu6_h=)CIU!z!f`SGlL z6jEw=$)WF-m6&Vp*74yBQE%s6Wv{nbw!m)-t$X9*Z~^Wye--$F3-E8QpK~#uiTm60 zEt$~8;an+`R)CE$W!w8&yv~cm0ZB_OXi~g%Txq{G#;s?Rku@FgV|zqg=)mgW{Rgz@ zd*qr-$G(O>B;Z4{kcyEyHQ#9T(Mi$BGZy$8Vw%7jO$UZtm+Qc=tEcCr2$k?mp@Z}9 zJxKN9#OMYsX-uliH^#Ds7{7w|5~ci%i^A7Ij`JDk!!`6@=A(X1a*};e){3!xZ?Joo5Z!$CF!IZujdeIH8jCV+)G1(>J-z|Q-VeTCkt@VH zLm2naucY2=oQp5*n-Xj-?J$Ih%@LE9oxs?}KKW#@RqLp%;kkeAx~dw{%`$3_zFmm# z$UXih*oQhJ&#d_Djy7-}>VzKpb{U?(3B(-Iw&09}dT12-Zdp9W>qOXvm=w-M+`}`B zby}(@L9CL`7wrBIUl^-tq8R7buc6-#@VR_0%FUTqRq`mlH)84ym0M+YL6*;|b;$B; zXCm^?L9alau6c7x@{!8;3=wCR2JEU7?n~`DT&NG@;k7)J&&B<2Ax81LC@jlzt8je` z^T|rQn@}msYqC7gODlzWpMy4ruwD%AyyP|?=$&|u&1d$+#TBy+!a+YVXslb=f+rnUCMU|-o(A|A|?uP zE3x1?IQw%dp23y^1Ff zttjXL=A1{UPlpcRbKp_nHXFEACxsr=vxBn#Ft04DMBeH@H)P?Xsc!Js$Sx%@N??05U6rP(_q3+E)5Gzpc-*BeyL3!9PstkLz=Q^Pq>!cUF zqIeqc;`=F_M;=2vYLH(Ej4nZp@t`hmviG46fa_yu+g7yoM%3Aa)Pwf5p&d`SwV98h z?SBPrbB$PrXI~XPxW0@l`?VBnC*aqO_ga>9y6<|6?U@}kp9|6s?3*fF?%>$!#(?bG zm6h7ED$qPW;Oi6NH_!(j@E--g40X%~KZLfiT{_zGXYwJd<5>^oUqznnIfkozcZOrv zBX)>GqI(Z8KwKyugzE<`cR`oS+fKY*!k*@Rtdowx2Qb!C=b+tr=J;5^F-jbUK<)+j zS`PHU2jug0EYynGFVuY;@~rPhT+i3FOZKl@>iP@DvlsHjVGr~+DV@xF4+XnF{DSjy z=)eis-*&bqqMv#CHGSGO&-CfX)Ho;3^rh7plU~?QAHu!#DJ#a%pM=;P@h6Vwl_8wd zVhp-f456N5Dvqo{93el1_OFB=wZb1(K8bghfWuMvQyJbHaP6H_qIKr2gT3W*;2#sw zKP%xEgAr5u!v^$6Y|t%Y?Y!yGhi7zIY%lyV*^Tq&f0}J8{}5M%Liw@J@0geITwZIh ze>~V-g*8$s&LDXvfwKYGUsXRYJ-td3J3`$rEaPn;}xTXd4c|@)O(-RTkDq3uzz8>=TL5r9_ldnrfKcZ-IQ1ITeE%3 z_F;XBwL}Nc2Cz1f=dG8bFDzWmz596VXLfJ<6V9qF>|eEPfq!0(XJR5A@2r5v`X0ko z;Jkc`%5PS(uyZEu#Cv0Se<;0uIq^1qXS)bZ2>-^^kNvI)KZP=Hfp_-y-?UkFS!Y|P z)@b2RamLF1p*-V4fAx$J9erUp>-`dEb=3)J>vY`X-2r@O6LVQ8=X4tQ&jrN4j-ub# zj(@+-*gihI33c6rgnc4n3C~DU+vy8@XUyJDTlCXo;Liohhuf#49)Wr2FSv3o)C!;C z8aZ-KcZXH*IFBcl6Xz>z%Oi}Q4BLD?$kpiPhB9%rymKLs6>#d&Hs=L3m>(8I$l{|M^g z3vkczBzYk{JV@p3>r*)E$qjD>yGJ6%RC@6Y;4Qo}06Q_RQD^V|3eP{EHv7bUzX>`c zAL`T8KHNIPGdlHftm><1T+iK8xx#MHxTji-EA<93-*FB9F7USRA7^3CPDTIM^WsZJz|8$H17Fh`lUza?e}={hXr>*akmr z<248$!Q9n767_e1$2}W$aL+~^q(i2|+Pho2N}=lzZ0teVOEi^trr?|u`umI4y4;$C6g%a;HRJKct!~u_zaeNJ+`M(XS<_Dhj7)o zW=9)>SRYh+OUCdVtqbE#W7{CxD?fbnDjoKoNnCa>?0xi={w39jQy;@Nya(M5KiFv5 zM|+AJ|4O& z(1i80g@@HQ)k)ZM!G@JdV#F%MAgk{v$Jn47<~mERXAl$o=&yRTp;Au@e~hz`N(d57fIn9=n>FkxS<1k1*X<1Vr4l!nJX2nyCHGNW2NcKN#n%c+-h~>969AIUl_w z&yR_1(QCC~Dd~r?f;s#^R!X?!U zj3sl8C3Q8mb>lFQ`7!F}-&Q-$5Jpu4{t8jL5MosgwKeC-lgH2Gy1FHG#yF$AcG>dU zddg9OF~8neSXFmpZJp6DuWGSTb#vAHh4beutTpPFR#n%=2r;Fuw$?zU#x3(3=Gja@ zy~cbP*r*J;ycSxFhFg}H_18!2gq+>*np+oFEt+3#EUKcxMwMv>^qb98tx@)lGb-lQ z8jETdEvdVerY>0yWpjL_bwn)27x!T1wMpaEsU2T0mh3i>`)vyNWsc)#NYp^6# zaZz4dUt4!`q>{OHOBPAfjfN%iDw}O<=#}gQ1NQbpwY2KS+InO0@_O(-mUfXtE(0&M9?wcBzKb^4f-~nyQAXZ!T$-t65a_KPvGxIL@8F zcz*r7+8Wv3^ZTW0ZUcJlKTD}@5p$N;)ZA*+--;o#$e267t{xr~86>994wn9H6d8rz zF-8;(F~+g%yju9TVSdILOY7!iBu|sHtC!R*tjV?X*VVG$EIE~9XPE$7Vq#&vQijVo zqki6!TVM^wDY~i-3g*@;NyLDNpk1zd$>Ih?lZZYw{-o?UYc$r>E?TN2>Xt9H>8V@3 z*jNq+L_?O`SXZ?uMpV_`y0}_Nj5EyKRi)(>2wYV)!*8jZ-(Zf=`UVRHX?Jad(J+5e zEl09hQFV30T&tpSMm2&E{8johp&gp*6h3`F%4>1`D%4AT(^)Fw@>C038vGp;vxnTpedj zUwm`b!ud6_PsonoTyg7C*-7xn>bJT(bLWANVyAuNZKaUGKYrd)G|QhriV zUON4<$>q7ZSh(?{{Fv?yXOXeOsBNr@e zF=Cjr0zI@|4RrcHL%>88Nr=r-&fmtu+M8<^TH!#{FRibeUAu6ERbjlUpmyOoWKnyr zn1%oJ#r4bQ&YfR9pV3OL!K~?VUTqa)v+AdbOBOBSsI(zy+FyZ{Qnkq(Cr6~J-|`1U z*t)7}&UxsKT1@t8NXJA1*-|XB%%10B64pQ#G4IBPdBcn{Gs{W2!3>BP|A_UNA?Gbw zzOcsl&c#NNtZ@n!l8htOm=7ATPN=G1FwVH#T*>t=evDc!OIZNkyI=(UNln$vUwB@A zq%ChQ49)N~-|8gjLGZt&YC)}m=}WF9&$ojS@S6;=d-v^k5-7hRt~vI;nERtQ`Zh&9;C;};qSR4#@b%Ke zhf0sUQTo=KlOocTibx!J1639w;e1zIzq_ZW6Zg;=eAxF$)T9mGX3v!S-1oaS>YKEh z_uhTuh-wM?0%9d7a{^_$a4#wnjECKixF&DVzyIF5ucNgBM@G;InXP+zdWf5tl#ukW z{)jf^y>}(Q7^D^8ZwLPfuBdm$!!eIUPrT22zh}w@Uvtz(_a@f^y1wAOci*(tO?&YU zowx>H)@{PQWp5cxowQLeYxZpLR-o~3lo5MbmjSU8D6)Ol#2|((gbW@4Q{w+fnD)L~8)P1?72MS}Y}?rB?{m6YqQ% zPPbm}>Dht%2;TIMi3EKz9i+-$C?8_ipv)eWDK>5I#ao|dHV`rfQV4SUU+L+&2KUe{ z;b)uUUJ#}p8LF0H@P;tZv8laI6lv{uk2k)X;xxo03Z-X?dc;tvIF5BNvG zUt#hkhL>*8FMnMsQJ^Y?ls^Ue!GG-O*>1{j_f35GF71&!wX*wGYZEs#Y0Yc2Iq$xA zNX9M3xO_a|*arDcro4;~W$b@B=zxrh4Ef;CfNb`kdV1t4PQ}A1jEDE>S3xkMvk`Lh zAUEFZQyDiWQf}gXx<1vCgq_g26|#+Z!9wYj?JL`$UkRuXY)WGh4Q0?_{re%?30eA$ zm}ti1G8K>EQqlnS0lr5q-1~cae3Zjy22vbeS`eUR+x?7QR7Q`PM3YVg|zTjLXY*|DL+IMbNaIEZv-aW6Kt9K%8jhG6x z4{D29^sUICkG#dpj@&*?_4WgOi%0Hu!Fp z;clX|UXH=uVa73NhDtdw&l`g=2VXBcd!!+yqZABlyaZI=`?o}B{ChX-5#5zi*y@4C-DWs|m1zZMYz zalzDXpzL5c%374Ep&m7);DgN?yqc!4uFD{^A2OCtkyeS!J{xT?Xbqt4?XADp_qk-4 z7a2~X1hTD=oq-n&;!NBv-*48wAHkqJa);iO0}SOj7T!Tw11~O}H*T7>@Ab;jMtmPr zG(wK|{4kznfYtySeOO#^?%Yke67aWy&-U;`+GU`1o=2+$?H$kEj@&Z zS9MGgM0rFq^qojNmHm(9q6~lELubk$g~(z>LAG@p$~2=)5&gg(*AOr7*XROf5H5|a zu-#vkAh=L@_dS#_gYf+tSE#0c;CD8}(sz4$LQo0&TeXK%AMsDxkkXty=|1AcPY@|T z7XAvkW)ke}MBP^$niz3E#6Hldc#kg#OC6RUOD|>&pFu6W0h@Ji z!p#xL$59?1(w+ou|9P}d(DvDA^!tOL?FCKxl6|b&#)kp9Gmtw8xf!^(#Ii zbOQ!t|D~tr8B?Zr?vt^ijIrV>x$r>HGaHZh7@IxT!kJ6yY34fIVjSl6k0>bnMI z*S@df2l58eLeTbuHXipD-dO8d)3>x^J!C$%WFSUeTS3b>-qS;y_#tg4Xp=x&D=DUr z?E|e7v{R(1eau9fI!SE~mPSmJ_MCxy(+839EB9U#H^g0SVa$3AtinEq%r&YWNyB{* zDTE}54cF;zW`OsN2)g(baWcTCL|rR$&HN0NzeZh8D*95DZ&X*2XUeZv`AzCtr0CmK zey6$y6@9_gip(cf5i2L(39B6 zv?ePBiM^$CcNF({y5_x$7u_=*JeS*phYLdYd155b$EBC9M@2)MI|u=HLf@Nk(S1?B zBgYqo_adRghu7YO$LIAmf*I9^60r%ZcwdP%qbuFK$9MaMtB-kK1G8Ki^4>QUbi)-$ z^5PmjkBlt*eh5A>^J^M~D?7Rj_rBf0%p^O8D#jNneXMeDeW5W;=Qj6%6+a8NeSqoXzFrZ7~nn4NX6Cb z`zwo3%vJ3A6!-BT;*aKvS_M+HYpL?F`1>KOd6LVi$7TIuq}NA_6Y#)HXx_eyC2y_r zLaz@$IAu1o2{*EtUJ?HyjMID`d|w87W+?561*~(I=G~uTdZOG`!vL-29|&Sec-xWe z9QL~0g5sKtrv@YrCGmGiPa>tffTsyS=R`6UWv=7Mu4Ztxv8k(p-8h`<>(~zD9^Zjjfm);K^c1Q>|hPZN;)pHf;R0hCTUvEuKC3E1=kh)b~kM zgpEqyp)#~gfg%FUipYxRLyN3DW4Z!4d*8Wb&=Qe2i=O$o=56Y0O6@?NAFX8}Oi5Wp zcY8uPBwCt;)UOkNXy7)}K;nNX=}9zPdhIW?zVzDPfJ)fXmVzUoFZCv&{ZdP2vv{=f zF_H*$s;X&q287t0J3-&8=xlG1qSKZ3+vKMydK2(T>Ss1V;*+g17Ct{jO=xZ*{%Gqp zZ&0zVO^?>H6NNMWiNI*FbRLjsVa@X)>d4^=C3y55JKN0dFj z645uL==_yGxSq675%x~SW{Vb^ zY^?}`9zP_OBm#SEg@0rf-Ww@=#8&ucl08$7-{ZDo_?2MO{L@ykzNc-)0&bfdp0s2K zPcwT*^vzIg+84;T$!3EfVX3ra1I0GkQ6}3JoR%*FL0h>BtK6nYxf!-{3r)6c#`U&h z>#SmXBgN*~*zFekgvHLa1}!^DBz{R>nyGm^vml8N7bg5@Eq?4Z%-Lb4mc@zS3<~@c z$($W#YJ*9{52y(I5Q&-{t}zE0`*RACIXisMBu1kG4T*#9dXsb~vOhpdd5i&NiAg*T z!Z8vL(~KqB5Dv6N?B%17(ke09Uc!wzL~qt|IYgI%um~xo1R+Md!z8wW@B~s|AG-t} z&J-OWaA@9(ztSiAp0RO7V4BL&!SQ>P%0sNk7nq^goEW}Rs_sM;m9}DivCWnaV4E0h z#YUNI*^v#3&hdS@qWcU?3^sKOEp@#U!@Y{l7}2DP-32R}ZR%QV>RN2_I}{zUCa~2e z|EftxIL)1=LepcZLS)t0;?(D+jD41{A};Zgjke7a*P>^%iJEtYa;=537eH%ypRUE# zCfI58A|BuDLrUV>62u(#`FvDYg_Op4eF#NT)`F@{F$4CW!J*M9_&E!qP1X8x$rS}D z4^kkc>ilom^*ji$tIe^ga3U-eo^6IO{Dva2f`7w3q|_9sssZdq_rS^tos>7 ztK-5b?^d=aPm7|#B4GNIe0GGa*21W3nxCho)BJI$wgAbrdXVYd{{-O#iE~(Jv?iCD zW3fRWgVg_s(pmu~KW~F*wy(f!-}gbd9x3p#k|gdw20>y!&+^m0XB3+r67Z>3Q1*A0 zY$zg|q}cT7^bD0zGY)6hv`PRx5Uu0DEzuI#w!5Kb6;i+T;F%VVH7)!*s3(xpHz^Zr zc#4dx;8IH!Ln~s(jn+~YL3id{a1wD7kJOKx{5nw58!l|rJCP@1yxv(&k*U8Y}iN)yC$0*i)zvxgQ~aH_`>L_5(?I6}jD%k}>-OX>}1c zw*^cx{(dO6Z9x7fNJANR*DE9SPQr0`z#K5-`utVgyvz*O=O=OVPo#89yb@mpV6)et z6@`R4HN$MIX5CmLMLX*0rkVi|>Vrd@G^ET7WX9uW9FlP%GI+CH%x30dWVYbuA*5l` zkjYkxgQ$rgV>*cc0QV!L^kT)ewjX!*c0*u?Y8ss+3Bsm}1okL02iw8*}<#2Z^V_9>XrJ^XJB2KX>`@E_d_y#OQ zIr5K~bd3JKtu}3eZML#!Ras6v+ZCN<)8KvVGtOf>ZSsYR&bm5nN+&D&4?*8+lfOaH zIZ++7>2EOUuq|+0k=ZRjjfkre5;$$+Za;?$6LJTuk;O?)4CWqR+wE;iGu^9`E`X2L zvNi={Np6vM58+B99g32WI3D)M@h}&;Iiz3^?~$WnD{_w@nd9gMDfQpT|ARESUw%>2 zQlUEqDUIhH4Y;{Lj{TSAu463nW02B6RyJ9_*Cc&!Ev!p_MzPHJBqP)CpRy&J(r9a! z-)zlR-1DQgF#HaAg}0jqFa|9|1=k}DkydRQO8#gDg?9q1A0U|%#&wD8?!O~{9I0OjI!$zM zkm!y^{}szVEV`B2#!BDQxL+J0Cz7#)S$@Pa+BNn<-YbJA$nqoIG%G0Y2eMJ6a%T;( z!92LpV!YN7>T%Hc(OTls!v%uecsbYHfcn3O)Q@aBq+cF7w1TvW<5Xkj%DaNqc^d{1&8w-?FZ3NizcQ6{LPkSr=TrpR~6Qq??fVDJGyz zDWXD3b$n3?nr57o#6|~mKQHD^CPcfs=q;wOVE=fYI zEvwNVauxU#6#N3o-~uoTUD|`p=oQEm!BdPM;AS4EbCHa@k$D<7Pcd^JGVkE#2$F19 zld41u(ZyC=u*X6xH3yLwNw(`E+>AvMeVRN z*5ekebJ4`_Bbf{0A|*%%+H2OT7R2XQ(Yqin<_fGx&6{Rlvg58sNiM?r z8Gr{#uDhj)J;FeyJ@qV?8u z8}kv6s~C)Pp98tS;W?1!?`}Lxi0>;)na_c|zBN*Xd<+!Ddr8=gn`llG9ub4zD-whC z_@sX#8_P(hC#3LR#PZ>do+vZESQoaXdQzN*7?2bjgvokxY!9R|Vq>8|Pl>()83Ru> zs5_3Fc>WOyc=mJ(SI-Y9=GV#g`l6sFkx!jGeG+~^ZWFlf)T9w0d3|H>H*PBa#8YWJ z??9zoQieM{`VQn{ABaJLKFPcnv8gPbAv3<%7{m^DW}gAzB%v7QU*W+IcM5mFbvbDA z$=O4=NfwD6ESH_aXC8^$AfkEWSfdo#4Wh&-UZhZ5i+zd|m-Xz=zkmf^_gc>?<-2Pr zthMw5BehXz??`~2$Q9x-q|{r5_P(SXMebcv@a*Qaq-5p63z5?12<N)-7f$^=#BW@NZQqvyjZ(x)lM8*uokkwVFjI8c@m7#rHIw<=p6C9Pi*vKmBZ@66eMeo}L)7@wB27*vPY=pvVvdO=ps|xm8ALN>UkWdd93R+O_vmQ(UBHD>hs4mc13a zFDTOUZG}HkT$(Xd(P>5u1_Rp;`OKiAvuUQk2tWDSi(czZfCh{pezca0ya?5=LaX*- z3J2v?c|y!Y3V39R97ctoBL8EgtZON^H{K80pOJr+v})2`mbB>phyh4h_;E=*kCe2D z$WK5@->zOlco0_oR$4n#D-!8@Y~(*FG7bWd*vKC!@(7WBT#+A#lCzR5AMm7qY@?^4 zMW!2w^iwu^p`x$By2*+rzlI*+A4PM2?zLW@*hFOT!B!2&=O#Emm*A{KLvBSf!TGra z=QZSCMao(ad$eC<+>DYr`B2SWPe9Ydjs3GAUO|RUy$j{ivlWp(W^QE*$Ya(d0DE2?WE;rc-(L6T7^R03O54T9) zs${-^%uNv)c(P6P-InU55!E|w>@B^;a`xEh(wg2)rd%!j39|jUTIg{J|1dUZrq_C7 zXay0$2j_}7pf^F8DSKkf0BkprOi*UZ9%(>+DN@!BxV$zimQ(su$p3=0SZOm(-KrFO&)BuGUJG1d$I1yIHfWv$fOI^&VI-|Y8C{Z zK9MKq|E=MLm=L&|q2Ah0PFnst+E=^E+bQ<(vM zA=Cls-y#i2M&^Co97P&91ey3DScM{q9IJc;f}~zw8qFRn^jdHE!AAMPdk7J83uQnV z3ss|#OmhomK)D(DI;6}q>dlNu4WhS(T?8b-Yi%voM`~ajO+XT4qLf{b`4 zk^dMey}?$)YcNfYi5b?(Q+mk8K54NVBkX%^Y(BG*rCTHHO*Zy0i@i6(-fClCZm~~B z*xPMvzCkLLCtcz*8=C%%jlIrd7e&~6ZR~c7eNBXY(8hk*VmC(ET{iX!i`{CmGp%lo z^vhn0B?jS(hC=gswbAH?T>0?DmniS=i$;g}^0;No7P?-oxFR?CCQzLH_$?V(`~al)TgA`d z<}^~yJlo< zlz!Z1>}F_^jpRx6nGi@Q&~n^3gPtr!=aNkKLI(W!}O^Aj_m@Mi-{Q z`Iz*8r?3iFCcU4xa0mEIQGQS1UtK~l`Lex*GeKkWj`SAdH?{Dgh zuF&;3nMrpyGZQZ}{oMC5lOQt#-8wUgGBeB_!%ULQjCS)~7d=^KzT+OlOp44*ac42( zmzgWv&oYxLGv9SjXC_T%zV9ByOuEd>6*2_)XeR%7BBw*X5K;s`7io$_op)N~ z`-an^=peB0CiJaBVfEH+)%T%9 zK_LbKQk-1a)sMlCLyC8h--{H#v;i-9HpEiykHfIwLrS=jWtU6ZSHtmK7b!7>S`t1* z=V-U&v4Urc;Lb=1mr^*C4qamX2qEr8O5oS?v{jO}7x@=Sdy=%KL{{`U@*g23y`yaZ zA$%zLge_BvL6d?l%H5+y@@Yk9$h^y>YsD$r%-DNyl!Z^AN#u!SUx5h&r5?9QdF~Nw z$RDcso5A0sv^SxSnRtvOlE>S)dG*x!92!VQw?4C6-887>)#=O;*}Gh8G)J_~BU1TAd|`)z#mSjdU= z{b=5QL8Ivj-;thh-zdDRi)4Djl$5I=Icu~KS0b67FjdkvBmV$t(i1L`p5Pk;tw^TJ zT`g$~k*`5Yx>q$uddDVP<_0O7>Z+nqUPl}bEbWaI(E=Y+<5H=krK|0RLv3RP5WI9fUbduz8 zD2!w}PNt;Yfc({@$@tYzI?0pBKaP~NRLwHdNmkf0kHK%*06NLNicTl_ok`bxys1pCgB8%EQB;zt0Te2eFfo09R=u0M7d_v|ST$$W~sLV2$&g6>qWPSk}lPkuP zX{|x<2t}?T+@cmWsyRFXx17UIs>pMOqaU9meJ~$=!*^fYXHb(K+xIHS;`=T3@4@^X zKBUL@T|$of5{>y7#O+39dP){X(Rq`oXFW(>AOA-AeCm5JEy(%Q_h5MM^=-u8=+RIz z*d605hov!Sl5oc+RD&U6-ex9FX529u5Oc@Nj4$R2W)fs3F6JK;OO%zM14^nIA)_0`~SET4wNJp+r(KQhY= z1o*@$K4B~FHFp%=(X29~c*1s4JfK+LZAyF@YPFEp`cBk5md8hHxf8QiQk&!sU?trc z9RKD3StMy=NGm~g7a}FejZJ7eP53eLO-RZ3ff;D7z^#ZH4;Mj7*{Z&J^+WXC#i+n9 z-@TjZ*Jeh$wp$@1WxtZz0IBOuDI8NW7&kFr@4U@cPmFG(90+XA_pkgq}NvlKI;l=>%f zyO1&jwu<;ieen1^2I6HYRQpaT0wPjIE0|wlG^NY_nU?tsm=BcUr{<9|l2G7pVD^z6 za7}8?+ z*UE9w>(^$42D74H8S+*nv3eVG2dFvx?#2tS`gtT_Sh30z>oKhOggugB+s_!QP!W?S z+AD$p)-CXl#9MLemryU`ma@7C>iO9cuty!+x9`3wn0)NiyT}(q&!AasL1#$s1%WPKo^pnGEl6C~)~RsMA2a zTZgNUoM`^RIxouCg{%7y6ibz_P{n@A`}B1DB0LIw3a&>!Fm}f$Re~g~a3`ej-n7D< zC^M!N?j)NP?qp>}ED&?2M9)AGT9J&hZay7$`*q$&`R3wp9HYcq+{AP7*@OKEy1+9q zz7eEYzLDY?WZv`Z44xrz)E1jWnF90v4bm?#@8z@I7c7(oL{+HBz4$h!siI_(D_y$!#D#frL14KUIajCzac? zk^E>aW1)&A?vG-L{gB?r66qx@u)=##nO8$;e6*HfZVTu;5~wC+G87;s%4alp^dW5w z@}rP4T4B$_G**JUQi6Lu7}p|+Elk$I|*;srARucrUfCuxY&jLMA2()Kom4 z8X+=6=cwMUa)V9HqB){^o>cu5)c%U958707+aXn3ex_6(IY;%0^Hl$LMD zrs}v6W6{vSMSy=ofQWAbf5VT~{@}?q4A|>Ic1VKwD zZ7TAUC2b){StKn)_9mp{233nSAh_o+hfd!(3Wg!{6C{z`c%GylWl8pv*8B!iJEY`_ z^CX8xBy*(X+mL!wN`}sp{BA_jh+*ww8bT^1CCnBg`hG5GGR;URESRkut0mfSkAJ<= z&w~@>FlQ#N;mb#@8b*F9W zeyxf%VXb8$N0gLhBD)C!TC!KmzK%C>Uac>kI;d3OR(`aWzVyl&|3U6&t(CBs>u0T% zJR`mR9zp*wxih2tS!c-ZfTy2zhV1U=6)Bjs+~Tk3WwrOKfMr}mEyYl>J~MOvzptNy zP!^TYw*ePx%_NV1yxh#`840(OKN*#4ah}U?Zw*uy;74nD8j;l3SOfw8JP?LV!+ehv zU5lZXlt9w0$Sy~UDORK0a?l4m4WzI6w zq%zUyFOhf&aAI-|^Cnuo?;7Dvw0hq)(ku5<+*7%8y@_14GU=1OiF7h1PmDKlD0DEn zMtKuwfUsm<>0q4ZQ>fl~*31vKFST%rIt zjQSyJ#IG@sg1u%XT0<&N0yMYh3S6RHt!ft?&6hp397%OwXi5&II6hiS9%_ie@A5)I zzB=>fG#s5E#ja)zIqB4;&5XmVHHLhP(mx&OBZ+uE9MR&U*5Q7;0;K}?{NT$cP@6DY zO7Q4iRG`QuNOAJKy-zGl9YX$fq{P#z_?IY@M2`zuVMN697)SHUS}f?TMTXYG0twt* zYF>HReg@i3BgM#Cyn|TF*h{cjLrM-)E-G;uXg4EYN7_TA`6TTrG)_+UdZ;*cyDGJ^4nWT(E#3*3YP)}8&eJ>!RJSgT5 zxR2e<^2eh-!M(;makAp$0ahG`CGzq9tWHGxDD6H<>9?eGg|a(?Y<%$EG;oi9T}q@< z)hX2cF_Ndg4vO9yNR{(1$8$O)?<t*0&g>n~<=>`v+TB=uK7XJ4wVxYxyq5kw?a< z!bFzY3Hc|H(xn#{23Vy9Z=v+$sfb1wBe9-g639Ox_Y9KvSFB~Yq&tAZa0$1nY3@v(uAcc3=nZ*+#99{mPxV)%^$y-zalMGU`Dpl8U8 zFD3@|>Y07+03!*-%5e3*0BH4q>v7!2zKcJnkm5u-7b#klK&@9;BpKp;fyfnwn~Ez}W|q8HB$t zH(*DRe*-D`e=+wy;B_5Yo#4H?x>tIZWc`{v;h?sUi9d9s~u zhjt??l58oFEk%+Or!j4Jx9M?1pxt1=EFNUQKw!h-1p@&xgNHGLXF3dKzswT01MT_9 zeq@F)8;0}{hV1nIPSyFeQ)Ir~bbC-qd2mWWOdJ*nW{+ zju*cVuGo_;89WhMrm0#ZLJK;7SgE|`uZi5b$gfBHw3woEYozEFBU*0VMZl|CCywAH zP@~O4)ObS6Z2;rd7a4Jd%a_%VC#?K4{9p5VVc!)U)biz9W%BqJz75-03)AfCkOrLm zZVUnVSS5A!OJj|W!5QFFd%*CxLvoBB1P&joxUPpTdN>yz2M(XMx*A*qfP_|q8)~E) zo1VbD9-sQxR06C}yq7=(EnqhrzwV}Z50d@winph*Uxwc1@3u;m1{9S6=ha_KunHg) zSyd|W1{Be+c*9E6y+0lcf$Pw1CQK zum0f#{+!~aZn*?r`l1M0nf2=TC-B!|`u0n`OR~W+%zIN_p-Nz+fWp*T|&_omXbeK+3y+Y{AzBbZf zjIge12+`nc=TFwjPaF94hQ;$BKZ8&GRV_`_{?E~OY;&NsoZ9QJD~Svfzpf;rh?|M5 z|C_-x6B6ImMA63I*i4DGYJ5+VKZ)d~>U*pvR+UNl@;WkUacO*ePEsXCF16^CVQ!~q zdh$-j%e|}^7+vLQ(HR~LIH2hIeI)%cD*F5Qbp0_RQxo`#D?Z(ShR8hTS6>BL&z~dm zEnxo|AFo&VUDCek-;g<2E;5`xJ?VLm;bS;`0l@d-Q-4`WrLHn7$v3<{dNfHkN!Mu< zuymPv$|tC+=$Bcpe1iIlejdKyptzqG+Hg0kUj{Jw1eH-gmj>mVqkdiv3)fck^Kx4` z-jj7WkfG(@*14hOr(pzQ&ULEvcTiV(g4V7BKYxh_A(`o6I7y5}<>LKA`G@1E zipoWVmF6S_U!D68h-CDua{_zj<$(C=oJ1-!avp=P&YeP}E+gkL`0AW6YR$+=2);Te zmXO7=^UDZV$VmvkCns>#AEH`i&2@hZxT5kKg88OkS`4Pz475Q8=cGC@ul{?G_~pR7 zq?j7nhVc(XSMRmPxC;dG_!kbKhAYj<#%F7U|I29e-^RzQ{XOYWpN{y>OBjlI{0l#Z zEOjp{r+c97dhtaUU5~H*P06`8;@dXkoHr!ri|L$a3|*P0 zT+RmBbMm`FQQ;+R{I{LNbI9HJC&Ig{Q!4pasNgs8u@zruD*nYOyzd&Hrk6DPM^Lk- zHWgN0<>EES2A3bL5EitsbFL7Ps!`e)FJe3e?6<+}Z}4f9*7c*UBHAw=f+NDG*$A`J z6nyVteD58frr|`vE!#Bm-QfCPAwG0mRyp7`9ZgVC;5n+dM6^U3+39|CioozEOQR)h~AFYegr4$?}wL5u6xyY934 zgE^W9U)P5wYrh5c`e#~y7`V$Yj$gv3woQ!dOrP*6o5nX|fUA?&aQk0v6zTQ@_ep%} zCza)H7~X40Fn+mC+X-Wke1{u@keQCvFR^@x^R^`}`x317yyD*qQ8FYlOe#mMuwK)p zL~?$TxAOlM*}o@ZiSfc!CN9lp75P1DMfraSY5xG9I&<85!nDEK8O$B=sWYd5C%U9v zMi9RbpO&p!2~^BHzXHMP{s(08Pt~HUc~c;oz{hLZmZJPqNBM<1q5OVOoe|3VjY=sM zeU}xz%$`!uA|<&F@}sh%pZbRr*@i40P42SgG+BO9B4?AU?w1w_XJPh2JU zTC1fow-`go?y#EfMU%+mUy#(%T_Ie+Qd(;duxm~?>5?m7E=_fKx!%OF+CJ z+a&T%GBTp(A}L<$Zjm@sE482+UN*IqdWxcJjUUbQNO%1`i24#fwo7F0{eIwfJcXlS zd~BDY_*i3FVN~!<#J?dpqly(q6{}}qg!t5bvla8{{sH^1&+8Q6PjXXtd^%peT z03wUXA|`ekM3)r5Rfw)=WCRg;SHBS1)d)!IUrvzzhNfb;XnRfZwnY+=rgCi_Q8##H zg4bxfc*O+_K|Yv!wR4-ld`r}xn5(sO&UsPY= z{kIAkOlq3kVDdPcLI#t|Y9?}ADbH_ghO2W|_!85w54j}}j({0njs3j{bYQVxsfo-g z-rQKYh%|G<`P*JbE}4||*PI0^(}0dxw$8$*A!pe@wXA3|a^a+Gy@ln%N!bPq|B2vl zGw=%G>Hn`0y#AE!&MRIN%&!XOkYZjE%#|<`yn0wM*97zH!0`R!D{ctpH-O*D@;KN^0>ve^#`dHf4sM?b5^Dt*1bR=la7tHB=B2EPF#wU>iA?#8DE z3+~%|vwZp?M8AyB%CDdmCY782b{%qVMz8%bVBbdaf58WX;V%it9zVLY%N7f3G>?Db zhs5QYeZ(HWQB=0-D8?0h>X(k-T3fHbLMVc-y>znSG4Q;q4Ezx(soxKeAhq@hq+#Eu+0Hb2!h# zXN_6I{x`FR{RzashR@m`1%o%0Z6NQ%^Z$Fxdf?iA9{=Q9NA14=;O{~DclcmZcS39X z*O2`aNP_(M7D4{kfKMxpNGIvvhm5WAJskhfqpTKoM!4beFNg@8W(@xGZgHjk^C%u4 zFFPsz@avJxQ~h59RaZA`;)c2Z1BOeI`Y)r44_Kva2bDbjg*SvDDF5YJ$+-+xKOyW| z<*d*Dt>|DuhDV{^j?;>kimd}e8s)`$RB2 z{)K;qgkD(w&zX}kKi3Dt|9NBge-9bIg-;(O{{_=>{MY-^mZ zmprJSP8ru8L3HVU%ed@v4GQ~bEi#%6$lKT3KabSUBJ*eP!6ud%eXkNb0M6As{@I!@ zAfxHFUj+Rr$+JPSj7Zg&nZE=&eQRxR!*Af4?$?{E1~{!uVbGUEuHxP zRGNQ=CZ1Hh1dwB(DIXk~{@b<@+CN6w>N0?_-Taz~Gi? zoM-3iGSqJ+P%f86)eibQR~x$U?y7aGr6wb-KmNdKVO1Ae4oLY}W7(?Td;nFf2ToWd zaSd8h64$6j85|lW8C6!zRsLhEq@0$oe9?zCHv?St{a^HPO7XP^AZ=?qP<#BB9;kY3 z)&8o-!%tTU@#@gqOkvhAqa>`gksp0v^=6}pwnQ8jhZr^$q>K(J7mmIPF)KiJYs|CD z5*jw>VEO9#SYw`oda59HLxq&yD=g5T^69fi8h_t^G? zwKwK#IM2@5dyp?_J+ zcE+~e_RtNEyYVX85pJ_SVWTMmwc1o@gzsl@X>%!0n@dO&i)dmMYJ0JjX7a6c1qX?$ ze0`>RXLVAs+LYq{ov&A%_AAdN!k&QbWQaH!=bKJYSwXYZc3MrN~Af zzG`9p>?+H^x#-qJ9G?Bd>pWImdXTl6jeEK6nphUaqS>yQNw=E}txkM1w6dE+&EiyQ z`q6u#O6k2asLRM252HY&+&PEQWbfrLn#46wy`uNVgx;Hwpkr5ap2k{|)zS7`1zft_ zTiF1slNm6Jx7^&=DLuC>zhytxX!}z;Ow6%GuP^9cILvh8a`vCHCDZK_rQ4^1ourZt zm9Y(FdJm>X$x7Qs$4ejWY^jD_ab7mF=r>bH;|T#uZ4nW?MD(+-=e*v}|#cm=p~{O4oO# zRSSmRq}O|FRlWb=rn%BxqC)joanBD$%$ zrG{7Lv9J^STIvY%{)C3=lOn5T8@^+$-BLPShbX9Yo>o;1SvWbDq`1m>M95ItHTmiiZ=a_WAjBKEF$0SvnPbEq-;AT;9^nBJUb0E3;@)bOL+JlW zdBj3i?`PA(Lp5{BWH3_ zTR3jg$zn-bupE_TZp!DTY`?ZhOXTTUoBWp36&*HZ1cj!g1)B5KX^lXXo@hV#S?D%t zUeK>)fw>EGo6jS!N!I4IpY2<19DijM3OU>as3U1N(%79Gk1&BwxMpc!%%0r<+a0f6 zdlEC@c;+0NRbQe=>}hmjahG_=u9ntN5fQfBV^5W{xrw|KGb=o}J|0n6P$^Mb-w?+CD78X*z^p51xLiEgC zEi)ZYHE7-}SQaR2lGVh#2~jsBXoKr2SQ-(tCQ(*$gW|*c*!;GP*D3Uwc(1$N#*>+k zb4|99R^<1Qcwob3TWamW(amnnq4~HhOzzdK%wG~?qYXn`!rRCKM)Z-)BlCh72gVHr zOr%*F^RZZMW8#|{_oSrKn}GQ(nP+a;3XD~w?UdJ)id$PCgop;GEWg8sV_;blJ@7ZAh;34&)7Rqo-8bD6Q{V?u%#^9UKc6cZAZGf8t%su%1)wZ5*cNQWGF~ge%y#=pm;Vj{JTxeRYWo0-%$8SQAl#N{G4KEXx<8FD%yv@smCmn8hnee>B zZ7!|}l=HCC?9&i^fZ(ScDo5~uq5|(rCzlyvG01A=ivPnaX%5y$>Jg_~2sJi!eg`LK z@-P%y!t#<&c~A(!CPf)x7|F(THbeX$!g#~gHojX!DT45v;@}zLOcuhqr;+dtj34r} zCbAP=a@i*co=}vLkdZSnon@B%?|YO+es)qG-`g{(U@YJsn->2!Dun4UH^XH8_BoDw z36gW*EuLIvBraxeT!4kxQrDH0TzZ#BiXr@};_AJ5FL1x09<^=hTV@i&#uUl6B+)mO zPjeBX9>2hdtRVcKU16c^8lp`JR%#pi-W0(X6lHxgV^?BAg4gm08M_e^5~QJg5N}Ue zA9k{i5~P5zdV-YBI&sEcbRtX;q;!^$vFkA*!KAFW^7dy{zDmd95Wx!$HN%3a35*E@ zUyrE>{)M9cU-9<7_)n`M;Eyw{s~uWxwpX)p7- zybGhdz#MJK819uhH6=ZT@IF`YEJ1m7yF9R0f)^cX)}|%@Z`H(8j_9dmvV)-smMS~1 z^7!5i!4Zd=Ab3Dg*3)a`R7_`iia{`SLByZaZ86$hl z%?Kt-D&7g@tMu})Vlon{c;pLymL~cCZOs=G-BP=f^`O0b3aJRnO0mVlP6wA}AAl*rf6!6QI&L z%gWi{3_lQ2;AOsDVBfyCq&mFrTB1PhG0_=ER3MeC3CQcXk{N|F5*JWl5waBVy>puD zl7`|J2*2nG9=)RA%P}ggAsLk<+f87ivGMSev}{!w1kYs#TS{Auy}?PW4}}19)c9d_Z}liS<1Yx zogn-pPOirY%GY4z5i-KmVwv~V6NFz)&=F=WgpP1rBl!wOiH9|ztiHFGAVn2D?OkS! z(t?m63$%oc#l;sa%cU>bXGs-!LPN8#XM{!i-eK1Ls#DuxmUA;k5oFPZ8;fEHw~oJ; zw7^$g3qJLlf^Rw0UUaA;i$BY& zQ1dx90_*O3vlQ`0%#a{OE#fG|ux`OW=a@~T>xC4v`j#)M%OhWil}E-n!oAKg9wRuQ zsK7hsFK^Yz_L$BxiT?{%-{Z>(DwWVIvK5y1a>;|WQJsP;tmtxyyy8L&oWGA3l8hLp zp7*eZkyrf!E@CV*{)XaxkKZUz1XO_Rq8ySk6sZZn;zKQ|Pz^w>i{f1h+d>j^K!*WPr&POp%i{ zV^K|x$tb~Wg30JIV>o#+5Be5C3S#F6jO~mG2`0rVz6auYq?vZva|EwB)FeTApW+p@ z^#7C`ZQW0)AkRC2asqNKTj` zCN{o9zUm6!`-Xxn5tB44Me_gKO7xC~>oGfd+FM(h?XArA-_g71S*R!4(i@*=cK1|9 zg}cVS*Q#}jODtv;URKF^oK|uKPdHS;pzM3B5M?g0MoyCzt+&+y8$sTWBoCU5;8{i4 z_F?RNOi1u@9--xv{(n~Y30`*l4>^LBm6lkJpA~G{DS2To<3AQ6K;Z_ECJ-f zWWM+W?52*NZ@O_bN04eLttw_ttbGV3GZ)i}=N;4%IW0iD5qw>fN|(&ci%#rOg2~Lq zOU7%%G}~#HJxB0I9BT9x1z&Zj0-q?;CZ6PY zSF@GJA`)zLD7TPkbEu*fxuMKn)esdSc$4LnT*ol;H(lmYg2~LqD{@gYz2GwE2$FAU z6*BX$xy+*klbH)k_T4WiUDvGGTgc)awFUF-qLgi3-Od8apcv1hlv3nbE%%&;&^W;h ziYi@iX8uW+d6Zx>b78%e-UO8{vwM{i`Iau33>sbLQG&_L#Y?`a!~VN&_|FmC_W@?7 zc*TQetWat!fC+9)Fc@8C?5>!QV6vn_F@5hnErTqI>q5E{DJeopX{fYxNKxX|M2_H< zM0Ik@jJ@QllOuRFk1$=YJCCP-m1zz|GwEEET0p9=G$tI1TXB0?lO?}#Ru#IVd`#jiV}921L& z^E!EX!A*s71b4f+%M`%_in7+n*zuTm z-3&p7nAQ_~MX9R2#7}T96Uz`ifZz?y5Met5zs9}HI1d*hFcLiDf8xX#CCEuJNpC92 zTaGkGaGz7v3^ji$Mp2HHOQ21ZmXe-svAcxy%^ty4;%wmNC}K z(lW-1fhoaI)Ue;FUDiGQy$c8C;yNMP|Ybr8n zSI(w1l2bG20|coSluVF10ad!zph{O6RO$Kxm8@hjII9!f{ThNXL9Xerbw%(!rLta= zu>sd*4iV%Dl_g{>7ZVbkRFoxTY(6F|CUg>4Sb zjO~vJ2~uQB$XHx~>7=j@F5yWfeOu`knRSgcL6Bj&_kA#J#u#GLh2ROzTkR!&$bR{Z zVi}4NDeA{vVWR{uI39_gxnCyslFN`Ic+;UK2)>~xID?-#xy%?1%vOW#QsLA+N-(Ra zYA-1Q+vj1IVWO}lCY<&YfO-alq1{kr=*$FPc2bL)8DpJ5NRSo!Ak|}Mv6W^Wa#{zA zO;^KW6BTgaK^1XQ!wkm8>Tly&vrNI^Y^RKg{f!SN#Mf=gmUEWf8Hwo%5l zQ9&_UM^_Lv3WFsVY6qyaYJf`X1t_Np1ymaIyTXEs%a~*tloV#qGGY^&EG*-F-Ki~l zyOThES=>A~9BPW-8;Y{7kFmF6LW1w*5i(Y(^+U}GwkgVT)Lh8`ZYLQPxJ?lh6axUk zeVPRGCdd#9qb}&+kdfegoRQ#H9cq*y*XYjS5Dt%!hMaf-gI+69lg*O61(L%-CBoA;DzvdkS2j zlwDZxUKX6pytim(72X7O8ri5JIwQdmC)fMO_#tA_t~JgtH2h^i!rKpj07Sh zz`{s^B8;pU`&AmYHEx6!w%g&t7CNl?Qo#X@b6Oq2dww5A8}eLITOdBonD`W1&t&6K znN5^QeFYB0ah{$3PzEX*RU&v+Dd8>&ava2k{S$6bjD7he!51}awKwnEYaFLhFJdn{ z#-jwUC<-?MzSrI9dZ{QEVz0+s2r|UoHG;1@#!KbPj4%wmrAmkVJI8Mi!FL_%5W)8p z6;JZNjG7T^RWExfdkL1S#&K8XdzTrhRAfFEVuv*qTnKJ;sL6v0&c>*;VPHp9#Y_Y; zubtQU2@U(uj_eHv(%v92dV>kj8`$hW`{A;sCH;V9Y1U{0EXpiaTIn3&*phZ-fgOHmn7RZm6c-8IWZeLAKlNZ}IH zN|Xq;DNH^^dq_-Qt{}(=vI@o9FV2du2fNIp1e2KySG#I(CL42L3PbSLnI#uxtac^m z2r_fE=yG#gsm%$KabEdc)eyBO$VO6i<#52oGY%J&C7(z3DaVN4CTHZVNYvgFE?w1RTM(it_!p%7pDxToeaavgr8TO zx$?`%Sw*6;30`ohJy#UG7Nc$`_^O5#xG|1)ZCmE06V^dGazPD>o*Vh}o_w%;EGC10@O_C3A-I^|#`M8hp`0ZH~As3zd1SBgMOg z3*emLxEs521k1H@wj(fBr&#bL$l`9{FZ9^ z_x%UdgFvMOH!2F>75A4JIS|tkJQ&lRTxR5WOm|wr^D&Cxg=E%?8hJIQdrQGOSL+J*?CH4 zYO8Ra%UURl;l;)1i@K^pe4VB1y!&EoEMT`Q|n^r(=RdO!hfm%}3aSefbUcn17iXa8P zgo$x`$p*7OgmV#C7E+|7MCc9YK`_fsVY?nm= zDQBw|#+-5#Dbuo!wq-WcaV1G4r8!|2Ly6`!Ecrz}U$@aODvy^mL?0n|RZ%(-+}yTI z%=P?~+uN3jVaO>W<2UkifY)n^xtX5=Uc}HUGSCC&!re$x+JeA-v-6_jFKdX&5JA=n zhV3sia#iUfZ^=wX8K=;d77t;GVW=sXrV_&nk{7GTO2oXh&}5)(aZqvd8lo)-o=_C^ z%J><@$CGtpxV6n3jGxyW6{^)@IyJN3gGxvdpiP1-owInxS$3tJ-9tUZuvF$y-f>`6 zfUp0vScd3+1i8Oq-gv+WWx^XGPP%s)P#~#f_81m7L{Oee?--KWZedcxD%*&LXbgh; z6lEswjO>r;2p&*W@exJGchIDZ68AEqd3R}OmY0k?tVlEoL5cw}39|TN-bxvmpw)59 z5gbrdamkaJn_T8mg2~K+3n zC3wZ5CJDZ)D4cLsy1}(PQP`+E#H(|I$0Wg|RE2E{Q#Rwc=TWAYv@~fN!f!YU@Umz| z-gJ^q5TsDp)gj2@Z*9siC@&TWtrGlQSIj6&e#fD51X&#V6~St!i=5KmGRP|VSe%XE zDTkUQ$jOUsYsStw!W_X@9BPu_O-0$fjJ@Fqa|E}#g~TMmZ4Q+q7~ge;-E{gopeCCD1$f*!%0uCk*9M-*k* zF-8>>xz<>u@<0{Ve-G<_%852XFj@aSMe4tY^=Av?sEXiCWhVmfS!Rrt#t=!6l}28I ztTdrwk zWQ?`O@i9Tx8UhkzRc+q!pbTOs`I9GDC4}gwJVO z;C)~5FHWT8-KYr2NN~SHO%WV(s2stAiV`*CmKmFLgi{1h=Mie;mH~%d^lO6D7LK|I zQV{VR%I=_sBGagoX-TojOE4)@;gAG+GbB+V!^!|Jn`vEUWV_=!L6DLex`UcdH555K zE^}vSNqGuAsI)2Bum&HZGS}1`-*O%1mVNY`3eHJIVt&ySb0Emk)tUigTuP$S1P^N7 zj2FB#UTMl8ieA2miZm0*uc}x#HN-m{3066=MkxT-!Y~ekOOEO>f^oq`t_Ep2c|oTu zJV%g?4$n{Upi<>`jp;Zq!BcsJjGc9aQv}&2mZPTMGN5=+06}(Um=3{%$|JwS%qbRm z37*O$WQ<~gqox-L*o(Gm8tjQ6#Sk;m)PphADFxX%kda_qa0yeU|9&`jr3Cjn)F{F8 zin^70$&n)-ltYkgFiH|kaxCg#v~K&gWS&x>js&?059KT=)o~~K#2E#jcc>gemR+Pf zX{j2tYKTG!vayhtAg#K%a(r(3XH+`$Sfu*(r_Pu6W$SAP+SpCmWB(E9@q18 z1Ubts>U>x+E|8Sd8jEvI-&9nblm1>4 z7@Sw&XEj7WB*=EasB)9!PLL^Lk|EXi2Z{tUg0XA`JyVEJX^xoe@J&U>-xu9X-Rc>EqBz|l8UV?n(JvQCSml=u6DL5qa zeF{V3BEpC)@91@kS|@XkAm7|x%56&aI?XohvQH4)?@*(Y3X&sqC7ILDRwc{1oO=s% z7F1QaXg#)R2;(96mO~vT$XXY#8vK*p&`I%>WeS>^bxoD$je+7yp@vW+!HbGA+kcF_ z64McUHA%&W&DYmM%8l`S+Mk25~zFKT0)19IY5%nOJS z8bfqp5ah*AXcIlJA(#+kh~DyJ%ZzZI4XZurzVN_d3&_teGjd5e8p;Ny*5&G4k^TJK?78 zN{|Y&I(X+agl8Z)si-pV=~=?_iYwJGIcK~Wvr83dqL(!JT1-aJb2geQmXl;RUCzC4 zDH!K0=#QR1sSbr9>X~N05eQp&rAfM2Z$ti2XmR@Y@LT1U?qHVcLzAKi# zwmARF&yfD|eU?AxXKDIgMR3>cVU4r9r|Abu&|g>lD;m<5r1Ni0c8QRa-gisn-)g&uw@pL7ig};L)Ahfo_!l(fZ@0Zxf}VK(wj0A< z`SM+n=WXTl9{DLR)OOZsY?qgulz z4Nq&B=2t3zxzbl^nC3UH_$3Ybo5E@SrSkK)innV1?HZ0~xJyI+eDJKs)BGdY-KX(`8qRCz1XX|wFpgtqmF}E|oab;&`GVr>bbMntqVWS7&T4o@ z!%G^b%jf(ey_P$tgbc50oZ;&lFBR6Q-WX;zo}O=4q)rpkVUyx_Ynan;zlH}ioYXKK z5I?U8OBx>6@Pvk^HB1NWA6Hb516ps+%hU8PD&18LuW5KwL;6v#g#PG{ng9LhxlY)q z{J2g?`{PMXzoy~!66Jqbe(Cy?Z@IR6rH1s&O&aI7wbJ=-s$6eq_?CumYxs_a|5*O} zw0w>W(;A=G@U({KG)!-vrsZwYc|)s)y&4W^xUEFETk$y!4`?{4;k1V5ON1{fJ}uAt zl|Q2Sc4_!w%fG1kE|n;shb}x}NgtA=@dbg( zA!^v-Wy-iy7-ak~Yz!MBKkOI^`+CBLwlIvk!VVyMd&AZ3VQ)`Z)6*074~IQLV>WCJ zp2>zC!BbfwYs3@wMRj3s7ot5Om^Jxfrl~RPkD3Ho(~ext*|0x2vOTQn2s2T4W7rGc z0yKp+e%R`V?O@Oo)Mmr_U@;qRTo=|v!RH3U`qg1gbJ!XM$Ng|^N7&j8{O#dwQSh7} z)&&jOur@fB4cmsoRbE+nS+D#X3NsQ2n;HS40Kd?Huu=Xs#Zb6G;NU2V7r?hHqM!<# z1+h-~95uNI1r-I&ez?*=zWmRIro`Z&VuP%q&4xXe8hBG6)N3ITDmqQ(%4eFzZ#XTz#ZrncV&f+w?K6EgKfXTh`Ca0aNSv)S+q;8X{E zkjdf+nPtcMLpX@>8aMnhegD11mph%Dj>Od6*Px;|P zLe|t1R<)s|A@E0j6d<(W+Mo(5jXJ`{$VWp)ec{@u7GXAAS1V1}A2o+9kfMJuL_20~ z+YY%_`9SnU_rbmz#Vj5|6}NSTgTabyI3`x~P-nPp2g>S%1&Bq!>Ll>PvB7Y4Hhf(4 z1~ZVLH~fUrVq4fDA;?VBhX}(>VJ!?O1KX%+vY)jF`EF@hK>E#`QStKWfP)F0l3JYlpoY?nZEk2ZiNj|$W@*wHQA zpV^L%;fI5p!@l-#N00nR4V$EjJAmIaNDE!L-&PUGk6XDH(7^-(r9nt7??Wa1aCb*o z+a1=Ub()*PHq^QvN^6E*8#}}1p{Q$UXlTb!ShEv&aEk)rWXpp@b=$*L(o7xUs_w9* zJ?!og`1bCwdr+cAy4#Vj&q^^f81`%N?Itw#jr2^kR;ngOCvDauCJg{7evtJC#ZK0S zYY=Vf+8(ayM6@gPqZTAocMgU_a1&w>Ln3{5IMl)a!{N|Ih2e(kJHs_YqFtlKHW-9F4hMyXdT#0U}kccRV}QLub+dsw#y4bU7`7#}3Pqop%!>k8LP^|N7TZHRuA zX%g*(NL)W8{UU6K4uXzB@c{Kva7gUsUz~&y*?tHQ0BUspXHX2%hkYq*-VfUX^uwov z914ef^L)-1v{ia0H_bwcZF@8;rbo;Kh)V3?#%9oE}9_uUwmF92lM*i zCww1#1;i)Q9@fLvh4+Q^9nxY^7KSOJ42My$9(hnc8WH61D`?NIaBU}=u+ufA3?bk% zXnaWx+IRqBfJ_WY3h0L)vNVI~CK`-_$9$u73`f@Oh*&k~^1W@n;r8GN)KG;{K}I{_ zC*2>R^qip~j7-6dP_Gil6`%*0(F{GTDcrs>Z0-)%n;{Gc5wS~b)3_3t9DGk7dOe0w z@ozQ82f)Kr8U8`Tpczr6#IPB?p$TGy_kBqN@I2wpaP97}b;v4YQwfE@Pyi=#QdCJHrsI3X8v^J8bRgsgtFOT#<&1AlfDz6<(h3FGSUGJPwc}dg_~fNGAem%?5NaCld5Z142+=T|*}<3r2()s$)@&%e*A^bGk#Jbi zo#945x}_`1r8o`wD$ z{E?4w5@|DjW4IYCHW(kdB`s_-Ne;&D<*kW;VPRscXc>I>Sv+^_r|GyIH!C_}W$BrnMnFgTyvSH}hKnZ$v&! zm@{Qp*V^`2CFN{H3$)!AZtMu#hV_3%HoP5`GhORA&#h)`yIH5fbU8&TtC>9aD9!tILhZ4_sSiBsDn;f`MT z2uu|*u|;06d=j%5%mXDiCQQIJN(=|edxC;YCW8zgwWv)8h7WYvMs&?D z%czCPOceYbM86~W%1I;x&W4qM2aCE6J65-gyFg}f6EOSWZ#_S1#n>M0=-Pqjar5^G zI?4`d12h3FSSF?@b_41a!lE%X9!3HzK-U|P5*|?I<3Y5^_TDZNL6H(}q!&y%s7`I& z;b^neX4rOxVd)BRJ&9iMsOtrr!kt6mgZG9R@lY5IVK#9709_ZrkSnvWp`pzfBfoJ1 zRn=KGCY$$xygm4#ARB%x_^&5q42Xgs4B#T*(Qc1+ipOYf468x4!kB*s(*{Jk(b7BA zvk$3f-(=%mrmKQspQ&(XxLQIOyNODp-=1U$1I-MIVMf6LxS%NL1xau~%oVeMdQwxh>O_U(X>eI%K^SF`tOcA1`v9m{AFM!m2IOuEIL+zk+e zMjJ|kKZe*+a6^}ri~rT@&|`bskR>Zy0C-S7Jalh}aau+oblgr1U6@nIw8)CwSE9^S zSVC==uFxY>RROwXnJFC*Zf&Sb_+dQ9YDU~LMhe*A0{RYSvslugclAd#7*MJO6)a`L z!TZDh_2F#;;b41s8x|Yuu;j#QGejqs6+#$|bT{rs58Y)Ze|}#$xYi_MRuXo(N zznBS{b%uTye%`_Nn~e{96&>{-?ZZ-@Diuxmq~ahvRlh(4RLsK)AydX1d%Djjy|`+J^x~Rb;Q*!;m?*6k$6qH9CQ$|&2p-E~oLVVsn<1HQ z$X**(H4V~_GEr}1V~c5X48yf{K~y6&nW%3SCSNrG1~BiCsYP2~SUZ3dc5M`7wi{J z$fQ;@@hC#{PZZr3RsASyqEcunvOR=rPUcfbeAEUytA(#H%L%Wxk% zvhtrq$FtEo%MJ4lqG`ym3OJ(@EM)EvJ|&cds=C6i zpxW9Bc1uv8XMYWU+V7_?XR4$9(hHwXg|bQ%I|dVwY*u38uc z6KKnz14~kw=VE)uo<7uIc<#hn7u#eTdcq-Ck!e0yN~14Z)lu*$mTpn7*@x*MPqR#? z5Qh;r!=7Xa3`UR^Z1u$i5PL*oclu2&&9cP+vM%hGNw)$x04AH8kiRY*><+h}kSx|B zv#F9kE|oc4SQ&I@KiFwEK!ab$atCJhb*zIjh)B}cJ=C`VhL)}&L8L=vWq|T~p^=(4 zS-*ZapvNQWQ|NY&qirzte;k8j7yg48W@upCFKS#5-Tv%JS==@Te!Z1v&3V>(%%P+~t0crc%|v0Z5@y3P_=|S9Ni3whu=NNfVy4s{cJ_wN zZDD&)cw2AS)h7Qtu|;eM&<;ofK}8#K_n2ik@*#H_dIt){>=KPM3~z>cZ&O&-i0y~r zumRKBwPBMirdq{mHS~om+ry@HvbT$aXG`=+Jn{o=j7n0Yd9?LL4rsiJ1;AOLjZ?| z!E>_qJZmcJD9N+sq3(y z2|t3ylBPf}t0s5xXj)JnxWZz~q9&~AcSK#CQo1=|31ut$v!XTW`rYCQy3tH!O%B~1 z1)WHj$pZ@P$+n;Z818z*OgA>2Fuh5DWoT17g_a#X9~st#XVDgLAjG*UBBoV1M$pt7SiVEhflLY<@F$IZ4)@Sor|FhzhC+L2X8 zbIW9hY{;}`!!5{)Vz!uKwn#B{ch(jIKG;nw#SA9>e%V`!W;QeO`+XUB|MPd^uTq{V z6-_vv;$UfdOuffv)JG-9wVy9*X>c#1)*;%`RU?=c)Xg3Z_&f|GA%xs*> zv5_ooyQ6ODhsHL`BAM9Xgh1>FyI?Cfng23t?drxOYxl-M9uqyP-YA ztU$I4WH;9w6>K#Qr@A|=k`t#c$t@J{qp}rYX5`=?XW^Otuv;z{WcooS`Q>B`huND= zscYegw%{I?jX3Y@h32dxBk=I({ClVM4$82~uSPW*bq6Uwj~ zRa;G%k=b130IJmog5YWRLAgqifnc)NFRdn0-v<3;4@uOh0LN@LyX-TGlax8FsWk*_ z16dyiG7Q~zXCfYJYh@${6PdqNVWjhMEFs%F7yz)|Tx%e>O$p`rSPanMP>4;-LrO$$ zrLgiwgWwEXozFHxZXCCX1h7?^A7gQe)fCDMup8TFm7&LAa{ZiKeYq-yT+(+HRJ%7cHUT#7;#2K9=7f zHMSCGkQH)Oy`jVaQYF*zEppH$^H#Q#(8w+nObZ7WB5x?G|HiP=>bk*mU#|GOOi74V4AbuN$ z%wuRV$&QspUH0Cvr4O;&%$6ty$`&z?CNz*acHW5T0_+-=EC;^0R|WlqFu4qR7dTYu zz%8967{IEg3Wi*bO)nrIB-%$>13d$lflUL|c$M@N$3rS(J)4{|%iasP3(+1Az05Y;xQLc zau?A|LN;OC;n!D#Kfd*T{;yOIKoM z7?CkYoU@#$AonLA3O4l29-R9RHcw?y+>o*8nn+FwaedL`2%i3UWVQ*horsEo8EV@a zJP1WMVv&e_xW2FzYyT}_>sg|T4*GFnXCwGw$zYfExHH#eTyLZCWY{o+jXnT}XD;u8vrWYn32gReTESl?$kGE= zfn&Q|9l+HrYtCwu8krJ^(2e$3xQliYY*ok63-KN*c{YBv` zRT~s-m=29`TlfazDGE4?PewJ&o?y2VW-U&rK#LoZFj2iE(1N`e#BgMW|DQDf(L6QM zJaG0Xv@5K^CYf9;t`U~Tm4JJDSD5KRBZ)7AiZHW;{#WXL@V|q{47>-huKEB6MYpiL z59G{02vNe&i-V z_CYbo??NqMy*AZMOpvx3{o7uQl5^nZutU0oJx-NwA$yAwmkYm88>Uaer(~Qm3uJWD zAyX9gpQXo&D9s4_5K3HnsD$Qh#_aV;CzMS0qu#g@Dv9?S)Q+wpTPO~7aOJp5(zD?z z@Wk9O#j*x7T+Ax7IOoN_yt#G^uqkZX2(@R5+!emP?jKzyood0-8Juq7Z%luWb%wU$c^GM~@1MH`}QS%A}>|4|{m`IrAc9J2JJ z#`LiG%qH1!+!QUbPb6Cde51!|*jKZev$u4~O0lJ@8(~}6($j@dt|tuXHCWvBj+%@u z%U$iJjvg^<3n~D!>WBZtrld_kyf17K9++mJX;xxG#LPAjgRd4MQL}Uovl)eHh|IUK zvss0?lW@Vor5trah{68i!AutWJIVFJ)sgZ8N^Bq zCWNhf-1Wy1lWeLA2Uwtd6~xEcssvbTN`T8MCNWWrbfxy*u(1tS9#GX@b5!7WWx)=k z5(Xg|L9vI`AQuJe@SU4>`QL>7bTie&VVx|-B6H_3#4;QeLS=x0^I|2iaug}y83r6b z`yG*e7(WZ@g8>`EX3&q;F_&0Y;dnLd4OeXl!`s7E+pxZ#$zr!z)_nD5Bn^%V)F3PG zy-3N(O>@k#$FrzCYHqLS7wLiWJ3XvY#5l`E+az` z74-&Nu~H9qXM;NiMS));VU?T@}(v&NL z{{vpDsTaa6<9M(RC-4|EUPtZB^g?2GV1WtB1VlH}3zX9ofe|fL;Zu{ZR@ZJ3NN~5bJ#C8 zc)KwG%G9)1kFbW|^s$g`HWRHnIon?)7pwG`Y9p9npla(0SKciZ5itT7^*VdL5Qd>6(s zk!T5;MVbur#xmv0J!bO*p_xjp!dCb&CMQww$2fCaVfK8JPG^POZlMSIj(rd2MZy1q z6Ff-$;^%QtSkwXGwC~@e<-`MNe_4iTroa3-#tqY7e)99uUyK*I34W#e%a6!8VzK`6 z=g3qS{LJSQ{pA}#x&C4ntxp`AoP2KVh&hqKsm}4SnWK|a$Gx$!siTu-<{Y0@;9Hza z`0nJf`7y=eoZ35vQTfiTV@uxR^xVQy7BPXI9UFgUd}en1iP6S-?b*oK+@V8@Q%l~VnT5qA%gfy8fOJdV?2O>R z#&hmxgpr zF+0A<_RC}S(N8{>eQ@(#+0Da)w-0X4-adT$=HbnohqIfG9G*HlwJ<)rX<_Q{;-03V+4(!SW;Y$qZhG|g?50Cf53~{ppy^GA#uuMEIx)R4 zcXaO9;-+IqpM~XZS`w34q?FGsE=?Wrj!w-So_+#Nwm5!dYHV&{a!U27O>FEfVJXJy ztg6JIq|~vA>6zI{@7Vn0_|nu^f_6+A%bM2o)bX)9x8@ZMBau1j*rMqSGe_oO&e~=r zg)$90a}_o!_r-#-2Vlb!^I8g4K@U z-&2NW;n+OOoSpMvP~#>lYLNX3-lU&^OOyWi(DA8>eURS@irT>54$Z)jjNcFeY%@T8 z;_<{;phdj-rG?GnZ|NT=<`$p_*@755G&_D6W_sulU~NLX(Jgg@ea*p#!k>&UdScS3 zh4^TzQnbkglr@en1m+7zCyt;lV@HH9LJ`Xt>;$r)!N<_mo;fo9gp%Fuz7+mX-`LSoF78Ye_TAEuLpEdOnVvG_VJ~9xD zEi9s1^Tr~!L205N=o^s8WG@~H=_Gpo(!#L`I8|8v*u*@vGB!W`+@f~~NvcKxmlnpQ z&?!@Z&4sRjZi(KnTugj^VQ${!oq$7rLfRHZE-lPX9hCqD={S+dC#6faF;ihs2_q## z(PGeZBAF-tV`2Qrp~W#W_huHJ9&|NgC{303+WAx0?LvuyapM?*Y8ngBVA2zNo z3w>f{7Or6&?^!qs)yMXz-PU%{rQ@!ksiVddL%CB6=rl|A`ywzP@wy8! zEA=I&eO!%jM@}4r_6o7^V`EZfG@@rKVf?EVJf>7Jr1`wDXU1o(+{H4YFIoktGDO8Q z=v!!1)9+MCm>S?VjIt5OFIJ=%WXx%l_5p)-Z>qp-N*KYm#$h;+W`0bZwsd@v3U23! zcs;B;nuBRr7>qbwH4w2}5!GIxoWN9WaZzTa)}OlmVx!{! zt>0gqf?Sh}X513btMsNLEF3$UbjK5O&@o3VLo4N(4XufIQ%}e|%Fewu-MKzJ3&Wn>`##v>1C71opCk@&C+W;X#qfcb9W910_i|&!@S*qG z!D9HxJE%X$lwWRzcf2URkcZ?8yi78?g9A_Bn&~hW2t2;+GCv{k_`0n$Uf`qsq+y=b`H`lA+=g~yws@%UbA3cpkF zy(#>6DSkMGpHTd^6yClt%=aEn;lHf(2lWNpCW?Rd#dh*$?)-YmxxdKi)#c;u3-5gI zati-%l>StTKlOP!g(v-)6#n0W&#l^pul+H_;opD22VZ#b_~Mwenqc`C_Lsj>`duxy zUN`gT3;T=ZQ{kOT*}uh?d-JLOW$}Txbu?dZVra$cMLBaH%crN__}xnt(_^{EOO!kO zSU#T&n($WTUjIZsJW)2}MQpM3ZQj(k34-lIRKFTtPfHSlP@JghIT!RD76c<(-*Pd{9OKl$)7X+9t5 zEmbb{cCo15%Dw9c^UJmL7%#pnAHV&5#JolceeSc!6} z=ND4-rG9wRCtsex+y5DsXj4A>KK!@k^6AN+_apN8S9q6G^<}+A4&?Khe4lbJmnv7! zmGjFj_ihwz#|rOi33*ySn=j9733*sw9?RvITjt$N>EG73!n=_wcM<%h-5p-;WZ|KH z-b~3OX~q1~3B#vwe)7Y>H=u;<4qLBY#O3)J#h<&^;yGjZWySBi)8bn#xhF5i6h7tp z!w3V4e+l?{$bUxbWpjC+yx>ykFX;~*ysh;AUhyOSmXa^({1e4zAGG*0O8=LNKlp&f zZ&$orGZ+5!w{4)4r&94Zc3S$JMSBg3zoO;NDt?XP`DOWCith%#4)dH>G|pg?(!bqh z`BQIqDW3NmSnfwiuYQ#;B>j})n}(H-%0CNyJzALl$EJGTGX`Jb@n=7YKc#$j=?^|k zs-Qoh^sgVblxkMqgGjG~-n>e3uo-?*`7~{@_^Zn2qT-i2Eq=e^e^>Em@3#0;ikF|= z75UlkSnfBJKBupsq5kEzq_iW)J4*F8z}La9ZmRss-unloznHSy2I&MN+|6@Oa$%QOXoAxZnb zs{AJv->CT9kS&+B=u`aLJr=`u*#x}U1LsSmzf1A2rtIV+%7?E`;){MCQ~K9Z^ixWI z`VPzahRQjsc)k*Ax3=%IiqC4hZ&ms)DE?-n<#S2te~|pUEuQ}HyyA0epIepwr-7Gt zOwYqFq8!mD=Uq!$?k_8!@;>FSe122$oL|)`{qF*A`qz}D2TSvOUFol=o$pq9`875v z*Hih275`1eUrzPw|E&D4r^c6WDg6z#t6j=Ren3R{kEHCO2KUnhKdk!z^kb_Pe`%MM z|FrVyR{ThZ#Z#YmD1LsE#a~wXhZKKso5jmKRi6EdzqsDwbBccgc=40mXK1tJ-lDk z|G!iGRc$Zo|5e2gYx~kpzM*)|KdI-xQoMJYE%&tYe^>DbwH@hC8YA0|IhFG@rI+tz zN&C)gf8qFYr{WLl{P1P1*Mq=|{<$7xyX;nau9x3X`cD(D^CJ3_1BxF}KSO&sqcNW{cma^85<$B0uNP;LkS%EfWI+Zo3Z$OK-F zjGb?srg~2-E@Jx?8^sf|Q{y-~MbsXBV@uiWyFVy<`TNYSWnx?3CVEdE!;uQk7|b4b z;juyfA%oXDnfP*}J&n^tYn;~)V*7V#a9EF6?GYSt@v&L*tuGV$8VFZ2>;mh~dVHA{ zsG_^nD2aR1+(4E(f`#tO+HHN1jeT_YqYvD_d+gDVd}QxK`^NU&|G@5t#&owg-VRP| zKg*UoHhgF24$E}kEX+&}(-5!81Etms|^Z|p@rshao28g+(??{-crY^7; zMy3}T2q&w0M<#j3Y8#{QfD1y~qgLB&^TiJ95=!HNTH(2vw7WZaHwVb6vxC%~mPD%2 zAOyhyPTt)Uu}^cVt~W!>y%Q-%kH}3HIY?6Tv&Xqew@2ALYBnY5IhnM#bvPi?D+8{L zaY|!Mmh#BialuI;bu1S$RP%DA1zA(Kk3{;!kzjcAl79VvG5o;SGo z+!2gC2w`m|oF=p+cTolx=FF{$!KrCnJdtz!K^s4et0jZ@H#m=hZxG`Y5~iLwb{NKV zXpZps6Hmz97frzhGJ@j^GE%xc`7v{5t$84fHz>N2Q`PVISqly_Wx;T-4@Y!6kva1a z@u_5ub|DnX+cnN}xib&h{6CsH(#q%VdFwSlmaXRD`CWF@<{wTSWih{!d-#P?Q$D68 z=HdK1C+|+c!}+I);9olb-M|SY^Yc9LwSzYQ8D`Xw`5E4q%70Mj;RnZU{?_-&|52n1 zFP6{q#p9ZPI&K)liRF^*ZUD9fL*`FmrXu1BrXNH@R3g-XSP!83PY6TA zLBWs&#IW=OOP8P-YFOHXsDzL!_CicOiI)Cg_QKSH%*Cd^5Ht`41na;gf7+8&z*TYBU4e_fC2K0h{PURC9Ib%3loKAA>?TAr194>xNX^K}Dq~?~X01jL0Yz#VqGV(T>0?vjo(Onk!y4ERN^D?z z;S9)uLB=Bv&hiXzP~GHr@C_HXjis|y0ZD{uAJMP6UL~qt1zB7 z3p)x=Y#TL3w!xy!h!HA9x^+8>Rzjw|M zqecmuH-iY=(l~Mp-v>Oi{le0Ah@K;GL_vWE!_n-k4RKt@3{lmgthi+ye_2NjC2??D zM$Gl|M2(x%YoniZAF%OVfY8Y&KX|{e{{Pm8;Vm=8`#{ec|1NA6Fn&NV-x;m2D&RNk zIJ1qQ>bGlNvZ#?XHMx(1rt^hZa~pwE#nHIF->kY(GjvvQ{%tpmK!RObiz>0uNw=Uv z0%)yzz7HZKrM1)LR#bx=6}Jd$Ldg9jV`SzH%i3a1u*3|4IUz(nW;ZpHV?AbMfgUXMgOXf;*> zuV!OwD}tf7*UK~^I37g#lt5Ir(r%B5uDc$1w%MvR zW^3MBQ?$X;zP)9|b#>JZWjJN%%Ioc@6-($>)N4^W3f)uS&y(vxfq&$&C+s7o{dQ^2 znRiO|{M>wLu2h<{i)$-h;DxSV484_Bu^ITM0rMMCp0`g2O^Xc;lI^dK*HL#Un?K9I*F1>{W1F@mz}gKB>=&x6B9$#?vQ6cH>@S$M8;J z0|q%n7P-|97wng^KR1_tlzGm0^7>!i`6DFAlmc%rypT8XFzPF2;>`lLWW34s4ko_x z3B{z-Ty2UI1fPX!3)+{5bq^>{$^;xqW_(EZ@MCBHkVY)xpvc`27TrKc(2^w0{9a7>90r(9$vjq;upe0K^ymx4c#g5z~5 z$?uaXxSxW5BL#mx1?Q|hQxh{AN=}iP1QWB8U2qR}_9_xWcdgzkS0VdV-0Ii0#M7S| z`*LY&nw0sTwm%G98T$^{fa)sqJ{|{L-36bByNRtDZWE4nCP>C=kAlOsrBm>T#=`b( zsR@DWi-qmmQWIh?)w=x!!uNw;9y3A*6&x;Do$@eA3mX4(3a;{x6OMlG?pP7xaRuL@ z;9pX3juk>*R&adhxtt^c?cd8F)bi>Nbp~)XOAHeSalGDMBYjlE-y)sYl=;sP&T~Y( zbGL`KU5Xtw+wgj^ot?zHU*Y3;zC!u|4Sx~*U^yIDa$d-<6VCBx`)3IMqQ)n+K8CsgCbP=2bB{+hzavxC?5bqyy~ zT-9)%|JxdVg7kN(X1|=-KT!A>=R>4_sNguBACmr&hW~(cK6-Wgn<*ZQ&k%oF!PUHR zpMqn2_&M*$$mq@(GKs!Z)rI1!)G;|_u)@9{3O}GsNwuR{f2OUuPzh+ zwG{kK4gVGKf1858rQsJy|3eD?XAOUY>|am8-_vl8|NANUzcie4!G|gMe>9x)EL{C% z;kYqAq~YJC{)H5r_YJ>qG+n{tVw`UzoZobOiaIjxlg{zbaXxn#kBHCvl5yU5U)AjM zne??3Jk)R=5ARF1&vsr&;d6X2&gyNG?>=mYx_2raAJFXcd~a(w8{jj}0>5hB6He>& z8hoZe9ffhd%2MQQM8c`Lkt>`^t0kPUi3&1H&H|{O?>a~VM1BVnRP!qB75HSVH=(zb z-AX0&PW3dy7jTd6hHkI|-%7F7xLX3`Hv*5X!Z?IeZLY1sAC$rgnvv(gH(n721DCPb zj<;H_!!6C@FnsJ9?+*Ct^ZK!&MHaLgxoVjL1u^}LXHg|7vfh6;wBee6-2S+4(B?e+ z)Urs*vgc|$n^IxZSe*Z}AyURZa4O#dtGJ)#f#UE;5Hc6XQGA}!6NZYhcmrc?pQqoO`D1uJj&b-+j zI`d}p-b_qVY(o)jn^qbrS|M#(5LCo}6k6*)Ci;gUB7UG2!6N;~{OJcsLXGj9`_7qp zb9c519@stS{O=YG7q``pndA0JQ(gcQ6BT}@B`XI)pG)#5B{f{g$vI5`b)*#YOJ z>sIOa0|2k8EigL0ymf3AX5VuFa#L{R>`j2v7LK9sduL$wwwj&3>;c>+pF7X|_&XT# zRs6Yf$AT-!Ujw-Gn>)|k_%@AyXu&5?KUGS>+3Of*%CUYom%p(YbB_}C_T9Uu$qxPC zXc#ubgU<0FYFDeZa?KA~PPFWmeWw;UttH=C^1bCDvWzK(1*f!_(bLY$fbf?^K#sQf zE4|?%WL9dBG)tv58?cF`Qg$t9ftAskr84nYY?;wa$FRmGzlcLt46&V^(Vt+CZ2( znXiFzvdM8+qYd(dmx(i-X0EQjfMJJ8Q~50gMv3K@TOp{8xun-x8UF~KM$~+FLcm$l zJy}NBUR@=JI7@m%GRu(8lHQffGD==*aP3*ihCIeHJs6CMfn7|48ddiUkLRr6$>C8o zHaLPidtd`t!v}K@=N`%(AIHVo3Ax-Mw7_L%5!b<9izq;Pf5P^$iAN@I0cnIBGreO2 zn{X*z_1J`!iG%N&I6h7}XE%L)ZbG5Mkc~S-5)W*AcMglmA=W8|LgX>3X|zU%WwRAw zhkHWAVb{L+yuzs$G3&@n&np<%bY%{Mk0wjz3dUTZi3P(_2e+@nyv|&~yohpk6r7S? z3#Vfso-GCkVCI_0FEEDD#APLy4YH+cEaD>_=%k287|Oyw)clUY?5)k$1p0K>T0|)> zVa-Mf_8`j==VPmtiw1Wm%%|8>rjVkdt|daR5cQ!)RKZCRlg=ksIP05+!-&WK>`Z=A zW1fRx*&<5jJe6JClD~_zc|`?#&@rw;^2d>6UvS(GE8#J>;9IDt)JMZ>Kp~-mKPn2# zfIoX(cW*5y*V`38A+A1>FiMC3jSHoyRjJn&+%koa)rwzrm#E-a#hW}CqstJTPF0R=ec z)!RNayy$7@1Sv0hA?RP!<t9Xn6~DAM03ZhApR4s_tJrbzLy^j%{d2_ppJ_ zkM86Mh9?dmKIrT|;xAA^@gxcd?lY$Ya=_HZQ;<5pO-<&fG=`V6CK;#uj*c0T{wkjs z9(iNnP4)N(f6^b!b%;NyM*(&-|2RhHEd_tO+t0?Lqtb^gIu(7$>f9jRLH(LoHI9BZ zb&XMq=eZg#H&l-cR-+$MJzyMXB~C_G{LJdHkMYDqF)?ZZe)0Q|1^GTG#n(%*V$ABS za_^AUeVTLz;`+yd*3%>l@ble=toYs2GeVYQiT=wznq*vby_XQX4}Szhu|xNxL~$yN z$liJY_0hz-%L*ORc(?!ZK{$qZzxX{j^v?6Jv(mYhdhdhoJweZ3zFxYwReXhYbByB_ zmYS$^c`s}=a5+)Q^WI0@)o3^V zHrAy-5wO1}=Ziyk+3>viu(7)aT7C6MKhc>DwjNf6AQfWsL~>LjtGul5=~Taf(BC zvz(1P2F|MPFUgXZ?g63+?w`b=^G-zPgh=p%u?jm9IPJq9Fzzxg`%3PHqlW!wS)Whf zRR41v=d^*#zO5LzT!l*p{%?-cU|i~vefDeum$ODLFDBwp?e}n;*An*0^YUH8zQ+1H z37qD&i}fEFxb*So1}^jbrGcMe{kI96>XiNZK?0||Z?pcPfxp4}UlKUQxq?4Le^1~P zN8@Wmc;fm?1i^t03rnl0bO=X3#|zvZXd z$zLi}L$BdW-~M0jU;tWLSucq<%fib7Fqb|HOy4xRlV$~Aev?0B@3T(dDas@7icO5) z%eeVM{RNMkjAA5d4=NOMHGjD;#mCf(I6yJ?i2?IpG2dn2Qoq!36vs(6^WS1Wv6nEW zK8pkW`gffUC6e@s`bTRd{({rHLux^>OAKa`hXzMY+ourgm;Zgv|7UI(<)_?c{xgV~ zF%g0cH{^gZXs8gZ;(v(qPW_kqpIycObG)HvsF(zq`7hvDzxn@=|NAKZG=JLC=KQ~k zm>Clxc!l$qjX^_&SJ1X!{+pa%)|v9to6pSuCSnv*>O@h~Uk77;$w(-waJsMi`7dW< z|J^a`{1!jq-)H}h0Sm9Qzln>V;6FowFk_iP{LhFXbD6)uKS7~i|Kv}uV{AzMqra`h zU;5fFH@V#6`rqQhHXtTvfX2n2%*?Y-4zne(T2eLw$WR4mf3W7hd?`u_*F CpB=~m literal 0 HcmV?d00001 diff --git a/demo/build/my_string.o b/demo/build/my_string.o new file mode 100755 index 0000000000000000000000000000000000000000..56659390684b076700fcb2088144ff2500b6caeb GIT binary patch literal 16712 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 literal 0 HcmV?d00001 diff --git a/demo/build/start.o b/demo/build/start.o new file mode 100755 index 0000000000000000000000000000000000000000..94bab4268af69bab3c9ee7d2c14a4d53a3549f65 GIT binary patch literal 8304 zcmeI1O=uHA6vtn>t7)~``q^l!O`#xy#8wmq#jdTbRjXD|^dL+(>9&a^*}7RZ>cRMN zkm^B2@M!ep^yEcUyyWKDLV6BGL_|eIq!lr~+02^Fn2LCC5q4;1-u!mv|7PCKPMX<^ zy#swUJ|Ec02T!0}vnfEw+On-!rUG?PTZW$HMZk-I7XdEHx29~=S_kzz||2dcaXI=K6aoPV3m;Ea)`wzP8A6)id@3Q|K{!Vdo|I51UKjX6h zA(#CtF8dF+`Lo_^IA(QjuL)9)8x78E=`z)!*7NDF?20{;GI<#fX?)a*vh9@N~8n!Tvm zhnjm(vmZ70qUJu-+>e?AsCfW252B_rTksE3Py(nMKwX96IB&7Dga2*3LC8!7rX)=?PF2c#vi81CZ zp~jMsit1-$$q{sIyMmZ;%28_{24Z=@!5XG*$Ife2x)Pk)a2%ahNc^N$Jni+m6mRrO zi+-^o*dKNh6H-+)lj`lKN2aGp6xV@fgkOv&xUN`I&?g|IL$#ocSa&QQx&LuG1 zSeizujM|o|rA-J8tELJe3_gSmEv|+b4TW`GeBzy=e{Qom;gDdy&_xmIc9petrZ%iF zChla4vysCV`>(@m?9ut#{+-yDX^P{wUxjCd=h)`h#Y!76XM3n()yi4_nv(sHBc{*V z*^jw>&zbLPyL*-|t}MTZ=kL~f5c{)zTAVu~Jf3GcUK0W)RDn&eTK|uH{5vd_awhiw E0e@kg)Bpeg literal 0 HcmV?d00001 diff --git a/demo/build/task.o b/demo/build/task.o new file mode 100755 index 0000000000000000000000000000000000000000..f2e5b91a9c523208b5735103a97fe819196cf595 GIT binary patch literal 9632 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 literal 0 HcmV?d00001 diff --git a/demo/build/timer.o b/demo/build/timer.o new file mode 100755 index 0000000000000000000000000000000000000000..6923a5f0211c0cbe2193240774cbff9d0a3817b5 GIT binary patch literal 13496 zcmbta4RBo5b-r)kzSYVrODnA`%Sf`GgbapSE6WyOjDeMm!A|*+WIIEC8hN$*ED5At zvAY60Cb5X!#!YFlvB547=$MpRZl+~gPY7*VQpTAuX_}@1r%7f?1x+V(NZNoQpk!S4 zoO{oCd-rOW(Du&k-gCZt&Uf!U_wT*CyMN2AHwP?BaI(a6qNp({#D<=toRDHdG>K*6 z!oI(q1N*}lY;olLc5CjuEl#^a908MK^LFes=6&JfhzY!U%+<~7Eh*sz}$PO&2z|w zZMv}U?5VHYBj3j|Yy;$e+u7z_@?qO{*FJ~wknN9%1&jsyyV!T?Kg8;YBN7W7;5%|OC>GKI zu@Hk?@{8Hw^O3{?#t_?#9LPBeoSje?5roY@Zc>xEcIhQz`Pz}NBL7k60U+3&>w zv&5;l6TssN@%-l3Th6&CLyr7!T)ep4h4v%^Vh-~JaG}q7;G2iC0C5C}197l|Vcc+>c>c@^(WmzhW%QvrgZ_=E!$;1ox1kQ6 z!#l=3cgoA>lVhGck>BWojZCiV-j}@Fb7!XAWC7rtlM|C}A?v1cUb5i1g^4LIx6!@L zo66?)y2;7OY${op$YxwGm&@js2;V;M6{K-?rm#e83kjHmn8LFD8YydECjvz!5UxTc zV1W~40T^{5?4UD|DTqK=Y5^;(%9LeLX0igiw(TDDVh(BNd;y>keu=7ZIJ_V7aCi@V zS0l7KP#gUT@p#}A;O!5S>q+h7gZ=dHm8YZ$U2xvNO~ zH1y!-$~bU92v`Iv{S=0)4q8+~A}6IR$Kui=p?bE@@7W+RSx;ac%kqVsu=cfJ@Hweo z+%Lz#z&dbTI5n{#2MCluhlVNV**cF4F<)f)L*Md&Xo;mCE$qqri#l3T9EJ8nXE8n{ zc#p!1K`s`*53GZ#IC4^fixBHf{(n;q>3d814rPZM1!3C$-K`oqpx={j@C&}oy!E^{s zeF`-F3YCUef53>~sUj1G+gQMDTo&vN73KAs+*6dDh$b&7%Ax9_T-8$L^MvZFgjH{? zs*OeL+LqdStD!0iiy_b@B9R*af`fuY*!Y7@!miyIxh`^TWE<>A&NA!r6&45~N1$F+ z2TrgpV}^Ql%(81E5#@k(OO|T>8^AQurvW#v*aVBGrcc}wQ!W8mflEs*5UPz^H?H7z zT)qOEoM=8iAX`%BXoP{~&kaCdqB;d(^}qW$3%cDK!)7&n;d7PsEb5Fy z6&R7`PGb9{&pOEBqz|PEB2C8gFcjE@fbm>pRDn)|Jq<~ zAon|c=AA4a@S!25J>f$;Sv>1QLoEIqK>=|f{07NEf53-W?D3(Ue#jRIJdFFO1O}bO zZ~M@07Uv04!C(z$icFT+&0-BV>jRd~;;M(Z>Sw7QOQc!U87nQF#f-zu_*I`V#iGtQ zyl63E2WH9XyT0?-Jc&WS&tru68I~L*t>`&EPf*cwoDd^BLHg5_!;rAZ<6sGIp1u5r zc#P;dhwqyN0vU_Nwk=wjXgo_EMYFMaf{I;O)Oob{zjYq>0ySgdDAf}0TN)(AZ`pA8 ziUH_;(E3&FQei=Y0{B?@TuQ*FCm!#a$fPD`(w?DysFMG!k!D|BtlWt5_8KaLd=ZYP zuzyM%$7oIM9myBc@TM9chhT`AWDcdE5Z<1YH;pgKpu#hgw98Fo#z2LKF6A~kF{<2z z(=MuMw}7Dj65a@%Sj=e;MIEQpXVY8athukmX{<)ggQQBOOi@T2kE(JXXkVvYe=WR~(A%Cf8XVx&eFD2tw^9 z$LXrjm_{d7Qn6j@I@OI%2Y^x6iMT-77I&6zc9w+fk3%mlE`=g!LtA_WJY(8>EoW({ z$7zN(uWSRc14M*6DThEU@5HdhorwKW-~)>~u&4(otg6)ou|qax8RV;EQHRq)c`M{g zLpD^&PW{mD)^_RCFO9D6=uwr{hwPjSq)_fU%YoB%Ov;w@y8S3Z(!YGLGko}^7p07X&I=b?5CvNYJL++yBO2GjNHIzUNPT{y?t-=Uh z3B7J|s#_fk3R*)~hTMP+YZtC>cED8++}?;(rZBQQ=iMV_U|wI{H&PGb--GG5wEjVE(Lm%U7KbkZ9EZ@6!onJ#FIz7tZHDCvp3;icMMVwCq%*-SbwZn=G@ zySeuow|8xPUA)&_w{~6c+TPx^Zuiufm+^AR$?lvtmhaAHCien1IZ-G~dfi?oJ(0|S zo*bRHescQiKDT?!?Y?83+r1ki=j97YFo3Ri?@s3TW>Vw1Y$iLC@1DurH<3wq7qE4C zAv>G#?vpXZpr)qxQfLZr2`6$hnGsnwvU@T)Ceq15Qgy$y9}`p45TPk~H75$m{N3aP zL4n<9WO}9mRb_!1Ug}3+Y!#e`E{L9NK0VQshPyq@QK*|g#UiG2-o46W+}lH~8;5ZO z%ABV+Z{*(Oq{w)CVE*vvi(58t-srBr$s5IBsQ`CheT5lnb+AO~e6c<~EP{JhS}is0 z!Uc>Ufd{d?zt;U?@JV~~(ZDh5j#vNXj@KW|n(V1lKO1Ru4J2ToXMzEzg@t8y2(4kIC?F4*w7-hrcm-&z7D zwW2?Q$K@F`fF#dvYTM0616$cbTY&-ywGwot8QopW2= zDzfV5wz`S&bre+l>x*}kTB%*UD$!6J7kQObf+5nNjhCFSfUSg2w8T;=_*PX8@2!Ae z2RQOGFJFOetziH03V5;to~?l2TLJ$(;Mg91o0IDVu;YaD8=71jfSrU-y*6)o#{7lE zgZ_-*nejJ-LnagBY7c@3v97e};vLD~a*A7?lyJ|Ig52&(HnuW{1RZN78!Bzfi_Rgn zF&B?8{rog`MrA6ubS29DllvcorKYb=zG_=$;JgpE0KSZa0=Y}FiR1o+iTT-ot%3#f zGu}tI$-{dq;{FXU*xpL^mjLcxPXo3`Q))J2VI^IY4 zN&}y+U_VPZ)~omTEa4{4d_Zz3G~#d8(=#rJsFFC8D$czCX%{Vom1 zJ(3e&rt!GkNd>cH&*Q@QLBeq!>f^#UaV8I6$C*5bwf5*de1ZjlUq8qBI0o^a-5{9W+F#B&B;o~a2Eze0Wk2Dto zBAj`8iGQ1B?`rnLhCLU3OtVJ{KBsw~Vg4J*VV}l>bDr13egkLzgBp(W@GUBMNW+nb z*Y8mSA0~Ugf93Y;*i1OvGyf_B=Y4RUf&ZBJZ#3|=)c)HD=XyELcN+FQzFEVb&$Ul$IL57+ z`uSM{uO<9|hGTqq|NjFGN1mf(|FD7oKH*EKdIr!^Y3K;jDi0v;eV>($iwsG zD;kbGSCRf#2Hs2h3mT3*Jg>f`;mE^r{EmU&P5R3kjy${%ysF{I!|i_E!2g)^pJ+Jp z@cMdN!;$BG(tly#?~wj0%6T5%4?dWpwCV8t;d$Gl;mE&^^mYS}lfH^_=AT7!NEEKkCT1}<;>6R|D=IGh?PPr82B*-iw6w+ON2jV;9n;EIRk%*@UsT~ zW5WN*z~3SKbqz<6&zGMO&hdYR*85u(@C5^JqkZ5)1>B(rFy?=g_^T`6^#=ZJYX7nd zc$JZ{XFAi@0k zna7ds@D2#K!UO}9PtySM^9KAcN!Amla(4LN<>J@uLII>_*x3l0cLWd-(%`xU3|kRG*mHC!GDAf>XWn&A}1!(KU)TqcJ=rT&&w+FzfJ$U zprl;?U+Pva?2q#Y_Y<@K2LLlU(X*H8|Bf*+Oxw?bZMpj2r}{b0Sbq(C%=#Y!3^}=- zAj))+UTXP$mvOG2^T(i|od0&Z)LqSvl(Qe_Pm{l4CidxHj~B8|YsE literal 0 HcmV?d00001 diff --git a/demo/build/uart.o b/demo/build/uart.o new file mode 100755 index 0000000000000000000000000000000000000000..9e457445aaf2ce066d39ede689243bc4bab09276 GIT binary patch literal 18696 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⩔WXQ|2Ov^vha^^ zkm$iI6|rY~*j4yP09^!sj`e=s!gq52I~Lx^@+BT3=XI9z8>XlEk~tzs&ZvY>VH&E+ znUC|IVN<0M5%({iB7GY$^|0 z_`DESdo6qx3?tG-(Y+!&%el#*B}!ar#R~y7~VIV4V>iXvD^zST=GL+>xq1MEpnMbPx4z> z{$c|s`B$<0ZvhY_K|Cxc4oa;#lio9kNdp^o^^4d{wiTfEI zm-xtQKA+uj5jhadY|R%)5k3Q1;)D#IpnXD>nwUX z$KPqtlRZCTy?0so^NinX;3PlB3JzKLe=zIX)XZ+ZpC%sF#|Eh)4=k`>7X5ge( zzE^pJagi_khRYk5;4d(pd}1WH@Lyuk>n6u@5#uz!q&JV_aFsz%&@z_4&7jxw%lPdU zevt8dEc|~M|0fH7jq$yVi~aH%`!R!_*7Y9F!zT@#?75QrU$O8HbN^`rCx7L9@GZtg zuN+2Rx9DY^{@TDv?~U9)ZQ%plf7ifCudGv-=Rwxv51B68!e3;(z`#k)L5>5yzSV{7 zXHwm7FmRej`D~)ukVElYr>T{?)WVN4F0a|e&Jw1(!l0)(;7es)mU1oeOmJSw=K(gp z(ULQh`?p$n8}~nB;AB5;#dZ0dg?BLiDC446?ysJ+@O^CO&n;Z;qw@GbEOL%AeYJs8 zQ_kU24V*}4bDqyKaBgb*KfxVYk5QK2Z{ZJVYNd8q_}lF7UJEZ|{2=3EKZ{Y%81yuc zx3K@;w(w6f{zFSn!1CX+=%xRzh5t(U@tFY?u}98%frZO+rArx?Je<${ITk*b`wO`i z`Evg6vFNYk{u&Ek#r^eMi=5-^@686i&co0h^%(=Fc<$r=4h!GI{apr5aynSfBaDk) zxi5X%!e!t4z9EP7zQp|>TlkN-|5F2}{p8M3s6copOLzC*TVjkH*}hsaxF?dTFwPkiNu)p+%`Y5=6V-L-P%VEhK@^$m2V zQR07j`&Z-j6cbC&kk!}QAD3aMQnBuVwQJ*e;}`26NW^1!qt=8sVBOcV*!Y^xRfAn? z;~d?;yb8cdDJyv?k~+9ye-0^mDs*(ePS@8C0l0p?Ic)rr_vwsnQ|J{y|L-@&m+AnSYHv!9}|BI|Y?eLd@mY(}$u443w*Q{e-=gtzz>53}oWZQ(EFl&hbQR+ZUS86ir4|}QjOTPq-O#B ../initramfs.cpio \ No newline at end of file diff --git a/demo/include/allocator.h b/demo/include/allocator.h new file mode 100755 index 000000000..37d4971a3 --- /dev/null +++ b/demo/include/allocator.h @@ -0,0 +1,73 @@ +#ifndef ALLOCATER_H +#define ALLOCATER_H + +#include "../include/my_stddef.h" +#include "../include/my_stdint.h" +#include "../include/my_stdlib.h" +#include "../include/uart.h" +#include "../include/my_string.h" + +#define BUDDY_METADATA_ADDR 0x10000000 +#define MAX_ORDER 11 +#define MEMORY_SIZE 0x10000000 // 256 MB +#define PAGE_SIZE 4096 +#define MAX_BLOCKS (MEMORY_SIZE / PAGE_SIZE) +#define NUM_POOLS 5 + +#define STATUS_X -1 +#define STATUS_F -2 +#define STATUS_D -3 + +extern char* __end; +extern char* _start; +extern char *cpio_addr; +extern char *dtb_addr; + +typedef struct buddy_block_list_t { + void *addr; + int idx; + int order; + int size; + struct buddy_block_list_t *next; +} buddy_block_list_t; + +typedef struct buddy_system_t { + buddy_block_list_t **buddy_list; + int first_avail[MAX_ORDER]; + void *list_addr[MAX_ORDER]; + void *buddy_start_address; + void *buddy_end_address; + int max_block_amount; + int max_index; +} buddy_system_t; + +typedef struct small_block_list_t { + void *addr; + struct small_block_list_t *next; +} small_block_list_t; + +typedef struct dynamic_memory_allocator_t { + small_block_list_t **small_block_pools; + //void* block_size; +} dynamic_memory_allocator_t; + + +void buddy_init(void); +buddy_block_list_t *get_block_addr(int order,int index); +void update_first_avail_list(void); +void* buddy_malloc(unsigned int size); +buddy_block_list_t* buddy_split(int start_index, int end_index, int req_size, int curr_order); +void mark_allocated(buddy_block_list_t* start); +void buddy_free(void *addr); +void free_child(int block_index, int order); + +void dma_init(void); +void *dma_malloc(int size); +void dma_free(void *addr,int size); + +void memory_reserve(void* start, void* end); +void startup_allocation(void); +void show_available_page(void); +void show_first_available_block_idx(void); + +#endif \ No newline at end of file diff --git a/demo/include/command.h b/demo/include/command.h new file mode 100755 index 000000000..5cf9224f3 --- /dev/null +++ b/demo/include/command.h @@ -0,0 +1,45 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include "../include/uart.h" +#include "../include/cpio_parser.h" +#include "../include/shell.h" +#include "../include/my_stddef.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" +#include "../include/timer.h" +#include "../include/task.h" +#include "../include/exception.h" +#include "../include/allocator.h" + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + + +typedef void (*command_handler_t)(int argc, char **argv); + +typedef struct { + const char *command; + const char *description; + command_handler_t handler; +} command_t; + +extern command_t commands[]; + +void set(long addr, unsigned int value); +void cmd_help(int argc, char **argv); +void cmd_hello(int argc, char **argv); +void cmd_reboot(int argc, char **argv); +void cmd_ls(int argc, char **argv); +void cmd_cat(int argc, char **argv); +void cmd_malloc(int argc, char **argv); +void cmd_rup(int argc, char **argv); +void cmd_cctf(int argc, char **argv); +void cmd_async(int argc, char **argv); +void cmd_ttm(int argc, char **argv); +void cmd_sto(int argc, char **argv); +void cmd_tci(int argc, char **argv); +void cmd_atest(void); + +#endif \ No newline at end of file diff --git a/demo/include/cpio_parser.h b/demo/include/cpio_parser.h new file mode 100755 index 000000000..08448847e --- /dev/null +++ b/demo/include/cpio_parser.h @@ -0,0 +1,29 @@ +#ifndef MY_CPIO_PARSER_H +#define MY_CPIO_PARSER_H + +#define CPIO_NEWC_MAGIC "070701" +#define HEADER_SIZE sizeof(struct cpio_newc_header) +#define MAX_ARCHIVE_SIZE (1024 * 1024 * 1024) // 1 GB + +struct cpio_newc_header { + char c_magic[6]; + 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]; +}; + +void cpio_ls(char *cpio_archive_start); +void cpio_cat(char *cpio_archive_start, const char *filename); +char *cpio_find(char *cpio_archive_start, const char *filename); + +#endif \ No newline at end of file diff --git a/demo/include/dtb.h b/demo/include/dtb.h new file mode 100755 index 000000000..80271233d --- /dev/null +++ b/demo/include/dtb.h @@ -0,0 +1,36 @@ +#ifndef DTB_H +#define DTB_H + +#include "../include/my_stdint.h" +#include "../include/uart.h" +#include "../include/my_string.h" + + +// Define the FDT header structure +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; +}; + +typedef void (*fdt_callback_t)(const char* name, const char* prop, const void* value, int len); + +// FDT tokens +#define FDT_BEGIN_NODE 0x1 +#define FDT_END_NODE 0x2 +#define FDT_PROP 0x3 +#define FDT_NOP 0x4 +#define FDT_END 0x9 + +uint32_t fdt32_to_cpu(uint32_t x); +void fdt_traverse(void* fdt, fdt_callback_t callback); +void initramfs_callback(const char* name, const char* prop, const void* value, int len); + +#endif \ No newline at end of file diff --git a/demo/include/exception.h b/demo/include/exception.h new file mode 100755 index 000000000..84747f972 --- /dev/null +++ b/demo/include/exception.h @@ -0,0 +1,22 @@ +#ifndef MY_EXCEPTION_H +#define MY_EXCEPTION_H + +#include "../include/uart.h" +#include "../include/my_stdint.h" +#include "../include/my_stdlib.h" +#include "../include/timer.h" +#include "../include/task.h" + +void enable_interrupt(void); +void disable_interrupt(void); + +void showinfo_exception_handler(void); +void core_timer_handler(void); +void irq_exception_handler(void); +void uart_rx_handler(void); +void uart_tx_handler(void); +void timer_interrupt_handler(void); + + + +#endif \ No newline at end of file diff --git a/demo/include/gpio.h b/demo/include/gpio.h new file mode 100755 index 000000000..399ae80f2 --- /dev/null +++ b/demo/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/demo/include/my_stddef.h b/demo/include/my_stddef.h new file mode 100755 index 000000000..efa35140a --- /dev/null +++ b/demo/include/my_stddef.h @@ -0,0 +1,8 @@ +#ifndef MY_STDDEF_H +#define MY_STDDEF_H + +#define NULL ((void *)0) + +typedef unsigned int size_t; + +#endif \ No newline at end of file diff --git a/demo/include/my_stdint.h b/demo/include/my_stdint.h new file mode 100755 index 000000000..34506dafa --- /dev/null +++ b/demo/include/my_stdint.h @@ -0,0 +1,23 @@ +#ifndef MY_STDINT_H +#define MY_STDINT_H + +#define __LP64__ 1 // Define __LP64__ macro to indicate a 64-bit system + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +// Define uintptr_t based on the size of a pointer +#if defined(__LP64__) || defined(_LP64) +typedef unsigned long int uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif + +#endif /* _STDINT_H */ \ No newline at end of file diff --git a/demo/include/my_stdio.h b/demo/include/my_stdio.h new file mode 100755 index 000000000..e17a409a5 --- /dev/null +++ b/demo/include/my_stdio.h @@ -0,0 +1,6 @@ +#ifndef MY_STDIO_H +#define MY_STDIO_H + +#define EOF (-1) + +#endif \ No newline at end of file diff --git a/demo/include/my_stdlib.h b/demo/include/my_stdlib.h new file mode 100755 index 000000000..6be3b7f3f --- /dev/null +++ b/demo/include/my_stdlib.h @@ -0,0 +1,31 @@ +#ifndef MY_STDLIB_H +#define MY_STDLIB_H + +//#include "../include/my_stddef.h" +//#include "../include/my_stdint.h" + +#include "../include/my_stddef.h" +#include "../include/my_stdint.h" +#include "../include/uart.h" + +extern char* __end; + +#define MAX_HEAP_SIZE (1024*1024) + +#define read_register(sys) ({ \ + uint64_t _val; \ + asm volatile ("mrs %0, " #sys : "=r" (_val)); \ + _val; \ +}) + +#define write_register(sys, _val) ({ \ + asm volatile ("msr " #sys ", %0" :: "r" (_val)); \ +}) + + +void* alignas(size_t alignment, void* ptr); +void* simple_malloc(size_t size); +int log(int num, int base); + +#endif + diff --git a/demo/include/my_string.h b/demo/include/my_string.h new file mode 100755 index 000000000..11434711d --- /dev/null +++ b/demo/include/my_string.h @@ -0,0 +1,21 @@ +#ifndef MY_STRING_H +#define MY_STRING_H + +#include "../include/my_stddef.h" + +#define HEX_DIGIT_TO_INT(c) ((c >= '0' && c <= '9') ? (c - '0') : ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : (c - 'A' + 10))) + +void strset( char * s1, int c, int size ); +int strlen(const char * s ); +int strncmp(const char *s1, const char *s2, size_t n); +int strcmp(const char *s1, const char *s2); +void itoa(int num, char *str, int base); +unsigned int hex_to_uint(char *hex); +char *strrchr(const char *str, int ch); +unsigned long long strtoull(const char *str, char **endptr, int base); +char *strtok(char *str, const char *delim); +char *strcpy(char *dest, const char *src); +char *strchr(const char *str, int c); +int atoi(const char *str); + +#endif diff --git a/demo/include/shell.h b/demo/include/shell.h new file mode 100755 index 000000000..696c119de --- /dev/null +++ b/demo/include/shell.h @@ -0,0 +1,18 @@ +#ifndef MYSHELL_H +#define MYSHELL_H + +#include "../include/my_stddef.h" + +#define MAX_BUFFER_LEN 64 +#define NEW_LINE 1001 +#define LINE_FEED 10 +#define CRRIAGE_RETURN 13 +#define BACKSPACE 8 + + +void shell_start(); +void command_controller(char c, char buffer[], int *counter, char **argv); +void execute_command(int argc, char **argv); +int parse_arguments(char *buffer, char **argv); + +#endif diff --git a/demo/include/task.h b/demo/include/task.h new file mode 100755 index 000000000..adf2fffa5 --- /dev/null +++ b/demo/include/task.h @@ -0,0 +1,32 @@ +#ifndef TASK_H +#define TASK_H + +#include "../include/my_stdint.h" +#include "../include/my_stddef.h" +#include "../include/my_stdlib.h" +#include "../include/exception.h" +#include "../include/timer.h" +#include "../include/my_string.h" +#include "../include/uart.h" + +// Structure to represent a task +typedef struct task{ + struct task* prev; + struct task* next; + void (*callback)(void *); + void *data; + int priority; +}task_t; + +extern task_t* task_head; +extern task_t* task_tail; + +// Function to insert a task into the task queue based on priority +task_t* create_task(void (*callback)(void *),int priority); +int add_task_to_queue(task_t *newTask); +void test_tesk1(void); +void test_tesk2(void); +void test_tesk3(void); +void ExecTasks(void); + +#endif \ No newline at end of file diff --git a/demo/include/timer.h b/demo/include/timer.h new file mode 100755 index 000000000..cab76f878 --- /dev/null +++ b/demo/include/timer.h @@ -0,0 +1,30 @@ +#ifndef TIMER_H +#define TIMER_H + +#include "../include/my_stdint.h" +#include "../include/my_stddef.h" +#include "../include/my_stdlib.h" +#include "../include/exception.h" +#include "../include/my_string.h" +#include "../include/uart.h" + +#define CORE0_TIMER_IRQ_CTRL (volatile unsigned int*)(0x40000040) + +// timer queue made from double linked list +typedef struct task_timer{ + struct task_timer *prev; + struct task_timer *next; + void (*callback)(void *); + void *data; + unsigned long long deadline; +}task_timer_t; + +extern task_timer_t* timer_head; +extern task_timer_t* timer_tail; + +task_timer_t *create_timer(void (*callback)(void *),void* message, int seconds); +int timer_add_queue(task_timer_t *temp); +void timer_callback(void *str); +void setTimeout (char *str, int second); + +#endif \ No newline at end of file diff --git a/demo/include/uart.h b/demo/include/uart.h new file mode 100755 index 000000000..55592e631 --- /dev/null +++ b/demo/include/uart.h @@ -0,0 +1,63 @@ +#ifndef UART_H +#define UART_H + +#include "../include/gpio.h" +#include "../include/shell.h" +#include "../include/command.h" +#include "../include/my_string.h" +#include "../include/my_stdlib.h" + +#define MMIO_BASE 0x3F000000 + + +/* 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)) +#define AUX_IRQ 29 + +#define CORE0_INT_SRC 0x40000060 +#define ENABLE_IRQS_1 0x3F00B210 +#define IRQ_PENDING_1 0x3F00B204 + +#define TMP_BUFFER_LEN 1024 + +#define BUFFER_SIZE (16*16) +#define MAX_ARGV_LEN 32 + +// Buffers and indices +extern char read_buffer[BUFFER_SIZE]; +extern char write_buffer[BUFFER_SIZE]; +extern int read_index_cur; +extern int read_index_tail; +extern int write_index_cur; +extern int write_index_tail; + + +void uart_init(void); +void uart_send(unsigned int c); +char uart_getc(void); +void uart_puts(const char *s); +char *get_string(void); +void uart_hex(unsigned int d); + +void initialize_async_buffers(void); +void uart_send_async(char c); +char uart_getc_async(void); +void uart_puts_async(const char *str); +void get_string_async(char *buffer_async); + +void uart_int(int num); +void uart_hex_64(uint64_t d); + + +#endif diff --git a/demo/initramfs.cpio b/demo/initramfs.cpio new file mode 100755 index 0000000000000000000000000000000000000000..c9204697d65ec4f5a8e797853301fb1bb35a1a49 GIT binary patch literal 1024 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 = (buddy_block_list_t**)(BUDDY_METADATA_ADDR + sizeof(buddy_system_t)); + buddy_block_list_t *list = (buddy_block_list_t *)(buddy_system->buddy_list); + buddy_system->buddy_start_address = (void *)(0x0); + buddy_system->buddy_end_address = (void *)(0x3C000000); + buddy_system->max_block_amount = (1 << (MAX_ORDER - 1)); + buddy_system->max_index = buddy_system->max_block_amount-1; + + for(int i = 0; i < MAX_ORDER; i++){ + + int alloc_offset = 0; + int block_amount = (1 << (MAX_ORDER - i - 1)); + + buddy_system->first_avail[i] = -1; + buddy_system->list_addr[i] = (void*)list; + + buddy_block_list_t *cur = list; + buddy_block_list_t *prev = NULL; + + for(int j = 0; j < block_amount; j++){ + cur->idx = (j * (1 << i)); + // all block are belonged to the largest continuous memory block + cur->order = STATUS_F; + if(i == MAX_ORDER - 1){ + cur->order = MAX_ORDER - 1; + } + if(cur!=buddy_system->list_addr[0]){ + prev->next = cur; + } + + cur->next = 0; + cur->addr = buddy_system->buddy_start_address + alloc_offset; + cur->size = PAGE_SIZE * (1 << i); + // update the offset of buddy system memory + alloc_offset += cur->size; + prev = cur; + // get next block of block list + cur++; + } + // goto next block list + list += block_amount; + } + // In the begining, only the largest block is available + buddy_system->first_avail[MAX_ORDER - 1] = 0; +} + +buddy_block_list_t *get_block_addr(int order,int index){ + //buddy_system->list_addr[order] can get he base address of the list containing blocks of same order + //buddy_system->first_avail[order] / (1 << order)) translate the global index into a local index within the array of blocks of a specific order. + + //don't known order (need more research) + if(order==-1){ + buddy_block_list_t *cur = get_block_addr(0,index); + buddy_block_list_t *last = cur; + for(int i = 0; i < MAX_ORDER; i++){ + cur = get_block_addr(i,index); + // index is illegal in this order, indicate that it must belonged to lower levels + if(index % (1 << i) != 0 | cur->order != STATUS_X) + return last; + + last = cur; + } + + return cur; + } + else{ + //get first avialible block + if(index==-1){ + return (buddy_block_list_t *)((void*)buddy_system->list_addr[order] + (buddy_system->first_avail[order] / (1 << order)) * sizeof(buddy_block_list_t)); + } + else{ + return (buddy_block_list_t *)((void*)buddy_system->list_addr[order] + (index / (1 << order)) * sizeof(buddy_block_list_t)); + } + } + + + +} + +void update_first_avail_list(void){ + int order,block_index; + for(order = 0; order < MAX_ORDER; order++){ + buddy_block_list_t *cur = (buddy_block_list_t *)buddy_system->list_addr[order]; + for(block_index = 0; block_index < buddy_system->max_block_amount ; block_index += (1 << order)){ + + if(cur->order >= 0) + break; + cur = cur->next; + } + if(block_indexmax_block_amount){ + buddy_system->first_avail[order] = block_index; + } + else{ + buddy_system->first_avail[order] = -1; + } + //uart_int(buddy_system->first_avail[order]); + //uart_send(' '); + } +} + +void* buddy_malloc(unsigned int size){ + int i; + + if(size > PAGE_SIZE * (1 << (MAX_ORDER - 1))){ + uart_puts("Error : Requested size is larger than availible space\n"); + return NULL; + } + + for(i = 0; i < MAX_ORDER; i++){ + //find the big enough block + if(PAGE_SIZE * (1 << i) >= size){ + if(buddy_system->first_avail[i] >= 0){ + + buddy_block_list_t *cur = get_block_addr(i,-1); + + // first assuming that there's smaller block in lower layer + cur->order = STATUS_F; + + int avail_index = buddy_system->first_avail[i]; + + //split the block as small as possible + buddy_block_list_t *buddy_allocated = buddy_split(avail_index, avail_index + (1 << i), size, i); + mark_allocated(buddy_allocated); + update_first_avail_list(); + + uart_puts("Allocated block of order "); + uart_int(log(buddy_allocated->size/PAGE_SIZE,2)); + uart_puts(" at: "); + uart_hex_64((unsigned long long)buddy_allocated->addr); + uart_puts("\n"); + return (void*)(buddy_allocated->addr); + } + else{ + continue; + } + } + } + + return NULL; +} + +buddy_block_list_t* buddy_split(int start_index, int end_index, int req_size, int curr_order){ + int i,j; + // to get relative offset as we need to cut it to half while spliting + int block_offset= end_index-start_index; + + // if the current block is already the smallest block that can be allocated or smaller block is not enough for the request + if((PAGE_SIZE * (1 << curr_order) / 2) < req_size || curr_order == 0){ + buddy_block_list_t *start = get_block_addr(curr_order,start_index); + start->order = STATUS_X; + return start; + } + // split the block until the smallest block that can be allocated + for(i = curr_order - 1; i >= 0; i--){ + buddy_block_list_t *start = get_block_addr(i,start_index); + buddy_block_list_t *cur = (buddy_block_list_t *)start; + + for(j = start_index; j < start_index + block_offset && cur != 0; j += (1 << i)){ + // mark it as usable + if(cur->order == STATUS_F){ + cur->order = i; + if(cur != start){ + uart_puts("Release redundent block of order:"); + uart_int(cur->order); + uart_puts(" size: "); + uart_int(cur->size); + uart_puts(" at: "); + uart_hex_64((unsigned long long)cur->addr); + uart_puts("\n"); + } + } + cur = cur->next; + } + block_offset /= 2; + start->order = STATUS_F; + // if the current block is already the smallest block that can be allocated or smaller block is not enough for the request + if((PAGE_SIZE * (1 << i) / 2) < req_size || i == 0){ + start->order = STATUS_X; + return start; + } + } + return NULL; +} + +void mark_allocated(buddy_block_list_t* start){ + int i,j; + int order = log(start->size / PAGE_SIZE, 2); + int end_index = start->idx + (1 << order); + + for(i = order - 1; i >= 0; i--){ + buddy_block_list_t *cur = get_block_addr(i,start->idx); + for(j = start->idx; j < end_index && cur != 0; j += (1 << i)){ + if(cur->order == STATUS_F) + cur->order = STATUS_X; + cur = cur->next; + } + } +} + + +void buddy_free(void *addr){ + int block_index = (addr-buddy_system->buddy_start_address)/ PAGE_SIZE; + //don't known order + buddy_block_list_t *cur_block = get_block_addr(-1,block_index); + int order = log(cur_block->size / PAGE_SIZE, 2); + + uart_puts("Free :"); + uart_hex_64((unsigned long long)addr); + uart_puts(" with order:"); + uart_int(log(cur_block->size / PAGE_SIZE, 2)); + uart_puts(" at index:"); + uart_int(block_index); + uart_send('\n'); + + free_child(block_index, order); + cur_block->order = order; + + //try to merge + int i,neighbor_same_order_block_index; + buddy_block_list_t *neighbor_same_order_block; + for(i = order; i < MAX_ORDER; i++){ + //get previous block whick is always order order i + neighbor_same_order_block_index = block_index ^ (1 << i); + + cur_block = get_block_addr(i,block_index); + neighbor_same_order_block = get_block_addr(i,neighbor_same_order_block_index); + + // reaching largest block, no need to merge + if(i == MAX_ORDER - 1){ + cur_block->order = i; + break; + } + + // its neighbor block is also available, combine them into a larger block + if(neighbor_same_order_block->order >= 0){ + cur_block->order = STATUS_F; + neighbor_same_order_block->order = STATUS_F; + uart_puts("Merge two blocks:"); + uart_int(block_index); + uart_send(' '); + uart_int(neighbor_same_order_block); + uart_puts(" at order:"); + uart_int(i); + uart_send('\n'); + } + else{ + cur_block->order = i; + break; + } + } + update_first_avail_list(); + +} + + +void free_child(int block_index, int order){ + int i,j; + + for(i = order - 1; i >= 0; i--){ + buddy_block_list_t *cur = get_block_addr(i,block_index); + for(j = 0; j < (1 << order); j += (1 << i)){ + cur->order = STATUS_F; + cur = cur->next; + } + } +} + + +void dma_init(void) { + //small_block_pool = {16, 32, 64, 128, 256, 512, 1024}; + dma->small_block_pools = (small_block_list_t **)simple_malloc(7 * sizeof(small_block_list_t *)); // for sizes 16, 32, 48, etc. + + for (int i = 0; i < 10; i++) { + dma->small_block_pools[i] = NULL; + } + + buddy_init(); +} + +void *dma_malloc(int size) { + if(size>1024){ + return buddy_malloc(size); + } + + int pool_idx = log(size/16, 2); // Assume sizes are 16, 32, 48, etc. + + if (dma->small_block_pools[pool_idx] != NULL) { + small_block_list_t *block = dma->small_block_pools[pool_idx]; + dma->small_block_pools[pool_idx] = block->next; + uart_puts("dynamic malloc a size "); + uart_int(small_block_pool[pool_idx]); + uart_puts(" block at: "); + uart_hex_64(block->addr); + uart_send('\n'); + return block->addr; + } + + + // Allocate a new page from buddy system + void *page = buddy_malloc(4096); // Order 0 for a single 4096 page + + for (int i = 0; i < PAGE_SIZE / size; i++) { + small_block_list_t *block = (small_block_list_t *)simple_malloc(sizeof(small_block_list_t)); + block->addr = page + (i * size); + block->next = dma->small_block_pools[pool_idx]; + dma->small_block_pools[pool_idx] = block; + //dma->block_size[addr]=small_block_pool[pool_idx]; + } + + return dma_malloc(size); +} + +void dma_free(void *addr, int size) { + //int size = dma->block_size[addr]; + if (size <= 1024) { + int pool_idx = log(size/16, 2); + small_block_list_t *block = (small_block_list_t *)simple_malloc(sizeof(small_block_list_t)); + block->addr = addr; + block->next = dma->small_block_pools[pool_idx]; + dma->small_block_pools[pool_idx] = block; + } else { + buddy_free(addr); + } +} + + +void memory_reserve(void* start, void* end){ + + if(start < buddy_system->buddy_start_address || end > buddy_system->buddy_end_address){ + uart_puts("Error: The memory is out of range\n"); + return; + } + + int start_index = (start - buddy_system->buddy_start_address) / PAGE_SIZE; + int end_index = (end - buddy_system->buddy_start_address) / PAGE_SIZE; + if((uint64_t)end % PAGE_SIZE != 0) + end_index++; + int i; + + if(end_index < start_index){ + uart_puts("Error: The end address is smaller than the start address\n"); + return; + } + + uart_puts("Reserve memory from:"); + + uart_hex_64((unsigned long long)start); + uart_puts(" to:"); + uart_hex_64((unsigned long long)end); + uart_send(' '); + uart_puts("with index:"); + uart_int(start_index); + uart_send(' '); + uart_int(end_index); + uart_send('\n'); + + int neighbor_same_order_block_index,cur_index; + // mark the protect blocks as STATUS_X(allocated) + for(i = 0; i < MAX_ORDER; i++){ + cur_index = start_index; + while(cur_index < end_index){ + + + buddy_block_list_t *cur = get_block_addr(i,cur_index); + + + if(cur->order >= 0 || cur->order == STATUS_F || i==0) + cur->order = STATUS_X; + + + neighbor_same_order_block_index = cur_index ^ (1 << i); + buddy_block_list_t *neighbor_same_order_block = get_block_addr(i,neighbor_same_order_block_index); + if (neighbor_same_order_block_index < buddy_system->max_index){ + if(neighbor_same_order_block->order == STATUS_F){ + //uart_int(i); + //uart_send(' '); + //uart_hex_64(neighbor_same_order_block->addr); + //uart_send('\n'); + neighbor_same_order_block->order = i; + } + } + + cur_index++; + } + } + update_first_avail_list(); +} + + +void startup_allocation(void){ + dma_init(); + uart_puts("Availibel pages before startup_allocation\n"); + show_available_page(); + uart_puts("startup_allocation starting\n"); + uart_puts("reserve Spin tables for multicore boot\n"); + memory_reserve((void*)0x0, (void*)0x1000); + uart_puts("reserve Kernel image in the physical memory\n"); + memory_reserve((void*)&_start, (void*)&__end); + uart_puts("reserve CPIO archive in the physical memory\n"); + memory_reserve((void*)cpio_addr, (void*)cpio_addr + 0x100000); + uart_puts("reserve device tree blob in the physical memory\n"); + memory_reserve((void*)dtb_addr, (void*)dtb_addr + 0x100000); + uart_puts("reserve allocator metadata in the physical memory\n"); + memory_reserve((void*)BUDDY_METADATA_ADDR, (void*)BUDDY_METADATA_ADDR + sizeof(buddy_system_t) + ((1 << MAX_ORDER) - 1) * sizeof(buddy_block_list_t)); + uart_puts("reserve dma metadata in the physical memory\n"); + memory_reserve((void*)&__end, (void*)allocated); + uart_puts("startup_allocation finished\n"); + uart_puts("Availibel pages after startup_allocation\n"); + show_available_page(); +} + +void show_available_page(void){ + int avail_count; + for(int i = 0; i < MAX_ORDER; i++){ + uart_puts("Order "); + uart_int(i); + uart_puts(" availible pages number : "); + avail_count = 0; + buddy_block_list_t *cur = (buddy_block_list_t *)buddy_system->list_addr[i]; + for(int j = 0; j < (1 << (MAX_ORDER - i - 1)); j++){ + if(cur->order >= 0){ + avail_count++; + } + cur = cur->next; + } + uart_int(avail_count); + uart_send('\n'); + } +} + +void show_first_available_block_idx(void){ + uart_puts("buddy system first availible block (order 0 -> 10) :\n"); + for(int i = 0; i < MAX_ORDER; i++){ + uart_int(buddy_system->first_avail[i]); + uart_send(' '); + } + uart_send('\n'); +} + +void memory_reserve_new(void* start, void* end){ + + if(start < buddy_system->buddy_start_address || end > buddy_system->buddy_end_address){ + uart_puts("Error: The memory is out of range\n"); + return; + } + + int start_index = (start - buddy_system->buddy_start_address) / PAGE_SIZE; + int end_index = (end - buddy_system->buddy_start_address) / PAGE_SIZE; + int i; + + if(end_index < start_index){ + uart_puts("Error: The end address is smaller than the start address\n"); + return; + } + + uart_puts("Reserve memory from:"); + uart_hex_64((unsigned long long)start); + uart_puts(" to:"); + uart_hex_64((unsigned long long)end); + uart_send(' '); + uart_puts("with index:"); + uart_int(start_index); + uart_send(' '); + uart_int(end_index); + uart_send('\n'); + + + buddy_block_list_t *cur = get_block_addr(0,0); + int count=0; + while(countmax_block_amount){ + if(cur->idx>=start_index && cur->idx<=end_index){ + for(int i=0;iidx)->order=STATUS_X; + } + } + count++; + cur++; + } +} diff --git a/demo/src/command.c b/demo/src/command.c new file mode 100755 index 000000000..39f2c3c54 --- /dev/null +++ b/demo/src/command.c @@ -0,0 +1,256 @@ +#include "../include/command.h" + + + +extern char *cpio_addr; +extern int core_timer_flag; + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + + +void cmd_help(int argc, char **argv) { + uart_puts("hello : print Hello World!\n"); + uart_puts("reboot : reboot the device\n"); + uart_puts("ls : show file in rootfs\n"); + uart_puts("cat : show file content\n"); + uart_puts("malloc : malloc demp\n"); + uart_puts("rup : run user program\n"); + uart_puts("async : async UART read/write\n"); + uart_puts("sto : set time out\n"); + uart_puts("cctf : change core timer flag\n"); + uart_puts("ttm : test timer multiplexing\n"); + uart_puts("tci : test concurrent I/O devices handling\n"); +} + +command_t commands[] = { + {"help", "print this help menu", cmd_help}, + {"hello", "print Hello World!", cmd_hello}, + {"reboot", "reboot the device", cmd_reboot}, + {"ls", "show file in rootfs", cmd_ls}, + {"cat", "show file content", cmd_cat}, + {"malloc", "malloc demo", cmd_malloc}, + {"rup", "run user program", cmd_rup}, + {"async", "async UART read/write", cmd_async}, + {"sto", "set time out", cmd_sto}, + {"cctf", "change timer type", cmd_cctf}, + {"ttm", "test timer multiplexing", cmd_ttm}, + {"tci", "test concurrent I/O devices handling", cmd_tci}, + {"atest", "allocator test", cmd_atest}, + {NULL, NULL, NULL} // Sentinel value to mark the end of the array +}; + +void cmd_hello(int argc, char **argv) { + uart_puts("Hello World!\n"); +} + +void cmd_reboot(int argc, char **argv) { + uart_puts("Start rebooting...\n"); + set(PM_RSTC, PM_PASSWORD | 0x20); +} + +void cmd_ls(int argc, char **argv) { + cpio_ls(cpio_addr); +} + +void cmd_cat(int argc, char **argv){ + uart_puts("Filename: "); + char *filename = get_string(); + if (filename == NULL) { + uart_puts("Error: Invalid filename\n"); + return; + } + cpio_cat(cpio_addr,filename); +} + +void cmd_malloc(int argc, char **argv) { + char *ptr1 = simple_malloc(7); + ptr1[0]='M'; + ptr1[1]='A'; + ptr1[2]='L'; + ptr1[3]='L'; + ptr1[4]='O'; + ptr1[5]='C'; + ptr1[6]='\0'; + uart_puts(ptr1); + uart_puts("\n"); +} + +void cmd_rup(int argc, char **argv) { + uart_puts("Filename: "); + char *filename = get_string(); + if (filename == NULL) { + uart_puts("Error: Invalid filename\n"); + return; + } + char *file_addr = cpio_find(cpio_addr,filename); + //uart_hex(file_addr); + //uart_puts("\n"); + void *stack_addr = simple_malloc(2048); + //make sure stack_addr and file_addr not NULL + if(stack_addr && file_addr){ + write_register(spsr_el1,0x3c0); + write_register(elr_el1,file_addr); + write_register(sp_el0,stack_addr); + asm volatile("eret"); + } +} + +void cmd_async(int argc, char **argv){ + + /*enable uart interrupts*/ + + // Enable mini second level interrupt controller’s + *((volatile unsigned int*)ENABLE_IRQS_1) |= (1 << AUX_IRQ); + + // Enable mini UART receive interrupt to start reading the data + *((volatile unsigned int*)AUX_MU_IER) |= 0x01; + + + //uart_puts_async("Async UART testing\n"); + uart_puts_async("Type in something\n"); + + char buffer_async[TMP_BUFFER_LEN]; + strset(buffer_async, 0, TMP_BUFFER_LEN); + + get_string_async(buffer_async); + uart_puts_async("\nWhat you type in is :\n"); + uart_puts_async(buffer_async); + uart_puts_async("\n"); + + + + + /*disable uart interrupts*/ + + // Disable mini second level interrupt controller’s + *((volatile unsigned int*)ENABLE_IRQS_1) &= ~(1 << AUX_IRQ); + + // Disable mini UART receive interrupts to stop reading the data + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x1); + +} + +void cmd_cctf(int argc, char **argv){ + if(core_timer_flag==0){ + uart_puts("enable core0 Timer\n"); + // enable core0 timer interrupt + *((volatile uint32_t*)CORE0_TIMER_IRQ_CTRL) = (0x2); + core_timer_flag=1; + } + else{ + uart_puts("disable core0 Timer\n"); + // disnable core0 timer interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + core_timer_flag=0; + } +} + +void cmd_sto(int argc, char **argv){ + + if (argc < 3) { // Ensure at least two arguments are present + uart_puts("need to send massage and second\n"); + return; + } + unsigned long long cur_cnt, cnt_freq; + asm volatile( + "mrs %[var1], cntpct_el0;" + "mrs %[var2], cntfrq_el0;" + :[var1] "=r" (cur_cnt), [var2] "=r" (cnt_freq) + ); + uart_puts("current time:\n"); + uart_hex(cur_cnt / cnt_freq); + uart_send('\n'); + + setTimeout(argv[1], atoi(argv[2])); + +} + +void cmd_ttm(int argc, char **argv){ + + unsigned long long cur_cnt, cnt_freq; + asm volatile( + "mrs %[var1], cntpct_el0;" + "mrs %[var2], cntfrq_el0;" + :[var1] "=r" (cur_cnt), [var2] "=r" (cnt_freq) + ); + uart_puts("current time:\n"); + uart_hex(cur_cnt / cnt_freq); + uart_send('\n'); + + char test_tesk[6]; + test_tesk[0]='t'; + test_tesk[1]='a'; + test_tesk[2]='s'; + test_tesk[3]='k'; + test_tesk[4]='1'; + test_tesk[5]='\0'; + + for(int i=1; ic_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + break; + } + + //The "new" ASCII format uses 8-byte hexadecimal fields for all numbers + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + /*Each file system object in a cpio archive comprises a header record + with basic numeric metadata followed by the full pathname of the entry and the file data.*/ + ptr += HEADER_SIZE; + char *filename = ptr; + ptr += namesize; + + //allign to 4 byte + //the filedata is padded to a multiple of four bytes.. + ptr = alignas(4, ptr); + + if (strcmp(filename, "TRAILER!!!") == 0) { + break; + } + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + uart_puts(filename); + uart_puts("\n"); + + } +} + +void cpio_cat(char *cpio_archive_start, const char *filename) { + char *ptr = cpio_archive_start; + int file_exist=0; + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + return; + } + + uint64_t namesize = hex_to_uint(header->c_namesize); + uint64_t filesize = hex_to_uint(header->c_filesize); + + ptr += HEADER_SIZE; + char *current_filename = ptr; + ptr += namesize; + + // Align to 4 bytes + ptr = alignas(4, ptr); + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + break; + } + + + char *content = ptr; + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + if (strcmp(current_filename, filename) == 0) { + // Print file content + uart_puts(content); + uart_puts("\n"); + return; + } + + // Check if we've reached the end of the archive + if (strcmp(current_filename, "TRAILER!!!") == 0) { + uart_puts("File not found\n"); + uart_puts("\n"); + return; + } + } + if (file_exist==0){ + uart_puts("Can't find :"); + uart_puts(filename); + uart_puts("Please check if the file name is correct!"); + } + +} + +char *cpio_find(char *cpio_archive_start, const char *filename) { + char *ptr = cpio_archive_start; + char *content = NULL; + while (1) { + struct cpio_newc_header *header = (struct cpio_newc_header *)ptr; + + // Safety check: Ensure ptr does not go beyond the end of the archive + if (strncmp(header->c_magic, CPIO_NEWC_MAGIC, 6) != 0) { + uart_puts("Invalid CPIO magic number\n"); + content = NULL; + return content; + } + + unsigned int namesize = hex_to_uint(header->c_namesize); + unsigned int filesize = hex_to_uint(header->c_filesize); + + ptr += HEADER_SIZE; + char *current_filename = ptr; + ptr += namesize; + + // Align to 4 bytes + ptr = alignas(4, ptr); + + + content = ptr; + ptr += filesize; + + //allign to 4 byte + ptr = alignas(4, ptr); + + // Safety check: Ensure content does not go beyond the end of the archive + if (ptr + filesize - cpio_archive_start >= MAX_ARCHIVE_SIZE) { + uart_puts("Error: File content exceeds archive size\n"); + content = NULL; + return content; + } + + + if (strcmp(current_filename, filename) == 0) { + return content; + } + + if (strcmp(current_filename, "TRAILER!!!") == 0) { + uart_puts("File not found\n"); + uart_puts("\n"); + content = NULL; + return content; + } + + } +} \ No newline at end of file diff --git a/demo/src/dtb.c b/demo/src/dtb.c new file mode 100755 index 000000000..a060fb182 --- /dev/null +++ b/demo/src/dtb.c @@ -0,0 +1,137 @@ +#include "../include/dtb.h" + + +char *cpio_addr; +char *dtb_addr; + +/*bcm2710-rpi-3-b-plus.dtb is a binary representation of the device tree for the Raspberry Pi 3 Model B Plus. +It contains the hardware description necessary for the operating system to understand the hardware layout and resources. +*/ + + +/* structur of DTB format (page 53) + * + * --------------------------- * + * | struct fdt_header | + * --------------------------- * + * | (free space) | + * --------------------------- * + * | memory reservation block| + * --------------------------- * + * | (free space) | + * --------------------------- * + * | structure block | + * --------------------------- * + * | (free space) | + * --------------------------- * + * | strings block | + * --------------------------- * + * | (free space) | + * --------------------------- * + */ + + +// FDT uses big-endian format, while the ARM CPU in Raspberry Pi uses little-endian +// swaps the endianness of a 32-bit integer from big-endian to little-endian. +uint32_t fdt32_to_cpu(uint32_t x) { + return ((x >> 24) & 0x000000FF) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + ((x << 24) & 0xFF000000); +} + + +void fdt_traverse(void* fdt, fdt_callback_t callback) { + struct fdt_header* header = (struct fdt_header*)fdt; + + // Validate the magic number + if (fdt32_to_cpu(header->magic) != 0xd00dfeed) { + uart_puts("Invalid FDT magic number\n"); + return; + } + + uint32_t off_dt_struct = fdt32_to_cpu(header->off_dt_struct); + uint32_t off_dt_strings = fdt32_to_cpu(header->off_dt_strings); + + // Pointers to the structure and strings blocks + uint8_t* struct_block = (uint8_t*)fdt + off_dt_struct; + char* strings_block = (char*)fdt + off_dt_strings; + + uint8_t* p = struct_block; + while (p < struct_block + fdt32_to_cpu(header->size_dt_struct)) { + /* The structure block is composed of a sequence of pieces, each beginning with a token (a big-endian 32-bit integer). + Some tokens are followed by extra data, the format of which is determined by the token value. (pg. 56) + */ + + uint32_t token = fdt32_to_cpu(*(uint32_t*)p); + p += 4; + + //The FDT_BEGIN_NODE token marks the beginning of a node’s representation. + // followed by the node’s unit name as extra data + if (token == FDT_BEGIN_NODE) { + const char* name = (const char*)p; + p += strlen(name) + 1; + + // All tokens in Structure Block shall be aligned on a 32-bit boundary (pg. 56) + p = (uint8_t*)(((uintptr_t)p + 3) & ~3); + + // Traverse properties + // The FDT_PROP token marks the beginning of the representation of one property in the devicetree. + /* + struct { + uint32_t len; //len gives the length of the property’s value in bytes + uint32_t nameoff; //nameoff gives an offset into the strings block + } + */ + while (fdt32_to_cpu(*(uint32_t*)p) == FDT_PROP) { + p += 4; + uint32_t len = fdt32_to_cpu(*(uint32_t*)p); + p += 4; + uint32_t nameoff = fdt32_to_cpu(*(uint32_t*)p); + p += 4; + + const char* prop_name = strings_block + nameoff; + + //After the structure, the property’s value is given as a byte string of length len. + //This value is followed by zeroed padding bytes (if necessary) to align to the next 32-bit boundary + const void* value = (const void*)p; + + // prevent execute a NLLL function + if (callback) { + callback(name, prop_name, value, len); + } + + p += len; + // Align to 4 bytes + p = (uint8_t*)(((uintptr_t)p + 3) & ~3); + } + //The FDT_END_NODE token marks the end of a node’s representation. + } else if (token == FDT_END_NODE) { + // Do nothing, just move to the next token + + //The FDT_NOP token will be ignored by any program parsing the device tree. + } else if (token == FDT_NOP) { + // Do nothing, just move to the next token + + //The FDT_END token marks the end of the structure block. + } else if (token == FDT_END) { + break; + } else { + uart_puts("Unknown token\n"); + break; + } + } +} + + + +void initramfs_callback(const char* name, const char* prop, const void* value, int len) { + if (strcmp(prop, "linux,initrd-start") == 0) { + cpio_addr = (char *)(uintptr_t)fdt32_to_cpu(*(uint32_t*)value); + uart_puts("Initramfs start address: 0x"); + uart_hex(cpio_addr); + uart_puts("\n"); + } +} + + diff --git a/demo/src/exception.c b/demo/src/exception.c new file mode 100755 index 000000000..e2d23b804 --- /dev/null +++ b/demo/src/exception.c @@ -0,0 +1,242 @@ +#include "../include/exception.h" + +extern char read_buffer[BUFFER_SIZE]; +extern char write_buffer[BUFFER_SIZE]; +extern int read_index_cur; +extern int read_index_tail; +extern int write_index_cur; +extern int write_index_tail; + +extern int core_timer_flag; + +void enable_interrupt(void){ + //write_register(daifclr,0xf); //fail + asm volatile ("msr daifclr, 0xf"); +} + +void disable_interrupt(void){ + //write_register(DAIFSet,0xf); //fail + asm volatile ("msr daifset, 0xf"); +} + + +void showinfo_exception_handler(void) { + + disable_interrupt(); + + + uint64_t spsr, elr, esr, el; + spsr = read_register(spsr_el1); + elr = read_register(elr_el1); + esr = read_register(esr_el1); + el = read_register(CurrentEL); + + uart_puts("Current exception level: "); + uart_hex(el>>2); // first two bits are preserved bit. + uart_puts("\n"); + uart_puts("spsr_el1: 0x"); + uart_hex(spsr); + uart_puts("\r\n"); + uart_puts("elr_el1: 0x"); + uart_hex(elr); + uart_puts("\r\n"); + uart_puts("esr_el1: 0x"); + uart_hex(esr); + uart_puts("\r\n"); + + enable_interrupt(); +} + +void irq_exception_handler(void) { + + disable_interrupt(); + + uint32_t cpu_irq_src, uart_irq_src, iir; + + //CORE0_INT_SRC provides information about the interrupt sources, specific to Core 0 + //bit 2 for interrupt request + cpu_irq_src = *((volatile unsigned int*)CORE0_INT_SRC); + + //IRQ_PENDING_1 indicates which interrupts are pending, System-wide, covers all interrupt sources across the entire system. + //bit 29 for UART interrupt + uart_irq_src = *((volatile unsigned int*)IRQ_PENDING_1); + + iir = *((volatile unsigned int*)AUX_MU_IIR); + + + + //uart_puts("In to Interrrupt\n"); + + // Handle timer interrupt + if(cpu_irq_src & (0x2)){ + + //uart_puts("Timer Interrrupt\n"); + if (core_timer_flag == 1){ + //uart_puts("In to core timer \n"); + //core_timer_handler(); + task_t* newtask = create_task(core_timer_handler, 1); + add_task_to_queue(newtask); + + } + else{ + //uart_puts("In to system timer \n"); + // disnable core0 timer interrupt, remove will lead to core0 timer infinite interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + //timer_interrupt_handler(); + task_t* newtask = create_task(timer_interrupt_handler, 1); + add_task_to_queue(newtask); + } + + } + + + + //uart_hex(gpu_irq_src & (1 << AUX_IRQ)); + // Handle UART interrupt + if (uart_irq_src & (1 << AUX_IRQ)) { + //uart_puts("Uart Interrrupt\n"); + // Check if it is a TX or RX interrupt + // [2:1]=10 : Receiver holds valid byte + if (iir & 0x4) { + // disable receive interrupt + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x1); + //uart_puts("in rx handler\n"); + task_t* newtask = create_task(uart_rx_handler, 1); + add_task_to_queue(newtask); + + // [2:1]=01 : Transmit holding register empty + } else if (iir & 0x2) { + // disable transmit interrupt + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x2); + //uart_puts("in tx handler\n"); + task_t* newtask = create_task(uart_tx_handler, 0); + add_task_to_queue(newtask); + } + } + + enable_interrupt(); + + ExecTasks(); + + +} + +void core_timer_handler(void){ + + uint64_t cur_cnt, cnt_freq; + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + + uart_puts("\nTime after boots: "); + uart_hex(cur_cnt / cnt_freq); + uart_puts(" sec.\n"); + uart_puts("# "); + cnt_freq *= 2; + write_register(cntp_tval_el0,cnt_freq); + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); +} + + + +//AUX_MU_IER 0x1 for reciev 0x2 for transmit + +//reciev data +void uart_rx_handler(void) { + //uart_puts("in rx_handler\n"); + // wait until something is in the buffer + while ( ! ( (*AUX_MU_LSR) & 0x01 ) ); + + char c = ( char )( *AUX_MU_IO ); + //c ='\r'?'\n':c; + //uart_send_async(c); + read_buffer[read_index_tail++] = c; + write_buffer[write_index_tail++] = c; + + // Enable mini UART transmiter interrupt + *((volatile unsigned int*)AUX_MU_IER) |= (0x2); + +} + +//transmit data +void uart_tx_handler(void) { + + char check; + while(write_index_cur != write_index_tail){ + + char c = write_buffer[write_index_cur++]; + check = c; + + while(!((*AUX_MU_LSR) & 0x20) ){ + // if bit 5 is set, break and return IO_REG + asm volatile("nop"); + } + *AUX_MU_IO = c; + if(c == '\n'){ + break; + } + } + + // If there is more data to send, ensure the interrupt is enabled + if (write_index_cur != write_index_tail) { + *((volatile unsigned int*)AUX_MU_IER) |= 0x02; + } else { + // Disable transmit interrupt if no more data to send + *((volatile unsigned int*)AUX_MU_IER) &= ~0x02; + //if(check != '\n'){ + //int time=150; + //while(time--); + //*((volatile unsigned int*)AUX_MU_IER) |= (0x1); + //} + + } + // enable mini UART receiver interrupt + //*((volatile unsigned int*)AUX_MU_IER) |= (0x1); + +} + +void timer_interrupt_handler(void) { + unsigned long long cur_cnt; + task_timer_t *cur = timer_head; + + if(cur==0){ + return; + } + + disable_interrupt(); + + cur_cnt = read_register(cntpct_el0); + //Processing Expired Timers + while(cur_cnt >= cur->deadline){ + + cur->callback(cur->data); + + timer_head = cur->next; + + //if list not empty + if(timer_head != 0){ + + timer_head->prev = 0; + write_register(cntp_cval_el0,timer_head->deadline); + // enable timer + write_register(cntp_ctl_el0,1); + + //asd turn on core0 timer interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); + } + else{ + uart_puts("Finish all timer\n"); + uart_puts("# "); + + // disable timer + write_register(cntp_ctl_el0,0); + + break; + } + cur = cur->next; + } + + enable_interrupt(); + +} + diff --git a/demo/src/link.ld b/demo/src/link.ld new file mode 100755 index 000000000..33118ef56 --- /dev/null +++ b/demo/src/link.ld @@ -0,0 +1,18 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + .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; diff --git a/demo/src/main.c b/demo/src/main.c new file mode 100755 index 000000000..722d3ee1e --- /dev/null +++ b/demo/src/main.c @@ -0,0 +1,38 @@ +#include "../include/uart.h" +#include "../include/shell.h" +#include "../include/dtb.h" +#include "../include/exception.h" +#include "../include/my_stdlib.h" +#include "../include/my_stdint.h" +#include "../include/allocator.h" + +extern char *cpio_addr; +extern char *dtb_addr; + +int main(uint64_t x0){ + // set up serial console + uart_init(); + + uint64_t el = 0; + //asm volatile ("mrs %0, CurrentEL":"=r"(el)); + el = read_register(CurrentEL); + uart_puts("Current exception level: "); + uart_hex(el>>2); // first two bits are preserved bit. + uart_puts("\n"); + + + dtb_addr = (void *) x0; + fdt_traverse(dtb_addr, initramfs_callback); + + startup_allocation(); + + enable_interrupt(); + + initialize_async_buffers(); + // start shell + shell_start(); + + + + return 0; +} diff --git a/demo/src/my_stdlib.c b/demo/src/my_stdlib.c new file mode 100755 index 000000000..475a8e8b8 --- /dev/null +++ b/demo/src/my_stdlib.c @@ -0,0 +1,38 @@ +#include "../include/my_stdlib.h" + +char *heap_curr = (char*)&__end; +int offset=0; + +void* alignas(size_t alignment, void* ptr) { + uintptr_t ptr_value = (uintptr_t)ptr; + uintptr_t mask = alignment - 1; + return (void*)((ptr_value + mask) & ~mask); +} + +void *simple_malloc(size_t size) { + // Align size to multiple of 8 + size = (size + 7) & ~7; + + // Check if there's enough space in the heap + if (offset + size > MAX_HEAP_SIZE) { + uart_puts("Error: Insufficient space in the heap\n"); + return NULL; // Out of memory + } + + // Allocate memory from the heap + void *ptr = (void *)heap_curr; + heap_curr += size; + offset += size; + + return ptr; +} + + +int log(int num, int base){ + int i=0; + while(num!=1){ + num/=base; + i++; + } + return i; +} diff --git a/demo/src/my_string.c b/demo/src/my_string.c new file mode 100755 index 000000000..08d7b8885 --- /dev/null +++ b/demo/src/my_string.c @@ -0,0 +1,271 @@ +#include "../include/my_string.h" + + +void strset (char * s1, int c, int size ) +{ + int i; + + for ( i = 0; i < size; i ++) + s1[i] = c; +} + +int strlen (const char * s ) +{ + int i = 0; + while ( 1 ) + { + if ( *(s+i) == '\0' ) + break; + i++; + } + + return i; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (n-- > 0) { + if (*s1 != *s2) return *(unsigned char *)s1 - *(unsigned char *)s2; + if (*s1 == '\0') return 0; + s1++; + s2++; + } + return 0; +} + +// Custom strcmp function +int strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +// Custom itoa function +void itoa(int num, char *str, int base) { + int i = 0; + int is_negative = 0; + + if (num == 0) { + str[i++] = '0'; + str[i] = '\0'; + return; + } + + if (num < 0 && base == 10) { + is_negative = 1; + num = -num; + } + + while (num != 0) { + int rem = num % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + num = num / base; + } + + if (is_negative) str[i++] = '-'; + + str[i] = '\0'; + + int start = 0; + int end = i - 1; + while (start < end) { + char temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} + + +unsigned int hex_to_uint(char *hex) { + unsigned int result = 0; + for (int i = 0; i < 8; i++) { // Assuming each field contains 8 hexadecimal characters + result = (result << 4) | HEX_DIGIT_TO_INT(hex[i]); + } + return result; +} + +char *strrchr(const char *str, int ch) { + const char *last_occurrence = NULL; + + // Traverse the string from beginning to end + while (*str != '\0') { + if (*str == ch) { + last_occurrence = str; // Update last occurrence pointer + } + str++; + } + + // Special case: check for '\0' (null terminator) if looking for '\0' + if (ch == '\0') { + return (char*)str; // Return pointer to the null terminator + } + + return (char*)last_occurrence; // Return pointer to the last occurrence of ch +} + +unsigned long long strtoull(const char *str, char **endptr, int base) { + unsigned long long result = 0; + int negative = 0; + + // Skip leading whitespace + while (*str == ' ' || (*str >= '\t' && *str <= '\r')) { + str++; + } + + // Handle optional sign + if (*str == '+' || *str == '-') { + negative = (*str == '-'); + str++; + } + + // Determine base if not specified + if (base == 0) { + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') { + base = 16; + str++; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base == 16 && *str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { + str += 2; + } + + // Convert characters to unsigned long long integer + while (*str != '\0') { + int digit; + + if (*str >= '0' && *str <= '9') { + digit = *str - '0'; + } else if (*str >= 'a' && *str <= 'z') { + digit = *str - 'a' + 10; + } else if (*str >= 'A' && *str <= 'Z') { + digit = *str - 'A' + 10; + } else { + break; // Invalid character encountered + } + + if (digit >= base) { + break; // Digit out of range for current base + } + + result = result * base + digit; + str++; + } + + // Set endptr if it's not NULL + if (endptr != NULL) { + *endptr = (char*)str; + } + + // Handle negative sign + if (negative) { + result = -result; + } + + return result; +} + +char *strtok(char *str, const char *delim) { + static char *next_token = NULL; + // If str is NULL, continue with the last token found + if (str == NULL && next_token == NULL) { + return NULL; + } + + // Initialize str to start tokenization + if (str != NULL) { + next_token = str; + } + + // Skip leading delimiters + while (*next_token != '\0' && strchr(delim, *next_token) != NULL) { + next_token++; + } + + // If reached end of string, return NULL + if (*next_token == '\0') { + next_token = NULL; + return NULL; + } + + // Save the beginning of the token + char *token = next_token; + + // Find the end of the token + while (*next_token != '\0' && strchr(delim, *next_token) == NULL) { + next_token++; + } + + // If not reached end of string, replace delimiter with '\0' + if (*next_token != '\0') { + *next_token = '\0'; + next_token++; + } else { + next_token = NULL; // Mark end of tokenization + } + + return token; +} + +char *strcpy(char *dest, const char *src) { + char *original_dest = dest; // Store original destination pointer + + // Copy characters from src to dest + while ((*dest++ = *src++) != '\0') + ; + + return original_dest; // Return original destination pointer +} + +char *strchr(const char *str, int c) { + while (*str != '\0') { + if (*str == c) { + return (char *)str; // Cast away constness for return type compatibility + } + str++; + } + + if (c == '\0') { + return (char *)str; // Return pointer to null terminator if c is '\0' + } + + return NULL; // Character not found +} + +int atoi(const char *str) { + int result = 0; + int sign = 1; + int i = 0; + + // Handle optional leading whitespace + while (str[i] == ' ') { + i++; + } + + // Handle optional sign + if (str[i] == '-') { + sign = -1; + i++; + } else if (str[i] == '+') { + i++; + } + + // Convert digits to integer + while (str[i] >= '0' && str[i] <= '9') { + result = result * 10 + (str[i] - '0'); + i++; + } + + // Apply sign + result *= sign; + + return result; +} diff --git a/demo/src/shell.c b/demo/src/shell.c new file mode 100755 index 000000000..c49148f09 --- /dev/null +++ b/demo/src/shell.c @@ -0,0 +1,103 @@ +#include "../include/my_string.h" +#include "../include/shell.h" +#include "../include/uart.h" +#include "../include/command.h" +#include "../include/my_stdint.h" +#include "../include/my_stdlib.h" +#include "../include/timer.h" + +void shell_start(void) { + int buffer_counter = 0; + char input_char; + char buffer[MAX_BUFFER_LEN]; + + strset(buffer, 0, MAX_BUFFER_LEN); + + char *argv[5]; + int buf_index; + //char input_char; + for(buf_index = 0; buf_index < 5; buf_index++){ + argv[buf_index] = simple_malloc(MAX_ARGV_LEN); + strset(argv[buf_index], 0, MAX_ARGV_LEN); + } + // New line head + uart_puts("# "); + + // Read input + while (1) { + input_char = uart_getc(); + command_controller(input_char, buffer, &buffer_counter, argv); + } +} + +void command_controller(char c, char buffer[], int *counter, char **argv) { + + if (!(c < 128 && c >= 0)) { + uart_puts("Invalid character received\n"); + return; + } else if (c == LINE_FEED || c == CRRIAGE_RETURN) { + uart_send(c); + + buffer[*counter] = '\0'; + int argc = parse_arguments(buffer, argv); + + if (argc > 0) { + execute_command(argc, argv); + } + + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } else if (c == BACKSPACE) { ///not working + uart_puts("Error: Command not found\n"); + if (*counter > 0) { + uart_send('h'); + uart_send('\b'); // Send Backspace to move cursor back + uart_send(' '); // Send space to clear the character on the screen + uart_send('\b'); // Send Backspace again to move cursor back + (*counter)--; // Decrement counter to remove the last character from the buffer + } + }else { + uart_send(c); + + if (*counter < MAX_BUFFER_LEN) { + buffer[*counter] = c; + (*counter)++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + *counter = 0; + strset(buffer, 0, MAX_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } +} + +void execute_command(int argc, char **argv) { + for (command_t *cmd = commands; cmd->command != NULL; cmd++) { + if (strcmp(argv[0], cmd->command) == 0) { + cmd->handler(argc,argv); + return; + } + } + + uart_puts("Error: Command not found\n"); + uart_puts("Try command: help\n"); +} + +int parse_arguments(char *buffer, char **argv) { + int argc = 0; + char *token = strtok(buffer, " "); // Tokenize buffer by space + + while (token != NULL && argc < 5) { + strcpy(argv[argc], token); // Copy token to argv + token = strtok(NULL, " "); + argc++; + } + + return argc; +} \ No newline at end of file diff --git a/demo/src/start.S b/demo/src/start.S new file mode 100755 index 000000000..7c7542e78 --- /dev/null +++ b/demo/src/start.S @@ -0,0 +1,184 @@ +.section ".text.boot" + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +.global _start + +_start: + // bootloader loads a dtb into memory and passes the loading address specified at register x0 to the kernel. + // store x0 value for dtb + mov x10, x0 + + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbnz x1, halt + // cpu id > 0, stop + +change_ell_stat: + bl from_el2_to_el1 + b init_sp + +//Set stack pointer before code starts +init_sp: + ldr x1, =_start + mov sp, x1 + b set_exception_vector_table + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + b bss_init + +// cpu id == 0 +bss_init: + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +clear_bss_memory: + cbz w2, enable_Core_Timer + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, clear_bss_memory + +enable_Core_Timer: + bl core_timer_enable + b jump_to_main + +// jump to C code, should not return +jump_to_main: + mov x0, x10 + + bl main + // for failsafe, halt this core too + b halt + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3C5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 + +halt: + wfe + b halt + +//exception +.macro exception_entry function + b \function + .align 7 // entry size is 0x80, .align will pad 0 +.endm + + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table + +exception_vector_table: +// Exception from the current EL while using SP_EL0 + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + +// Exception from the current EL while using SP_ELx + exception_entry showinfo_exception + exception_entry irq_exception // el1 + exception_entry showinfo_exception + exception_entry showinfo_exception + +// Exception from a lower EL and at least one lower EL is AArch64 + exception_entry showinfo_exception + exception_entry irq_exception // el0 + exception_entry showinfo_exception + exception_entry showinfo_exception + +// Exception from a lower EL and all lower EL are AArch32 + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + exception_entry showinfo_exception + + +// save general registers to stack +.macro save_all + sub sp, sp, 32 * 9 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + str x30, [sp, 16 * 15] + + mrs x0, spsr_el1 + mrs x1, elr_el1 + stp x0, x1, [sp, 16 * 16] + // restore x0 and x1(as we just use it to save the information of spsr and elr) + ldp x0, x1, [sp, 16 * 0] + +.endm + +// load general registers from stack +.macro load_all + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + + ldp x0, x1, [sp, 16 * 16] + msr spsr_el1, x0 + msr elr_el1, x1 + // restore x0 and x1(as we just use it to restore the information of spsr and elr) + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 32 * 9 +.endm + + +showinfo_exception: + save_all + bl showinfo_exception_handler + load_all + eret + +irq_exception: + save_all + bl irq_exception_handler + load_all + eret + + +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mrs x0, cntfrq_el0 + msr cntp_tval_el0, x0 // set expired time + mov x0, 2 + ldr x1, =CORE0_TIMER_IRQ_CTRL + str w0, [x1] // unmask timer interrupt + ret + + diff --git a/demo/src/task.c b/demo/src/task.c new file mode 100755 index 000000000..6e6da328b --- /dev/null +++ b/demo/src/task.c @@ -0,0 +1,110 @@ +#include "../include/task.h" + +task_t* task_head = 0; +task_t* task_tail = 0; + +task_t * create_task(void (*callback)(void *), int priority){ + if(priority < 0){ + uart_puts("pririty should >= 0\n"); + return 0; + } + + + disable_interrupt(); + task_t *newTask = (task_t*)simple_malloc(sizeof(task_t)); + if(!newTask){ + uart_puts("Fail to create task: Memory allocation error\n"); + return 0; + } + + //disable core0 timer interrupt, otherwise will stuck in here + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + + newTask->prev = 0; + newTask->next = 0; + newTask->callback = callback; + newTask->data = (void *)0; + newTask->priority = priority; + enable_interrupt(); + + return newTask; +} + +int add_task_to_queue(task_t *newTask){ + + disable_interrupt(); + //disable core0 timer interrupt, otherwise will stuck in here + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x0); + + task_t *cur = task_head; + + if(task_head == 0){ + task_head = newTask; + task_tail = newTask; + return 0; + } + + while(1){ + // insert into appropiate location based on increase-order + if(newTask->priority <= cur->priority){ + newTask->prev = cur->prev; + if(cur->prev != 0) + cur->prev->next = newTask; + cur->prev = newTask; + newTask->next = cur; + // if it is inserted into the head of queue + if(cur == task_head){ + task_head = newTask; + } + break; + } + // traverse to last element + else if(cur == task_tail){ + task_tail->next = newTask; + newTask->prev = task_tail; + task_tail = newTask; + break; + } + cur = cur->next; + } + + // enable all interrupt + enable_interrupt(); + + return 1; + +} + + +void test_tesk1(void){ + uart_puts("tesk1 finished\n"); +} + +void test_tesk2(void){ + uart_puts("tesk2 finished\n"); +} + +void test_tesk3(void){ + uart_puts("tesk3 finished\n"); +} + +// Function to print the tasks in the task queue +void ExecTasks(void) { + task_t* cur = task_head; + //uart_puts("exec\n"); + //if not empty + while(cur != 0){ + task_head = cur->next; + if(task_head != 0){ + task_head->prev = 0; + } + //uart_puts((char*)cur->data); + cur->callback(cur->data); + + cur = cur->next; + } + //uart_puts("Finish all task\n"); + + // enable all interrupt + //enable_interrupt(); +} \ No newline at end of file diff --git a/demo/src/timer.c b/demo/src/timer.c new file mode 100755 index 000000000..82ee3819f --- /dev/null +++ b/demo/src/timer.c @@ -0,0 +1,154 @@ +#include "../include/timer.h" + + +task_timer_t* timer_head = 0; +task_timer_t* timer_tail = 0; + +int core_timer_flag = 1; + +task_timer_t *create_timer(void (*callback)(void *),void* message, int seconds){ + unsigned long long cur_cnt, cnt_freq; + + if(seconds == 0) + return NULL; + + + disable_interrupt(); + + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + // preserve data + char *copy = simple_malloc(strlen((char*)message) + 1); + if(!copy){ + + enable_interrupt(); + uart_puts("Fail to create timer: Memory allocation error\n"); + return NULL; + } + + strcpy(copy, (char*)message); + task_timer_t *temp = simple_malloc(sizeof(task_timer_t)); + + if(!temp){ + enable_interrupt(); + uart_puts("Fail to create timer: Memory allocation error\n"); + return NULL; + } + + temp->callback = callback; + temp->data = (void*)copy; + // set to current_time + waiting seconds, as this is be compared with current_time in the irq_handler + temp->deadline = cur_cnt + seconds * cnt_freq; + temp->next = 0; + temp->prev = 0; + + enable_interrupt(); + + return temp; +} + +int timer_add_queue(task_timer_t *temp){ + int run_timer_flag = 0; + unsigned long long cur_cnt, cnt_freq; + + disable_interrupt(); + + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + task_timer_t *cur = timer_head; + + if(timer_head == 0){ + timer_head = temp; + timer_tail = temp; + // enable core0 timer interrupt + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); + write_register(cntp_cval_el0,temp->deadline); + write_register(cntp_ctl_el0,1); + enable_interrupt(); + return 1; + + + } + + //list not empty + while(1){ + // insert into appropiate location based on increase-order + if(temp->deadline <= cur->deadline){ + if(temp->deadline < cur->deadline){ + temp->prev = cur->prev; + if(cur->prev != 0) + cur->prev->next = temp; + cur->prev = temp; + temp->next = cur; + } + else{ + temp->prev = cur; + temp->next = cur->next; + if(cur->next != 0) + cur->next->prev = temp; + cur->next = temp; + } + + // if it is inserted into the timer_head of queue and have the smallest deadline + if(cur == timer_head && temp->deadline < cur->deadline){ + timer_head = temp; + *((volatile unsigned int*)CORE0_TIMER_IRQ_CTRL) = (0x2); + write_register(cntp_cval_el0,temp->deadline); + write_register(cntp_ctl_el0,1); + enable_interrupt(); + return 1; + } + + break; + } + // traverse to last element and have the biggest deadline + if(cur == timer_tail){ + timer_tail->next = temp; + temp->prev = timer_tail; + + timer_tail = temp; + break; + } + cur = cur->next; + } + + enable_interrupt(); + + return 1; +} + + +void timer_callback(void *str){ + unsigned long long cur_cnt, cnt_freq; + uart_puts("The message is: "); + uart_puts((char*)str); + + cur_cnt = read_register(cntpct_el0); + cnt_freq = read_register(cntfrq_el0); + + uart_puts(" wake up at: "); + uart_hex(cur_cnt / cnt_freq); + uart_send('\n'); +} + +void setTimeout (char *message, int seconds) { + + //if(add_timer(timer_callback, (void*)message, seconds) == 0) + // uart_puts("Fail to set timeout\n"); + + + //strcpy(copy, message); + task_timer_t *newtimer = create_timer(timer_callback, message, seconds); + if(!newtimer){ + uart_puts("Fail to set timeout\n"); + } + + if (timer_add_queue(newtimer) == 0) { + uart_puts("Fail to set timeout\n"); + } + + +} + diff --git a/demo/src/uart.c b/demo/src/uart.c new file mode 100755 index 000000000..b3c6ae971 --- /dev/null +++ b/demo/src/uart.c @@ -0,0 +1,307 @@ + +#include "../include/uart.h" + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int reg; + + /* initialize UART */ + *AUX_ENABLE |= 1; /* enable mini UART */ + *AUX_MU_CNTL = 0; /* Disable transmitter and receiver during configuration. */ + + *AUX_MU_IER = 0; /* Disable interrupt */ + *AUX_MU_LCR = 3; /* Set the data size to 8 bit. */ + *AUX_MU_MCR = 0; /* Don’t need auto flow control. */ + *AUX_MU_BAUD = 270; /* 115200 baud */ + *AUX_MU_IIR = 6; /* No FIFO */ + // *AUX_MU_IIR = 0xc6; /* No FIFO */ + + /* map UART1 to GPIO pins */ + // GPFSEL1 register controls the function of GPIO pins + reg = *GPFSEL1; + reg &= ~((7<<12)|(7<<15)); /* address of gpio 14, 15 */ + reg |= (2<<12)|(2<<15); /* set to alt5 */ + + *GPFSEL1 = reg; + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + // ensures that GPIO pins are not affected by internal resistors + *GPPUD = 0; /* Disable pull-up/down */ + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + *GPPUDCLK0 = (1<<14)|(1<<15); + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + *GPPUDCLK0 = 0; /* flush GPIO setup */ + //Stabilizing the Signal to ensure Proper Configuration + reg=150; + while ( reg-- ) + { + asm volatile("nop"); + } + + // ensures that GPIO pins are returned to a neutral state + *GPPUDCLK0 = 0; /* flush GPIO setup */ + + *AUX_MU_CNTL = 3; // Enable the transmitter and receiver. + + //*((volatile unsigned int*)AUX_MU_IER) &= ~0x03; + +} + +/** + * Send a character + */ +void uart_send(unsigned int c) +{ + /* Wait until UART transmitter is ready to accept new data. */ + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + /* write the character to the buffer */ + *AUX_MU_IO = c; + + // ensure proper line termination + if ( c == '\n' ) + { + do { + + asm volatile("nop"); + + } while( ! ( *AUX_MU_LSR&0x20 )); + + *AUX_MU_IO = '\r'; + } +} + + +/** + * 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 the data*/ + r = ( char )( *AUX_MU_IO ); + + /* convert carrige return to newline */ + //standardize newline characters across different systems. + return r == '\r' ? '\n' : r; +} + +/** + * Display a string + */ +void uart_puts(const char *s) +{ + while( *s ) + { + + uart_send(*s++); + + } +} + +char *get_string(void){ + int buffer_counter = 0; + char input_char; + static char buffer[TMP_BUFFER_LEN]; + strset(buffer, 0, TMP_BUFFER_LEN); + while (1) { + input_char = uart_getc(); + if (!(input_char < 128 && input_char >= 0)) { + uart_puts("Invalid character received\n"); + return NULL; + } else if (input_char == LINE_FEED || input_char == CRRIAGE_RETURN) { + uart_send(input_char); + buffer[buffer_counter] = '\0'; + return buffer; + }else { + uart_send(input_char); + + if (buffer_counter < TMP_BUFFER_LEN) { + buffer[buffer_counter] = input_char; + buffer_counter++; + } + else { + uart_puts("\nError: Input exceeded buffer length. Buffer reset.\n"); + buffer_counter = 0; + strset(buffer, 0, TMP_BUFFER_LEN); + + // New line head + uart_puts("# "); + } + } + } +} + +/** + * 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_send(n); + } +} + +char read_buffer[BUFFER_SIZE]; +char write_buffer[BUFFER_SIZE]; + +int read_index_cur = 0; +int read_index_tail = 0; +int write_index_cur = 0; +int write_index_tail = 0; + +void initialize_async_buffers(void) { + strset(read_buffer, 0, BUFFER_SIZE); + strset(write_buffer, 0, BUFFER_SIZE); +} + +void uart_send_async(char c) { + //uart_puts("uart_send_async\n"); + + write_buffer[write_index_tail++] = c; + + if (write_index_tail >= BUFFER_SIZE) { + write_index_tail = 0; + } + + // Enable mini UART transmit interrupt to start sending the data + *((volatile unsigned int*)AUX_MU_IER) |= 0x02; +} + +char uart_getc_async(void) { + //*((volatile unsigned int*)AUX_MU_IER) |= (0x1); + //uart_puts("uart_getc_async\n"); + if(read_index_cur != read_index_tail){ + //uart_puts("test"); + char c = read_buffer[read_index_cur++]; + //uart_send(c); + if (read_index_cur >= BUFFER_SIZE) { + read_index_cur = 0; + } + + return c; + + } + else{ + return '!'; + } +} + +void uart_puts_async(const char *str) { + //uart_puts("uart_puts_async\n"); + while (*str) { + + if(*str == '\n'){ + write_buffer[write_index_tail++] = '\r'; + } + + + if (write_index_tail >= BUFFER_SIZE) { + write_index_tail = 0; + } + + write_buffer[write_index_tail++] = *str++; + + + } + // Enable mini UART transmit interrupt to start sending the data + *((volatile unsigned int*)AUX_MU_IER) |= 0x02; +} + +void get_string_async(char *buffer_async){ + //uart_puts("uart_string_async\n"); + int buffer_counter = 0; + char input_char; + + while(1){ + //uart_send(buffer_counter+'0'); + input_char = uart_getc_async(); + //uart_puts("in get\n"); + // Disable mini UART transmit interrupt + *((volatile unsigned int*)AUX_MU_IER) &= ~(0x2); + + if(input_char == '!'){ + //uart_puts("empty\n"); + continue; + } + //uart_puts("check input : "); + //uart_send(input_char); + //uart_puts("\n"); + // Get non ASCII code + if (input_char >= 128 || input_char < 0) { + //uart_puts("Invalid character received\n"); + continue; + } + if (input_char == CRRIAGE_RETURN) { + //uart_send_async(input_char); + buffer_async[buffer_counter] = '\0'; + //uart_puts_async("\n"); + return; + } + if (buffer_counter < TMP_BUFFER_LEN - 1) { + buffer_async[buffer_counter] = input_char; + buffer_counter++; + *((volatile unsigned int*)AUX_MU_IER) |= (0x1); + //uart_puts(buffer_async); + //uart_puts("\n"); + } else { + //uart_puts_async("\nError: Input exceeded buffer length. Buffer reset.\n"); + buffer_counter = 0; + strset(buffer_async, 0, TMP_BUFFER_LEN); + + // New line head + uart_puts_async("# "); + } + + } +} + +void uart_int(int num){ + char tmp[65]; + itoa(num,tmp,10); + uart_puts(tmp); +} + +void uart_hex_64(uint64_t d) { + unsigned int n; + int c; + for(c=60;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_send(n); + } +} \ No newline at end of file diff --git a/demo/user_program/asm2img.sh b/demo/user_program/asm2img.sh new file mode 100755 index 000000000..f427cdc06 --- /dev/null +++ b/demo/user_program/asm2img.sh @@ -0,0 +1,3 @@ +aarch64-linux-gnu-as -o user_program.o user_program.S +aarch64-linux-gnu-ld -o user_program.elf user_program.o +aarch64-linux-gnu-objcopy -O binary user_program.elf -O binary ../rootfs/userprogram.img \ No newline at end of file diff --git a/demo/user_program/user_program.S b/demo/user_program/user_program.S new file mode 100755 index 000000000..87b4851f3 --- /dev/null +++ b/demo/user_program/user_program.S @@ -0,0 +1,11 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b +1: + b 1b \ No newline at end of file diff --git a/demo/user_program/user_program.elf b/demo/user_program/user_program.elf new file mode 100755 index 0000000000000000000000000000000000000000..e506290ce656b96b1201b2e1318e4fd0af734487 GIT binary patch literal 864 zcmbtSF;2rk5ZpKpf-Z;@NE9T9mK0RbnIecH>F7@v#R^Rbx;rFO!4tweXz22fC?ClK zkh6QX6fss?EM6F z*3yY~8i)b(?Z?dNF`_dCzDVcN%;64))&(9w-{^=BlJ}J{KW7w(rD3G(&aYQa<$vmu n0jr4@Wsiwq$+;)k)2v#*oEudJESKsjc6IqbHug$q(NyzWLZw4B literal 0 HcmV?d00001 diff --git a/demo/user_program/user_program.o b/demo/user_program/user_program.o new file mode 100755 index 0000000000000000000000000000000000000000..f84f74464ba18b1899788834c6ce00a0fc474de1 GIT binary patch literal 736 zcmb<-^>JfjWMqH=MuzPS2p&w7fk6RD&;cy$z`)MH24po{VqjsI2$a4eFT(I~_5c4N zKtU0(5*!3GRvQ=?m>HO`>R<-SpaY0=kQ@b7zyhQNu$iw?!4O|ul2}y2z@S%LnOl;W z1f)xfAan+dRgzj!!l0LuSdz$~msDJgZY$}0X`mL6D?uTJ3>=^w31mSa8{~dupa|rE z^rMGB1hOI|HhPGt1LZg<&<`>XTdctBp8&O+6-a|H$Sx3o`HK_CMt3_%{so8t0&WNe XC(+$62$aF5|1(sF4qPXMfvz6_dRQPB literal 0 HcmV?d00001