├── include ├── elf.h ├── main.h ├── init.h ├── types │ ├── types.h │ ├── queue.h │ └── string.h ├── util │ ├── memutil.h │ ├── mmio.h │ └── utilities.h ├── hardware │ ├── device │ │ ├── sdBlockDevice.h │ │ └── blockDevice.h │ ├── framebuffer.h │ ├── uart.h │ ├── timer.h │ ├── mmu_c.h │ ├── keyboard.h │ ├── paging.h │ ├── mailbox.h │ ├── miniUart.h │ └── interrupts.h ├── terminal.h ├── terminalCommands.h ├── syscalls.h ├── debugging.h ├── interruptHandlers.h ├── scheduler.h ├── mem.h ├── memory.h ├── stdbool.h ├── process.h ├── thread.h ├── fs │ ├── fat32driver.h │ └── fs.h ├── asm.h ├── dwarf.h ├── memory_map.h ├── atags.h ├── stdarg.h └── myfont.h ├── .gitattributes ├── qemud ├── qemu ├── user ├── dummy1 │ ├── memorymap │ ├── source │ │ └── main.c │ └── makefile └── dummy2 │ ├── memorymap │ ├── source │ └── main.c │ └── makefile ├── .gitignore ├── visualstudio ├── PiOSVisualStudio.vcxproj.user ├── vsbuild.bat ├── pios.sln └── PiOSVisualStudio.vcxproj ├── source ├── hardware │ ├── gpio.c │ ├── interrupts.c │ ├── timer.c │ ├── device │ │ └── sdBlockDevice.c │ ├── uart.c │ ├── miniUart.c │ ├── mmu_c.c │ ├── paging.c │ ├── framebuffer.c │ ├── keyboard.c │ └── mailbox.c ├── platform.c ├── util │ ├── memutil.c │ └── utilities.c ├── types │ └── queue.c ├── asm │ ├── irq.s │ ├── start.S │ ├── utility.s │ ├── interrupt_handlers.S │ └── mmu.S ├── syscalls.c ├── atags.c ├── debugging.c ├── thread.c ├── main.c ├── elf.c ├── mem.c ├── scheduler.c ├── init.c └── interruptHandlers.c ├── LICENSE.md ├── linker.c ├── README.md └── makefile /include/elf.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonGustavsson/PiOS/HEAD/include/elf.h -------------------------------------------------------------------------------- /include/main.h: -------------------------------------------------------------------------------- 1 | 2 | void callFoo(); 3 | void foo(); 4 | 5 | // The entry point of the kernel following the initialization 6 | int cmain(void); 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enable line ending normalization 2 | * text=auto 3 | 4 | # Don't bother normalizing VS projects 5 | *.vcxproj eol=crlf 6 | *.filters eol=crlf 7 | -------------------------------------------------------------------------------- /include/init.h: -------------------------------------------------------------------------------- 1 | 2 | // Sets up the MMU and maps the kernel into high memory 3 | void sysinit_stage1(int, int, int) __attribute__((section(".text.init"))); 4 | 5 | // Performs initialization of the peripherals and calls cmain 6 | 7 | void sysinit_stage2(int, int, int); -------------------------------------------------------------------------------- /include/types/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | #ifndef __cplusplus 4 | #ifndef bool 5 | typedef enum { false, true } bool; 6 | #endif 7 | typedef struct { 8 | int width; 9 | int height; 10 | } size; 11 | #endif 12 | #endif -------------------------------------------------------------------------------- /include/util/memutil.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMUTIL_H 2 | #define MEMUTIL_H 3 | 4 | void DataMemoryBarrier(void); 5 | void DataSyncBarrier(void); 6 | void FlushCache(void); 7 | void FlushTLB(unsigned int mva); 8 | void InvalidateAllUnlockedTLB(void); 9 | void* my_memset(void* dest, unsigned char c, unsigned int size); 10 | 11 | #endif -------------------------------------------------------------------------------- /include/hardware/device/sdBlockDevice.h: -------------------------------------------------------------------------------- 1 | #include "hardware/device/blockDevice.h" 2 | 3 | unsigned int Sd_Register(BlockDevice* device); 4 | 5 | int Sd_Initialize(void); 6 | unsigned int Sd_DeviceOperation(BlockDevOp opCode, void* arg, void *arg2); 7 | unsigned int Sd_GetSector(unsigned int sector, unsigned char* buf); 8 | void Sd_Cleanup(void); -------------------------------------------------------------------------------- /qemud: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /opt/qemu-rpi/bin/qemu-system-arm -kernel bin/kernel.elf -cpu arm1176 -m 512 -M raspi -no-reboot -sd /media/simon/Storage/deployer-sd.img -device usb-kbd -device usb-mouse -s -append "bcm2708_fb.fbwidth=1024 bcm2708_fb.fbheight=768 bcm2708.boardrev=0xf bcm2708.serial=0xcad0eedf bcm2708.emmc_clock_freq=100000000 vc_mem.mem_base=0x1c000000 vc_mem.mem_size=0x20000000" -s -S 3 | -------------------------------------------------------------------------------- /qemu: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /opt/qemu-rpi/bin/qemu-system-arm -kernel bin/kernel.elf -cpu arm1176 -m 512 -M raspi -no-reboot -sd /media/simon/Storage/deployer-sd.img -device usb-kbd -device usb-mouse -s -append "bcm2708_fb.fbwidth=1024 bcm2708_fb.fbheight=768 bcm2708.boardrev=0xf bcm2708.serial=0xcad0eedf bcm2708.emmc_clock_freq=100000000 vc_mem.mem_base=0x1c000000 vc_mem.mem_size=0x20000000" -serial stdio 3 | -------------------------------------------------------------------------------- /user/dummy1/memorymap: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | /* Hardcoded 1 MB max application size */ 4 | ram : ORIGIN = 0x00000000, LENGTH = 1M 5 | } 6 | 7 | SECTIONS 8 | { 9 | .text : { *(.text*) } > ram 10 | .bss : { *(.bss*) } > ram 11 | .data : { *(.data) } > ram 12 | .rodata : { *(.rodata) } > ram 13 | .rodata.str1.4 : { *(.rodata.str1.4) } > ram 14 | .rel.plt : { *(.rel.plt) } > ram 15 | } -------------------------------------------------------------------------------- /user/dummy2/memorymap: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | /* Hardcoded 1 MB max application size */ 4 | ram : ORIGIN = 0x00000000, LENGTH = 1M 5 | } 6 | 7 | SECTIONS 8 | { 9 | .text : { *(.text*) } > ram 10 | .bss : { *(.bss*) } > ram 11 | .data : { *(.data) } > ram 12 | .rodata : { *(.rodata) } > ram 13 | .rodata.str1.4 : { *(.rodata.str1.4) } > ram 14 | .rel.plt : { *(.rel.plt) } > ram 15 | } -------------------------------------------------------------------------------- /include/terminal.h: -------------------------------------------------------------------------------- 1 | 2 | //#define TERMINAL_DEBUG 3 | 4 | void Terminal_Print(char* string, unsigned int length); 5 | void Terminal_PrintImportant(char* string, unsigned int length); 6 | 7 | int Terminal_Initialize(void); 8 | void Terminal_Clear(void); 9 | void Terminal_Update(void); 10 | void Terminal_PrintPrompt(void); 11 | void Terminal_PrintWelcome(void); 12 | 13 | void Terminal_back(void); 14 | 15 | int Terminal_GetIsInitialized(void); 16 | -------------------------------------------------------------------------------- /include/terminalCommands.h: -------------------------------------------------------------------------------- 1 | #ifndef TERMINAL_COMMANDS 2 | #define TERMINAL_COMMANDS 3 | 4 | #define TERMINAL_PROMPT_MAX_LENGTH 10 5 | typedef struct 6 | { 7 | char* name; 8 | char* description; 9 | unsigned int (*execute)(char**, unsigned int); 10 | } TerminalCommand; 11 | 12 | 13 | void TerminalCommands_Initialize(void); 14 | TerminalCommand* TerminalCommands_GetCommand(char* name); 15 | unsigned int TerminalCommands_Execute(char* cmd); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/types/queue.h: -------------------------------------------------------------------------------- 1 | #ifndef PQUEUE_H 2 | #define PQUEUE_H 3 | 4 | // We hav eto do this as Node contains a reference to "Node" 5 | typedef struct Node Node; 6 | 7 | struct Node { 8 | void* data; 9 | Node* next; 10 | }; 11 | 12 | typedef struct { 13 | Node* front; 14 | Node* back; 15 | unsigned int numNodes; 16 | } Queue; 17 | 18 | void Queue_Enqueue(Queue* queue, void* item); 19 | void* Queue_Dequeue(Queue* queue); 20 | void* Queue_Peek(Queue* queue); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/syscalls.h: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | 3 | #define SWI_PARAM_WITH_RES(SWI_NR, ARG, RESULT) \ 4 | asm volatile(\ 5 | "mov r0,%1 \t\n" \ 6 | "swi %a2 \n\t" \ 7 | "mov %0,r0 \n\t" \ 8 | : "=r" (RESULT) : "r" (ARG), "I" (SWI_NR) : "r0", "lr") 9 | 10 | #define SYS_PRINT_SWI 12 11 | #define SYS_THREAD_CREATE 42 12 | 13 | // Invokes the system call to print a string 14 | void pios_print(const char* str); 15 | thread* pios_thread_create(thread_entry entry); 16 | 17 | void syscalls_init(void); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | # Dependency Files 4 | *.d 5 | # Compiled libraries 6 | #*.a 7 | *.suo 8 | *.sdf 9 | *.opensdf 10 | 11 | # Libraries 12 | *.lib 13 | *.map 14 | 15 | # Shared objects (inc. Windows DLLs) 16 | *.dll 17 | *.so 18 | *.so.* 19 | *.dylib 20 | 21 | # Executables 22 | *.exe 23 | *.out 24 | *.app 25 | *.elf 26 | *.img 27 | Debug/ 28 | bin/ 29 | 30 | # Debug output 31 | disassembly.txt 32 | symbols.txt 33 | 34 | # Gedit temporary files 35 | *.c~ 36 | *.h~ 37 | *.py~ 38 | makefile~ 39 | *.gitignore~ 40 | *.sublime-workspace 41 | -------------------------------------------------------------------------------- /include/debugging.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGGING_H_C 2 | #define DEBUGGING_H_C 3 | 4 | #define MAX_FRAME_DEPTH 10 5 | 6 | typedef struct { 7 | int* pc; 8 | int* lr; 9 | int* sp; 10 | int* fp; 11 | } call_frame; 12 | 13 | typedef struct { 14 | char* name; 15 | unsigned int address; 16 | } func_info; 17 | 18 | char* Debug_GetClosestPreviousFunction(unsigned int address); 19 | void Debug_ReadFunctionNames(char* symbolAddr); 20 | 21 | // skipFrames is the amount of stack from to skip (from the current) 22 | void Debug_PrintCallstack(unsigned int skipFrames); 23 | 24 | #endif -------------------------------------------------------------------------------- /include/interruptHandlers.h: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | 3 | #define MAX_SWI_NUM 200 4 | typedef void*(*swi_handler)(int, int, int); 5 | 6 | void c_undefined_handler(void* lr); 7 | void c_abort_data_handler(unsigned int address, unsigned int errorType, unsigned int accessedAddr, unsigned int fault_reg); 8 | void c_abort_instruction_handler(unsigned int address, unsigned int errorType); 9 | void c_swi_handler(unsigned int r0, unsigned int r1, unsigned int r2, unsigned int swi); 10 | void c_irq_handler(volatile unsigned int* sp); 11 | void print_abort_error(unsigned int errorType); 12 | 13 | bool swi_install(unsigned int swiNum, swi_handler handler); -------------------------------------------------------------------------------- /visualstudio/PiOSVisualStudio.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cmd.exe 5 | WindowsLocalDebugger 6 | /C "$(ProjectDir)..\..\PiOSLoader\deployer\bin\Debug\PiOSDeployer.exe $(ProjectDir)..\bin\kernel.elf 460800" 7 | ManagedOnly 8 | 9 | -------------------------------------------------------------------------------- /source/hardware/gpio.c: -------------------------------------------------------------------------------- 1 | #include "hardware/gpio.h" 2 | #include "memory_map.h" 3 | 4 | static void delay(unsigned int count) 5 | { 6 | volatile unsigned int i; 7 | for (i = 0; i < count; i++){ /* Do Nothing */ } 8 | } 9 | 10 | void Gpio_EnableUart(void) 11 | { 12 | gpio_reg* gpio = (gpio_reg*)(PERIPHERAL_VA_GPIO); 13 | 14 | // Disable pull up/down for all GPIO pins & delay for 150 cycles. 15 | gpio->gppud.raw = 0x00000000; 16 | delay(150); 17 | 18 | // Disable pull up/down for pin 14,15 & delay for 150 cycles. 19 | gpio->gppudclk0.raw = (1 << 14) | (1 << 15); 20 | delay(150); 21 | 22 | // Write 0 to GPPUDCLK0 to make it take effect. 23 | gpio->gppudclk0.raw = 0x00000000; 24 | } 25 | -------------------------------------------------------------------------------- /include/hardware/device/blockDevice.h: -------------------------------------------------------------------------------- 1 | #define BLOCK_SIZE 512 2 | 3 | #ifndef BLOCK_DEVICE_H 4 | #define BLOCK_DEVICE_H 5 | 6 | typedef enum { 7 | BlockDevUnknown, 8 | BlockDevRemovable, 9 | BlockDevPermanent 10 | } BlockDeviceType; 11 | 12 | typedef enum { 13 | OpRead, 14 | OpWrite, 15 | OpGetStatus //BANANA 16 | } BlockDevOp; 17 | 18 | typedef struct { 19 | char name[11]; 20 | unsigned char* buffer; 21 | unsigned int name_length; 22 | BlockDeviceType type; 23 | 24 | int(*init)(void); 25 | 26 | // For reading, arg = Sector to read, arg2 = Buffer to read to 27 | unsigned int(*operation)(BlockDevOp opCode, void* arg, void *arg2); 28 | void(*cleanup)(void); 29 | } BlockDevice; 30 | 31 | #endif -------------------------------------------------------------------------------- /include/util/mmio.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utility functions for interacting with the memory mapped IO peripherals 3 | // 4 | 5 | // C Function for the assembly instruction 6 | // str val, [addr] 7 | // which stores the value of val in addr 8 | static inline void Mmio_Write(unsigned int addr, unsigned int data) 9 | { 10 | asm volatile("str %[data], [%[address]]" 11 | : : [address]"r"((unsigned int*)addr), [data]"r"(data)); 12 | } 13 | 14 | // C Function for the assembly instruction 15 | // ldr val, [addr] 16 | // Which loads the value at addr into val 17 | static inline void unsigned int Mmio_Read(unsigned int addr) 18 | { 19 | unsigned int data; 20 | asm volatile("ldr %[data], [%[addr]]" 21 | : [data]"=r"(data) : [addr]"r"((unsigned int*)addr)); 22 | 23 | return data; 24 | } -------------------------------------------------------------------------------- /visualstudio/vsbuild.bat: -------------------------------------------------------------------------------- 1 | REM Store transform tool in variable so we can modify it 2 | SET "transformtool=%~dp0..\tools\gnu2msdev.exe" 3 | 4 | REM Turn backslashes into forward slashes that bash understand 5 | SET "transformtool=%transformtool:\=/% 6 | 7 | REM Change C:/ into /cygdrive/c 8 | SET "transformtool=%transformtool:c:=/cygdrive/c%" 9 | 10 | REM Call make inside bash to compile our code, redirecting the output via gnu2msdev for 11 | REM Pretty, clickable error messages in Visual Studio 12 | echo c:/cygwin64/bin/bash.exe --login -c "cd /cygdrive/c/git/PiOS/ && make %1 1>&2 %transformtool%" 13 | c:/cygwin64/bin/bash.exe --login -c "cd /cygdrive/c/git/PiOS/ && make %1 2<&1 | sed -e 's|/cygdrive/\([a-z]\)/|\1:/|' -e 's/\.\([ch]\):\([0-9]*\)/.\1 (\2)/' ; exit ${PIPESTATUS[0]} -------------------------------------------------------------------------------- /include/scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEDULER_H 2 | #define SCHEDULER_H 3 | 4 | #define TASK_SCHEDULER_TICK_MS 200 5 | #include "types/queue.h" 6 | #include "process.h" 7 | #include "thread.h" 8 | 9 | typedef struct { 10 | thread* currentThread; 11 | Queue threads; 12 | } taskScheduler; 13 | 14 | void Scheduler_Initialize(void); 15 | void Scheduler_Start(void); 16 | 17 | // Switches to the next task in line Save registers and call this function from assembly 18 | void Scheduler_TimerTick(thread_regs* registers); 19 | 20 | // Loads the given elf and enqueues it 21 | void Scheduler_Enqueue(Process* p); 22 | 23 | unsigned int Scheduler_GetNextTID(void); 24 | // Switches to the next task in the list 25 | void Scheduler_NextTask(thread_regs* regs); 26 | void Scheduler_StartTask(Process* p); 27 | thread* Scheduler_GetCurrentThread(void); 28 | 29 | #endif -------------------------------------------------------------------------------- /source/platform.c: -------------------------------------------------------------------------------- 1 | unsigned long long __aeabi_uidivmod(unsigned int value, unsigned int divisor) { 2 | unsigned long long answer = 0; 3 | 4 | unsigned int i; 5 | for (i = 0; i < 32; i++) { 6 | if ((divisor << (31 - i)) >> (31 - i) == divisor) { 7 | if (value >= divisor << (31 - i)) { 8 | value -= divisor << (31 - i); 9 | answer |= (unsigned long long)(1 << (31 - i)); 10 | if (value == 0) break; 11 | } 12 | } 13 | } 14 | 15 | answer |= (unsigned long long)value << 32; 16 | return answer; 17 | }; 18 | 19 | unsigned int __aeabi_uidiv(unsigned int value, unsigned int divisor) { 20 | return (unsigned int)__aeabi_uidivmod(value, divisor); 21 | }; -------------------------------------------------------------------------------- /include/mem.h: -------------------------------------------------------------------------------- 1 | // Cover the entire 32-bit range 2 | #define PAGE_SIZE 4096 3 | #define MAX_AVAILABLE_MEMORY 536870912 // 512MB 4 | #define MAX_ALLOCATED_PAGES (MAX_AVAILABLE_MEMORY / PAGE_SIZE) 5 | 6 | //#define PAGEMEM_DEBUG 7 | 8 | int mem_init(void); 9 | 10 | // Returns the next available page 11 | int mem_nextFree(void); 12 | 13 | // Returns the address of the first page in the first series of available num_pages 14 | int mem_nextFreeContiguous(unsigned int num_pages); 15 | 16 | // Frees the page that covers the given physical address 17 | void mem_free(unsigned int addr); 18 | 19 | int mem_reserve(unsigned int startAddr, unsigned int size); 20 | // Marks the page that covers addr as used 21 | int mem_reserveSingle(unsigned int addr); 22 | int mem_reserveRange(unsigned int startAddr, unsigned int endAddr); 23 | 24 | unsigned int mem_getAvailable(void); 25 | unsigned int mem_getAllocated(void); 26 | void mem_printUsage(void); -------------------------------------------------------------------------------- /user/dummy1/source/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // Example application Zero 3 | // Test to make sure loaded relocatable binaries can call SVC 4 | // Functions repeatedly and return as expected 5 | // 6 | #define SWI_PARAM_WITH_RES(SWI_NR, ARG, RESULT) \ 7 | asm volatile(\ 8 | "mov r0,%1 \t\n" \ 9 | "swi %a2 \n\t" \ 10 | "mov %0,r0 \n\t" \ 11 | : "=r" (RESULT) : "r" (ARG), "I" (SWI_NR) : "r0", "lr") 12 | 13 | #define SYS_PRINT_SWI 12 14 | 15 | // Forward declare 16 | void sys_print(const char* str); 17 | 18 | int main(void) 19 | { 20 | unsigned int i; 21 | while(1) 22 | { 23 | sys_print("Hello, I'm dummy1!\n"); 24 | 25 | // Wait a bit 26 | for(i = 0; i < 9999999; i++); 27 | } 28 | 29 | // We don't actually return 30 | return 4; 31 | } 32 | 33 | void sys_print(const char* str) 34 | { 35 | // Note: res is not actually used at all 36 | unsigned int res; 37 | SWI_PARAM_WITH_RES(SYS_PRINT_SWI, str, res); 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /user/dummy2/source/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // Example application Zero 3 | // Test to make sure loaded relocatable binaries can call SVC 4 | // Functions repeatedly and return as expected 5 | // 6 | #define SWI_PARAM_WITH_RES(SWI_NR, ARG, RESULT) \ 7 | asm volatile(\ 8 | "mov r0,%1 \t\n" \ 9 | "swi %a2 \n\t" \ 10 | "mov %0,r0 \n\t" \ 11 | : "=r" (RESULT) : "r" (ARG), "I" (SWI_NR) : "r0", "lr") 12 | 13 | #define SYS_PRINT_SWI 12 14 | 15 | // Forward declare 16 | void sys_print(const char* str); 17 | 18 | int main(void) 19 | { 20 | unsigned int i; 21 | while(1) 22 | { 23 | sys_print("Hello, I'm dummy2!\n"); 24 | 25 | // Wait a bit 26 | for(i = 0; i < 9999999; i++); 27 | } 28 | 29 | // We don't actually return 30 | return 4; 31 | } 32 | 33 | void sys_print(const char* str) 34 | { 35 | // Note: res is not actually used at all 36 | unsigned int res; 37 | SWI_PARAM_WITH_RES(SYS_PRINT_SWI, str, res); 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /visualstudio/pios.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PiOSVisualStudio", "PiOSVisualStudio.vcxproj", "{C99F3786-0FAF-45D4-B4F9-2B73E4C7AC44}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C99F3786-0FAF-45D4-B4F9-2B73E4C7AC44}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {C99F3786-0FAF-45D4-B4F9-2B73E4C7AC44}.Debug|Win32.Build.0 = Debug|Win32 16 | {C99F3786-0FAF-45D4-B4F9-2B73E4C7AC44}.Release|Win32.ActiveCfg = Debug|Win32 17 | {C99F3786-0FAF-45D4-B4F9-2B73E4C7AC44}.Release|Win32.Build.0 = Debug|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /source/util/memutil.c: -------------------------------------------------------------------------------- 1 | #include "util/memutil.h" 2 | 3 | void* my_memset(void* dest, unsigned char c, unsigned int size) 4 | { 5 | unsigned char* ptr = (unsigned char*)dest; 6 | 7 | while (size--) 8 | *ptr++ = c; 9 | 10 | return dest; 11 | } 12 | 13 | void DataMemoryBarrier(void) 14 | { 15 | asm volatile ("mcr p15, #0, %[zero], c7, c10, #5" : : [zero] "r" (0)); 16 | } 17 | 18 | void DataSyncBarrier(void) 19 | { 20 | asm volatile ("mcr p15, #0, %[zero], c7, c10, #4" : : [zero] "r" (0)); 21 | } 22 | 23 | void FlushCache(void) 24 | { 25 | asm volatile ("mcr p15, #0, %[zero], c7, c14, #0" : : [zero] "r" (0)); 26 | } 27 | 28 | void InvalidateAllUnlockedTLB(void) 29 | { 30 | asm volatile ("mcr p15,0, %[zero],c8, c5, 0" : : [zero] "r" (0)); 31 | } 32 | 33 | void FlushTLB(unsigned int mva) 34 | { 35 | // c5 = Instruction TLB 36 | // c6 = Data TLB 37 | // c7 = Unified TLB 38 | // TODO: Make generic and take in arg which to clear 39 | asm volatile ("MCR P15, 0, r0, c8, c6, 1" : : [mva] "r" (mva)); 40 | } 41 | -------------------------------------------------------------------------------- /include/memory.h: -------------------------------------------------------------------------------- 1 | #include "memory_map.h" 2 | 3 | #define BYTES_PER_SLICE 4 4 | #define MAX_BYTES_PER_SIZE_BYTE ((2^7) - 1) 5 | #define MAX_ALLOCATED_BYTES 104857600 // 100 MB, TODO: Don't hardcode this 6 | #define MAX_ALLOCATED_SLICES (MAX_ALLOCATED_BYTES / BYTES_PER_SLICE) // 26214400 7 | #define EXTENDED_SIZE_BYTE_FLAG (1 << 7) 8 | 9 | //#define DEBUG_MEM 10 | 11 | // Initializes the allocator 12 | void Pallocator_Initialize(void); 13 | 14 | // Allocates 'size' bytes and returns a pointer to the newly allocated memory 15 | void* palloc(unsigned int size); 16 | 17 | // Allocates memory for an array of 'size' with elements of 'itemSize' 18 | // Example: pcalloc(sizeof(int), 4); // Allocates an array of 4 ints 19 | void* pcalloc(unsigned int itemSize, unsigned int size); 20 | 21 | void phree(void* pointer); 22 | 23 | // Resizes a previously allocated chunk of memory and returns a pointer 24 | // to the new chunk. If size is 0, ptr is freed and NULL is returned. 25 | // if ptr is NULL, a new chunk is allocated. 26 | void* realloc(void* ptr, unsigned int size); -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ###The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Simon Gustavsson (https://github.com/SimonGustavsson) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /source/types/queue.c: -------------------------------------------------------------------------------- 1 | #include "types/queue.h" 2 | #include "memory.h" 3 | 4 | void Queue_Enqueue(Queue* queue, void* data) 5 | { 6 | // Create a node 7 | Node* node = (Node*)palloc(sizeof(Node)); 8 | node->data = data; 9 | node->next = 0; 10 | //printf("Allocated node at 0x%08x.\n", node); 11 | 12 | Node* prevBack = queue->back; 13 | if (queue->back != 0) 14 | prevBack->next = node; 15 | queue->back = node; 16 | 17 | // If this was the first element that was added, it's also the front 18 | if (queue->front == 0) 19 | queue->front = node; 20 | 21 | queue->numNodes++; 22 | } 23 | 24 | void* Queue_Dequeue(Queue* queue) 25 | { 26 | // Get a reference to the front node so we don't lose it when modifying front 27 | Node* prevFront = queue->front; 28 | 29 | // Set the next element to be the front of the queue 30 | 31 | queue->front = queue->front->next; 32 | 33 | queue->numNodes--; 34 | 35 | if (queue->numNodes == 0) 36 | { 37 | queue->front = 0; 38 | queue->back = 0; 39 | } 40 | 41 | void* data = prevFront->data; 42 | 43 | phree(prevFront); 44 | 45 | return data; 46 | } 47 | 48 | void* Queue_Peek(Queue* queue) 49 | { 50 | if (queue->front != 0) 51 | return queue->front->data; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /source/hardware/interrupts.c: -------------------------------------------------------------------------------- 1 | #include "memory_map.h" 2 | #include "hardware/interrupts.h" 3 | 4 | static ArmInterrupts* gInterrupts; 5 | 6 | void Arm_InterruptInitialize(void) 7 | { 8 | gInterrupts = (ArmInterrupts*)(PERIPHERAL_VA_IRPT); 9 | } 10 | 11 | void Arm_IrqEnable(interrupt_source source) 12 | { 13 | if (source < 32) 14 | gInterrupts->irq_enable1.raw |= (1 << source); 15 | else 16 | gInterrupts->irq_enable2.raw |= (1 << (source - 32)); 17 | } 18 | 19 | void Arm_IrqDisableall(void) 20 | { 21 | gInterrupts->irq_disable1.raw = 0xFFFFFFFF; 22 | gInterrupts->irq_disable2.raw = 0xFFFFFFFF; 23 | } 24 | 25 | interrupt_source Arm_IrqGetPending(void) 26 | { 27 | if (gInterrupts->irq_pending1.bits.system_timer) 28 | return interrupt_source_system_timer; 29 | else if (gInterrupts->irq_pending2.bits.uart) 30 | return interrupt_source_uart; 31 | 32 | // Unknown 33 | return gInterrupts->irq_pending1.raw; 34 | } 35 | 36 | void Arm_FiqEnable(interrupt_source source) 37 | { 38 | fiq_control_req r = gInterrupts->fiq_control; 39 | 40 | r.bits.enable = 1; 41 | r.bits.source = source; 42 | 43 | gInterrupts->fiq_control.raw = r.raw; 44 | } 45 | 46 | void Arm_FiqDisable(void) 47 | { 48 | gInterrupts->fiq_control.raw = 0; 49 | } 50 | -------------------------------------------------------------------------------- /source/asm/irq.s: -------------------------------------------------------------------------------- 1 | ;@ 2 | ;@ This file contains utility functions for enabling/disabling IRQ/FIQ in the CPU 3 | ;@ 4 | 5 | ;@ 6 | ;@ Updates CPSR to enable IRQ interrupts 7 | ;@ C Signature: void enable_irq(void) 8 | ;@ 9 | .type enable_irq %function 10 | .globl enable_irq ;@ 11 | enable_irq: 12 | mrs r0, cpsr ;@ Retrieve status 13 | bic r0, r0, #0x80 ;@ Clear bit 7 to enable IRQ 14 | msr cpsr_c, r0 ;@ Write update register back to status register 15 | bx lr 16 | 17 | ;@ 18 | ;@ Updates CPSR to disable IRQ interrupts 19 | ;@ C Signature: void disable_irq(void) 20 | ;@ 21 | .type disable_irq %function 22 | .globl disable_irq 23 | disable_irq: 24 | mrs r0, cpsr ;@ Retrieve status 25 | orr r0, r0, #0x80 ;@ Set bit 7 to disable IRQ 26 | msr cpsr_c, r0 ;@ Write new status back to register 27 | bx lr 28 | 29 | ;@ 30 | ;@ Updates CPSR to enable FIQ interrupts 31 | ;@ C Signature: void enable_fiq(void) 32 | ;@ 33 | .type enable_fiq %function 34 | .globl enable_fiq 35 | enable_fiq: 36 | mrs r0, cpsr 37 | bic r0, r0, #0x40 ;@ Clear bit 6 to enable FIQ 38 | msr cpsr_c, r0 39 | bx lr 40 | 41 | ;@ 42 | ;@ Updates CPSR to disable FIQ interrupts 43 | ;@ C Signature: void disable_fiq(void) 44 | ;@ 45 | .type disable_fiq %function 46 | .globl disable_fiq 47 | disable_fiq: 48 | mrs r0, cpsr 49 | orr r0, r0, #0x40 50 | msr cpsr_c, r0 51 | bx lr 52 | -------------------------------------------------------------------------------- /source/hardware/timer.c: -------------------------------------------------------------------------------- 1 | #include "hardware/timer.h" 2 | 3 | volatile timer* gTimer = (timer*)PERIPHERAL_VA_TIMER; 4 | 5 | // The timer has 4 channels, we use the forth channel for period interrupts 6 | const unsigned int TIMER_PERIODIC_CHANNEL = 3; 7 | 8 | unsigned int Timer_Initialize(void) 9 | { 10 | // Setup period irq interval before enabling interrupts 11 | //timer_sp_clearmatch(); 12 | //timer_sp_setinterval(TIMER_INTERRUPT_INTERVAL); 13 | 14 | return 0; 15 | } 16 | 17 | // Set the interval for the system period timer 18 | void Timer_SetInterval(unsigned int milliSeconds) 19 | { 20 | unsigned int currentCounter = gTimer->clo; 21 | 22 | // Convert to micro seconds 23 | currentCounter += (milliSeconds * 1000); 24 | 25 | // Note: SP uses channel 3 26 | gTimer->c3 = currentCounter; 27 | } 28 | 29 | void Timer_Clear(void) 30 | { 31 | // Setting the channels bit in the status registers clears this match 32 | // (Note: SP uses channel 1) 33 | gTimer->cs.bits.m3 = 1; 34 | } 35 | 36 | // Gets the value of the free running timer 37 | long long Timer_GetTicks(void) 38 | { 39 | return (gTimer->chi << 32) | gTimer->clo; 40 | } 41 | 42 | void wait(unsigned int milliSeconds) 43 | { 44 | unsigned int ttw = 1048 * milliSeconds; 45 | unsigned int start = gTimer->clo; 46 | while(1) 47 | { 48 | if(gTimer->clo - start >= ttw) 49 | break; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /include/types/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRINGUTIL_H 2 | #define STRINGUTIL_H 3 | 4 | #include // Needed for varying argument length 5 | 6 | #define MAX_PRINTF_LENGTH 4096 7 | #define INT_MIN (-2147483647 - 1) 8 | #define INT_MAX 2147483647 9 | 10 | // Match c in str and returns the number of matches, -1 if not found 11 | int strchrmatch(char* str, unsigned int str_len, char c); 12 | 13 | unsigned int atoi(char* str); 14 | int my_strlen(char* str); 15 | char* my_strcpy(const char* src, char* dst); 16 | char* my_strcpy_s(const char* src, unsigned int dest_len, char* dst); 17 | unsigned int my_strcmp(char* str1, char* str2); 18 | int my_strcmp_s(char* str1, unsigned int size, char* str2); 19 | unsigned int my_strcasecmp(char* str1, char* str2); 20 | void itoa(int number, char* buf); 21 | void utoa(unsigned int number, char* buf); 22 | void dec_to_hex(char* buf, unsigned int dec, unsigned int lowerCase); 23 | void printf(char* text, ...); 24 | void printf_i(char* text, ...); 25 | void printf_s(char* text, unsigned int length, ...); 26 | void vprintf_s(char* text, unsigned int length, va_list args); 27 | 28 | int my_sscanf(char* s, const char* format, ...); 29 | int my_sscanf_s(char* s, int sLength, const char* format, ...); 30 | int my_vsscanf(char* s, const char* format, va_list ap); 31 | int my_vsscanf_s(char* s, int sLength, const char* format, va_list ap); 32 | 33 | #endif // STRINGUTIL_H 34 | -------------------------------------------------------------------------------- /linker.c: -------------------------------------------------------------------------------- 1 | #include "memory_map.h" 2 | 3 | /* 4 | Note the .c extension of this file, this is so that we can run it through the C preprocessor 5 | Which allows us to specify all memory related constants in one place instead of having to dig 6 | Through multiple files 7 | */ 8 | 9 | ENTRY(reset) 10 | 11 | SECTIONS 12 | { 13 | /* 14 | The startup code as per Rpi requirements gets placed at the start of the binary 15 | So that it can be jumped to. The init section which performs initialization of 16 | Virtual memory is placed directly afterwards 17 | */ 18 | . = LD_KRNL_ORIGIN; 19 | .text.boot LD_KRNL_ORIGIN : { *(.text.boot*) } 20 | .text.init LD_KRNL_ORIGIN + SIZEOF(.text.boot) : { *(.text.init*) } 21 | 22 | /* 23 | Set the VMA of the remaining part of the kernel to 24 | be in high memory as this code runs after the MMU has been turned on 25 | */ 26 | . = KERNEL_VA_START + ADDR(.text.init) + SIZEOF(.text.init); 27 | 28 | .text . : AT(ADDR(.text.init) + SIZEOF(.text.init)) { *(.text*) } 29 | . = ALIGN(LD_PAGE_SIZE); /* align to page size */ 30 | 31 | .bss : { *(.bss*) } 32 | . = ALIGN(LD_PAGE_SIZE); /* align to page size */ 33 | 34 | .data . : { *(.data) } 35 | .rodata . : { *(.rodata) } 36 | 37 | /* 38 | Store the end of the kernel so we can use it to calculate 39 | The full size of the binary image in memory 40 | */ 41 | LNK_KERNEL_END = .; 42 | } -------------------------------------------------------------------------------- /source/syscalls.c: -------------------------------------------------------------------------------- 1 | #include "interruptHandlers.h" 2 | #include "syscalls.h" 3 | #include "types/string.h" 4 | #include "stddef.h" 5 | #include "scheduler.h" 6 | #include "hardware/uart.h" 7 | 8 | void pios_print(const char* str) 9 | { 10 | // Note: res is not actually used at all 11 | unsigned int res; 12 | SWI_PARAM_WITH_RES(SYS_PRINT_SWI, str, res); 13 | } 14 | 15 | thread* pios_thread_create(thread_entry entry) 16 | { 17 | Uart_SendString("pios_create_thread called\n"); 18 | unsigned int res = 0; 19 | SWI_PARAM_WITH_RES(SYS_THREAD_CREATE, entry, res); 20 | 21 | return (thread*)res; 22 | } 23 | 24 | void* sys_printf(int arg1, int arg2, int arg3) 25 | { 26 | char* s = (char*)arg1; 27 | 28 | printf(s); 29 | 30 | return NULL; 31 | } 32 | 33 | void* sys_dummy1(int arg1, int arg2, int arg3) 34 | { 35 | printf("Dummy1 swi called\n"); 36 | 37 | return NULL; 38 | } 39 | 40 | void* sys_dummy2(int arg1, int arg2, int arg3) 41 | { 42 | printf("Dummy1 swi called\n"); 43 | 44 | return NULL; 45 | } 46 | 47 | void* sys_create_thread(int arg1, int arg2, int arg3) 48 | { 49 | printf("sys_create_thread called from SWI\n"); 50 | return thread_create((thread_entry)arg1); 51 | } 52 | 53 | void syscalls_init(void) 54 | { 55 | swi_install(12, &sys_printf); 56 | swi_install(SYS_THREAD_CREATE, &sys_create_thread); 57 | swi_install(95, &sys_dummy1); 58 | swi_install(96, &sys_dummy2); 59 | } 60 | -------------------------------------------------------------------------------- /source/atags.c: -------------------------------------------------------------------------------- 1 | #include "atags.h" 2 | #include "types/string.h" 3 | 4 | void atags_parse(int* addr) 5 | { 6 | atag* tag = (atag*)addr; 7 | 8 | while (tag->hdr.tag != ATAG_NONE) 9 | { 10 | switch (tag->hdr.tag) 11 | { 12 | case ATAG_CORE: 13 | if (tag->hdr.size == 5) // Has data 14 | printf("ATAG_CORE - Flags: %d Page Size: %d Root dev: %d\n", tag->u.core.flags, tag->u.core.pagesize, tag->u.core.rootdev); 15 | else 16 | printf("ATAG_CORE - No data\n"); 17 | break; 18 | case ATAG_MEM: 19 | printf("ATAG_MEM\n"); 20 | break; 21 | case ATAG_VIDEOTEXT: 22 | printf("ATAG_VIDEOTEXT\n"); 23 | break; 24 | case ATAG_RAMDISK: 25 | printf("ATAG_RAMDISK\n"); 26 | break; 27 | case ATAG_INITRD2: 28 | printf("ATAG_INITRD2\n"); 29 | break; 30 | case ATAG_SERIAL: 31 | printf("ATAG_SERIAL\n"); 32 | break; 33 | case ATAG_REVISION: 34 | printf("ATAG_REVISION\n"); 35 | break; 36 | case ATAG_VIDEOLFB: 37 | printf("ATAG_VIDEOLFB\n"); 38 | break; 39 | case ATAG_CMDLINE: 40 | printf("ATAG_CMDLINE\n"); 41 | break; 42 | } 43 | 44 | // Go to next tag 45 | tag = (atag*)( ((unsigned int)tag) + tag->hdr.size); 46 | } 47 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PiOS 2 | ==== 3 | 4 | My experimental bare metal OS for the raspberry pi. 5 | This file is used to track its current state and what I'm currently working on. 6 | 7 | #### What it does right now: 8 | * GPIO - Example: Flash LED 9 | * Framebuffer - Drawing pixels 10 | * Terminal - Character based display 11 | * System Timer 12 | * Interrupts 13 | * MMU 14 | * eMMC reading/writing 15 | * Fat32 - Small subset (read-only) 16 | * Loading and executing binaries (ELFs) 17 | * UART and MiniUart send/receive (interrupt based receive) 18 | * Virtual memory (high memory kernel, Low memory user) 19 | * Stacktraces on faults 20 | 21 | #### What I'm planning to do / working on: 22 | * Multitasking 23 | * Fat32 - Writing 24 | * Audio 25 | * Support for addition file systems: SFS, EXT2(?) 26 | 27 | #### Build requirements: 28 | * [GNU Tools for ARM](https://launchpad.net/gcc-arm-embedded) 29 | * [Cygwin](http://www.cygwin.com/) (Windows only) 30 | 31 | #### Building: 32 | Just clone the repository and run make in the root directory 33 | 34 | #### Branches: 35 | ##### master 36 | Latest and greatest, not guaranteed to be stable. 37 | 38 | ##### 0.01 39 | - Simple terminal 40 | - Framebuffer 41 | - Keyboard input (using Chadderz usb driver) 42 | 43 | ##### 0.10 44 | Essentially started over, removed USB driver (I intend to write my own). 45 | - UART 46 | - Terminal output 47 | - Interrupt handling 48 | - Emmc driver 49 | - Mailbox 50 | - MMU 51 | - Timer 52 | - Reading elf 53 | - Stack trace with function names 54 | - Very crude multitasking (Multiple processes, each with one main thread) -------------------------------------------------------------------------------- /include/hardware/framebuffer.h: -------------------------------------------------------------------------------- 1 | #define FB_DEBUG 2 | #define CHAR_HEIGHT 10 3 | #define CHAR_WIDTH 6 4 | #define FB_BPP 16 5 | #define PREFERRED_WIDTH 640 6 | #define PREFERRED_HEIGHT 480 7 | 8 | #include "types/types.h" 9 | 10 | // The raspberry pi framebuffer, this maps directly onto the mailbox buffer 11 | // to send to retrieve the framebuffer 12 | typedef struct { 13 | unsigned int width; // Requested screen width 14 | unsigned int height; // Requested screen height 15 | unsigned int v_width; // Requested virtual screen width 16 | unsigned int v_height; // Requested virtual screen height 17 | unsigned int pitch; // Initialize to 0, VC fills out with value 18 | unsigned int depth; // BPP - Initialize to 0, VC fills out with value 19 | unsigned int offset_x; // X offset of virtual framebuffer 20 | unsigned int offset_y; // Y offset of virtual framebuffer 21 | unsigned int address; // Initialize to 0, VC fills out with value 22 | unsigned int size; // Initialize to 0, VC fills out with value 23 | } rpi_fb; 24 | 25 | int Fb_Initialize(); 26 | void Fb_DrawPixel(unsigned int x, unsigned int y, unsigned short int color); 27 | void Fb_DrawCharacterAt(unsigned int c, unsigned int x, unsigned int y); 28 | void Fb_DrawColoredCharacterAt(unsigned int ch, unsigned int x, unsigned int y, unsigned short color); 29 | unsigned int Fb_GetPhyAddr(void); 30 | 31 | // Gets the screen size in pixels 32 | size Fb_GetScreenSize(void); 33 | 34 | // Gets the size of the framebuffer in memory (in bytes) 35 | unsigned int Fb_GetSize(void); 36 | 37 | void Fb_Clear(void); 38 | -------------------------------------------------------------------------------- /include/hardware/uart.h: -------------------------------------------------------------------------------- 1 | /* uart.h - UART initialization & communication */ 2 | 3 | #ifndef UART_H 4 | #define UART_H 5 | 6 | typedef volatile struct{ 7 | unsigned int dr; // 0x00 Data Register 8 | unsigned int rsrecr; // 0x04 ? 9 | unsigned int reserved[4]; // - 10 | unsigned int fr; // 0x18 Flag Register 11 | unsigned int reserved2; // - 12 | unsigned int ilpr; // 0x20 Not used 13 | unsigned int ibrd; // 0x24 Integer baud rate divisor 14 | unsigned int fbrd; // 0x28 Fractional baud rate divisor 15 | unsigned int lcrh; // 0x2C Line control register 16 | unsigned int cr; // 0x30 Control Register 17 | unsigned int ifls; // 0x34 Interrupt FIFO Level Select Register 18 | unsigned int imsc; // 0x38 Interrupt mask set clear register 19 | unsigned int ris; // 0x3C Raw interrupt status register 20 | unsigned int mis; // 0x40 Masked interrupt status register 21 | unsigned int icr; // 0x44 Interrupt clear Register 22 | unsigned int dmacr; // 0x48 DMA control register 23 | unsigned int reserved3[13];// - 24 | unsigned int itcr; // 0x80 Test control register 25 | unsigned int itip; // 0x84 Integration test input reg 26 | unsigned int itop; // 0x88 Integration test output reg 27 | unsigned int tdr; // 0x8C Test data reg 28 | } Uart; 29 | 30 | void Uart_Initialize(); 31 | void Uart_EnableInterrupts(void); 32 | void Uart_Send(unsigned char byte); 33 | unsigned char Uart_Read(); 34 | void Uart_SendString(const char *str); 35 | 36 | #endif // #ifndef UART_H -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1998, 1999, 2000, 2009 Free Software Foundation, Inc. 2 | 3 | This file is part of GCC. 4 | 5 | GCC is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3, or (at your option) 8 | any later version. 9 | 10 | GCC is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | Under Section 7 of GPL version 3, you are granted additional 16 | permissions described in the GCC Runtime Library Exception, version 17 | 3.1, as published by the Free Software Foundation. 18 | 19 | You should have received a copy of the GNU General Public License and 20 | a copy of the GCC Runtime Library Exception along with this program; 21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 | . */ 23 | 24 | /* 25 | * ISO C Standard: 7.16 Boolean type and values 26 | */ 27 | 28 | #ifndef _STDBOOL_H 29 | #define _STDBOOL_H 30 | 31 | #ifndef __cplusplus 32 | 33 | #define bool _Bool 34 | #define true 1 35 | #define false 0 36 | 37 | #else /* __cplusplus */ 38 | 39 | /* Supporting in C++ is a GCC extension. */ 40 | #define _Bool bool 41 | #define bool bool 42 | #define false false 43 | #define true true 44 | 45 | #endif /* __cplusplus */ 46 | 47 | /* Signal that all the definitions are present. */ 48 | #define __bool_true_false_are_defined 1 49 | 50 | #endif /* stdbool.h */ 51 | -------------------------------------------------------------------------------- /include/hardware/timer.h: -------------------------------------------------------------------------------- 1 | #include "memory_map.h" 2 | 3 | #ifndef TIMER_H 4 | #define TIMER_H 5 | 6 | #define SYSTIMER_COUNTER (PERIPHERAL_TIMER + 0x4) // 0x20003004 7 | #define TIMER_INTERRUPT_INTERVAL 0x00200000 8 | 9 | typedef struct { 10 | volatile union{ 11 | unsigned int raw; 12 | struct { 13 | unsigned int m0 : 1; 14 | unsigned int m1 : 1; // 0 = No timer x match since last clear 15 | unsigned int m2 : 1; // 1 = Timer x match detected 16 | unsigned int m3 : 1; 17 | unsigned int reserved : 28; 18 | } bits; 19 | } cs; 20 | volatile unsigned int clo; // Free running counter Lower 32 bits (Read-only) 21 | volatile unsigned int chi; // Free running counter higher 32 bits (Read-only) 22 | volatile unsigned int c0; // Compare 0 23 | volatile unsigned int c1; // Compare 1 | These 4 registers holds the compare value for each channel. 24 | volatile unsigned int c2; // Compare 2 | When a match is found, the corresponding bit is set in cs 25 | volatile unsigned int c3; // Compare 3 / 26 | } timer; 27 | 28 | // 29 | // The timer on the Pi has four channels 30 | // Sources vary on which channels are in use, but 31 | // Channel 1 is definitely free and the one PiOS uses 32 | // 33 | 34 | // 35 | // The timer ticks at 1MHz 36 | // 1 MHz = 1 000 000 hz (cycles/second) 37 | // Which means the free running timer increments every 38 | // microsecond and there are 1 000 000 microseconds per second 39 | // 40 | 41 | unsigned int Timer_Initialize(void); 42 | void Timer_SetInterval(unsigned int milliSeconds); 43 | void Timer_Clear(void); 44 | void wait(unsigned int milliSeconds); 45 | 46 | // Gets the value of the free running timer 47 | long long Timer_GetTicks(void); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /source/asm/start.S: -------------------------------------------------------------------------------- 1 | #include "memory_map.h" 2 | 3 | .type reset %function 4 | .section .text.boot 5 | .globl reset 6 | reset: 7 | ;@ Args from bootloader 8 | mov r4, r0 ;@ Machine type (Rpi bootloader) 9 | mov r5, r1 ;@ Atags PA (Rpi bootloader) 10 | mov r6, r2 ;@ Debugging symbols (PiOS Loader) 11 | 12 | mov r0,#0x8000 13 | mov r1,#0x0000 14 | 15 | ;@ Setup the stacks for the different interrupt modes (make sure interrupts are disabled first) 16 | ;@ IRQ 17 | mov r0,#0xD2 ;@ PSR_IRQ_MODE (0x12) | PSR_FIQ_DIS(0x40) | PSR_IRQ_DIS (0x80) 18 | msr cpsr_c,r0 19 | ldr sp, =IRQ_STACK_PA_START 20 | 21 | ;@ FIQ 22 | mov r0,#0xD1 ;@ PSR_FIQ_MODE (0x11) |PSR_FIQ_DIS (0x40) | PSR_IRQ_DIS (0x80) 23 | msr cpsr_c,r0 24 | ldr sp, =FIQ_STACK_PA_START 25 | 26 | ;@ ABORT PSR_ABORT_MODE (0x17) | PSR_FIQ_DIS (0x40) | PSR_IRQ_DIS (0x80) 27 | mov r0, #0xD7 28 | msr cpsr_c,r0 29 | ldr sp, =ABORT_STACK_PA_START 30 | 31 | ;@ SYSTEM PSR_SYSTEM_MODE (0x1F) | PSR_FIQ_DIS(0x40) | PSR_IRQ_DIS (0x80) 32 | mov r0, #0xDF ;@ 001 1111 33 | msr cpsr_c, r0 34 | ldr sp, =SM_STACK_PA_START 35 | 36 | ;@ UNDEFINED PSR_UNDEFINED_MODE (0x1B) | PSR_FIQ_DIS (0x40) | PSR_IRQ_DIS (0x80) 37 | mov r0, #0xDB 38 | msr cpsr_c, r0 39 | ldr sp, =UD_STACK_PA_START 40 | 41 | ;@ SVC 42 | mov r0,#0xD3 ;@ PSR_SVC_MODE (0x13) PSR_FIQ_DIS (0x40) | PSR_IRQ_DIS (0x80) 43 | msr cpsr_c,r0 44 | ldr sp, =SVC_STACK_PA_START 45 | 46 | ;@ Pass in the args 47 | mov r0, r4 48 | mov r1, r5 49 | mov r2, r6 50 | 51 | ;@ Kick of system initialization (init.c) 52 | ldr r3, =sysinit_stage1 53 | blx r3 54 | 55 | ;@ cmain should never return, just hang around (heh.. get it?) 56 | 57 | .type hang %function 58 | .section .text.boot 59 | .globl hang 60 | hang: 61 | b hang 62 | -------------------------------------------------------------------------------- /source/hardware/device/sdBlockDevice.c: -------------------------------------------------------------------------------- 1 | #include "hardware/device/blockDevice.h" 2 | #include "hardware/emmc.h" 3 | #include "memory.h" 4 | #include "hardware/device/sdBlockDevice.h" 5 | #include "util/utilities.h" 6 | #include "types/string.h" 7 | 8 | Emmc* _emmc; 9 | 10 | unsigned int Sd_Register(BlockDevice* device) 11 | { 12 | my_memcpy(device->name, "SDBLKDEV\0", 9); 13 | device->name_length = 10; 14 | device->init = Sd_Initialize; 15 | device->cleanup = Sd_Cleanup; 16 | device->operation = Sd_DeviceOperation; 17 | device->buffer = (unsigned char*)palloc(BLOCK_SIZE); 18 | device->type = BlockDevRemovable; 19 | 20 | return 0; 21 | } 22 | 23 | int Sd_Initialize(void) 24 | { 25 | int result = Emmc_Initialise(); 26 | 27 | if (result != 0) { 28 | printf("sd - Failed to initialize emmc\n"); 29 | } 30 | 31 | // Just do a dummy read on the first sector 32 | // To check that we can read 33 | 34 | char* buffer = (char*)palloc(BLOCK_SIZE); 35 | if ((int)Emmc_ReadBlock(buffer, BLOCK_SIZE, 0) != BLOCK_SIZE) 36 | printf("dummy read in SD Initialize failed :("); 37 | 38 | phree(buffer); 39 | 40 | return result; 41 | } 42 | 43 | unsigned int Sd_DeviceOperation(BlockDevOp opCode, void* arg, void *arg2) 44 | { 45 | switch (opCode) 46 | { 47 | case OpRead: 48 | if (Emmc_ReadBlock((char*)arg2, BLOCK_SIZE, *(unsigned int*)arg) == -1) 49 | return -1; 50 | else 51 | return 0; 52 | case OpWrite: 53 | printf("Sd write is not yet implemented.\n"); 54 | return 2; 55 | case OpGetStatus: 56 | return 0; 57 | default: 58 | return 4; 59 | break; 60 | } 61 | } 62 | 63 | void Sd_Cleanup(void) 64 | { 65 | // Not implemented for Sd - What would we do? 66 | } -------------------------------------------------------------------------------- /source/hardware/uart.c: -------------------------------------------------------------------------------- 1 | /* uart.c - UART initialization & communication */ 2 | /* Reference material: 3 | * http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf 4 | * Chapter 13: UART 5 | */ 6 | 7 | #include "memory_map.h" 8 | #include "hardware/uart.h" 9 | #include "hardware/gpio.h" 10 | 11 | Uart* gUart; 12 | 13 | void Uart_Initialize() { 14 | 15 | gUart = (Uart*)(PERIPHERAL_VA_UART); 16 | 17 | // Disable UART0. 18 | gUart->cr = 0x00000000; 19 | 20 | // Setup GPIO for uart use 21 | Gpio_EnableUart(); 22 | 23 | // Clear pending interrupts. 24 | gUart->icr = 0x7FF; 25 | 26 | // Set integer & fractional part of baud rate. 27 | // At 8MHz uart clock, this is 460800 baud 28 | // See: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0183g/I49493.html 29 | // For calculations 30 | gUart->ibrd = 1; 31 | gUart->fbrd = 5; 32 | 33 | // 8 bit data transmission (1 stop bit, no parity). (Note: Not enabling fifo) 34 | gUart->lcrh = (1 << 5) | (1 << 6); 35 | 36 | // Mask all interrupts. 37 | gUart->imsc = (1 << 1) | (1 << 4) | (1 << 5) | 38 | (1 << 6) | (1 << 7) | (1 << 8) | 39 | (1 << 9) | (1 << 10); 40 | 41 | // Enable UART0, receive & transfer part of UART. 42 | gUart->cr = (1 << 0) | (1 << 8) | (1 << 9); 43 | } 44 | 45 | void Uart_EnableInterrupts(void) 46 | { 47 | gUart->imsc = 0x0010; 48 | } 49 | 50 | void Uart_Send(unsigned char byte) 51 | { 52 | // wait for UART to become ready to transmit 53 | while (1) 54 | { 55 | if (!(gUart->fr & (1 << 5))) 56 | break; 57 | } 58 | 59 | gUart->dr = byte; 60 | } 61 | 62 | unsigned char Uart_Read() 63 | { 64 | // wait for UART to have recieved something 65 | while (1) 66 | { 67 | if (!(gUart->fr & (1 << 4))) 68 | break; 69 | } 70 | 71 | return gUart->dr; 72 | } 73 | 74 | void Uart_SendString(const char *str) 75 | { 76 | while (*str) 77 | { 78 | Uart_Send(*str++); 79 | } 80 | 81 | Uart_Send(0); 82 | } 83 | -------------------------------------------------------------------------------- /include/process.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESS_H 2 | #define PROCESS_H 3 | 4 | #include "hardware/mmu_c.h" 5 | #include "hardware/paging.h" 6 | #include "stdint.h" 7 | #include "stdbool.h" 8 | 9 | typedef struct thread; 10 | 11 | #define PROCESS_START_PAGE_COUNT 8 12 | 13 | // int main() of processes 14 | typedef int(*process_entry_func)(void); 15 | 16 | typedef enum { 17 | TS_Running, // Currently executing 18 | TS_Waiting, // Waiting for resource/IO etc 19 | TS_Ready // Ready to be executed 20 | } processState; 21 | 22 | typedef enum { 23 | processPriorityLow, 24 | processPriorityMedium, 25 | processPriorityHigh, 26 | processPriorityVeryHigh 27 | } processPriority; 28 | 29 | typedef struct Process { 30 | unsigned int id; 31 | unsigned int active; // Whether this task is currently executing 32 | processState state; // Current state of task 33 | char* name; // Print friendly name 34 | char* path; // Path to the executable (if any) 35 | unsigned int* ttb0; // Address to page table for this task 36 | unsigned int* mem_pages; // Array of all allocated pages for the user memory 37 | unsigned int num_mem_pages; // Numer of elements in mem_pages 38 | unsigned int* ttb0_physical; // Physical address to the ttb0 39 | unsigned int num_ttb0_pages;// Number of pages the ttb0 spans 40 | ttbc_ttbr0_size ttb0_size; // The size of the ttb0 to set TTBC split to 41 | uint32_t nThreads; // The number of threads 42 | struct thread** threads; // An array of all threads in the process 43 | struct thread* mainThread; // Gets the main thread of the application 44 | } Process; 45 | 46 | Process* Process_Create(unsigned int entryFuncAddr, char* name, bool start); 47 | Process* Process_CreateFromFile(char* filename, char* name, bool start); 48 | 49 | // Frees all memory associated with the given task 50 | void Process_Delete(Process* p); 51 | 52 | #endif -------------------------------------------------------------------------------- /source/asm/utility.s: -------------------------------------------------------------------------------- 1 | ;@ 2 | ;@ Various ASM snippets that enables you to do some things C doesn't 3 | ;@ 4 | 5 | ;@ This function isn't actually used, it's only used to 6 | ;@ Show how prologue/epilogue works 7 | .globl fp_showoff 8 | fp_showoff: 9 | 10 | ;@ Save FP and LR from previous function 11 | push {fp, lr} 12 | 13 | ;@ Save the location of the values we just pushed 14 | add fp, sp, #4 15 | 16 | ;@ Because we only store 2 values in this frame, increase the stack 17 | ;@ By two more words to make sure we have a clean, readable stack frame 18 | sub sp, sp, #8 19 | 20 | ;@ 21 | ;@ SP is now usuable, function body here... 22 | ;@ 23 | 24 | ;@ Restore the stack to the location where we stored FP and LR in the proloque 25 | sub sp, fp, #4 26 | 27 | ;@ Pop the old frame pointer off the stack, and return to the caller 28 | ;@ By restoring LR into PC 29 | pop {fp, pc} 30 | 31 | ;@ 32 | ;@ Gets the Frame Pointer (FP) register 33 | ;@ C Signature: int* get_frame_pointer(void) 34 | ;@ 35 | .type get_fp %function 36 | .align 2 37 | .globl get_fp 38 | get_fp: 39 | mov r0, fp 40 | mov pc, lr 41 | 42 | ;@ 43 | ;@ Gets the current address of the Stack Pointer 44 | ;@ C Signature: unsigned int get_sp(void) 45 | ;@ 46 | .type get_sp %function 47 | .globl get_sp 48 | get_sp: 49 | mov r0, sp 50 | 51 | bx lr 52 | 53 | ;@ 54 | ;@ Branch to the give function (WARNING: this trashes FP and does not set up LR!) 55 | ;@ C Signature: void branch(unsigned int* addr) 56 | ;@ addr: The address to branch to 57 | ;@ 58 | .type branch %function 59 | .globl branch 60 | branch: 61 | bx r0 62 | 63 | ;@ 64 | ;@ Call the function at the given memory address 65 | ;@ C Signature: void call(unsigned int* addr) 66 | ;@ addr: The address to branch to 67 | ;@ 68 | .type call %function 69 | .globl call 70 | call: 71 | push {fp, lr} 72 | add fp, sp, #4 73 | 74 | blx r0 75 | pop {fp, lr} 76 | 77 | bx lr 78 | -------------------------------------------------------------------------------- /include/hardware/mmu_c.h: -------------------------------------------------------------------------------- 1 | #define PAGE_TABLE_SIZE 4096 // 4 GB, map all of the addressesies 2 | #ifndef UTILITIES_H 3 | #define UTILITIES_H 4 | 5 | #define MMU_DEBUG 6 | 7 | typedef struct { 8 | unsigned int sectionTypeIdentifier : 2; // Must be 2 (b10) 9 | unsigned int bufferable : 1; 10 | unsigned int cacheable : 1; 11 | unsigned int executeNever : 1; 12 | unsigned int domain : 4; 13 | unsigned int present : 1; 14 | unsigned int accessPermission : 2; 15 | unsigned int typeExtension : 3; 16 | unsigned int apx : 1; 17 | unsigned int shared : 1; 18 | unsigned int notGlobal : 1; 19 | unsigned int mustBeZero : 1; 20 | unsigned int notSecure : 1; 21 | unsigned int baseAddress : 12; 22 | } SectionPageTable; 23 | 24 | typedef union { 25 | struct { 26 | unsigned int sectionTypeIdentifier : 2; // Must be 2 (b10) 27 | unsigned int bufferable : 1; 28 | unsigned int cacheable : 1; 29 | unsigned int executeNever : 1; 30 | unsigned int domain : 4; 31 | unsigned int present : 1; 32 | unsigned int accessPermission : 2; 33 | unsigned int typeExtension : 3; 34 | unsigned int apx : 1; 35 | unsigned int shared : 1; 36 | unsigned int notGlobal : 1; 37 | unsigned int mustBeZero : 1; 38 | unsigned int notSecure : 1; 39 | unsigned int baseAddress : 12; 40 | } bits; 41 | unsigned int raw; 42 | } SectionPageTable2; 43 | 44 | typedef enum { 45 | APNone = 0, 46 | APNoneSvcRw = 1, 47 | APReadOnly = 2, 48 | APReadWrite = 3 49 | } AccessPermission; 50 | 51 | // We only store the top 12 bits as that's 52 | // What the page table needs 53 | typedef struct { 54 | short int virtAddr; 55 | short int phyAddr; 56 | unsigned int active; 57 | } MemoryMapping; 58 | 59 | typedef struct { 60 | MemoryMapping* mappings; 61 | unsigned int* startAddr; 62 | } Pfa; 63 | 64 | void Mmu_Initialize(unsigned int*); 65 | void Mmu_MapSection(unsigned int physicalAddressStart, unsigned int virtualAddressStart, 66 | unsigned int numSections, unsigned int ap, unsigned int cacheable, unsigned int bufferable); 67 | void Mmu_UnmapSection(unsigned int virtualAddr); 68 | 69 | //void mmu_AllocateUserPage(unsigned int physicalAddr, unsigned int virtualAddr); 70 | //void mmu_DeallocateUserPage(unsigned int virtualAddr); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | 4 | #include "stdbool.h" 5 | #include "stdint.h" 6 | #include "process.h" 7 | 8 | #define THREAD_DEFAULT_STACK_SIZE (4096 * 2) 9 | #define THREAD_STACK_VA_START 0x40000 10 | #define THREAD_MAX_PAGES 10 11 | 12 | typedef int(*thread_entry)(char*); 13 | 14 | typedef struct { 15 | uint32_t sprs; 16 | uint32_t sp; 17 | uint32_t lr; 18 | 19 | uint32_t r0; 20 | uint32_t r1; 21 | uint32_t r2; 22 | uint32_t r3; 23 | uint32_t r4; 24 | uint32_t r5; 25 | uint32_t r6; 26 | uint32_t r7; 27 | uint32_t r8; 28 | uint32_t r9; 29 | uint32_t r10; 30 | uint32_t r11; 31 | uint32_t r12; 32 | uint32_t lr2; 33 | } thread_regs; 34 | 35 | typedef enum { 36 | THREAD_PRIO_LOW, 37 | THREAD_PRIO_MED, 38 | THREAD_PRIO_HIGH 39 | } thread_priority; 40 | 41 | typedef enum { 42 | // Thread is currently executing 43 | THREAD_STATE_RUNNING, 44 | 45 | // Thread is in a wait state (Waiting for IO etc..) 46 | THREAD_STATE_WAITING, 47 | 48 | // Thread is ready to run 49 | THREAD_STATE_READY 50 | } thread_state; 51 | 52 | typedef struct thread { 53 | bool isRunning; // Whether the thread is currently running 54 | unsigned int timeElapsed; // How long this task has been running since it was switched in 55 | thread_priority priority; // Current priority 56 | thread_state state; // Current state of the thread 57 | Process* owner; // The process that owns this thread 58 | char* name; // (Optional?) Name of the thread 59 | thread_regs registers; // Saved register state 60 | int32_t result; // Return value of the threads main function 61 | thread_entry entry; // The entry point of the thread 62 | uint32_t* virtStack; // Virtual stack address (Growing downwards 63 | uint32_t* stackPages; // Physical address of pages in the stack 64 | uint32_t nStackPages; // Stack size (in pages) 65 | } thread; 66 | 67 | thread* thread_create(thread_entry entry); 68 | thread* thread_createWithOwner(thread_entry entry, Process* owner); 69 | 70 | void thread_kill(thread*); 71 | 72 | #endif -------------------------------------------------------------------------------- /include/hardware/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef PIOS_KEYBOARD_C 2 | #define PIOS_KEYBOARD_C 3 | #include "types/types.h" 4 | 5 | typedef enum 6 | { 7 | VK_A, 8 | VK_B, 9 | VK_C, 10 | VK_D, 11 | VK_E, 12 | VK_F, 13 | VK_G, 14 | VK_H, 15 | VK_I, 16 | VK_J, 17 | VK_K, // 10 18 | VK_L, 19 | VK_M, 20 | VK_N, 21 | VK_O, 22 | VK_P, 23 | VK_Q, 24 | VK_R, 25 | VK_S, 26 | VK_T, 27 | VK_U, // 20 28 | VK_V, 29 | VK_W, 30 | VK_X, 31 | VK_Y, 32 | VK_Z, 33 | VK_0, 34 | VK_1, 35 | VK_2, 36 | VK_3, 37 | VK_4, // 30 38 | VK_5, 39 | VK_6, 40 | VK_7, 41 | VK_8, 42 | VK_9, 43 | VK_ENTER, 44 | VK_ESC, 45 | VK_BSP, 46 | VK_TAB, 47 | VK_SPACE, // 40 48 | VK_MINUS, 49 | VK_EQUALS, 50 | VK_SBLEFT, 51 | VK_SBRIGHT, 52 | VK_BACKSLASH, 53 | VK_HASH, 54 | VK_SEMICOLON, 55 | VL_APOSTROPHE, 56 | VK_GRAVE, 57 | VK_COMMA, // 50 58 | VK_FULLSTOP, 59 | VK_FORWARDSLASH, 60 | VK_CAPS, 61 | VK_F1, 62 | VK_F2, 63 | VK_F3, 64 | VK_F4, 65 | VK_F5, 66 | VK_F6, 67 | VK_F7, // 60 68 | VK_F8, 69 | VK_F9, 70 | VK_F10, 71 | VK_F11, 72 | VK_F12, 73 | VK_PRTSCN, 74 | VK_SCL, 75 | VK_BREAK, 76 | VK_INSERT, 77 | VK_HOME, // 70 78 | VK_PGUP, // 71 79 | VK_DELETE, // 72 80 | VK_END, //73 81 | VK_PG_DN, // 74 82 | VK_RIGHT, // 75 83 | VK_LEFT, // 76 84 | VK_DOWN, // 77 85 | VK_UP, // 78 86 | VK_NUMLOCK, // 79 87 | VK_NUM_DIV, // 80 88 | VK_NUM_MUL, 89 | VK_NUM_SUB, 90 | VK_NUM_ADD, 91 | VK_NUM_ENTER, // 83 92 | VK_NUM1, 93 | VK_NUM2, // 85 94 | VK_NUM3, 95 | VK_NUM4, // 87 96 | VK_NUM5, 97 | VK_NUM6, // 90 98 | VK_NUM7, 99 | VK_NUM8, 100 | VK_NUM9, 101 | VK_NUM0, 102 | VK_NUM_DEL, 103 | VK_BACKSLASH2, 104 | VK_RMENU, 105 | VK_INVALID 106 | } virtualkey; 107 | 108 | unsigned int KeyboardInitialise(void); 109 | void KeyboardUpdate(void); 110 | unsigned short KeyboardGetChar(void); 111 | bool EnsureKeyboard(void); 112 | virtualkey ScanToVirtual(unsigned int scanCode); 113 | unsigned char VirtualToAsci(virtualkey vk, bool shiftDown); 114 | char* GetKeyName(char* buf, unsigned int bufLen, virtualkey vk); 115 | bool KeyboardShiftDown(void); 116 | bool KeyboardCtrlDown(void); 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /user/dummy1/makefile: -------------------------------------------------------------------------------- 1 | ####################################################### 2 | # PiOS Application Makefile template # 3 | # Update these variables on a per application basis # 4 | ####################################################### 5 | APP_NAME=dummy1 6 | ####################################################### 7 | # End per application variables # 8 | ####################################################### 9 | TOOL = arm-none-eabi 10 | 11 | # Directories 12 | C_INCLUDE_PATH=include 13 | export C_INCLUDE_PATH 14 | 15 | LIBRARIES = 16 | BUILD_DIR = bin 17 | SOURCE_DIR = source 18 | OBJ_DIR = $(BUILD_DIR)/obj 19 | 20 | # Flags 21 | # Note that this creates a relocatable ELF (Required for PiOS) 22 | CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding --no-common -Wpadded -march=armv6j -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -fno-omit-frame-pointer -fpic 23 | LINKER_FLAGS = --no-wchar-size-warning --no-undefined --Map $(BUILD_DIR)/$(APP_NAME).map -T memorymap -pie --nmagic 24 | 25 | CHEADERS := $(wildcard include/*.h) 26 | CSOURCE := $(wildcard $(SOURCE_DIR)/*.c) 27 | _COBJECT := $(patsubst %.c,%.o, $(CSOURCE)) 28 | COBJECT = $(addprefix $(OBJ_DIR)/, $(notdir $(_COBJECT))) 29 | 30 | .PHONY: directories 31 | 32 | App: directories $(BUILD_DIR)/$(APP_NAME).img 33 | 34 | # Create the final binary 35 | $(BUILD_DIR)/$(APP_NAME).img: $(BUILD_DIR)/$(APP_NAME).elf $(BUILD_DIR)/symbols.txt $(BUILD_DIR)/disassembly.txt 36 | @$(TOOL)-objcopy $(BUILD_DIR)/$(APP_NAME).elf -O binary $(BUILD_DIR)/$(APP_NAME).img 37 | 38 | # Create disassembly for ease of debugging 39 | $(BUILD_DIR)/disassembly.txt: $(BUILD_DIR)/$(APP_NAME).elf 40 | @$(TOOL)-objdump -D $< > $@ 41 | 42 | # Dump symbol table for functions 43 | $(BUILD_DIR)/symbols.txt: $(BUILD_DIR)/$(APP_NAME).elf 44 | @$(TOOL)-objdump -t $< | awk -F ' ' '{if(NF >= 2) print $$(1), "\t", $$(NF);}' > $@ 45 | 46 | # Link all of the objects 47 | $(BUILD_DIR)/$(APP_NAME).elf: $(COBJECT) 48 | @$(TOOL)-ld $(LINKER_FLAGS) $(COBJECT) -o $(BUILD_DIR)/$(APP_NAME).elf 49 | 50 | # Build C files 51 | $(OBJ_DIR)/%.o: $(SOURCE_DIR)/%.c $(CHEADERS) 52 | $(TOOL)-gcc -c $< -o $@ $(CFLAGS) 53 | 54 | # Create directories 55 | directories: 56 | @mkdir -p $(OBJ_DIR) 57 | 58 | .PHONY: clean 59 | clean: 60 | @rm -rf $(BUILD_DIR)/* -------------------------------------------------------------------------------- /user/dummy2/makefile: -------------------------------------------------------------------------------- 1 | ####################################################### 2 | # PiOS Application Makefile template # 3 | # Update these variables on a per application basis # 4 | ####################################################### 5 | APP_NAME=dummy2 6 | ####################################################### 7 | # End per application variables # 8 | ####################################################### 9 | TOOL = arm-none-eabi 10 | 11 | # Directories 12 | C_INCLUDE_PATH=include 13 | export C_INCLUDE_PATH 14 | 15 | LIBRARIES = 16 | BUILD_DIR = bin 17 | SOURCE_DIR = source 18 | OBJ_DIR = $(BUILD_DIR)/obj 19 | 20 | # Flags 21 | # Note that this creates a relocatable ELF (Required for PiOS) 22 | CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding --no-common -Wpadded -march=armv6j -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -fno-omit-frame-pointer -fpic 23 | LINKER_FLAGS = --no-wchar-size-warning --no-undefined --Map $(BUILD_DIR)/$(APP_NAME).map -T memorymap -pie --nmagic 24 | 25 | CHEADERS := $(wildcard include/*.h) 26 | CSOURCE := $(wildcard $(SOURCE_DIR)/*.c) 27 | _COBJECT := $(patsubst %.c,%.o, $(CSOURCE)) 28 | COBJECT = $(addprefix $(OBJ_DIR)/, $(notdir $(_COBJECT))) 29 | 30 | .PHONY: directories 31 | 32 | App: directories $(BUILD_DIR)/$(APP_NAME).img 33 | 34 | # Create the final binary 35 | $(BUILD_DIR)/$(APP_NAME).img: $(BUILD_DIR)/$(APP_NAME).elf $(BUILD_DIR)/symbols.txt $(BUILD_DIR)/disassembly.txt 36 | @$(TOOL)-objcopy $(BUILD_DIR)/$(APP_NAME).elf -O binary $(BUILD_DIR)/$(APP_NAME).img 37 | 38 | # Create disassembly for ease of debugging 39 | $(BUILD_DIR)/disassembly.txt: $(BUILD_DIR)/$(APP_NAME).elf 40 | @$(TOOL)-objdump -D $< > $@ 41 | 42 | # Dump symbol table for functions 43 | $(BUILD_DIR)/symbols.txt: $(BUILD_DIR)/$(APP_NAME).elf 44 | @$(TOOL)-objdump -t $< | awk -F ' ' '{if(NF >= 2) print $$(1), "\t", $$(NF);}' > $@ 45 | 46 | # Link all of the objects 47 | $(BUILD_DIR)/$(APP_NAME).elf: $(COBJECT) 48 | @$(TOOL)-ld $(LINKER_FLAGS) $(COBJECT) -o $(BUILD_DIR)/$(APP_NAME).elf 49 | 50 | # Build C files 51 | $(OBJ_DIR)/%.o: $(SOURCE_DIR)/%.c $(CHEADERS) 52 | $(TOOL)-gcc -c $< -o $@ $(CFLAGS) 53 | 54 | # Create directories 55 | directories: 56 | @mkdir -p $(OBJ_DIR) 57 | 58 | .PHONY: clean 59 | clean: 60 | @rm -rf $(BUILD_DIR)/* -------------------------------------------------------------------------------- /source/hardware/miniUart.c: -------------------------------------------------------------------------------- 1 | #include "hardware/miniUart.h" 2 | #include "hardware/gpio.h" 3 | #include "memory_map.h" 4 | 5 | static gpio_reg *gGpio; 6 | static MiniUart *gUart; 7 | 8 | unsigned int MiniUart_Initialize(void) 9 | { 10 | gGpio = (gpio_reg*)PERIPHERAL_VA_GPIO; 11 | gUart = (MiniUart*)PERIPHERAL_VA_MINIUART; 12 | 13 | // Setup the uart 14 | gUart->enables.raw = 1; // Can't set individual bits 15 | gUart->mu_ier.raw = 0; 16 | gUart->mu_cntl.raw = 0; 17 | gUart->mu_lcr.bits.data_size = 3; // 8-bit.. !? Set second bit to 1 as well? REserved? huh? 18 | gUart->mu_mcr.raw = 0; 19 | gUart->mu_ier.raw = 0; 20 | 21 | // Note: Can't set individual bits on iir - just doesn't work. TODO: Investigate? 22 | gUart->mu_iir.raw = 0xC6; // fifo_clear = 2, fifo_enables = 2 23 | 24 | gUart->baud_rate.bits.baud_rate = 270; // ((250,000,000 / 115200) / 8) + 1; 25 | 26 | // Enable Uart on the GPIO pins 27 | gGpio->gpfsel1.bits.fsel14 = 2; // Pin 14 - Alt 5 (TXD1) 28 | gGpio->gpfsel1.bits.fsel15 = 2; // Pin 15 - Alt 5 (RXD1) 29 | 30 | unsigned volatile int i; 31 | for(i = 0; i < 150000; i++) { } 32 | 33 | gGpio->gppud.raw = 0; 34 | 35 | // Enable pull down/up clock on pin 14 and 15 36 | // TODO: Comment why this is necessary 37 | gGpio->gppudclk0.bits.pin14 = 1; 38 | gGpio->gppudclk0.bits.pin15 = 1; 39 | 40 | for(i = 0; i < 150000; i++) { } 41 | 42 | // Disable pull down/up clocks 43 | gGpio->gppudclk0.raw = 0; 44 | 45 | // We have to set receiver_enabled and transmitter_enabled in 46 | // one operation here - not sure why. But it breaks if we dont :-( 47 | gUart->mu_cntl.raw = 3; 48 | 49 | return 0; 50 | } 51 | 52 | unsigned int MiniUart_ReadChar(unsigned int block) 53 | { 54 | if(block) 55 | { 56 | while(gUart->mu_lsr.bits.data_ready == 0) { /* Do nothing */ } 57 | } 58 | 59 | return gUart->mu_io.bits.data; 60 | } 61 | 62 | void MiniUart_SendString(char* s) 63 | { 64 | while(*s != '\0') 65 | { 66 | MiniUart_SendChar(*s); 67 | 68 | s++; 69 | } 70 | } 71 | 72 | void MiniUart_SendChar(unsigned int c) 73 | { 74 | while(1) 75 | { 76 | if(gUart->mu_lsr.raw & 0x20) // Transmitter empty 77 | break; 78 | } 79 | 80 | if(c == '\n') 81 | { 82 | gUart->mu_io.raw = '\n'; // LF 83 | 84 | MiniUart_SendChar('\r'); // Carriage return 85 | } 86 | else 87 | { 88 | gUart->mu_io.raw = c; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /include/fs/fat32driver.h: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | #include "fs/fs.h" 3 | #include "util/utilities.h" 4 | 5 | #define LONG_FILE_ENTRY_SIG 0x0F 6 | 7 | typedef struct { 8 | unsigned char name[255]; 9 | unsigned int length; 10 | } fat32_lfe; 11 | 12 | 13 | typedef struct { 14 | unsigned char jump_instruction[3]; // 0xEB 0x58 0x90 15 | unsigned char partition_type_name[9]; // MSDOS5.0 16 | 17 | // BIOS Parameter block 18 | unsigned short bytes_per_sector; // 0x00 0x02 (dec 2) 19 | unsigned char sectors_per_cluster; // 0x8 (dec 8) 20 | unsigned short num_reserved_sectors; // 0xEC 0x04 (dec 1260) (Swapped) 21 | unsigned char num_fats; // 0x02 (dec 2) 22 | unsigned short root_entries; // 0x00 0x00 (dec 0) 23 | unsigned short small_sectors; // 0x00 0x00 (dec 0) 24 | unsigned char media_type; // F8 (Harddisk) 25 | unsigned short sectors_per_fat; // 0x00 0x00 (dec 0) 26 | unsigned short sectors_per_head; // 0x3F 0x00 (dec 16128) (63 swapped) 27 | unsigned short number_of_heads; // 0xFF 0x00 (dec 65280) (255 swapped) 28 | unsigned int hidden_sectors; // 0x80 0x00 0x00 0x00 (dec 2147483648) (Swapped dec 128) 29 | unsigned int large_sectors; // 0x80 0x67 0x76 0x00 (dec 2154264064) (Swapped dec 7759744) 30 | unsigned int large_sectors_per_fat; // 0x8A 0x1D (dec 35357) (7562 swapped) 31 | 32 | // Extended FAT32 33 | unsigned short flags; // 0x00 0x00 (dec 0) 34 | unsigned short version; // 0x00 0x00 (dec 0) 35 | unsigned int root_dir_start; // 0x02 0x00 0x00 0x00 (Cluster where the root directory can be found) (dec 2) 36 | unsigned short info_sector; // 0x01 0x00 (File system info sector) (dec 1) 37 | unsigned short backup_sector; // 0x06 0x00 (Sector of FAT backup of this sector) (dec 6) 38 | 39 | // NOTE: Omitted some information here such as volume ID 40 | 41 | // NOTE: Omitted bootstrapper code and signature 42 | 43 | unsigned int root_start_sector; 44 | } fat_boot_sector; 45 | 46 | typedef struct { 47 | fs_driver_info basic; 48 | 49 | fat_boot_sector boot_sector; // This is really a struct, TODO 50 | unsigned int first_sector; 51 | unsigned int root_dir_sector; 52 | } fat32_driver_info; 53 | 54 | // Public functions 55 | int fat32_driver_factory(BlockDevice* device, part_info* pInfo, fs_driver_info** driver_info); 56 | int fat32_driver_operation(fs_driver_info* info, fs_op operation, void* arg1, void* arg2, void* arg3); 57 | -------------------------------------------------------------------------------- /source/util/utilities.c: -------------------------------------------------------------------------------- 1 | #include "util/utilities.h" 2 | #include "memory_map.h" 3 | #include "types/string.h" 4 | 5 | #define PM_PASSWORD 0x5a000000 6 | #define PM_RSTC_WRCFG_FULL_RESET 0x00000020 7 | 8 | void* my_memcpy(const void *dest, const void *src, unsigned int bytesToCopy) 9 | { 10 | char *s = (char *)src; 11 | char *d = (char *)dest; 12 | while (bytesToCopy > 0) 13 | { 14 | *d++ = *s++; 15 | bytesToCopy--; 16 | } 17 | return (void*)dest; // Disregards const modifier 18 | } 19 | 20 | void reboot(void) 21 | { 22 | *(unsigned int*)(PERIPHERAL_VA_WDOG) = (PM_PASSWORD | 1); // timeout = 1/16th of a second? (whatever) 23 | *(unsigned int*)(PERIPHERAL_VA_RSTC) = (PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET); 24 | 25 | // Watch for the watchdog to do its thing 26 | while (1); 27 | } 28 | 29 | static void swap(void *x, void *y, unsigned int l) { 30 | char *a = x, *b = y, c; 31 | while (l--) { 32 | c = *a; 33 | *a++ = *b; 34 | *b++ = c; 35 | } 36 | } 37 | 38 | // sort() shamelessly copied from Wikipedia because I'm tired 39 | // TODO: Look into better ways to do this? 40 | static void sort(char *array, unsigned int size, int(*cmp)(const void*, const void*), int begin, int end) { 41 | if (end > begin) { 42 | void *pivot = array + begin; 43 | int l = begin + size; 44 | int r = end; 45 | while (l < r) { 46 | if (cmp(array + l, pivot) <= 0) { 47 | l += size; 48 | } 49 | else if (cmp(array + r, pivot) > 0) { 50 | r -= size; 51 | } 52 | else if (l < r) { 53 | swap(array + l, array + r, size); 54 | } 55 | } 56 | l -= size; 57 | swap(array + begin, array + l, size); 58 | sort(array, size, cmp, begin, l); 59 | sort(array, size, cmp, r, end); 60 | } 61 | } 62 | 63 | void qsort(void* base, unsigned int nitems, unsigned int element_size, int(*comparer)(const void*, const void*)) 64 | { 65 | sort(base, element_size, comparer, 0, (nitems - 1)*element_size); 66 | } 67 | 68 | void HexDump(void* mem, unsigned int size) 69 | { 70 | unsigned char* memPtr = (unsigned char*)mem; 71 | do 72 | { 73 | unsigned int i; 74 | for (i = 0; i < 16; i++) 75 | { 76 | char buf[10]; 77 | my_sscanf(&buf[0], "%2X ", *memPtr++); 78 | printf(buf); 79 | 80 | size--; 81 | 82 | if (size == 0) 83 | break; 84 | } 85 | 86 | printf("\n"); 87 | 88 | } while (size > 0); 89 | } 90 | -------------------------------------------------------------------------------- /include/util/utilities.h: -------------------------------------------------------------------------------- 1 | #include "hardware/uart.h" 2 | 3 | #define assert(expression) (!expression ? printf("Assertion failed at %s(%d), expression: " #expression, __FILE__, __LINE__) : (void)0) 4 | #define assert2(expression, message) (!expression ? printf("Assertion failed at %s(%d), expression: " #expression "%s", __FILE__, __LINE__, message) : (void)0) 5 | #define assert3(expression, message, ...) (!(expression) ? printf(message, __VA_ARGS__) : (void)0) 6 | #define assert_uart(expression, message) (!(expression) ? Uart_SendString(message) : (void)0) 7 | #define ReturnOnFailure(result, message) if(((result) != 0)) { printf((char*)message); goto fExit; } 8 | #define ReturnOnFailureF(result, message, ...) if((result > 0)) { printf((char*)message, __VA_ARGS__); goto fExit; } 9 | #define ReturnOnNull(result, message) if((result) == NULL) { printf((char*)message); goto fExit; } 10 | #define inline __inline 11 | 12 | #ifndef UTILITIES_H 13 | #define UTILITIES_H 14 | 15 | // Defines to get the VS editor to stop complaining about various GNU stuff 16 | #ifdef _MSC_VER 17 | #define volatile(a) 18 | #define __attribute__(a) 19 | #define asm 20 | #endif 21 | 22 | #define S_OK 0 23 | #define E_GENERIC_ERROR -1 24 | 25 | // Support for unaligned data access 26 | static inline void write_word(unsigned int val, unsigned char* buf, int offset) 27 | { 28 | buf[offset + 0] = val & 0xff; 29 | buf[offset + 1] = (val >> 8) & 0xff; 30 | buf[offset + 2] = (val >> 16) & 0xff; 31 | buf[offset + 3] = (val >> 24) & 0xff; 32 | } 33 | 34 | static inline unsigned int read_word(unsigned char* buf, int offset) 35 | { 36 | unsigned int b0 = buf[offset + 0] & 0xff; 37 | unsigned int b1 = buf[offset + 1] & 0xff; 38 | unsigned int b2 = buf[offset + 2] & 0xff; 39 | unsigned int b3 = buf[offset + 3] & 0xff; 40 | 41 | return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); 42 | } 43 | 44 | static inline unsigned int byte_swap(unsigned int in) 45 | { 46 | unsigned int b0 = in & 0xff; 47 | unsigned int b1 = (in >> 8) & 0xff; 48 | unsigned int b2 = (in >> 16) & 0xff; 49 | unsigned int b3 = (in >> 24) & 0xff; 50 | unsigned int ret = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 51 | return ret; 52 | } 53 | 54 | void qsort(void* base, unsigned int nitems, unsigned int element_size, int(*comparer)(const void*, const void*)); 55 | void* my_memcpy(const void* dest, const void* src, unsigned int bytesToCopy); 56 | void HexDump(void* mem, unsigned int size); 57 | void reboot(void); 58 | 59 | static inline unsigned int byte_to_int(unsigned char* buf) 60 | { 61 | // NOTE: Assumes little endian 62 | return (buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24)); 63 | } 64 | 65 | static inline unsigned int byte_to_short(char* buf) 66 | { 67 | return (buf[0] + ((int)buf[1] << 8)); 68 | } 69 | 70 | #endif -------------------------------------------------------------------------------- /include/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef ASM_H 2 | #define ASM_H 3 | 4 | #define PT_CACHEABLE 1 5 | #define PT_NONCACHEABLE 0 6 | 7 | // Value to set in TTBC 8 | #define TTBC_SPLIT_16KB 0 // 4 GB TTB0 9 | #define TTBC_SPLIT_8KB 1 // 2 GB TTB0 10 | #define TTBC_SPLIT_4KB 2 // 1 GB TTB0 11 | #define TTBC_SPLIT_2KB 3 // 512 MB TTB0 12 | #define TTBC_SPLIT_1KB 4 // 256 MB TTB0 13 | #define TTBC_SPLIT_512B 5 // 128 MB TTB0 14 | #define TTBC_SPLIT_256B 6 // 64 MB TTB0 15 | #define TTBC_SPLIT_128B 7 // 32 MB TTB0 16 | 17 | #define TTBC_PD0_DISABLED (1 << 4) 18 | #define TTBC_PD0_ENABLED (0 << 4) 19 | #define TTBC_PD1_DISABLE (1 << 5) 20 | #define TTBC_PD1_ENABLED (0 << 5) 21 | 22 | // Client - Memory access is controlled by TLB entry 23 | #define DAC_CLIENT 0x55555555 24 | 25 | // Client - No access (Reset value) 26 | #define DAC_NONE 0x00000000 27 | 28 | // Reserved - Any access generates domain fault 29 | #define DAC_RESERVED 0xAAAAAAAA 30 | 31 | // Manager - TLB entry is not checked for access, no domain faults are generated 32 | #define DAC_MANAGER 0xFFFFFFFF 33 | 34 | // 35 | // interrupt vector 36 | // 37 | extern void irq(void); 38 | extern void fiq(void); 39 | extern void reset(void); 40 | extern void data_abort(void); 41 | extern void instruction_abort(void); 42 | extern void reset(void); 43 | 44 | // 45 | // irq.s 46 | // 47 | extern void enable_irq(void); 48 | extern void disable_irq(void); 49 | extern void enable_fiq(void); 50 | extern void disable_fiq(void); 51 | 52 | // 53 | // mmu.s 54 | // 55 | 56 | // Installs the page tables and enables the MMU 57 | extern void do_mmu(unsigned int* ttb0, unsigned int* ttb1, unsigned int split); 58 | 59 | // Sets the translation table base 0 register 60 | // NOTE: If cacheable is set, make sure pt is stored in Inner-write through memory 61 | void set_ttb0(unsigned int* pt, unsigned int cacheable); 62 | 63 | // Gets the value of the current program control register 64 | extern unsigned int get_crcd(void); 65 | 66 | // Gets the value of the Translation Table 0 base register 67 | extern unsigned int get_ttb0(void); 68 | 69 | // Gets the value of the Translation Table 1 Base register 70 | extern unsigned int get_ttb1(void); 71 | 72 | // Gets the value of the Translation Table Base Control register 73 | extern unsigned int get_ttbc(void); 74 | 75 | // Sets the value of the Translation Table Base Control register 76 | extern void set_ttbc(unsigned int val); 77 | 78 | // Gets the value of the domain register 79 | extern unsigned int get_domain_register(void); 80 | 81 | extern unsigned int set_domain_register(unsigned int value); 82 | 83 | // 84 | // utility.s 85 | // 86 | // Gets the current frame pointer 87 | extern int* get_fp(void); 88 | 89 | // Gets the current address of the stack pointer 90 | extern unsigned int get_sp(void); 91 | 92 | // Utility function for branching to an arbitrary memory address 93 | extern void call(unsigned int addr); 94 | 95 | // Unconditionally branches to the given address 96 | // WARNING: this trashes FP and does not set up LR! 97 | extern void branch(unsigned int* addr); 98 | 99 | #endif -------------------------------------------------------------------------------- /include/dwarf.h: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | DW_TAG_access_declaration, 3 | DW_TAG_array_type, 4 | DW_TAG_base_type, 5 | DW_TAG_catch_block, 6 | DW_TAG_class_type, 7 | DW_TAG_common_block, 8 | DW_TAG_common_inclusion, 9 | DW_TAG_compile_unit, 10 | DW_TAG_const_type, 11 | DW_TAG_constant, 12 | DW_TAG_entry_point, 13 | DW_TAG_enumeration_type, 14 | DW_TAG_enumerator, 15 | DW_TAG_file_type, 16 | DW_TAG_formal_parameter, 17 | DW_TAG_friend, 18 | DW_TAG_imported_declaration, 19 | DW_TAG_inheritance, 20 | DW_TAG_inlined_subroutine, 21 | DW_TAG_label, 22 | DW_TAG_lexical_block, 23 | DW_TAG_member, 24 | DW_TAG_module, 25 | DW_TAG_namelist, 26 | DW_TAG_namelist_item, 27 | DW_TAG_packed_type, 28 | DW_TAG_pointer_type, 29 | DW_TAG_ptr_to_member_type, 30 | DW_TAG_reference_type, 31 | DW_TAG_set_type, 32 | DW_TAG_string_type, 33 | DW_TAG_structure_type, 34 | DW_TAG_subprogram, 35 | DW_TAG_subrange_type, 36 | DW_TAG_subroutine_type, 37 | DW_TAG_template_type_param, 38 | DW_TAG_template_value_param, 39 | DW_TAG_thrown_type, 40 | DW_TAG_try_block, 41 | DW_TAG_typedef, 42 | DW_TAG_union_type, 43 | DW_TAG_unspecified_parameters, 44 | DW_TAG_variable, 45 | DW_TAG_variant, 46 | DW_TAG_variant_part, 47 | DW_TAG_volatile_type, 48 | DW_TAG_with_stmt 49 | } dwarf_tag_name; 50 | 51 | typedef enum { 52 | DW_AT_abstract_origin, 53 | DW_AT_accessibility, 54 | DW_AT_address_class, 55 | DW_AT_artificial, 56 | DW_AT_base_types, 57 | DW_AT_bit_offset, 58 | DW_AT_bit_size, 59 | DW_AT_byte_size, 60 | DW_AT_calling_convention, 61 | DW_AT_common_reference, 62 | DW_AT_comp_dir, 63 | DW_AT_const_value, 64 | DW_AT_containing_type, 65 | DW_AT_count, 66 | DW_AT_data_member_location, 67 | DW_AT_decl_column, 68 | DW_AT_decl_file, 69 | DW_AT_decl_line, 70 | DW_AT_declaration, 71 | DW_AT_default_value, 72 | DW_AT_discr, 73 | DW_AT_discr_list, 74 | DW_AT_discr_value, 75 | DW_AT_encoding, 76 | DW_AT_external, 77 | DW_AT_frame_base, 78 | DW_AT_friend, 79 | DW_AT_high_pc, 80 | DW_AT_identifier_case, 81 | DW_AT_import, 82 | DW_AT_inline, 83 | DW_AT_is_optional, 84 | DW_AT_language, 85 | DW_AT_location, 86 | DW_AT_low_pc, 87 | DW_AT_lower_bound, 88 | DW_AT_macro_info, 89 | DW_AT_name, 90 | DW_AT_namelist_item, 91 | DW_AT_ordering, 92 | DW_AT_priority, 93 | DW_AT_producer, 94 | DW_AT_prototyped, 95 | DW_AT_return_addr, 96 | DW_AT_segment, 97 | DW_AT_sibling, 98 | DW_AT_specification, 99 | DW_AT_start_scope, 100 | DW_AT_static_link, 101 | DW_AT_stmt_list, 102 | DW_AT_stride_size, 103 | DW_AT_string_length, 104 | DW_AT_type, 105 | DW_AT_upper_bound, 106 | DW_AT_use_location, 107 | DW_AT_variable_parameter, 108 | DW_AT_virtuality, 109 | DW_AT_visibility, 110 | DW_AT_vtable_elem_location 111 | } dwarf_attr_name; -------------------------------------------------------------------------------- /include/memory_map.h: -------------------------------------------------------------------------------- 1 | // NOTE: This file needs to be kept to strictly defines as it's shared between C and asm. 2 | 3 | #ifndef MEMORY_MAP_H 4 | #define MEMORY_MAP_H 5 | 6 | 7 | #define QEMU 1 8 | 9 | // Misc memory relevant defines 10 | #define SMALL_STACK_SIZE (PAGE_SIZE) 11 | #define MED_STACK_SIZE (PAGE_SIZE * 3) 12 | #define LARGE_STACK_SIZE (PAGE_SIZE * 8) 13 | 14 | #define MAX_USER_TASKS 20 15 | #define USER_PT_SIZE_IN_BYTES (2048 * sizeof(int)) 16 | 17 | // Physical addresses 18 | #define FIQ_STACK_PA_START 0x00004000 19 | #define IRQ_STACK_PA_START 0x00007900 20 | #define SVC_STACK_PA_START 0x00C08000 21 | #define SM_STACK_PA_START 0x0A827000 22 | #define UD_STACK_PA_START 0x01008000 23 | #define ABORT_STACK_PA_START 0x01208000 24 | // NOTE Frmebuffer is at: 0x0C006000 25 | #define KERNEL_PA_START 0x00000000 26 | #define KERNEL_PA_PT 0x000A8000 // was F 27 | #define KERNEL_PA_TMP_TTB0 (0x4000) 28 | #define USR_PA_START (0x00F00000) 29 | #define PERIPHERAL_PA_START 0x20000000 30 | #define DYN_MEM_PA_START 0x01209000 31 | 32 | // 33 | // Virtual addresses 34 | // 35 | 36 | // Misc 37 | #define KERNEL_VA_START 0x80000000 38 | #define DYN_MEM_VA_START (KERNEL_VA_START + DYN_MEM_PA_START) 39 | #define USR_VA_START 0x00001000 40 | #define KERNEL_PT_VA_START (KERNEL_VA_START + KERNEL_PA_PT) 41 | #define USER_TTB0S_START (KERNEL_VA_START + USR_PA_START) 42 | #define USER_TASKS_START (USER_TTB0S_START + (MAX_USER_TASKS * USER_PT_SIZE_IN_BYTES)) 43 | 44 | // Stacks 45 | #define FIQ_STACK_VA_START (KERNEL_VA_START + FIQ_STACK_PA_START) 46 | #define IRQ_STACK_VA_START (KERNEL_VA_START + IRQ_STACK_PA_START) 47 | #define SVC_STACK_VA_START 0x80C08000 48 | #define SM_STACK_VA_START (KERNEL_VA_START + SM_STACK_PA_START) 49 | #define UD_STACK_VA_START (KERNEL_VA_START + UD_STACK_PA_START) 50 | #define ABORT_STACK_VA_START (KERNEL_VA_START + ABORT_STACK_PA_START) 51 | 52 | // Peripherals 53 | #define PERIPHERAL_VA_START (KERNEL_VA_START + PERIPHERAL_PA_START) 54 | #define PERIPHERAL_VA_TIMER (PERIPHERAL_VA_START + 0x3000) 55 | #define PERIPHERAL_VA_IRPT (PERIPHERAL_VA_START + 0xB200) 56 | #define PERIPHERAL_VA_MAILBOX_BASE (PERIPHERAL_VA_START + 0xb880) 57 | #define PERIPHERAL_VA_RSTC (PERIPHERAL_VA_START + 0x10001c) 58 | #define PERIPHERAL_VA_WDOG (PERIPHERAL_VA_START + 0x100024) 59 | #define PERIPHERAL_VA_GPIO (PERIPHERAL_VA_START + 0x200000) 60 | #define PERIPHERAL_VA_UART (PERIPHERAL_VA_START + 0x201000) 61 | #define PERIPHERAL_VA_MINIUART (PERIPHERAL_VA_START + 0x215000) 62 | #define PERIPHERAL_VA_EMMC (PERIPHERAL_VA_START + 0x300000) 63 | 64 | #ifdef QEMU 65 | // Same thing here, thoguh it seems to be 0x1C100000 or 0x1C000000 66 | #define FRAMEBUFFER_VA_START (KERNEL_VA_START + 0x1C000000) 67 | #else 68 | // Note: The offset is the physical address of the FB, well, at least 69 | // The address it has been allocated to in my tests 70 | #define FRAMEBUFFER_VA_START (KERNEL_VA_START + 0x0C006000) 71 | #endif 72 | 73 | // 74 | // Linker constants 75 | // 76 | 77 | #define LD_KRNL_ORIGIN 0x8000 78 | 79 | 80 | #define LD_PAGE_SIZE 4096 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /source/hardware/mmu_c.c: -------------------------------------------------------------------------------- 1 | #include "hardware/mmu_c.h" 2 | #include "types/string.h" 3 | #include "memory.h" 4 | #include "asm.h" 5 | 6 | Pfa* gPfa; 7 | unsigned int* gPageTableBase; 8 | 9 | void Mmu_Initialize(unsigned int* pageTableBase) 10 | { 11 | gPageTableBase = pageTableBase; 12 | 13 | // Initialize all PTEs to translation fault (0) 14 | unsigned int i; 15 | for (i = 0; i < 4096; i++) 16 | *(pageTableBase + i) = 0; // STMIA? 17 | 18 | #ifdef MMU_DEBUG 19 | printf("mmu - Initializing page table at 0x%h to 0x%h\n", pageTableBase, pageTableBase + (4096)); 20 | printf("mmu - Kernel: 0x000 -> C800000 (200MB)\n"); 21 | printf("mmu - Peripherals: 0x20000000 -> 0x10000000(256MB)\n"); 22 | #endif 23 | 24 | // The first 200 MB is all kernel data (including memory allocator), do a 1:1 mapping 25 | Mmu_MapSection(0x00000000, 0x00000000, 200, APNoneSvcRw, 1, 1); 26 | Mmu_MapSection(0x20000000, 0x20000000, 256, APNoneSvcRw, 0, 0); //0xA0000000 27 | 28 | // The remaining 312 MB is all usermode 29 | // To map user mode (Note that the physical address will probably change based on proc id) 30 | // mmuMapSection(0x008C00000, 0xB0000000, 5, ReadWrite, true, true); 31 | Mmu_MapSection(0x0A827000, 0xC0000000, 5, APReadWrite, 1, 1); 32 | 33 | do_mmu(pageTableBase, 0, TTBC_SPLIT_16KB); 34 | 35 | printf("mmu - Initializing complete\n"); 36 | } 37 | 38 | void Mmu_MapSection(unsigned int physicalAddressStart, unsigned int virtualAddressStart, 39 | unsigned int numSections, unsigned int ap, unsigned int cacheable, unsigned int bufferable) 40 | { 41 | // Top 12 bits of virtual address index into the page table directory 42 | unsigned int vaBase = (virtualAddressStart >> 20) & 0xFFF; 43 | unsigned int paBase = (physicalAddressStart >> 20) & 0xFFF; 44 | 45 | unsigned int i; 46 | for (i = 0; i < numSections; i++) 47 | { 48 | SectionPageTable* section = (SectionPageTable*)(gPageTableBase + vaBase + i); 49 | section->baseAddress = paBase + i; 50 | section->domain = 0; // Hardcoded domain - We don't use domains 51 | section->present = 1; 52 | section->cacheable = cacheable; 53 | section->bufferable = bufferable; 54 | section->accessPermission = ap; 55 | section->sectionTypeIdentifier = 2; 56 | } 57 | } 58 | 59 | void Mmu_UnmapSection(unsigned int virtualAddr) 60 | { 61 | // Reset the page completely 62 | *(gPageTableBase + ((virtualAddr >> 20) & 0xFFF)) = 0; 63 | } 64 | 65 | // Allocate shouldn't tkae in address - it should just give the caller an addr 66 | // from the pool and return a MemoryMapping describing it 67 | //void mmu_AllocateUserPage(unsigned int physicalAddr, unsigned int virtualAddr) 68 | //{ 69 | // unsigned int physicalBase = (physicalAddr >> 20) & 0xFFF; 70 | // unsigned int virtualBase = (virtualAddr >> 20) & 0xFFF; 71 | // 72 | // mmuMapSection(physicalAddr, virtualAddr, 1, APReadWrite, 1, 1); 73 | // 74 | // gPfa->mappings[virtualBase].phyAddr = physicalAddr; 75 | //} 76 | // 77 | //void mmu_DeallocateUserPage(unsigned int physAddr) 78 | //{ 79 | // unsigned int physAddrBase = (physAddr >> 20) & 0xFFF; 80 | // 81 | // MemoryMapping* mapping = &gPfa->mappings[physAddrBase]; 82 | // 83 | // mapping->active = 0; 84 | // mapping->virtAddr = 0; 85 | //} 86 | -------------------------------------------------------------------------------- /source/asm/interrupt_handlers.S: -------------------------------------------------------------------------------- 1 | ;@ 2 | ;@ Interrupt vector functions - do NOT call these from C code! 3 | ;@ 4 | 5 | .type irq %function 6 | .globl irq 7 | irq: 8 | sub lr, #4 ;@ (Required to return from exception) 9 | 10 | ;@ Save context 11 | push {r0-r12, lr} ;@ Save registers onto IRQ stack 12 | 13 | mrs r0, spsr ;@ Save SPSR 14 | cps #0x13 ;@ SVC mode 15 | mov r1, sp 16 | mov r2, lr 17 | 18 | cps #0x12 ;@ IRC mode 19 | push {r0-r2} ;@ Push values to IRQ stack 20 | 21 | mov r0, sp ;@ Pass in a pointer to the registers as a param to the irq handler 22 | add r0, #4 23 | 24 | bl c_irq_handler ;@ Osdev note: All this does is print out the registers struct 25 | 26 | ;@ Restore context 27 | pop {r0-r2} ;@ Pop the saved banked registers off the IRQ stack 28 | msr spsr, r0 ;@ Restore SPSR (Which is SPSR in the previous mode) 29 | 30 | cps #0x13 ;@ SVC mode 31 | mov sp, r1 ;@ Restore SP 32 | mov lr, r2 ;@ Restore LR 33 | 34 | cps #0x12 ;@ IRQ mode 35 | 36 | pop {r0-r12,lr} 37 | 38 | movs pc, lr 39 | 40 | .type data_abort %function 41 | .globl data_abort 42 | data_abort: 43 | ;@ Proloque 44 | push {fp, lr} 45 | add fp, sp, #4 46 | sub sp, sp, #8 47 | 48 | push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 49 | 50 | ;@ Pass the address where it happened as the 1st argument 51 | subs r0, lr, #8 52 | 53 | ;@ Pass the error type as the 2nd argument 54 | mrc p15, 0, r1, c5, c0, 0 55 | and r1, r1, #0xF 56 | 57 | ;@ Pass the address that was accessed as the 3rd argumnet 58 | mrc p15, 0, r2, c6, c0, 0 59 | 60 | ;@ Pass the Fault Status Register as the 4th argument 61 | mrc p15, 0, r3, c5, c0, 0 62 | 63 | bl c_abort_data_handler 64 | 65 | pop {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 66 | 67 | sub sp, fp, #4 68 | pop {fp, lr} 69 | 70 | subs PC, lr, #4 71 | 72 | 73 | .type instruction_abort %function 74 | .globl instruction_abort 75 | instruction_abort: 76 | push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 77 | 78 | ;@ Get the address that caused it 79 | subs r0, lr, #4 80 | 81 | ;@ Get the error type 82 | mrc p15, 0, r1, c5, c0, 0 83 | and r1, r1, #0xF 84 | 85 | bl c_abort_instruction_handler 86 | 87 | pop {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 88 | 89 | subs PC, lr, #4 90 | 91 | 92 | .type undefined %function 93 | .globl undefined 94 | undefined: 95 | push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 96 | 97 | mov r0, lr 98 | 99 | bl c_undefined_handler 100 | 101 | pop {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 102 | 103 | subs PC, lr, #4 104 | 105 | 106 | .type swi %function 107 | .globl swi 108 | swi: 109 | ;@ Save registers and LR onto stack 110 | stmfd sp!, {r4-r5,lr} 111 | 112 | ;@ Don't touch r0-r2 as they contain arguments 113 | ;@ To the SWI 114 | 115 | ;@ SWI number is stored in top 8 bits of the instruction 116 | ldr r3, [lr, #-4] 117 | bic r3, r3, #0xFF000000 118 | 119 | bl c_swi_handler 120 | 121 | ;@ Restore registers and return 122 | LDMFD sp!, {r4, r5, pc}^ 123 | -------------------------------------------------------------------------------- /source/debugging.c: -------------------------------------------------------------------------------- 1 | #include "debugging.h" 2 | #include "types/string.h" // printf(...) 3 | #include "asm.h" // get_fp() 4 | #include "memory.h" 5 | #include "util/utilities.h" 6 | 7 | extern unsigned int LNK_KERNEL_END; 8 | 9 | func_info* gFunctions; 10 | unsigned int gNFunctions; 11 | 12 | int func_info_comparer(const void* item0, const void* item1) 13 | { 14 | func_info* first = (func_info*)item0; 15 | func_info* second = (func_info*)item1; 16 | 17 | return second->address - first->address; 18 | } 19 | 20 | void Debug_ReadFunctionNames(char* blob) 21 | { 22 | printf("Reading debugging symbols from 0x%h\n", blob); 23 | 24 | unsigned int num_funcs = (blob[0] << 24) | (blob[1] << 16) | (blob[2] << 8) | blob[3]; 25 | blob += 5; 26 | 27 | gFunctions = (func_info*)palloc(sizeof(func_info) * num_funcs); 28 | gNFunctions = num_funcs; 29 | 30 | unsigned int i; 31 | for (i = 0; i < num_funcs; i++) 32 | { 33 | func_info* cur = &gFunctions[i]; 34 | 35 | int nameLen = my_strlen(blob); 36 | 37 | cur->name = (char*)palloc(nameLen + 1); 38 | my_memcpy(cur->name, blob, nameLen); 39 | cur->name[nameLen] = 0; 40 | 41 | blob += nameLen + 1; 42 | 43 | cur->address = (blob[0] << 24) | (blob[1] << 16) | (blob[2] << 8) | (blob[3]); 44 | 45 | //printf("Found '%s' at 0x%h\n", cur->name, cur->address); 46 | 47 | blob += 4; 48 | } 49 | 50 | printf("Loaded %d function names, sorting by address... ", num_funcs); 51 | 52 | qsort(gFunctions, num_funcs, sizeof(func_info), func_info_comparer); 53 | 54 | printf("Done!\n"); 55 | } 56 | 57 | char* Debug_GetClosestPreviousFunction(unsigned int address) 58 | { 59 | unsigned int i; 60 | func_info* best_match = (void*)0; 61 | int best_match_diff = 0xFFFF; 62 | for (i = 0; i < gNFunctions; i++) 63 | { 64 | func_info* cur = &gFunctions[i]; 65 | 66 | int diff = address - cur->address; 67 | if (diff > 0 && diff < best_match_diff) 68 | { 69 | best_match = cur; 70 | best_match_diff = diff; 71 | } 72 | } 73 | 74 | if (best_match == ((void*)0)) 75 | return "Unknown"; 76 | 77 | return best_match->name; 78 | } 79 | 80 | void Debug_PrintCallstack(unsigned int skipFrames) 81 | { 82 | int lr = 0; 83 | int depth = 0; 84 | int* fp = get_fp(); 85 | 86 | // Depth is 0-index, compensate for this 87 | skipFrames -= 1; 88 | 89 | do 90 | { 91 | lr = *fp; 92 | fp = (int*)*(fp - 1); 93 | 94 | // Skip the two data_fault functions 95 | if (depth > skipFrames) 96 | printf("Frame %d: %s (0x%h)\n", depth - 2, Debug_GetClosestPreviousFunction(lr), lr); 97 | 98 | // Have we reached the end? 99 | // Note: FP Might point to the physical location of the stack 100 | // If the frame was set up before virtual memory was enabled, if so, compensate 101 | if (fp < KERNEL_VA_START) 102 | fp += KERNEL_VA_START; 103 | else if (fp > KERNEL_VA_START + 0x10000000) 104 | break; 105 | } while (fp != 0 && depth++ < MAX_FRAME_DEPTH && lr != 0x80CC); // Address of branch to cmain from asm 106 | } 107 | 108 | void debugDumpStack(unsigned int* sp) 109 | { 110 | printf("~~~ Stack dump~~~~"); 111 | 112 | unsigned int i; 113 | for (i = 0; i < 40; i++){ 114 | printf("0x%h ", *(sp + i)); 115 | 116 | if (i % 10 == 0){ 117 | printf("\n"); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /source/thread.c: -------------------------------------------------------------------------------- 1 | #include "mem.h" 2 | #include "thread.h" 3 | #include "stddef.h" 4 | #include "hardware/paging.h" 5 | #include "types/string.h" 6 | #include "process.h" 7 | #include "scheduler.h" 8 | #include "util/memutil.h" 9 | 10 | static bool thread_initStack(thread* t, Process* owner) 11 | { 12 | int freePage0 = mem_nextFree(); 13 | if (freePage0 == -1) 14 | return false; 15 | 16 | int freePage1 = mem_nextFree(); 17 | if(freePage1 == -1) 18 | { 19 | mem_free(freePage0); 20 | return false; 21 | } 22 | 23 | //printf("Initializing thread stack at 0x%h (phys: 0x%h)\n", THREAD_STACK_VA_START, freePage); 24 | 25 | map_page(owner->ttb0, owner->ttb0_size, (unsigned int)freePage0, THREAD_STACK_VA_START - PAGE_SIZE, 26 | PAGE_BUFFERABLE | PAGE_CACHEABLE | PAGE_AP_K_RW_U_RW); 27 | 28 | map_page(owner->ttb0, owner->ttb0_size, (unsigned int)freePage1, (THREAD_STACK_VA_START - (PAGE_SIZE * 2)), 29 | PAGE_BUFFERABLE | PAGE_CACHEABLE | PAGE_AP_K_RW_U_RW); 30 | 31 | t->stackPages = (int*)pcalloc(THREAD_MAX_PAGES, sizeof(int)); 32 | t->stackPages[0] = freePage0; 33 | t->stackPages[1] = freePage1; 34 | t->nStackPages = 2; 35 | 36 | t->virtStack = (uint32_t*)(THREAD_STACK_VA_START); 37 | 38 | //printf("Virtual stack: 0x%h - Physical stack: 0x%h\n", t->virtStack, t->phyStack); 39 | 40 | return true; 41 | } 42 | 43 | thread* thread_create(thread_entry entry) 44 | { 45 | //printf("Creating a new thread with entry 0x%h\n", entry); 46 | 47 | thread* currentThread = Scheduler_GetCurrentThread(); 48 | 49 | if (currentThread == NULL) 50 | { 51 | printf("Cannot create a thread without an owner.\n"); 52 | return NULL; 53 | } 54 | 55 | Process* cur = currentThread->owner; 56 | if (cur == NULL) 57 | { 58 | printf("Cannot create a thread as no process is running...\n"); 59 | return NULL; 60 | } 61 | 62 | return thread_createWithOwner(entry, cur); 63 | } 64 | 65 | thread* thread_createWithOwner(thread_entry entry, Process* owner) 66 | { 67 | //printf("Creating thread with owner %s\n", owner->name); 68 | 69 | thread* t = (thread*)pcalloc(sizeof(thread), 1); 70 | 71 | t->priority = THREAD_PRIO_MED; 72 | t->state = THREAD_STATE_READY; 73 | t->owner = owner; 74 | t->result = -1; 75 | t->entry = entry; 76 | 77 | if (!thread_initStack(t, owner)) 78 | { 79 | printf("Not page available for stack\n"); 80 | phree(t); 81 | } 82 | 83 | // Initialize registers 84 | //printf("Creating thread, virtual SP: 0x%h, entry point: 0x%h\n", t->virtStack, entry); 85 | t->registers.r0 = 1; 86 | t->registers.r1 = 2; 87 | t->registers.sp = (uint32_t)t->virtStack; 88 | t->registers.r7 = (uint32_t)t->virtStack; // FP! Or is it r11/r12? 89 | t->registers.r12 = (uint32_t)t->virtStack; 90 | t->registers.sprs = 0x53; // SVC MODE, TODO: User threads? 91 | t->registers.lr2 = entry; 92 | 93 | return t; 94 | } 95 | 96 | void thread_setPriority(thread* t, thread_priority p) 97 | { 98 | if (t->priority == p) 99 | return; 100 | 101 | // TODO: Take thread out of current scheduler queue and 102 | // insert into new one 103 | } 104 | 105 | void thread_kill(thread* t) 106 | { 107 | if (Scheduler_GetCurrentThread() == t) 108 | { 109 | // Thread is currently running 110 | // Remote it from the scheduler 111 | } 112 | 113 | // TODO: unmap_page t->phyStack 114 | for(int i = 0; i < THREAD_MAX_PAGES; i++) 115 | mem_free(t->stackPages[i]); 116 | 117 | phree(t->stackPages); 118 | 119 | if (t->name == NULL) 120 | { 121 | phree(t->name); 122 | } 123 | 124 | phree(t); 125 | } -------------------------------------------------------------------------------- /include/atags.h: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | 3 | // Empty tag used to end list 4 | ATAG_NONE = 0x00000000, 5 | 6 | // Start tag used to begin list 7 | ATAG_CORE = 0x54410001, 8 | 9 | // Tag used to describe a physical area of memory. 10 | ATAG_MEM = 0x54410002, 11 | 12 | // Tag used to describe VGA text type displays 13 | ATAG_VIDEOTEXT = 0x54410003, 14 | 15 | // Tag describing how the ramdisk will be used by the kernel 16 | ATAG_RAMDISK = 0x54410004, 17 | 18 | // Tag describing the physical location of the compressed ramdisk image 19 | ATAG_INITRD2 = 0x54420005, 20 | 21 | // Tag with 64 bit serial number of the board 22 | ATAG_SERIAL = 0x54410006, 23 | 24 | // Tag for the board revision 25 | ATAG_REVISION = 0x54410007, 26 | 27 | // Tag describing parameters for a framebuffer type display 28 | ATAG_VIDEOLFB = 0x54410008, 29 | 30 | // Tag used to pass the commandline to the kernel 31 | ATAG_CMDLINE = 0x54410009 32 | } atag_type; 33 | 34 | typedef struct { 35 | 36 | // bit 0 = read - only 37 | unsigned int flags; 38 | // Systems page size (usually 4k) 39 | unsigned int pagesize; 40 | 41 | // Root device number 42 | unsigned int rootdev; 43 | } atag_core; 44 | 45 | typedef struct { 46 | 47 | // Size of memory area 48 | unsigned int size; 49 | 50 | // Physical start address 51 | unsigned int start; 52 | } atag_mem; 53 | 54 | typedef struct { 55 | 56 | // Display width 57 | unsigned char x; 58 | 59 | // Display height 60 | unsigned char y; 61 | unsigned short video_page; 62 | unsigned char video_mode; 63 | unsigned char video_cols; 64 | unsigned short video_ega_bx; 65 | unsigned char video_lines; 66 | unsigned char video_isvga; 67 | unsigned short video_points; 68 | } atag_videotext; 69 | 70 | typedef struct { 71 | 72 | // bit 0 = load, bit 1 = prompt 73 | unsigned int flags; 74 | 75 | // Decompressed ramdisk size in _kilo_ bytes 76 | unsigned int size; 77 | 78 | // Starting block of floppy-based RAM disk image 79 | unsigned int start; 80 | } atag_ramdisk; 81 | 82 | typedef struct { 83 | 84 | // Physical start address 85 | unsigned int start; 86 | 87 | // Size of compressed ramdisk image in bytes 88 | unsigned int size; 89 | } atag_initrd2; 90 | 91 | typedef struct { 92 | unsigned int low; 93 | unsigned int high; 94 | } atag_serialnr; 95 | 96 | typedef struct { 97 | 98 | // Board revision 99 | unsigned int rev; 100 | } atag_revision; 101 | 102 | typedef struct { 103 | // 1 is the minimum size 104 | char cmdline[1]; 105 | } atag_cmdline; 106 | 107 | typedef struct { 108 | unsigned short lfb_width; 109 | unsigned short lfb_height; 110 | unsigned short lfb_depth; 111 | unsigned short lfb_linelength; 112 | unsigned int lfb_base; 113 | unsigned int lfb_size; 114 | unsigned char red_size; 115 | unsigned char red_pos; 116 | unsigned char green_size; 117 | unsigned char green_pos; 118 | unsigned char blue_size; 119 | unsigned char blue_pos; 120 | unsigned char rsvd_size; 121 | unsigned char rsvd_pos; 122 | } atag_videolfb; 123 | 124 | typedef struct { 125 | // Length of tag in words including this header 126 | unsigned int size; 127 | 128 | // Tag type (see atag_type) 129 | unsigned int tag; 130 | } atag_header; 131 | 132 | typedef struct { 133 | atag_header hdr; 134 | 135 | union { 136 | atag_core core; 137 | atag_mem mem; 138 | atag_videotext videotext; 139 | atag_ramdisk ramdisk; 140 | atag_initrd2 initrd2; 141 | atag_serialnr serialnr; 142 | atag_revision revision; 143 | atag_videolfb videolfb; 144 | atag_cmdline cmdline; 145 | } u; 146 | } atag; 147 | 148 | void atags_parse(int* addr); -------------------------------------------------------------------------------- /include/hardware/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGING_H 2 | #define PAGING_H 3 | 4 | #include "memory.h" 5 | 6 | // First kernel VA is 0x80000000 7 | // If we take this address: 0x80000000 (_1_0000000000000000000000000000000b) 8 | // If the 31th bit of a VA is set (ie the address is > 2GB) then the kernel's page table is used 9 | // Otherwise the user page table is searched 10 | 11 | // "Size" is the size of the address space it covers, value is number of level 1 entries 12 | #define TTB_SIZE_4GB_SIZE 4096 13 | #define TTB_SIZE_2GB_SIZE 2048 14 | #define TTB_SIZE_1GB_SIZE 1024 15 | #define TTB_SIZE_512MB_SIZE 512 16 | #define TTB_SIZE_256MB_SIZE 256 17 | #define TTB_SIZE_128MB_SIZE 128 18 | #define TTB_SIZE_64MB_SIZE 64 19 | #define TTB_SIZE_32MB_SIZE 32 20 | 21 | // Values and their meanings for Translation Table Base Control Register 2:0 22 | typedef enum { 23 | ttbc_16KB = 0, // 4GB Address space 24 | ttbc_8KB = 1, // 2GB Address space 25 | ttbc_4KB = 2, // 1GB Address space 26 | ttbc_2KB = 3, // 512MB Adress space 27 | ttbc_1KB = 4, // 256MB Address sapce 28 | ttbc_512byte = 5, // 128MB Address space 29 | ttbc_256byte = 6, // 64MB Address space 30 | ttbc_128bytes = 7 // 32MB Address space 31 | } ttbc_ttbr0_size; 32 | 33 | enum PAGE_TABLE_TYPE{ 34 | PAGE_TABLE_FAULT = 0x0, 35 | PAGE_TABLE_COARSE = 0x1, 36 | PAGE_TABLE_SECTION = 0x2, 37 | PAGE_TABLE_RESERVED = 0x3, 38 | PAGE_TABLE_MASK = 0x3 // Masks out the type of the page table 39 | }; 40 | 41 | // Extended 4KB small pages ARMv6 level 2 descriptor attributes 42 | enum PAGE_ATTR{ 43 | PAGE_FAULT = 0x0, // Access to page results in translation fault 44 | PAGE_EXECUTE_NEVER = 0x1, // Page contains no executable code 45 | PAGE_SMALL = 0x2, // Small 4KB extended page 46 | PAGE_BUFFERABLE = 0x4, // Bufferable 47 | PAGE_CACHEABLE = 0x8 // Cacheable 48 | }; 49 | 50 | // Sets bit 15 (when applicable) and 11:10 51 | enum SECTION_AP { 52 | SECTION_AP_NONE = 0x0, // APX: b0, AP: b00 No access 53 | SECTION_AP_K_RW = 0x400, // APX: b0, AP: b01 Kernel Read/Write, User None 54 | SECTION_AP_K_RW_U_R = 0x800, // APX: b0, AP: b10 Kernel Read/Write, User Read-Only 55 | SECTION_AP_K_RW_U_RW = 0xC00, // APX: b0, AP: b11 Kernel Read/Write, User Read/Write 56 | SECTION_AP_NONE_DOMAIN = 0x0, // APX: b1, AP: b00 Kernel None, domain fault encoded field 57 | SECTION_AP_K_R = 0x8400,// APX: b1, AP: b01 Kernel Read-Only, User None 58 | SECTION_AP_K_R_U_R = 0x8800 // APX: b1, AP: b10 Kernel Read-Only, User Read-Only 59 | }; 60 | 61 | // Sets bit 6 (when applicable) and 5:4 62 | enum PAGE_AP { 63 | PAGE_AP_NONE = 0, // APX: b0, AP: b00 No access 64 | PAGE_AP_K_RW = 0x10, // APX: b0, AP: b01 Kernel Read/Write, User None 65 | PAGE_AP_K_RW_U_R = 0x20, // APX: b0, AP: b10 Kernel Read/Write, User Read Only (Writes in user mode generate permission fault) 66 | PAGE_AP_K_RW_U_RW = 0x30, // APX: b0, AP: b11 Kernel Read/Write, User Read/Write 67 | PAGE_AP_NONE_DOMAIN = 0x40, // APX: b1, AP: b00 Domain fault encoded field 68 | PAGE_AP_K_R = 0x50, // APX: b1, AP: b01 Kernel Read Only, User None 69 | PAGE_AP_K_R_U_R = 0x60 // APX: b1, AP: b10 Kernel Read Only, User Read Only 70 | }; 71 | 72 | // Creates a section mapping (ONLY CALLABLE DURING INIT STAGE 1) 73 | void INIT_map_section(unsigned int* pt, unsigned int pa, unsigned int va, unsigned int flags) __attribute__((section(".text.init"))); 74 | 75 | // Creates a kernel page table that covers the top 2GB and a temporary ttb0 to use before 76 | // jumping into high memory (ONLY CALLABLE DURING INIT STAGE 1) 77 | int INIT_kernel_tt_setup(unsigned int* pt, unsigned int* tmp_ttb0) __attribute__((section(".text.init"))); 78 | 79 | // Creates a section mappin to the given virtual address 80 | void map_section(unsigned int* pt, unsigned int pa, unsigned int va, unsigned int flags); 81 | 82 | // Note: we expect pt to point towards section of USR_PT_SIZE allocated bytes 83 | void map_page(unsigned int* pt, unsigned int num_lvl1_entries, unsigned int pa, unsigned int va, unsigned int flags); 84 | 85 | // Prints out everything you'd ever want to know about a virtual address to a page and how it's mapped 86 | void mem_print_page_va_info(unsigned int* pt, unsigned int va); 87 | 88 | #endif -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | #include "stddef.h" 3 | #include "scheduler.h" 4 | #include "terminal.h" 5 | #include "types/string.h" 6 | #include "util/utilities.h" 7 | #include "hardware/paging.h" 8 | #include "asm.h" 9 | #include "hardware/mailbox.h" 10 | #include "syscalls.h" 11 | #include "memory_map.h" 12 | #include "hardware/framebuffer.h" 13 | 14 | // This variable makes sure we have something in the .data section, 15 | // Because we place .bss before data, this will make sure that the compiler 16 | // Zeroes out the .bss region for us, as it pads it with 0's 17 | volatile unsigned int dataVarForPadding = 42; 18 | 19 | void foo3() 20 | { 21 | unsigned int i; 22 | unsigned int num = 0; 23 | while (1) 24 | { 25 | printf("\rFoo3(%d)", num); 26 | num++; 27 | 28 | for (i = 0; i < 30000000; i++); 29 | 30 | volatile unsigned int asd = *(int*)(0x1000 + 4092); 31 | volatile unsigned int sff = *(int*)(0x2000 + 4092); 32 | volatile unsigned int fasa = *(int*)(0x3000 + 4092); 33 | // printf("Values: 0x%h, 0x%h, 0x%h\n", asd, sff, fasa); 34 | } 35 | } 36 | 37 | void foo2() 38 | { 39 | unsigned int i; 40 | unsigned int num = 0; 41 | while (1) 42 | { 43 | printf("\rFoo2(%d)", num); 44 | num++; 45 | 46 | for (i = 0; i < 30000000; i++); 47 | 48 | volatile unsigned int asd = *(int*)(0x1000 + 4092); 49 | volatile unsigned int sff = *(int*)(0x2000 + 4092); 50 | volatile unsigned int fasa = *(int*)(0x3000 + 4092); 51 | // printf("Values: 0x%h, 0x%h, 0x%h\n", asd, sff, fasa); 52 | } 53 | } 54 | 55 | void foo() 56 | { 57 | //thread* child = pios_thread_create((thread_entry)&foo3); 58 | 59 | //unsigned int va = KERNEL_VA_START + Scheduler_GetCurrentThread()->owner->mem_pages[0]; 60 | //printf("0x%h = 0x%h\n", va, *(unsigned int*)va); 61 | 62 | unsigned int i; 63 | unsigned int num = 0; 64 | while (1) 65 | { 66 | printf("\rFoo(%d)", num); 67 | num++; 68 | 69 | for (i = 0; i < 30000000; i++); 70 | 71 | // volatile unsigned int asd = *(int*)(0x1000 + 4092); 72 | // volatile unsigned int sff = *(int*)(0x2000 + 4092); 73 | // volatile unsigned int fasa = *(int*)(0x3000 + 4092); 74 | // printf("Values: 0x%h, 0x%h, 0x%h\n", asd, sff, fasa); 75 | } 76 | } 77 | 78 | void test_ttb0(void) 79 | { 80 | Process* p = Process_Create((unsigned int)&foo, "TTB0 Test", false); 81 | 82 | printf("Setting ttbc to 0x%h\n", p->ttb0_size); 83 | printf("Switching in ttb0, address: 0x%h\n", p->ttb0_physical); 84 | unsigned int ttbc = get_ttbc(); 85 | ttbc &= p->ttb0_size; 86 | set_ttbc(ttbc); 87 | set_ttb0(p->ttb0_physical, 1); 88 | 89 | FlushCache(); 90 | InvalidateAllUnlockedTLB(); 91 | FlushTLB(0x1000); 92 | 93 | printf("First entries: 0x%h 0x%h 0x%h\n", p->ttb0[0], p->ttb0[1], p->ttb0[2]); 94 | 95 | unsigned int bytesToCheck = PROCESS_START_PAGE_COUNT * LD_PAGE_SIZE; 96 | 97 | printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 98 | printf("Testing %d bytes (0x%h)\n", bytesToCheck, bytesToCheck); 99 | for (int i = 0; i < bytesToCheck; i++) 100 | { 101 | volatile int* k = *(int*)(0x1000 + i); 102 | } 103 | 104 | printf("Tested %d bytes (%d pages). No output = Good output\n", bytesToCheck, bytesToCheck / 4096); 105 | 106 | printf("Reading bottom of stack...\n"); 107 | int stackbottom = *(int*)(THREAD_STACK_VA_START - 4); 108 | } 109 | 110 | int cmain(void) 111 | { 112 | Uart_SendString("Initialization complete. Go main!\n"); 113 | 114 | Scheduler_Initialize(); 115 | 116 | Terminal_PrintWelcome(); 117 | Terminal_PrintPrompt(); 118 | 119 | Process* fooProcess = Process_Create((unsigned int)&foo, "Foo(Test)", true); 120 | if (fooProcess == NULL) 121 | printf("Failed to create foo task!\n"); 122 | 123 | Process* fooProcess2 = Process_Create((unsigned int)&foo2, "Foo2(Test)", true); 124 | if (fooProcess2 == NULL) 125 | printf("Failed to create foo2 task!\n" ); 126 | 127 | 128 | Process* fooProcess3 = Process_Create((unsigned int)&foo3, "Foo3(Test)", true); 129 | if (fooProcess3 == NULL) 130 | printf("Failed to create foo3 task!\n"); 131 | 132 | printf("Starting scheduler...\n"); 133 | Scheduler_Start(); 134 | 135 | unsigned int i; 136 | while (1) 137 | { 138 | Terminal_Update(); 139 | 140 | // Wait a bit 141 | for (i = 0; i < 10000; i++); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | TOOL = arm-none-eabi 2 | CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding --no-common -Wpadded -march=armv6j -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -fno-omit-frame-pointer -mno-thumb-interwork -mlong-calls -marm -g -std=gnu11 3 | LINKER_FLAGS = --no-wchar-size-warning --no-undefined 4 | 5 | ASSEMBLER_FLAGS = -march=armv6j -mfpu=vfp -mfloat-abi=hard 6 | 7 | LIBRARIES = 8 | BUILD_DIR = bin 9 | SOURCE_DIR = source 10 | INCLUDE_DIR = include 11 | OBJ_DIR := $(BUILD_DIR)/obj 12 | DEPENDENCY_DIR := $(BUILD_DIR)/dependencies 13 | LINK_SCRIPT_SRC = linker.c 14 | LINK_SCRIPT = $(BUILD_DIR)/memory.ld 15 | 16 | # Make sure gcc searches the include folder 17 | C_INCLUDE_PATH := $(shell find $(INCLUDE_DIR)/ -type d) 18 | C_INCLUDE_PATH += $(shell find $(SOURCE_DIR)/ -type d) 19 | 20 | GCC_INCLUDE = $(foreach d, $(C_INCLUDE_PATH), -I$d) 21 | 22 | export C_INCLUDE_PATH 23 | 24 | # When building C files, look in all subdirectories of source 25 | #VPATH := $(shell find $(SOURCE_DIR)/ -type d) 26 | # (And headers too!) 27 | #VPATH += $(shell find $(INCLUDE_DIR)/ -type d) 28 | null := 29 | SPACE := $(null) $(null) 30 | VPATH := $(subst $(SPACE),:,$(C_INCLUDE_PATH)) 31 | 32 | CHEADERS := $(shell find $(INCLUDE_DIR)/ -name '*.h') 33 | CSOURCE := $(shell find $(SOURCE_DIR)/ -name '*.c') 34 | ASOURCE := $(shell find $(SOURCE_DIR)/ -name '*.s') 35 | ASOURCE += $(shell find $(SOURCE_DIR)/ -name '*.S') 36 | 37 | _COBJECT := $(patsubst %.c,%.o, $(CSOURCE)) 38 | _AOBJECT := $(patsubst %.S,%.o, $(patsubst %.s,%.o, $(ASOURCE))) 39 | AOBJECT := $(addprefix $(OBJ_DIR)/, $(notdir $(_AOBJECT))) 40 | COBJECT := $(addprefix $(OBJ_DIR)/, $(notdir $(_COBJECT))) 41 | 42 | # To figure out why objects are being build, uncomment this: 43 | #OLD_SHELL := $(SHELL) 44 | #SHELL = $(warning [Evaluating target:'$@' Prereqs:'$^' Never:'$?'])$(OLD_SHELL) 45 | 46 | .PHONY: directories 47 | 48 | PiOS: directories $(BUILD_DIR)/kernel.img 49 | 50 | # Create the final binary 51 | $(BUILD_DIR)/kernel.img: $(BUILD_DIR)/kernel.elf $(BUILD_DIR)/kernel.elf.debug 52 | @echo Creating flat binary... 53 | @$(TOOL)-objcopy $(BUILD_DIR)/kernel.elf -O binary $(BUILD_DIR)/kernel.img 54 | 55 | # Create disassembly for ease of debugging 56 | debug: 57 | @echo Dumping disassembly... 58 | @$(TOOL)-objdump -D $(BUILD_DIR)/kernel.elf > $(BUILD_DIR)/disassembly 59 | 60 | @echo Dumping symbol table... 61 | @$(TOOL)-objdump -t $(BUILD_DIR)/kernel.elf | awk -F ' ' '{if(NF >= 2) print $$(1), "\t", $$(NF);}' > $(BUILD_DIR)/symbols.txt 62 | 63 | # Extract debugging symbols into separate file 64 | $(BUILD_DIR)/kernel.elf.debug: $(BUILD_DIR)/kernel.elf 65 | @$(TOOL)-objcopy --only-keep-debug $(BUILD_DIR)/kernel.elf $(BUILD_DIR)/kernel.elf.debug 66 | # @$(TOOL)-objcopy --strip-debug $(BUILD_DIR)/kernel.elf 67 | 68 | # Link all of the objects (Temporarily removed -l $(LIBRARIES)) 69 | $(BUILD_DIR)/kernel.elf: $(AOBJECT) $(COBJECT) $(LINK_SCRIPT) 70 | @echo Linking kernel.elf... 71 | @$(TOOL)-ld $(LINKER_FLAGS) $(AOBJECT) $(COBJECT) $(GCC_INCLUDE) -Map $(BUILD_DIR)/kernel.map -T $(LINK_SCRIPT) -o $(BUILD_DIR)/kernel.elf 72 | 73 | # Run the linker script through the preprocessor 74 | $(LINK_SCRIPT): $(LINK_SCRIPT_SRC) 75 | @echo Creating linker script... 76 | @$(TOOL)-gcc $< -o $@ -E -P $(GCC_INCLUDE) 77 | 78 | # If make was run previously, we will have .d dependency files 79 | # Describing wihich headers the objects depend on, import those targets 80 | 81 | -include $(addprefix $(DEPENDENCY_DIR)/, $(notdir $(COBJECT:.o=.d))) 82 | 83 | #build c files 84 | # The dependency stuff here is a hack, shouldn't have to do this? 85 | $(OBJ_DIR)/$(notdir %).o: %.c 86 | @echo Building $< 87 | @$(TOOL)-gcc -c $< -o $@ $(CFLAGS) $(GCC_INCLUDE) -MD -MF $(DEPENDENCY_DIR)/$*.d 88 | 89 | # Create a temp file 90 | @mv -f $(DEPENDENCY_DIR)/$*.d $(DEPENDENCY_DIR)/$*.d.tmp 91 | 92 | # Open dependency file, append OBJ_DIR to target and create empty targets for all dependencies 93 | # So that MAKE doesn't complain if a dependency is removed/renamed and still builds everything that used to depend on it 94 | @sed -e 's|.*: |$(OBJ_DIR)/$*.o:|' < $(DEPENDENCY_DIR)/$*.d.tmp > $(DEPENDENCY_DIR)/$*.d 95 | @sed -e 's/.*: //' -e 's/\\$$//' < $(DEPENDENCY_DIR)/$*.d.tmp | fmt -1 | sed -e 's/*//' -e 's/$$/: /' >> $(DEPENDENCY_DIR)/$*.d 96 | 97 | # Remove the temp file 98 | @rm -f $(DEPENDENCY_DIR)/$*.d.tmp 99 | 100 | #build s files (Assembly) 101 | $(OBJ_DIR)/%.o: %.s 102 | @echo Building $< 103 | @$(TOOL)-as $(ASSEMBLER_FLAGS) $< -o $@ 104 | 105 | # Uppercase S indicates header includes, run it through GCC instead of as 106 | $(OBJ_DIR)/%.o: %.S 107 | @echo "Building $< (gcc)" 108 | @$(TOOL)-gcc -P -E -c $< -o $@.s $(ASSEMBLER_FLAGS) $(GCC_INCLUDE) 109 | @$(TOOL)-as -c $@.s -o $@ $(ASSEMBLER_FLAGS) 110 | @rm $@.s 111 | 112 | directories: 113 | @mkdir -p $(OBJ_DIR) 114 | @mkdir -p $(DEPENDENCY_DIR) 115 | 116 | .PHONY: clean debug 117 | clean: 118 | @rm -rf $(BUILD_DIR)/* 119 | @rmdir $(BUILD_DIR) 120 | -------------------------------------------------------------------------------- /source/elf.c: -------------------------------------------------------------------------------- 1 | #include "elf.h" 2 | #include "memory.h" 3 | #include "types/string.h" 4 | #include "util/utilities.h" 5 | #include "debugging.h" 6 | #include "stddef.h" 7 | 8 | int elf_verify_header_ident(elf32_header* header) 9 | { 10 | // Header size 11 | if (header->ehsize != sizeof(elf32_header)) 12 | { 13 | printf("Unexpected header size\n"); 14 | return -1; 15 | } 16 | 17 | // Magic bytes 18 | if (*(int*)header->ident != ELF_MAGIC) 19 | { 20 | printf("Unexpected elf header\n"); 21 | return -1; 22 | } 23 | 24 | // Version 25 | if (header->ident[6] != EV_CURRENT) 26 | { 27 | printf("Invalid elf version\n"); 28 | return -1; 29 | } 30 | 31 | // Max segments 32 | if (header->phnum > EXE_MAX_SEGMENTS) 33 | { 34 | printf("Too many segments in header\n"); 35 | return -1; 36 | } 37 | 38 | // Machine type 39 | if (header->machine != EM_ARM) 40 | { 41 | printf("Invalid machine type\n"); 42 | return -1; 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | char* elf_get_sh_type(elf_shtype type) 49 | { 50 | switch (type) 51 | { 52 | case SHT_NULL: 53 | return "Empty"; 54 | case SHT_PROGBITS: 55 | return "Code"; 56 | case SHT_SYMTAB: 57 | return "Symbol table"; 58 | case SHT_STRTAB: 59 | return "String table"; 60 | case SHT_RELA: 61 | return "Relocation (addend)"; 62 | case SHT_REL: 63 | return "Relocation"; 64 | case SHT_HASH: 65 | return "Hash table"; 66 | case SHT_DYNAMIC: 67 | return "Dynamic"; 68 | case SHT_NOTE: 69 | return "Note"; 70 | case SHT_NOBITS: 71 | return "bss"; 72 | case SHT_SHLIB: 73 | return "reserved (shtlib)"; 74 | case SHT_DYNSYM: 75 | return "Symbol table (minimal)"; 76 | default: 77 | return "reserved/unknown"; 78 | } 79 | } 80 | 81 | int elf_get_func_info(char* elf, int elf_size, func_info** info) 82 | { 83 | elf32_header* header = (elf32_header*)elf; 84 | 85 | if (elf_verify_header_ident(header) != 0) 86 | return NULL; 87 | 88 | elf_shdr* shdrs = (elf_shdr*)&elf[header->shoff]; 89 | 90 | // Find the string table so we can resolve function names 91 | char* strtab = NULL; 92 | int numSymbols = 0; 93 | elf_sym* symtab = NULL; 94 | unsigned int i; 95 | for (i = 0; i < header->shnum; i++) 96 | { 97 | // TODO: This doesn't deal well with multiple STRTAB/SYMTAB 98 | if (shdrs[i].type == SHT_STRTAB && i != header->shstrndx) 99 | { 100 | strtab = elf + shdrs[i].offset; 101 | } 102 | 103 | if (shdrs[i].type == SHT_SYMTAB) 104 | { 105 | symtab = (elf_sym*)(elf + shdrs[i].offset); 106 | numSymbols = shdrs[i].size / shdrs[i].entsize; 107 | } 108 | } 109 | 110 | // Count number of functions 111 | int numFunctions = 0; 112 | for (i = 0; i < numSymbols; i++) 113 | { 114 | if (ELF32_ST_TYPE(symtab[i].info) == STT_FUNC && symtab[i].name > 0) 115 | numFunctions++; 116 | } 117 | 118 | // We now know the number of functions, we have the symbol table and the string table 119 | // Time to combine it all into the result 120 | *info = (func_info*)palloc(numFunctions * sizeof(func_info)); 121 | int curFuncIndex = 0; 122 | for (i = 0; i < numSymbols; i++) 123 | { 124 | // Skip irrelevant symbols 125 | if (ELF32_ST_TYPE(symtab[i].info) != STT_FUNC || symtab[i].name == 0) 126 | continue; 127 | 128 | elf_sym* sym = &symtab[i]; 129 | 130 | func_info* curFun = &(*info)[curFuncIndex++]; 131 | curFun->address = sym->value; 132 | 133 | char* name = strtab + sym->name; 134 | int nameLen = my_strlen(name); 135 | 136 | curFun->name = (char*)palloc(nameLen + 1); 137 | my_strcpy_s(curFun->name, nameLen + 1, name); 138 | } 139 | 140 | return numFunctions; 141 | } 142 | 143 | int elf_load(char* file, int file_size, unsigned int mem_base) 144 | { 145 | // Make sure the data is large enough 146 | if (file_size < sizeof(elf32_header) + sizeof(elf_ph)) 147 | { 148 | printf("File not large enough to be an elf.\n"); 149 | return -1; 150 | } 151 | 152 | // Parse & verify elf header 153 | elf32_header* header = (elf32_header*)file; 154 | if (elf_verify_header_ident(header) != 0) 155 | { 156 | printf("Invalid ELF header\n"); 157 | return -1; 158 | } 159 | 160 | elf_shdr* shdrs = (elf_shdr*)&file[header->shoff]; 161 | 162 | // Copy sections into memory 163 | unsigned int i; 164 | for (i = 0; i < header->shnum; i++) 165 | { 166 | elf_shdr* cur = &shdrs[i]; 167 | 168 | if ((cur->flags & SHF_ALLOC) != SHF_ALLOC) 169 | continue; // Skip sections that don't get loaded into memory 170 | 171 | unsigned int dest_addr = mem_base + cur->addr; 172 | 173 | if (cur->type == SHT_NOBITS) 174 | my_memset((char*)dest_addr, 0, cur->size); 175 | else 176 | my_memcpy((char*)dest_addr, &file[cur->offset], cur->size); 177 | } 178 | 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2009 Free Software Foundation, Inc. 2 | 3 | This file is part of GCC. 4 | 5 | GCC is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3, or (at your option) 8 | any later version. 9 | 10 | GCC is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | Under Section 7 of GPL version 3, you are granted additional 16 | permissions described in the GCC Runtime Library Exception, version 17 | 3.1, as published by the Free Software Foundation. 18 | 19 | You should have received a copy of the GNU General Public License and 20 | a copy of the GCC Runtime Library Exception along with this program; 21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 | . */ 23 | 24 | /* 25 | * ISO C Standard: 7.15 Variable arguments 26 | */ 27 | 28 | #ifndef _STDARG_H 29 | #ifndef _ANSI_STDARG_H_ 30 | #ifndef __need___va_list 31 | #define _STDARG_H 32 | #define _ANSI_STDARG_H_ 33 | #endif /* not __need___va_list */ 34 | #undef __need___va_list 35 | 36 | /* Define __gnuc_va_list. */ 37 | 38 | 39 | /* Define the standard macros for the user, 40 | if this invocation was from the user program. */ 41 | #ifdef _STDARG_H 42 | 43 | /* Hack to get intellisense to shut up about builtin_va_list */ 44 | #ifdef _MSC_VER 45 | #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) 46 | #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 47 | #define va_start _crt_va_start 48 | #define va_arg _crt_va_arg 49 | #define va_end _crt_va_end 50 | #else 51 | #ifndef __GNUC_VA_LIST 52 | #define __GNUC_VA_LIST 53 | typedef __builtin_va_list __gnuc_va_list; 54 | #endif 55 | 56 | #define va_start(v,l) __builtin_va_start(v,l) 57 | #define va_end(v) __builtin_va_end(v) 58 | #define va_arg(v,l) __builtin_va_arg(v,l) 59 | #if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L || defined(__GXX_EXPERIMENTAL_CXX0X__) 60 | #define va_copy(d,s) __builtin_va_copy(d,s) 61 | #endif 62 | #define __va_copy(d,s) __builtin_va_copy(d,s) 63 | #endif 64 | /* Define va_list, if desired, from __gnuc_va_list. */ 65 | /* We deliberately do not define va_list when called from 66 | stdio.h, because ANSI C says that stdio.h is not supposed to define 67 | va_list. stdio.h needs to have access to that data type, 68 | but must not use that name. It should use the name __gnuc_va_list, 69 | which is safe because it is reserved for the implementation. */ 70 | 71 | #ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ 72 | #undef _VA_LIST 73 | #endif 74 | 75 | #ifdef _BSD_VA_LIST 76 | #undef _BSD_VA_LIST 77 | #endif 78 | 79 | #if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) 80 | /* SVR4.2 uses _VA_LIST for an internal alias for va_list, 81 | so we must avoid testing it and setting it here. 82 | SVR4 uses _VA_LIST as a flag in stdarg.h, but we should 83 | have no conflict with that. */ 84 | #ifndef _VA_LIST_ 85 | #define _VA_LIST_ 86 | #ifdef __i860__ 87 | #ifndef _VA_LIST 88 | #define _VA_LIST va_list 89 | #endif 90 | #endif /* __i860__ */ 91 | typedef __gnuc_va_list va_list; 92 | #ifdef _SCO_DS 93 | #define __VA_LIST 94 | #endif 95 | #endif /* _VA_LIST_ */ 96 | #else /* not __svr4__ || _SCO_DS */ 97 | 98 | /* The macro _VA_LIST_ is the same thing used by this file in Ultrix. 99 | But on BSD NET2 we must not test or define or undef it. 100 | (Note that the comments in NET 2's ansi.h 101 | are incorrect for _VA_LIST_--see stdio.h!) */ 102 | #if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) 103 | /* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ 104 | #ifndef _VA_LIST_DEFINED 105 | /* The macro _VA_LIST is used in SCO Unix 3.2. */ 106 | #ifndef _VA_LIST 107 | /* The macro _VA_LIST_T_H is used in the Bull dpx2 */ 108 | #ifndef _VA_LIST_T_H 109 | /* The macro __va_list__ is used by BeOS. */ 110 | #ifndef __va_list__ 111 | #ifdef _MSC_VER 112 | typedef char * va_list; 113 | #else 114 | typedef __gnuc_va_list va_list; 115 | #endif 116 | #endif /* not __va_list__ */ 117 | #endif /* not _VA_LIST_T_H */ 118 | #endif /* not _VA_LIST */ 119 | #endif /* not _VA_LIST_DEFINED */ 120 | #if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) 121 | #define _VA_LIST_ 122 | #endif 123 | #ifndef _VA_LIST 124 | #define _VA_LIST 125 | #endif 126 | #ifndef _VA_LIST_DEFINED 127 | #define _VA_LIST_DEFINED 128 | #endif 129 | #ifndef _VA_LIST_T_H 130 | #define _VA_LIST_T_H 131 | #endif 132 | #ifndef __va_list__ 133 | #define __va_list__ 134 | #endif 135 | 136 | #endif /* not _VA_LIST_, except on certain systems */ 137 | 138 | #endif /* not __svr4__ */ 139 | 140 | #endif /* _STDARG_H */ 141 | 142 | #endif /* not _ANSI_STDARG_H_ */ 143 | #endif /* not _STDARG_H */ 144 | -------------------------------------------------------------------------------- /include/hardware/mailbox.h: -------------------------------------------------------------------------------- 1 | 2 | #define MAILBOX_FULL 0x80000000 3 | #define MAILBOX_EMPTY 0x40000000 4 | 5 | #define REQUEST_FLAG 0x00000000 6 | #define RESPONSE_SUCCESS 0x80000000 7 | #define RESPONSE_FAILURE 0x80000001 8 | 9 | // Unique Voltage Ids to use with Get/Set voltage messages 10 | typedef enum { 11 | MBV_RESERVED = 0x000000000, 12 | MBV_CORE = 0x000000001, 13 | MBV_SDRAM_C = 0x000000002, 14 | MBV_SDRAM_P = 0x000000003, 15 | MBV_SDRAM_I = 0x000000004 16 | } mb_voltage_id; 17 | 18 | typedef enum { 19 | MBC_ID_RESERVED = 0x000000000, 20 | MBC_ID_EMMC = 0x000000001, 21 | MBC_ID_UART = 0x000000002, 22 | MBC_ID_ARM = 0x000000003, 23 | MBC_ID_CORE = 0x000000004, 24 | MBC_ID_V3D = 0x000000005, 25 | MBC_ID_H264 = 0x000000006, 26 | MBC_ID_ISP = 0x000000007, 27 | MBC_ID_SDRAM = 0x000000008, 28 | MBC_ID_PIXEL = 0x000000009, 29 | MBC_ID_PWM = 0x00000000A, 30 | } mb_clock_id; 31 | 32 | typedef enum 33 | { 34 | MEM_FLAG_DISCARDABLE = 1 << 0, /* can be resized to 0 at any time. Use for cached data */ 35 | MEM_FLAG_NORMAL = 0 << 2, /* normal allocating alias. Don't use from ARM */ 36 | MEM_FLAG_DIRECT = 1 << 2, /* 0xC alias uncached */ 37 | MEM_FLAG_COHERENT = 2 << 2, /* 0x8 alias. Non-allocating in L2 but coherent */ 38 | MEM_FLAG_L1_NONALLOCATING = (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT), /* Allocating in L2 */ 39 | MEM_FLAG_ZERO = 1 << 4, /* initialise buffer to all zeros */ 40 | MEM_FLAG_NO_INIT = 1 << 5, /* don't initialise (default is initialise to all ones */ 41 | MEM_FLAG_HINT_PERMALOCK = 1 << 6, /* Likely to be locked for long periods of time. */ 42 | } mb_mem_flags; 43 | 44 | typedef enum { 45 | MBT_GET_BOARD_MODEL = 0x00010001, 46 | MBT_GET_BOARD_REVISION = 0x00010002, 47 | MBT_GET_BOARD_MAC = 0x00010003, 48 | MBT_GET_BOARD_SERIAL = 0x00010004, 49 | MBT_GET_ARM_MEMORY = 0x00010005, 50 | MBT_GET_VC_MEMORY = 0x00010006, 51 | MBT_GET_CLOCKS = 0x00010007, 52 | MBT_GET_CMDLINE = 0x00050001, 53 | MBT_GET_DMA_CHANS = 0x00060001, 54 | MBT_GET_POWER_STATE = 0x00020001, 55 | MBT_GET_TIMING = 0x00020002, 56 | MBT_SET_POWER_STATE = 0x00028001, 57 | MBT_GET_CLOCK_STATE = 0x00030001, 58 | MBT_SET_CLOCK_STATE = 0x00038001, 59 | MBT_GET_CLOCKRATE = 0x00030002, 60 | MBT_SET_CLOCKRATE = 0x00038002, 61 | MBT_GET_CLOCKRATE_MAX = 0x00030004, 62 | MBT_GET_CLOCKRATE_MIN = 0x00030007, 63 | MBT_GET_TURBO = 0x00030009, 64 | MBT_SET_TURBO = 0x00038009, 65 | MBT_GET_VOLTAGE = 0x00030003, 66 | MBT_SET_VOLTAGE = 0x00038003, 67 | MBT_GET_VOLTAGE_MAX = 0x00030005, 68 | MBT_GET_VOLTAGE_MIN = 0x00030008, 69 | MBT_GET_TEMP = 0x00030006, 70 | MBT_GET_TEMP_MAX = 0x0003000A, 71 | MBT_ALLOC_MEMORY = 0x0003000C, 72 | MBT_LOCK_MEMORY = 0x0003000D, 73 | MBT_UNLOCK_MEMORY = 0x0003000E, 74 | MBT_RELEASE_MEMORY = 0x0003000F, 75 | MBT_EXECUTE_CODE = 0x00030010, 76 | MBT_FB_ALLOC = 0x00040001, 77 | MBT_FB_RELEASE = 0x00048001, 78 | MBT_FB_BLANK = 0x00040002, 79 | MBT_FB_GET_PHYSIZE = 0x00040003, 80 | MBT_FB_TST_PHYSIZe = 0x00044003, 81 | MBT_FB_SET_PHYSIZE = 0x00048003, 82 | MBT_FB_GET_VIRTSIZE = 0x00040004, 83 | MBT_FB_TST_VIRTSIZE = 0x00044004, 84 | MBT_FB_SET_VIRTSIZE = 0x00048004, 85 | MBT_FB_GET_DEPTH = 0x00040005, 86 | MBT_FB_TST_DEPTH = 0x00044005, 87 | MBT_FB_SET_DEPTH = 0x00048005, 88 | MBT_FB_GET_PIXEL_ORDER = 0x00040006, 89 | MBT_FB_TST_PIXEL_ORDER = 0x00044006, 90 | MBT_FB_SET_PIXEL_ORDER = 0x00048006, 91 | MBT_FB_GET_ALPHA_MODE = 0x00040007, 92 | MBT_FB_TST_ALPHA_MODE = 0x00044007, 93 | MBT_FB_SET_ALPHA_MODE = 0x00048007, 94 | MBT_FB_GET_PITCH = 0x00040008, 95 | MBT_FB_GET_VIRT_OFFSET = 0x00040009, 96 | MBT_FB_TST_VIRT_OFFSET = 0x00044009, 97 | MBT_FB_SET_VIRT_OFFSET = 0x00048009, 98 | MBT_FB_GET_OVERSCAN = 0x0004000A, 99 | MBT_FB_TST_OVERSCAN = 0x0004400A, 100 | MBT_FB_SET_OVERSCAN = 0x0004800a, 101 | MBT_FB_GET_PALETTE = 0x0004000B, 102 | MBT_FB_TST_PALETTE = 0x0004400B, 103 | MBT_FB_SET_PALETTE = 0x0004800B, 104 | } mailbox_tag; 105 | 106 | // Device Ids for power management 107 | typedef enum { 108 | HwId_Emmc = 0x00000000, 109 | HwId_Uart0 = 0x00000001, 110 | HwId_Uart1 = 0x00000002, 111 | HwId_UsbHcd = 0x00000003, 112 | HwId_I2c0 = 0x00000004, 113 | HwId_I2c1 = 0x00000005, 114 | HwId_I2c2 = 0x00000006, 115 | HwId_Spi = 0x00000007, 116 | HwId_Ccp2tx = 0x00000008 117 | } HardwareId; 118 | 119 | typedef enum { 120 | // Setting 121 | HwPowerState_OffDontWait = 0, 122 | HwPowerState_OffWait = 1, 123 | HwPowerState_OnDontWait = 2, 124 | HwPowerState_OnWait = 3, 125 | 126 | // Status result 127 | HwPowerState_OffExists = 0, 128 | HwPowerState_OffDoesntExist = 1, 129 | HwPowerState_OnExists = 2, 130 | HwPowerState_OnDoesntExist = 3, 131 | } HardwarePowerState; 132 | 133 | void Mailbox_Write(unsigned int channel, unsigned int data); 134 | unsigned int Mailbox_Read(unsigned int channel); 135 | unsigned int Mailbox_GetPowerState(unsigned int deviceId); 136 | int Mailbox_SetDevicePowerState(unsigned int deviceId, unsigned int powerState); 137 | int Mailbox_GetClockRate(unsigned int clockId); 138 | 139 | unsigned int Mailbox_SdGetBaseFrequency(void); 140 | -------------------------------------------------------------------------------- /source/mem.c: -------------------------------------------------------------------------------- 1 | /* 2 | Runtime memory map manager 3 | This allocator works in 4KB chunks, any and all pages allocated/freed by 4 | it will be 4 KB in size. Though it works in page-sized chunks, the memory 5 | addresses handled by this allocator are PHYSICAL. 6 | 7 | The pfa_Reserve* functions are meant to be permanent, so they are not expected 8 | to be freed, because of this, the only thing returned is a status code. 9 | ONLY important kernel memory that is never expected to move should be reserved 10 | (i.e kernel code, framebufferetc). 11 | 12 | NOTE: Peripherals need not be mapped as they are outside the physical memory range 13 | */ 14 | 15 | #include "mem.h" 16 | #include "memory.h" 17 | #include "types/string.h" 18 | 19 | // TODO: Make this a bitmap instead of int array 20 | int* gPages; 21 | 22 | static inline unsigned int pfa_GetFirstAddrOfPage(unsigned int pageIndex) 23 | { 24 | return pageIndex * PAGE_SIZE; 25 | } 26 | 27 | static inline unsigned int pfa_GetPageIndexOfAddr(unsigned int addr) 28 | { 29 | return addr / PAGE_SIZE; 30 | } 31 | 32 | int mem_init(void) 33 | { 34 | gPages = (int*)pcalloc(sizeof(int), MAX_ALLOCATED_PAGES); 35 | } 36 | 37 | // Returns the next available page 38 | int mem_nextFree(void) 39 | { 40 | unsigned int i; 41 | for (i = 0; i < MAX_ALLOCATED_PAGES; i++) 42 | { 43 | if (gPages[i] == 0) 44 | { 45 | // Mark as used 46 | gPages[i] = 1; 47 | 48 | #ifdef PAGEMEM_DEBUG 49 | printf("Found free page %d\n", i); 50 | #endif 51 | 52 | return pfa_GetFirstAddrOfPage(i); 53 | } 54 | } 55 | 56 | return -1; 57 | } 58 | 59 | int mem_nextFreeContiguous(unsigned int num_pages) 60 | { 61 | int start_page = -1; 62 | 63 | unsigned int i; 64 | unsigned int contiguous_found = 0; 65 | for (i = 0; i < MAX_ALLOCATED_PAGES; i++) 66 | { 67 | if (gPages[i] == 0) 68 | { 69 | if (start_page == -1) 70 | start_page = i; 71 | 72 | contiguous_found++; 73 | } 74 | else 75 | { 76 | contiguous_found = 0; 77 | } 78 | 79 | if (start_page != -1 && contiguous_found == num_pages) 80 | { 81 | for (i = 0; i < num_pages; i++) 82 | gPages[start_page + i] = 1; 83 | 84 | return pfa_GetFirstAddrOfPage(start_page); 85 | } 86 | } 87 | 88 | return -1; 89 | } 90 | 91 | // Frees the page that covers the given physical address 92 | void mem_free(unsigned int addr) 93 | { 94 | unsigned pageIndex = pfa_GetPageIndexOfAddr(addr); 95 | 96 | // Mark as unused, tadaaa! 97 | gPages[pageIndex] = 0; 98 | 99 | #ifdef PAGEMEM_DEBUG 100 | printf("Freeing page %d\n", pageIndex); 101 | #endif 102 | 103 | } 104 | 105 | // Marks the page that covers addr as used 106 | int mem_reserveSingle(unsigned int addr) 107 | { 108 | unsigned int pageIndex = pfa_GetPageIndexOfAddr(addr); 109 | 110 | if (gPages[pageIndex] == 1) 111 | return -1; 112 | 113 | gPages[pageIndex] = 1; 114 | 115 | #ifdef PAGEMEM_DEBUG 116 | printf("Reserving page %d\n", pageIndex); 117 | #endif 118 | 119 | return 0; 120 | } 121 | 122 | int mem_reserveRange(unsigned int startAddr, unsigned int endAddr) 123 | { 124 | if (startAddr > endAddr) 125 | { 126 | printf("Invalid call to pfa_ReserveRange, startAddr(%d) must be lower than endAddr(%d)\n", startAddr, endAddr); 127 | return -1; 128 | } 129 | 130 | unsigned int startIndex = pfa_GetPageIndexOfAddr(startAddr); 131 | unsigned int endIndex = pfa_GetPageIndexOfAddr(endAddr); 132 | 133 | // First make sure they're all available 134 | unsigned int i = startIndex; 135 | for (; i <= endIndex; i++) 136 | { 137 | if (gPages[i] == 1) 138 | { 139 | printf("Ooops! Trying to reserve page '%d' in pfa_ReserveRange that's already allocated!\n", i); 140 | return -1; 141 | } 142 | } 143 | 144 | // Actually allocate the pages 145 | for (i = startIndex; i <= endIndex; i++) 146 | gPages[i] = 1; 147 | 148 | #ifdef PAGEMEM_DEBUG 149 | printf("Reserved pages %d->%d\n", startIndex, endIndex); 150 | #endif 151 | 152 | return 0; 153 | } 154 | 155 | int mem_reserve(unsigned int startAddr, unsigned int size) 156 | { 157 | if (size == 0) return -1; 158 | 159 | unsigned int endAddr = startAddr + size; 160 | 161 | return mem_reserveRange(startAddr, endAddr); 162 | } 163 | 164 | unsigned int mem_getAllocated(void) 165 | { 166 | unsigned int allocatedPages = 0; 167 | unsigned int i; 168 | for (i = 0; i < MAX_ALLOCATED_PAGES; i++) 169 | { 170 | if (gPages[i] == 1) allocatedPages++; 171 | } 172 | 173 | return allocatedPages * PAGE_SIZE; 174 | } 175 | 176 | unsigned int mem_getAvailable(void) 177 | { 178 | int allocatedMemory = mem_getAllocated(); 179 | 180 | return MAX_AVAILABLE_MEMORY - allocatedMemory; 181 | } 182 | 183 | void mem_printUsage(void) 184 | { 185 | unsigned int allocated = mem_getAllocated(); 186 | 187 | if (allocated > 1048576) // Show MB 188 | { 189 | printf("mem stat: %d/%d mB allocated\n", allocated / 1024 / 1024, MAX_AVAILABLE_MEMORY / 1024 / 1024); 190 | } 191 | else if (allocated > 1024) // Show KB 192 | { 193 | printf("mem stat: %d/%d kB allocated\n", allocated / 1024, MAX_AVAILABLE_MEMORY / 1024); 194 | } 195 | else // Bytes 196 | { 197 | printf("mem stat: %d/%d bytes allocated\n", allocated, MAX_AVAILABLE_MEMORY); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /source/scheduler.c: -------------------------------------------------------------------------------- 1 | #include "util/utilities.h" 2 | #include "asm.h" 3 | #include "main.h" 4 | #include "mem.h" 5 | #include "memory.h" 6 | #include "memory_map.h" 7 | #include "scheduler.h" 8 | #include "stddef.h" 9 | #include "hardware/interrupts.h" 10 | #include "hardware/mmu_c.h" 11 | #include "hardware/timer.h" 12 | #include "types/string.h" 13 | #include "types/queue.h" 14 | #include "thread.h" 15 | #include "process.h" 16 | #include "thread.h" 17 | 18 | static taskScheduler* gScheduler; 19 | static unsigned int gNextTID; 20 | 21 | void Scheduler_PrintRegs(thread_regs* regs) 22 | { 23 | printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 24 | printf("0x%h r0: 0x%h\n", ®s->r0, regs->r0); 25 | printf("0x%h r1: 0x%h\n", ®s->r1, regs->r1); 26 | printf("0x%h r2: 0x%h\n", ®s->r2, regs->r2); 27 | printf("0x%h r3: 0x%h\n", ®s->r3, regs->r3); 28 | printf("0x%h r4: 0x%h\n", ®s->r4, regs->r4); 29 | printf("0x%h r5: 0x%h\n", ®s->r5, regs->r5); 30 | printf("0x%h r6: 0x%h\n", ®s->r6, regs->r6); 31 | printf("0x%h r7: 0x%h\n", ®s->r7, regs->r7); 32 | printf("0x%h r8: 0x%h\n", ®s->r8, regs->r8); 33 | printf("0x%h r9: 0x%h\n", ®s->r9, regs->r9); 34 | printf("0x%h r10: 0x%h\n", ®s->r10, regs->r10); 35 | printf("0x%h r11: 0x%h\n", ®s->r11, regs->r11); 36 | printf("0x%h r12: 0x%h\n", ®s->r12, regs->r12); 37 | printf("0x%h LR: 0x%h\n", ®s->lr, regs->lr); 38 | 39 | printf("0x%h lr2: 0x%h\n", ®s->lr2, regs->lr2); 40 | printf("0x%h SPRS: 0x%h\n", ®s->sprs, regs->sprs); 41 | printf("0x%h SP: 0x%h\n", ®s->sp, regs->sp); 42 | printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 43 | } 44 | 45 | void Scheduler_Initialize(void) 46 | { 47 | gScheduler = (taskScheduler*)palloc(sizeof(taskScheduler)); 48 | gScheduler->currentThread = NULL; 49 | gScheduler->threads.back = NULL; 50 | gScheduler->threads.front = NULL; 51 | gScheduler->threads.numNodes = 0; 52 | 53 | gNextTID = 1; 54 | } 55 | 56 | void Scheduler_Start(void) 57 | { 58 | Timer_Clear(); 59 | Timer_SetInterval(TASK_SCHEDULER_TICK_MS); 60 | Arm_IrqEnable(interrupt_source_system_timer); 61 | 62 | // Switch in first task? 63 | } 64 | 65 | unsigned int Scheduler_GetNextTID(void) 66 | { 67 | // For now: Just an incremental integer, need to do someting better in the future 68 | return gNextTID++; 69 | } 70 | 71 | // This is obsolete, don't use it? Should enqueue threads instead 72 | void Scheduler_Enqueue(Process* task) 73 | { 74 | // Add it to the queue for processing 75 | Queue_Enqueue(&gScheduler->threads, task->mainThread); 76 | } 77 | 78 | void Scheduler_NextTask(thread_regs* reg) 79 | { 80 | //printf("Scheduler - cpsr is: 0x%h\n", reg->sprs); 81 | 82 | unsigned int shouldSwitchTask = 0; 83 | thread* cur = gScheduler->currentThread; 84 | if (cur != NULL && gScheduler->threads.numNodes > 0) 85 | { 86 | //printf("Scheduler: Have a current running task!\n"); 87 | 88 | cur->timeElapsed += TASK_SCHEDULER_TICK_MS; 89 | 90 | // Has this task had it's fair share? 91 | if (cur->timeElapsed >= (TASK_SCHEDULER_TICK_MS * 2)) 92 | { 93 | //printf("Scheduler: Switching out %s\n", cur->name); 94 | 95 | shouldSwitchTask = 1; 96 | 97 | // Save registers 98 | my_memcpy(&cur->registers, reg, sizeof(thread_regs)); 99 | 100 | //printf("saved registers, sp: 0x%h\n", cur->registers.sp); 101 | 102 | cur->state = TS_Ready; 103 | cur->isRunning = false; 104 | 105 | // Put it back in the queue 106 | Queue_Enqueue(&gScheduler->threads, cur); 107 | } 108 | } 109 | else if (cur == NULL) 110 | { 111 | //printf("Scheduler: First run? Switch to a task!\n"); 112 | shouldSwitchTask = 1; 113 | } 114 | 115 | if (!shouldSwitchTask || gScheduler->threads.numNodes == 0) 116 | return; 117 | 118 | //printf("Registers before: \n"); 119 | //Scheduler_PrintRegs(reg); 120 | 121 | thread* next = (thread*)Queue_Dequeue(&gScheduler->threads); 122 | 123 | if (next == NULL) 124 | { 125 | printf("Failed to retrieve next thread, how can it be null!? Skippin CTX switch...\n"); 126 | return; 127 | } 128 | 129 | //printf("Scheduler: Switching in %s\n", next->name); 130 | 131 | next->isRunning = true; 132 | next->state = TS_Running; 133 | gScheduler->currentThread = next; 134 | 135 | //printf("Scheduler - Setting SPSR to: 0x%h\n", next->registers.sprs); 136 | //printf("Updating TTBC, Size: %d\n", next->ttb0_size); 137 | 138 | // Update TTCR 139 | unsigned int ttbc = get_ttbc(); 140 | ttbc = next->owner->ttb0_size; 141 | set_ttbc(ttbc); 142 | //printf("Set ttbc to: 0x%h\n", ttbc); 143 | 144 | // Switch in the process' TT 145 | //printf("Switch to task's TTB0, ttb0 addr (Physical): 0x%h\n", next->ttb0_physical); 146 | set_ttb0(next->owner->ttb0_physical, 1); 147 | 148 | for (int i = 0; i < 1000; i++); 149 | 150 | // Restore the tasks registers 151 | my_memcpy(reg, &next->registers, sizeof(thread_regs)); 152 | 153 | //printf("\n* * Switching in thread '%s' in process %s * *\n", next->name, next->owner->name); 154 | //Scheduler_PrintRegs(reg); 155 | } 156 | 157 | void Scheduler_TimerTick(thread_regs* regs) 158 | { 159 | // A switch isn't necessary 160 | if (gScheduler->threads.numNodes == 0 && gScheduler->currentThread != NULL) 161 | { 162 | printf("Scheduler: Not enough threads running to bother...\n"); 163 | } 164 | else 165 | { 166 | Scheduler_NextTask(regs); 167 | } 168 | 169 | // Restart the timer 170 | Timer_Clear(); 171 | Timer_SetInterval(TASK_SCHEDULER_TICK_MS * 2); 172 | Arm_IrqEnable(interrupt_source_system_timer); // Don't think I have to do this? 173 | } 174 | 175 | thread* Scheduler_GetCurrentThread(void) 176 | { 177 | return gScheduler->currentThread; 178 | } -------------------------------------------------------------------------------- /source/hardware/paging.c: -------------------------------------------------------------------------------- 1 | #include "hardware/paging.h" 2 | #include "asm.h" 3 | #include "types/string.h" 4 | #include "hardware/uart.h" 5 | #include "mem.h" 6 | 7 | void map_page(unsigned int* pt, unsigned int num_lvl1_entries, unsigned int pa, unsigned int va, unsigned int flags) 8 | { 9 | unsigned int* physical_tt = ((unsigned int)pt) - KERNEL_VA_START; 10 | 11 | // The shifts of the virtual address explained: 12 | // 31:20 map into lvl 1 table 13 | // 19:12 map into lvl 2 page 14 | // 11:0 index into the lvl 2 page (Not relevant to us) 15 | unsigned int lvl1_index = va >> 20; 16 | unsigned int* lvl1_entry = (physical_tt + lvl1_index); 17 | unsigned int* lvl1_entry_va = (pt + lvl1_index); 18 | 19 | // TODO: Check to make sure that it actually fits into the page table, or if we need to expand it (reallocate a series of more pages, update ttbc etc) 20 | // Level 2 entries start on the first clean page after the end of the level 1 entries 21 | unsigned int lvl1_entries_num_pages = num_lvl1_entries / PAGE_SIZE; 22 | 23 | // Might not fit exactly into pages, add one if the level 1 entries spills over into a page 24 | lvl1_entries_num_pages += (num_lvl1_entries % PAGE_SIZE) == 0 ? 0 : 1; 25 | 26 | unsigned int level2_entries_start_addr = ((unsigned int)physical_tt) + (lvl1_entries_num_pages * PAGE_SIZE); 27 | unsigned int level2_entries_start_addr_va = level2_entries_start_addr + KERNEL_VA_START; 28 | 29 | unsigned int lvl2_index = (va >> 12) & 0xFF; 30 | unsigned int* lvl2_entry = (unsigned int*)(level2_entries_start_addr + ( (lvl1_index * 256) * sizeof(int) ) + (lvl2_index << 2 ) ); 31 | unsigned int* lvl2_entry_va = ((unsigned int)lvl2_entry) + KERNEL_VA_START; 32 | 33 | // Make sure the level 1 entry is initialized 34 | if ((*lvl1_entry_va & PAGE_TABLE_MASK) == 0) 35 | { 36 | *lvl1_entry_va = (((unsigned int)lvl2_entry) & 0xFFFFFC00) | PAGE_TABLE_COARSE; 37 | //*lvl1_entry_va = ((((unsigned int)lvl2_entry) & 0x3FFFFF) << 10) | PAGE_TABLE_COARSE; 38 | } 39 | 40 | unsigned int entry = (pa & 0xFFFFF000) | PAGE_SMALL | flags; 41 | 42 | // Set the value of the level 2 entry 43 | *lvl2_entry_va = entry; 44 | 45 | #ifdef PAGEMEM_DEBUG 46 | printf("Mapped 0x%h (0x%h) to 0x%h: lvl1: 0x%h(at 0x%h) lvl2: 0x%h(at 0x%h) ~ TT addr: 0x%h\n", pa, (pa & 0xFFFFF000), va, *lvl1_entry_va, lvl1_entry, 47 | *lvl2_entry_va, lvl2_entry, pt); 48 | #endif 49 | } 50 | 51 | void map_section(unsigned int* pt, unsigned int pa, unsigned int va, unsigned int flags) 52 | { 53 | unsigned int va_base = (va >> 20) & 0xFFF; 54 | unsigned int pa_base = (pa >> 20) & 0xFFF; 55 | 56 | *(pt + va_base) = (pa_base << 20) | PAGE_TABLE_SECTION | flags; 57 | } 58 | 59 | // NOTE: This is placed in low memory and NOT acessible after initialization 60 | void INIT_map_section(unsigned int* pt, unsigned int pa, unsigned int va, unsigned int flags) 61 | { 62 | unsigned int va_base = (va >> 20) & 0xFFF; 63 | unsigned int pa_base = (pa >> 20) & 0xFFF; 64 | 65 | *(pt + va_base) = (pa_base << 20) | PAGE_TABLE_SECTION | flags; 66 | } 67 | 68 | int INIT_kernel_tt_setup(unsigned int* ttb1, unsigned int* tmp_ttb0) 69 | { 70 | // Kernel 71 | unsigned int i; 72 | for (i = 0; i < TTB_SIZE_4GB_SIZE; i++) 73 | *(ttb1 + i) = PAGE_TABLE_FAULT; // STMIA? 74 | 75 | // First things first - Create the persistent TTB1 and fill it with 1MB sections covering the first 200MB 76 | for (i = 0; i < 200; i++) 77 | INIT_map_section(ttb1, (i << 20), KERNEL_VA_START + (i << 20), PAGE_CACHEABLE | PAGE_BUFFERABLE | SECTION_AP_K_RW); 78 | 79 | // Addtionally, add 256 1MB sections to cover the peripherals 80 | for (i = 0; i < 256; i++) 81 | INIT_map_section(ttb1, PERIPHERAL_PA_START + (i << 20), PERIPHERAL_VA_START + (i << 20), SECTION_AP_K_RW); 82 | 83 | // Create temporary ttb0 with identity mapping that will be used 84 | // during the very early stages of boot while we're enabling paging 85 | // and before we have a chance to jump into the high-memory mapping of the kernel 86 | // Note that TTB0 does NOT map the peripherals, we have to jump to high-memory before accessing them 87 | for (i = 0; i < 20; i++) 88 | INIT_map_section(tmp_ttb0, (i << 20), (i << 20), PAGE_CACHEABLE | PAGE_BUFFERABLE | SECTION_AP_K_RW); 89 | 90 | // Qemu Frame buffer 91 | unsigned int qemuFbAddress2 = 0x1C100000; 92 | for(i = 0; i < 2; i++) 93 | INIT_map_section(ttb1, qemuFbAddress2 + (i << 20), FRAMEBUFFER_VA_START + (i << 20), SECTION_AP_K_RW); 94 | 95 | return 0; 96 | } 97 | 98 | void mem_print_page_va_info(unsigned int* pt, unsigned int va) 99 | { 100 | // This function basically does the same as the MMU would when performing a 101 | // second level page table walk over Extended 4KB ARMv6 small pages. 102 | // Note: The pt param is assumed to point to a Translation table containing coarse table entries. 103 | printf("Info for Virtual Address: 0x%h\n", va); 104 | printf("Translation table base: 0x%h\n", pt); 105 | 106 | unsigned int first_level_table_index = (va >> 20) & 0xFFF; 107 | unsigned int second_level_table_index = (va >> 12) & 0x7F; 108 | unsigned int page_index = (va & 0xFFF); 109 | printf("First level table index: 0x%h\n", first_level_table_index); 110 | printf("Second level table index: 0x%h\n", second_level_table_index); 111 | printf("Page index: 0x%h\n", page_index); 112 | 113 | unsigned int* first_level_descriptor = (unsigned int*)(((unsigned int)pt) + (first_level_table_index << 2)); 114 | printf("First level descriptor address: 0x%h\n", first_level_descriptor); 115 | printf("First level descriptor: 0x%h\n", *first_level_descriptor); 116 | 117 | unsigned int coarse_table_base_addr = ((*first_level_descriptor >> 10) & 0x3FFFFF); 118 | printf("Coarse table base address: 0x%h ( 0x%h )\n", coarse_table_base_addr, (coarse_table_base_addr << 10)); 119 | 120 | unsigned int* second_level_descriptor = (unsigned int*)((coarse_table_base_addr << 10) | (second_level_table_index << 2)); 121 | 122 | printf("Second level descriptor address: 0x%h\n", second_level_descriptor); 123 | printf("Second level descriptor: 0x%h\n", *second_level_descriptor); 124 | 125 | unsigned int physical_address = ((*second_level_descriptor & 0xFFFFF000) | page_index); 126 | 127 | // Note: this relies on the kernel ttb1 to identity map physical memory to KERNEL_VA_START 128 | printf("Physical address: 0x%h, Value: 0x%h\n", physical_address, *((unsigned int*)(KERNEL_VA_START + physical_address))); 129 | } 130 | -------------------------------------------------------------------------------- /source/init.c: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | #include "atags.h" 3 | #include "debugging.h" 4 | #include "fs/fat32driver.h" 5 | #include "fs/fs.h" 6 | #include "init.h" 7 | #include "hardware/framebuffer.h" 8 | #include "hardware/interrupts.h" 9 | #include "hardware/uart.h" 10 | #include "hardware/paging.h" 11 | #include "hardware/timer.h" 12 | #include "hardware/device/sdBlockDevice.h" 13 | #include "main.h" 14 | #include "mem.h" 15 | #include "memory.h" 16 | #include "memory_map.h" 17 | #include "syscalls.h" 18 | #include "types/string.h" 19 | #include "terminal.h" 20 | 21 | extern unsigned int LNK_KERNEL_END; 22 | 23 | __attribute__((naked, aligned(32))) static void interrupt_vector(void) 24 | { 25 | asm volatile("b reset\n" // Reset 26 | "b undefined\n" // Undefined 27 | "b swi\n" // SWI 28 | "b instruction_abort\n" // Instruction abort 29 | "b data_abort \n" // Data abort 30 | "b hang\n" // Unused 31 | "b irq\n" // IRQ 32 | "b hang\n" // FIQ 33 | ); 34 | } 35 | 36 | void sysinit_stage1(int machineType, int aTagsPA, int dbgsymboladdr) 37 | { 38 | // First thing we want to do is map the kernel and peripherals into high memory 39 | unsigned int* basePageTable = (unsigned int *)KERNEL_PA_PT; 40 | unsigned int* tmp_ttb0 = (unsigned int*)KERNEL_PA_TMP_TTB0; 41 | 42 | // (This also sets up a temporary mapping for ttb0 that we trash once we're in high memory) 43 | INIT_kernel_tt_setup(basePageTable, tmp_ttb0); 44 | 45 | // Enable MMU - Note this MUST be called from the sysinit() function chain 46 | // As this function never returns. If called from a returning function 47 | // That messes with the Frame Pointer (basically any C function) 48 | // The return from that function will reset SP to the physical address of the 49 | // FP and not the Virtual address set up by do_mmu 50 | do_mmu(tmp_ttb0, basePageTable, TTBC_SPLIT_8KB); 51 | 52 | // Memory is all set up, time to branch into high memory 53 | // to move to stage 2 of initialization 54 | sysinit_stage2(machineType, aTagsPA, dbgsymboladdr); 55 | } 56 | 57 | void sysinit_stage2(int machineType, int atagsPa, int dbgsymboladdr) 58 | { 59 | // Setup the interrupt vector 60 | asm volatile("mcr p15, 0, %[addr], c12, c0, 0" : : [addr] "r" (&interrupt_vector)); 61 | 62 | volatile unsigned int usrStartValBefore = *(unsigned int*)0x100000; 63 | volatile unsigned int usr2StartValBefore = *(unsigned int*)0x200000; 64 | 65 | // TODO: Trash the temporary TTB0, we shouldn't need it past this point 66 | // Currently I think the emmc driver uses a hardcoded buffer in low memory 67 | unsigned int cur = 0; 68 | for (cur = 0; cur < 8192; cur++) 69 | *(char*)KERNEL_PA_TMP_TTB0 = 0; 70 | 71 | // First things first, enable the serial so we can send the deployer some feedback 72 | Uart_Initialize(); 73 | Uart_EnableInterrupts(); 74 | Arm_InterruptInitialize(); 75 | Arm_IrqDisableall(); 76 | Arm_IrqEnable(interrupt_source_uart); 77 | enable_irq(); 78 | 79 | Uart_SendString("Welcome to PiOS!\n\n"); 80 | 81 | Pallocator_Initialize(); 82 | 83 | // Initialize page allocator 84 | mem_init(); 85 | 86 | // Calculate kernel size 87 | unsigned int kernel_physical_end = &LNK_KERNEL_END; 88 | kernel_physical_end -= KERNEL_VA_START; 89 | unsigned int kernel_size = kernel_physical_end - LD_KRNL_ORIGIN; 90 | 91 | // Reserve kernel regions of the memory in the page allocator 92 | mem_reserve(0x0, 0x2000); // Reserve the first 3 pages, contains boot parameters and such 93 | mem_reserve(FIQ_STACK_PA_START - SMALL_STACK_SIZE, SMALL_STACK_SIZE); 94 | mem_reserve(0x5000, 0x100); 95 | mem_reserve(IRQ_STACK_PA_START - SMALL_STACK_SIZE, SMALL_STACK_SIZE); 96 | mem_reserve(LD_KRNL_ORIGIN, kernel_size); 97 | mem_reserve(KERNEL_PA_PT, TTB_SIZE_4GB_SIZE + (TTB_SIZE_4GB_SIZE * 256)); 98 | mem_reserve(SVC_STACK_PA_START - SMALL_STACK_SIZE, SMALL_STACK_SIZE); 99 | mem_reserve(UD_STACK_PA_START - SMALL_STACK_SIZE, SMALL_STACK_SIZE); 100 | mem_reserve(ABORT_STACK_PA_START - SMALL_STACK_SIZE, SMALL_STACK_SIZE); 101 | // Pallocator (TODO: Pallocator should dynamically request pages as and when needed 102 | // instead of reserving a mahossive chunk straight up) 103 | mem_reserve(DYN_MEM_PA_START, MAX_ALLOCATED_BYTES); 104 | 105 | mem_reserve(SM_STACK_PA_START - SMALL_STACK_SIZE, SMALL_STACK_SIZE); 106 | // TODO: Need to allocate all static things, see memory_map.h 107 | 108 | char* dbgSymbolsVa = (char*)(KERNEL_VA_START + dbgsymboladdr); 109 | Debug_ReadFunctionNames(dbgSymbolsVa); 110 | // Initialize terminal first so we can print error messages if any (Hah, unlikely!) 111 | if(Terminal_Initialize() != 0) 112 | { 113 | Uart_SendString("Failed to initialize terminal\n"); 114 | } 115 | 116 | // Reserve physical pages for framebuffer 117 | mem_reserve(Fb_GetPhyAddr(), Fb_GetSize()); 118 | 119 | Fb_Clear(); 120 | Terminal_Clear(); 121 | 122 | printf("Kernel size: %d\n", kernel_size); 123 | 124 | // Example usage of timer to measure performance 125 | long long start = Timer_GetTicks(); 126 | 127 | // Initialize the SD card and filesystem 128 | BlockDevice* sd = (BlockDevice*)palloc(sizeof(BlockDevice)); 129 | 130 | if(sd == 0) 131 | { 132 | Uart_SendString("Failed to allocate memory for SD device\n"); 133 | } 134 | else 135 | { 136 | // Initialize the SD block device 137 | //Sd_Register(sd); 138 | 139 | // Initialize global filesystem 140 | //fs_initialize(); 141 | 142 | // Add support for FAT32 partitions to filesystem 143 | //fs_register_driver_factory(&fat32_driver_factory); 144 | 145 | // Add the SD card to the file system 146 | //fs_add_device(sd); 147 | } 148 | 149 | long long end = Timer_GetTicks(); 150 | 151 | // (This should be long long, but printf doesn't support that yet, also no long long div func) 152 | unsigned int time_taken = ((unsigned int)(end - start)) / 1000; 153 | printf("It took %dms to initialize the SD card and file system.\n", time_taken); 154 | 155 | // Show some usage of reserved memory at boot now that we're done reserving 156 | mem_printUsage(); 157 | 158 | printf("Our machine type is: 0x%h\n", machineType); 159 | printf("ATAGS start at 0x%h\n", atagsPa); 160 | printf("Debugging symbols are at 0x%h\n", dbgsymboladdr); 161 | 162 | atags_parse((int*)(KERNEL_VA_START + atagsPa)); 163 | 164 | syscalls_init(); 165 | 166 | // Enter... the kernel! 167 | cmain(); 168 | } -------------------------------------------------------------------------------- /source/hardware/framebuffer.c: -------------------------------------------------------------------------------- 1 | #include "hardware/framebuffer.h" 2 | #include "hardware/mailbox.h" 3 | #include "memory_map.h" 4 | #include "myfont.h" 5 | #include "types/string.h" 6 | #include "types/types.h" 7 | #include "debugging.h" 8 | #include "hardware/timer.h" 9 | 10 | rpi_fb gFb __attribute__ ((aligned (16))); 11 | size gScreenSize; 12 | unsigned int gFbMaxAddr; 13 | 14 | extern int gTerminalInitialized; 15 | 16 | unsigned int Fb_GetSize(void) 17 | { 18 | return gFb.size; 19 | } 20 | 21 | unsigned int Fb_GetPhyAddr(void) 22 | { 23 | return gFb.address; 24 | } 25 | 26 | size Fb_GetScreenSize(void) 27 | { 28 | size s; 29 | s.width = gFb.width; 30 | s.height = gFb.height; 31 | 32 | return s; 33 | } 34 | 35 | void Fb_DrawPixel(unsigned int x, unsigned int y, unsigned short int color) 36 | { 37 | // Offset into framebuffer 38 | unsigned int offset = (y * gFb.pitch) + (x * 2); 39 | 40 | unsigned short int* ptr = (unsigned short int*)((FRAMEBUFFER_VA_START) + offset); 41 | 42 | if((unsigned int)ptr >= gFbMaxAddr) 43 | { 44 | gTerminalInitialized = 0; // Stop printing to Framebuffer 45 | 46 | printf("Framebuffer: Warning! Attempting to write outside buffer!\n"); 47 | 48 | Debug_PrintCallstack(2); 49 | 50 | for(;;) 51 | { 52 | wait(2000); 53 | } 54 | 55 | } 56 | else 57 | { 58 | *ptr = color; 59 | } 60 | } 61 | 62 | void Fb_DrawCharacterAt(unsigned int ch, unsigned int x, unsigned int y) 63 | { 64 | Fb_DrawColoredCharacterAt(ch, x, y, 0xFFFF); 65 | } 66 | 67 | void Fb_DrawColoredCharacterAt(unsigned int ch, unsigned int x, unsigned int y, unsigned short color) 68 | { 69 | // Ensure valid char table lookup 70 | ch = ch < 32 ? 0 : ch > 127 ? 0 : ch - 32; 71 | 72 | int col; 73 | unsigned int row; 74 | for(row = 0; row < CHAR_HEIGHT; row++) 75 | { 76 | unsigned int i = 0; 77 | for(col = CHAR_HEIGHT - 2; col >= 0 ; col--) 78 | { 79 | if(row < (CHAR_HEIGHT - 1) && (gKernelFont[ch][row] & (1 << col))) 80 | { 81 | Fb_DrawPixel(x + i, y + row, color); 82 | } 83 | else 84 | { 85 | Fb_DrawPixel(x + i, y + row, 0x0000); // Same as background 86 | } 87 | i++; 88 | } 89 | } 90 | } 91 | 92 | // 0: Success. 1: Invalid response to property request, 2: Invalid screen size returned 93 | static int GetScreenSizeFromTags() 94 | { 95 | volatile unsigned int mailbuffer[256] __attribute__ ((aligned (16))); 96 | unsigned int mailbufferAddr = (unsigned int)mailbuffer; 97 | mailbufferAddr -= KERNEL_VA_START; 98 | 99 | mailbuffer[0] = 8 * 4; // Total size 100 | mailbuffer[1] = 0; // Request 101 | mailbuffer[2] = 0x40003; // Display size 102 | mailbuffer[3] = 8; // Buffer size 103 | mailbuffer[4] = 0; // Request size 104 | mailbuffer[5] = 0; // Space for horizontal resolution 105 | mailbuffer[6] = 0; // Space for vertical resolution 106 | mailbuffer[7] = 0; // End tag 107 | 108 | Mailbox_Write(8, mailbufferAddr); 109 | 110 | Mailbox_Read(8); 111 | 112 | if(mailbuffer[1] != 0x80000000) 113 | return 1; 114 | 115 | if (mailbuffer[5] == 0 || mailbuffer[6] == 0) 116 | return 2; 117 | 118 | gScreenSize.width = mailbuffer[5]; 119 | gScreenSize.height = mailbuffer[6]; 120 | 121 | #ifdef FB_DEBUG 122 | printf("Framebuffer: Got screen size: %dx%d\n", gScreenSize.width, gScreenSize.height); 123 | #endif 124 | 125 | return 0; 126 | } 127 | 128 | void Fb_Clear(void) 129 | { 130 | // Draw background color to make it visually obvious how large the drawing area is 131 | unsigned int i, j; 132 | for (i = 0; i < gFb.width; i++) 133 | { 134 | for (j = 0; j < gFb.height; j++) 135 | Fb_DrawPixel(i, j, 0x0000); 136 | } 137 | } 138 | 139 | int fb_allocateBuffer(void) 140 | { 141 | int width = PREFERRED_WIDTH; 142 | int height = PREFERRED_HEIGHT; 143 | 144 | // Attempt to retrieve the physical resolution of the monitor 145 | if(GetScreenSizeFromTags() == 0) 146 | { 147 | width = gScreenSize.width; 148 | height = gScreenSize.height; 149 | 150 | printf("Framebuffer: Allocating buffer based on resolution retrieved from VC (%dx%d)\n", width, height); 151 | } 152 | else 153 | { 154 | printf("Framebuffer: WARNING - using default resolution (%dx%d).\n", width, height); 155 | } 156 | 157 | gFb.width = width; // Requested width of the physical display 158 | gFb.height = height; // Requested height of the physical display 159 | gFb.v_width = width; // Requested width of the virtual framebuffer 160 | gFb.v_height = height; // Requested height of the virtual framebuffer 161 | gFb.pitch = 0; // Pitch - Request: Set to 0, Response: Number of bytes between each row of the frame buffer 162 | gFb.depth = FB_BPP; // Requested depth (bits per pixel) 163 | gFb.offset_x = 0; // Requested X offset of the virtual framebuffer 164 | gFb.offset_y = 0; // Requested Y offset of the virtual framebuffer 165 | gFb.address = 0; // Framebuffer address - Request: 0, Response: Address of buffer allocated by VC, or zero if request fails 166 | gFb.size = 0; // Framebuffer size - Request: 0, Response: Size of buffer allocated by VC 167 | 168 | unsigned int fbStructAddr = &gFb; 169 | 170 | // Mailbox requires the physical address 171 | // TODO: Add some sort of function to do this instead? Doing his in a lot of places now... 172 | fbStructAddr -= KERNEL_VA_START; 173 | 174 | Mailbox_Write(1, fbStructAddr); 175 | 176 | Mailbox_Read(1); 177 | 178 | if(gFb.address == 0) 179 | return 1; // Invalid FB address 180 | 181 | return 0; 182 | } 183 | 184 | int Fb_Initialize() 185 | { 186 | unsigned int result = 0; 187 | gScreenSize.width = 0; 188 | gScreenSize.height = 0; 189 | 190 | 191 | // For some reason known to no one, allocating the buffer might fail 192 | // The first (few) time(s), so retry a couple of times (seems to succeed more often than not on the second) 193 | int tries = 1; 194 | do 195 | { 196 | result = fb_allocateBuffer(); 197 | }while(tries++ < 5 && result != 0); 198 | 199 | if(result == 0) 200 | { 201 | printf("Framebuffer: Successfully retrieved buffer after %d tries.\n", tries); 202 | printf("Framebuffer: Allocated buffer at 0x%h, %d BPP, pitch: %d, %dx%d (virtual %dx%d)\n", 203 | gFb.address, 204 | gFb.depth, 205 | gFb.pitch, 206 | gFb.width, 207 | gFb.height, 208 | gFb.v_width, 209 | gFb.v_height); 210 | 211 | gFbMaxAddr = FRAMEBUFFER_VA_START + gFb.size; 212 | printf("Framebuffer: Framebuffer resides between 0x%h (phy: 0x%h) -> 0x%h (phy: 0x%h) (size: %d)\n", 213 | FRAMEBUFFER_VA_START, 214 | gFb.address, 215 | gFbMaxAddr, 216 | gFb.address + gFb.size, 217 | gFb.size); 218 | } 219 | else 220 | { 221 | printf("Framebuffer: Failed to allocate framebuffer on VC\n"); 222 | } 223 | 224 | return result; 225 | } 226 | -------------------------------------------------------------------------------- /source/asm/mmu.S: -------------------------------------------------------------------------------- 1 | ;@ 2 | ;@ This file contains functions to set up page tables and enable the MMU 3 | ;@ 4 | 5 | #include "memory_map.h" 6 | 7 | ;@ C Signature void do_mmu(uint* ttb0, uint* ttb1, uint split) 8 | .type do_mmu %function 9 | .section .text.init 10 | .globl do_mmu 11 | do_mmu: 12 | 13 | ;@ Save the SP so we can restore its relative position 14 | ;@ After we've enabled virtual memory 15 | mov r5, sp 16 | ldr r6, =SVC_STACK_PA_START 17 | sub r5, r6, r5 18 | 19 | ;@ Disable page coloring 20 | mrc p15, 0, r3, c1, c0, 1 21 | orr r3, #0x40 22 | mcr p15, 0, r3, c1, c0, 1 23 | 24 | ;@ Setup domains 25 | ldr r3, =0x55555555 26 | mcr p15, 0, r3, c3, c0, 0 27 | 28 | ;@ Setup TTBC 29 | mcr p15, 0, r2, c2, c0, 2 30 | 31 | ;@ Setup TTB0 (always cacheable) 32 | orr r0, #1 33 | mcr p15, 0, r0, c2, c0, 0 34 | 35 | ;@ Setup TTB1 (always cacheable) 36 | orr r1, #1 37 | mcr p15, 0, r1, c2, c0, 1 38 | 39 | ;@ Flush prefetch buffer 40 | mov r1, #0 41 | mcr p15, 0, r1, c7, c5, 4 42 | ;@ Invalidate Entire Data Cache 43 | mcr p15, 0, r1, c7, c6, 0 44 | 45 | ;@ Enable MMU 46 | mov r1, #0 47 | mrc p15, 0, r1, c1, c0, 0 ;@ Control register configuration data (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/Chdgjaid.html) 48 | ldr r2, =0x801805 ;@ (used to be 0x0480180D) 49 | orr r1, r2 50 | mcr p15, 0, r1, c1, c0, 0 51 | 52 | ;@ Now that the MMU is enabled, we need to modify the location of the stacks 53 | 54 | mov r0,#0xD2 ;@ IRQ 55 | msr cpsr_c,r0 56 | ldr sp, =IRQ_STACK_VA_START 57 | 58 | mov r0,#0xD1 ;@ FIQ 59 | msr cpsr_c,r0 60 | ldr sp, =FIQ_STACK_VA_START 61 | 62 | mov r0, #0xD7 ;@ Abort 63 | msr cpsr_c,r0 64 | ldr sp, =ABORT_STACK_VA_START 65 | 66 | mov r0, #0xDF ;@ System 67 | msr cpsr_c, r0 68 | ldr sp, =SM_STACK_VA_START 69 | 70 | mov r0, #0xDB ;@ Undefined 71 | msr cpsr_c, r0 72 | ldr sp, =UD_STACK_VA_START 73 | 74 | add r1, #KERNEL_VA_START 75 | mov r0,#0xD3 ;@ SVC 76 | msr cpsr_c,r0 77 | 78 | ;@ Restore the saved relative stack pointer 79 | ldr r0, =SVC_STACK_VA_START 80 | sub r0, r5 81 | 82 | mov sp, r0 83 | 84 | bx lr 85 | 86 | ;@ 87 | ;@ Sets TTB0 88 | ;@ C Signature: void set_ttb0(unsigned int* pt, unsigned int cacheable) 89 | ;@ pt: Physical address of the page table to install into ttb0 90 | ;@ cacheable: Whether the memory is cacheable. 1 = Cacheable, 0 = Noncacheable 91 | .type set_ttb0 %function 92 | .section .text 93 | .globl set_ttb0 94 | set_ttb0: 95 | 96 | ;@ Add Inner cacheable flag to address 97 | orr r0, r1 98 | 99 | ;@ Set TTB0: (using defaults: No outer cacheable PT walks, not shared) 100 | mcr p15, 0, r0, c2, c0, 0 101 | 102 | mov r0, #0 103 | mcr p15, 0, r0, c7, c14, 0 ;@ Write clean and invalidate entire data cache 104 | mcr p15, 0, r0,c8, c5, 0 ;@ Invalidate all unlocked TLB entries 105 | 106 | mov r0, #0 107 | mcr p15, 0, r0, c7, c5, 4 ;@ Flush prefetch buffer 108 | mcr p15, 0, r0, c7, c5, 0 ;@ Invalidate Entire Instruction Cache 109 | mcr p15, 0, r0, c7, c6, 0 ;@ Invalidate Entire Data Cache 110 | 111 | bx lr 112 | 113 | ;@ 114 | ;@ Gets the value of the Control register configuration data 115 | ;@ C Signature: unsigned int get_crcd(void) 116 | ;@ 117 | .type get_crcd %function 118 | .globl get_crcd 119 | get_crcd: 120 | mrc p15, 0, r0, c1, c0, 0 121 | bx lr 122 | 123 | ;@ 124 | ;@ Gets the value of the Translation table 0 base register 125 | ;@ C Signature: unsigned int get_ttb0(void) 126 | ;@ 127 | .type get_ttb0 %function 128 | .globl get_ttb0 129 | get_ttb0: 130 | mrc p15, 0, r0, c2, c0, 0 131 | bx lr 132 | 133 | ;@ 134 | ;@ Gets the value of the Translation Table 1 Base Register 135 | ;@ C Signature: unsigned int get_ttb1(void) 136 | ;@ 137 | .type get_ttb1 %function 138 | .globl get_ttb1 139 | get_ttb1: 140 | mrc p15, 0, r0, c2, c0, 1 141 | bx lr 142 | 143 | ;@ 144 | ;@ Gets the value of the Translation table base control register 145 | ;@ C Signature: unsigned int get_ttbc(void) 146 | ;@ 147 | .type get_ttbc %function 148 | .globl get_ttbc 149 | get_ttbc: 150 | mrc p15, 0, r0, c2, c0, 2 151 | bx lr 152 | 153 | ;@ 154 | ;@ Sets the value of the Translation Table Base Control register 155 | ;@ C Signature: void set_ttbc(unsigned int val); 156 | ;@ 157 | 158 | .type set_ttbc %function 159 | .globl set_ttbc 160 | set_ttbc: 161 | mcr p15, 0, r0, c2, c0, 2 162 | bx lr 163 | 164 | ;@ 165 | ;@ Sets the value of the Domain Access Control Register 166 | ;@ C Signature: void set_domain_register(unsigned int) 167 | ;@ 168 | .type set_domain_register %function 169 | .globl set_domain_register 170 | set_domain_register: 171 | MCR p15, 0, r0, c3, c0, 0 172 | 173 | bx lr 174 | 175 | ;@ 176 | ;@ Gets the value of the domain register 177 | ;@ C Signature: unsigned int get_domain_register(void) 178 | ;@ 179 | .type get_domain_register %function 180 | .type get_domain_register %function 181 | .globl get_domain_register 182 | get_domain_register: 183 | mrc p15, 0, r0, c3, c0, 0 184 | 185 | bx lr 186 | 187 | ;@ ===================================================================================================================== 188 | 189 | ;@ 190 | ;@ Reference documentation 191 | ;@ 192 | ;@ Translation table base control register: 193 | ;@ [31:6] UNP/SBZ 194 | ;@ [5] PD1 - Specifies whether to perform PT walk on TTB1 on TLB miss 195 | ;@ 0 = Enabled (Reset value) 196 | ;@ 1 = Disabled 197 | ;@ [4] PD0 - Specifies whether to perform PT walk on TTB0 on TLB miss 198 | ;@ [3] UNO/SBZ 199 | ;@ [2-0] N - Specifies boundry of Translation table base register 0 200 | ;@ 000 = 16 KB - 4 GB of memory (Reset value) 201 | ;@ 001 = 8 KB - 2 GB of memory 202 | ;@ 010 = 4 KB - 1 GB of memory 203 | ;@ 011 = 2 KB - 512 MB of memory 204 | ;@ 100 = 1 KB - 256 MB of memory 205 | ;@ 101 = 512 Byte - 128 MB of memory 206 | ;@ 110 = 256 Byte - 64 MB of memory 207 | ;@ 111 = 128-Byte - 32 MB of memory 208 | ;@ 209 | ;@ Translation table register: 210 | ;@ [31:14-n] Translation table base 211 | ;@ [13-n:5] UNP/SBZ 212 | ;@ [4:3] Outer cachable for page table walks. 213 | ;@ 00 = No Cacheable (Reset value) 214 | ;@ 01 = Write back, Write allocate 215 | ;@ 10 = Write-through, No allocate on write 216 | ;@ 11 = Write back, no allocate on write 217 | ;@ [2] SBZ (ECC not supported on ARM1176ZF-S) 218 | ;@ [1] Shared 219 | ;@ 0 = Not shared (Reset value) 220 | ;@ 1 = Shared 221 | ;@ [0] Inner cacheable 222 | ;@ 0 = Inner noncacheable (Reset value) 223 | ;@ 1 = Inner cacheable 224 | -------------------------------------------------------------------------------- /include/hardware/miniUart.h: -------------------------------------------------------------------------------- 1 | typedef union { 2 | unsigned int raw; 3 | 4 | struct { 5 | unsigned int mini_uart : 1; 6 | unsigned int spi1 : 1; 7 | unsigned int spi2 : 1; 8 | unsigned int reserved : 29; 9 | } bits; 10 | } aux_reg; 11 | 12 | typedef union { 13 | unsigned int raw; 14 | 15 | struct { 16 | unsigned int data : 8; 17 | unsigned int reserved : 24; 18 | } bits; 19 | } aux_mu_io_reg; 20 | 21 | typedef union { 22 | unsigned int raw; 23 | struct { 24 | unsigned int interrupt_pending : 1; 25 | unsigned int interrupt_id_fifo_clear : 2; // On write: bit 1 will clear receive FIFO and bit 2 will clear. On read 0 = no interrupt, 1 = transmit holding registry empty, 2 = Receiver holds valid byte 26 | unsigned int timeout : 1; // NOTE: Always 0 as mini uart has no timeout function 27 | unsigned int reserved : 2; 28 | unsigned int fifo_enables : 2; 29 | unsigned int reserved2 : 24; 30 | } bits; 31 | } aux_mu_iir_reg; 32 | 33 | typedef union { 34 | unsigned int raw; 35 | 36 | struct { 37 | unsigned int enable_transmit_interrupt : 1; 38 | unsigned int enable_receive_interrupt : 1; 39 | unsigned int reserved: 30; 40 | 41 | } bits; 42 | } aux_mu_ier_reg; 43 | 44 | typedef union { 45 | unsigned int raw; 46 | 47 | struct { 48 | unsigned int data_size : 2; // 11 = 8-bit, 1 = 7-bit 49 | unsigned int reserved : 4; 50 | unsigned int break_field : 1; // 51 | unsigned int dlab_access : 1; 52 | unsigned int reserved2 : 24; 53 | } bits; 54 | } uax_mu_lcr_reg; 55 | 56 | typedef union { 57 | unsigned int raw; 58 | 59 | struct { 60 | unsigned int reserved : 1; 61 | unsigned int rts : 1; 62 | unsigned int reserved2 : 30; 63 | } bits; 64 | } uax_mu_mcr_reg; 65 | 66 | typedef union { 67 | unsigned int raw; 68 | 69 | struct { 70 | unsigned int data_ready : 1; 71 | unsigned int receiver_overrun : 1; 72 | unsigned int reserved : 3; 73 | unsigned int transmitter_empty : 1; 74 | unsigned int transmitter_idle : 1; 75 | unsigned int reserved2: 25; 76 | } bits; 77 | } aux_mu_lsr_reg; 78 | 79 | typedef union { 80 | unsigned int raw; 81 | 82 | struct { 83 | unsigned int reserved : 4; 84 | unsigned int cts_status : 1; 85 | unsigned int reserved2 : 27; 86 | } bits; 87 | } aux_mu_msr_reg; 88 | 89 | typedef union { 90 | unsigned int raw; 91 | 92 | struct { 93 | unsigned int scratch : 8; 94 | unsigned int reserved : 24; 95 | } bits; 96 | } aux_mu_scratch; 97 | 98 | typedef union { 99 | unsigned int raw; 100 | 101 | struct { 102 | unsigned int receiver_enabled : 1; 103 | unsigned int transmitter_enabled : 1; 104 | unsigned int enable_receive_auto_flow : 1; 105 | unsigned int enable_transmit_auto_flow : 1; 106 | unsigned int rts_auto_flow_level : 2; // 0 = 3, 1 = 2, 2 = 1, 3 = 4 107 | unsigned int rts_assert_level : 1; 108 | unsigned int cts_assert_level : 1; 109 | unsigned int reserved : 24; 110 | } bits; 111 | } aux_mu_cntl_reg; 112 | 113 | typedef union { 114 | unsigned int raw; 115 | 116 | struct { 117 | unsigned int symbol_available : 1; 118 | unsigned int space_available : 1; 119 | unsigned int receiver_idle : 1; 120 | unsigned int transmitter_idle : 1; 121 | unsigned int receiver_overrun : 1; 122 | unsigned int transmit_fifo_full : 1; 123 | unsigned int rts_status : 1; 124 | unsigned int cts_status : 1; 125 | unsigned int transmit_fifo_empty : 1; 126 | unsigned int transmitter_done : 1; 127 | unsigned int reserved : 6; 128 | unsigned int receive_fifo_fill_level : 4; 129 | unsigned int reserved2 : 4; 130 | unsigned int transmit_fifo_fill_level : 4; 131 | unsigned int reserved3 : 4; 132 | } bits; 133 | } aux_mu_stat_reg; 134 | 135 | typedef union { 136 | unsigned int raw; 137 | struct { 138 | unsigned int baud_rate : 16; // Mini Uart baudrate counter 139 | unsigned int reserved : 16; 140 | } bits; 141 | } aux_mu_baud_reg; 142 | 143 | typedef union { 144 | unsigned int raw; 145 | 146 | struct { 147 | unsigned int shift_length : 6; 148 | unsigned int shift_out_ms : 1; 149 | unsigned int invert_spi_clk : 1; 150 | unsigned int out_rising : 1; 151 | unsigned int clear_fifos : 1; 152 | unsigned int in_rising : 1; 153 | unsigned int enable : 1; 154 | unsigned int dout_hold_time : 2; 155 | unsigned int variable_width : 1; 156 | unsigned int variable_cs : 1; 157 | unsigned int post_input_mode : 1; 158 | unsigned int chip_selects : 3; 159 | unsigned int speed : 12; 160 | } bits; 161 | } aux_spi_cntl0_reg; 162 | 163 | typedef union { 164 | unsigned int raw; 165 | 166 | struct { 167 | unsigned int keep_input : 1; 168 | unsigned int shift_in_ms_bit : 1; 169 | unsigned int reserved : 4; 170 | unsigned int done_irq : 1; 171 | unsigned int tx_empty_irq : 1; 172 | unsigned int cs_high_time : 3; 173 | unsigned int reserved2 : 20; 174 | } bits; 175 | } aux_spi_cntl1_reg; 176 | 177 | typedef union { 178 | unsigned int raw; 179 | 180 | struct { 181 | unsigned int bit_count : 6; 182 | unsigned int busy : 1; 183 | unsigned int reserved : 5; 184 | unsigned int rx_fifo_level : 12; 185 | unsigned int tx_fifo_level : 7; 186 | } bits; 187 | } aux_spi_stat; 188 | 189 | typedef union { 190 | unsigned int raw; 191 | 192 | struct { 193 | unsigned int data : 16; 194 | unsigned int reserved : 16; 195 | } bits; 196 | } aux_spi_peek; 197 | 198 | typedef union { 199 | unsigned int raw; 200 | 201 | struct { 202 | unsigned int data : 16; 203 | unsigned int reserved : 16; 204 | } bits; 205 | } aux_spi_io; 206 | 207 | typedef volatile struct { // Located at 0x20215000 208 | aux_reg irq; // Auxiliary Interrupt status 209 | aux_reg enables; // Auxiliary enables 210 | unsigned int reserved[14]; // - 211 | aux_mu_io_reg mu_io; // Mini Uart I/O Data 212 | aux_mu_ier_reg mu_ier; // Mini Uart Interrupt Enable 213 | aux_mu_iir_reg mu_iir; // Mini Uart Interrupt Identify 52 214 | uax_mu_lcr_reg mu_lcr; // Mini Uart Line Control 215 | uax_mu_mcr_reg mu_mcr; // Mini uart Modem Control 216 | aux_mu_lsr_reg mu_lsr; // Mini Uart Line Status 217 | aux_mu_msr_reg mu_msr; // Mini Uart Modem Status 218 | aux_mu_scratch mu_scratch; // Mini Uart Scratch 219 | aux_mu_cntl_reg mu_cntl; // Mini Uart Extra control 220 | aux_mu_stat_reg mu_stat; // Mini Uart Extra Status 221 | aux_mu_baud_reg baud_rate; // Mini Uart Baudrate 222 | aux_spi_cntl0_reg spi0_cntl0; // SPI 1 Control register 0 223 | aux_spi_cntl1_reg spi0_cntl1; // SPI 1 Control register 1 224 | aux_spi_stat spi0_stat; // SPI 1 Status 225 | aux_spi_io spi0_io; // SPI 1 Data 226 | aux_spi_peek spi0_peek; // SPI 1 Peek 227 | aux_spi_cntl0_reg spi1_cntl0; // SPI 2 Control register 0 228 | aux_spi_cntl1_reg spi1_cntl1; // SPI 2 Control register 1 229 | } MiniUart; 230 | 231 | unsigned int MiniUart_Initialize(void); 232 | void MiniUart_SendString(char* s); 233 | void MiniUart_SendChar(unsigned int c); 234 | unsigned int MiniUart_ReadChar(unsigned int block); 235 | -------------------------------------------------------------------------------- /source/interruptHandlers.c: -------------------------------------------------------------------------------- 1 | #include "interruptHandlers.h" 2 | #include "hardware/interrupts.h" 3 | #include "hardware/timer.h" 4 | #include "hardware/uart.h" 5 | #include "types/string.h" 6 | #include "util/utilities.h" 7 | #include "debugging.h" 8 | #include "scheduler.h" 9 | #include "stddef.h" 10 | #include "stdbool.h" 11 | #include "stdint.h" 12 | 13 | // Because I sometimes mess up and end up getting spammed with 14 | // Abort interrupts of various types, this adds a delay to the abort handlers 15 | // So that I have time to read the error before spam scrolls it out of view 16 | // :-) 17 | #define INTERRUPT_HANDLER_DELAY 2000 // in ms 18 | 19 | extern int gTerminalInitialized; 20 | 21 | bool in_fault = false; 22 | 23 | swi_handler gSwiHandlers[MAX_SWI_NUM]; 24 | 25 | void swi_init(void) 26 | { 27 | for (uint32_t i = 0; i < MAX_SWI_NUM; i++) 28 | gSwiHandlers[i] = NULL; 29 | } 30 | 31 | bool swi_install(unsigned int swiNum, swi_handler handler) 32 | { 33 | if (swiNum > MAX_SWI_NUM) 34 | { 35 | printf("Swi: Can't install swi handler for %d, MAX_SWI_NUL=%d\n", swiNum, MAX_SWI_NUM); 36 | return false; 37 | } 38 | 39 | if (gSwiHandlers[swiNum] != NULL) 40 | { 41 | printf("Swi: Can't install swi handler for %d, a handler is already present\n", swiNum); 42 | return false; 43 | } 44 | 45 | gSwiHandlers[swiNum] = handler; 46 | 47 | return true; 48 | } 49 | 50 | void double_fault(void) 51 | { 52 | printf("Double fault!\n"); 53 | printf("* * * PANIC * * *\n"); 54 | while (1); 55 | } 56 | 57 | void c_undefined_handler(void* lr) 58 | { 59 | bool doubleFault = in_fault == true; 60 | in_fault = true; 61 | 62 | printf("Undefined instruction at 0x%h. (instruction: %d).\n", lr, *((unsigned int*)lr)); 63 | 64 | //unsigned int* instAddr = (unsigned int*)*(r14 - 1) + 4; 65 | //printf("Instruction that cause abort is at 0x%h (%d) - SPSR: 0x%h.\n", instAddr, *instAddr, 42);// spsr); 66 | 67 | wait(INTERRUPT_HANDLER_DELAY); 68 | 69 | in_fault = false; 70 | 71 | if (doubleFault) 72 | double_fault(); 73 | } 74 | 75 | void c_abort_data_handler(unsigned int address, unsigned int errorType, unsigned int accessedAddr, unsigned int fault_reg) 76 | { 77 | bool doubleFault = in_fault == true; 78 | in_fault = true; 79 | 80 | // NOTE: fault_reg isn't used (yet), we should just use that and extract the Fault status from 81 | // it here as opposed to doing it in asm and pass it in as a separate argument 82 | printf("Instruction in %s at 0x%h caused a data abort accessing memory at 0x%h (", Debug_GetClosestPreviousFunction(address), address, accessedAddr); 83 | print_abort_error(errorType); 84 | printf(")\n"); 85 | 86 | //Debug_PrintCallstack(2); 87 | 88 | wait(INTERRUPT_HANDLER_DELAY); 89 | in_fault = false; 90 | 91 | // Temporarily allow double faults due to bug with the translation tables 92 | // when switching tasks 93 | /* if (doubleFault) 94 | double_fault();*/ 95 | } 96 | 97 | void c_abort_instruction_handler(unsigned int address, unsigned int errorType) 98 | { 99 | bool doubleFault = in_fault == true; 100 | in_fault = true; 101 | 102 | if (*(unsigned int*)address == 0xE1200070) 103 | { 104 | printf("* * Breakpoint! * * \n"); 105 | } 106 | else 107 | { 108 | printf("Instruction at 0x%h (value: %d) caused instruction abort ", address, *(unsigned int*)address); 109 | 110 | print_abort_error(errorType); 111 | } 112 | 113 | wait(INTERRUPT_HANDLER_DELAY); 114 | 115 | in_fault = false; 116 | 117 | if (doubleFault) 118 | double_fault(); 119 | } 120 | 121 | void c_swi_handler(unsigned int r0, unsigned int r1, unsigned int r2, unsigned int swi) 122 | { 123 | // This shouldn't happen, but who knows what users do.. 124 | if (swi > MAX_SWI_NUM) 125 | return; 126 | 127 | printf("SWI %d invoked\n", swi); 128 | 129 | swi_handler handler = gSwiHandlers[swi]; 130 | if (handler != NULL) 131 | { 132 | handler(r0, r1, r2); 133 | } 134 | else 135 | { 136 | printf("swi: Undefined SWI handler for swi %d\n", swi); 137 | } 138 | } 139 | 140 | void c_irq_handler(volatile unsigned int* sp) 141 | { 142 | unsigned int pendingIrq = Arm_IrqGetPending(); 143 | 144 | switch (pendingIrq) 145 | { 146 | case interrupt_source_system_timer: 147 | { 148 | // Note IRQ has no acccess to peripherals? :( 149 | 150 | Scheduler_TimerTick((thread_regs*)(sp - 1)); 151 | 152 | break; 153 | } 154 | case interrupt_source_uart: 155 | { 156 | unsigned char read = Uart_Read(); 157 | 158 | // Echo it back 159 | Uart_Send(read); 160 | 161 | if (read == 'x') 162 | { 163 | Uart_SendString("\r\n* * * Rebooting. * * *\r\n"); 164 | reboot(); 165 | } 166 | break; 167 | } 168 | default: 169 | printf("Unhandled IRQ pending, id:%d.\n", pendingIrq); 170 | break; 171 | } 172 | } 173 | 174 | void print_abort_error(unsigned int errorType) 175 | { 176 | // Documentation for the Fault register (Which is where the errorType code is obtained from): 177 | // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0290g/Babbcbhc.html 178 | switch (errorType) 179 | { 180 | case 0x0: 181 | // This is the reset value 182 | printf("No error"); 183 | break; 184 | case 0x1: 185 | printf("Alignment fault"); 186 | break; 187 | case 0x2: 188 | printf("Instruction debug event"); 189 | break; 190 | case 0x3: 191 | printf("Access bit fault on section"); 192 | break; 193 | case 0x4: 194 | printf("No function"); 195 | break; 196 | case 0x5: 197 | printf("Translation section fault"); 198 | break; 199 | case 0x6: 200 | printf("Access bit fault on page"); 201 | break; 202 | case 0x7: 203 | printf("Translation page fault"); 204 | break; 205 | case 0x8: 206 | printf("Precise external abort"); 207 | break; 208 | case 0x9: 209 | printf("Domain section fault"); 210 | break; 211 | case 0xA: 212 | printf("No function"); 213 | break; 214 | case 0xB: 215 | printf("Domain page fault"); 216 | break; 217 | case 0xC: 218 | printf("External abort on translation, first level table"); 219 | break; 220 | case 0xD: 221 | printf("Permission section fault"); 222 | break; 223 | case 0xE: 224 | printf("External abort on translation, second level table"); 225 | break; 226 | case 0xF: 227 | printf("Permission page fault"); 228 | break; 229 | default: 230 | printf("print_abort_error() called with invalid errorType '%d'", errorType); 231 | break; 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /include/hardware/interrupts.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTS_H 2 | #define INTERRUPTS_H 3 | 4 | // Note: Read-only 5 | typedef union { 6 | unsigned int raw; 7 | 8 | struct { 9 | int arm_timer : 1; 10 | int arm_mailbox : 1; 11 | int arm_doorbell0 : 1; 12 | int arm_doorbell1 : 1; 13 | int gpu0_halted : 1; 14 | int gpu1_halted : 1; 15 | int illegal_access_type1 : 1; 16 | int illegal_access_type0 : 1; 17 | int pending_reg_1_set : 1; 18 | int pending_reg_2_set : 1; 19 | int gpu_irq7 : 1; 20 | int gpu_irq9 : 1; 21 | int gpu_irq10 : 1; 22 | int gpu_irq_18 : 1; 23 | int gpu_irq_19 : 1; 24 | int gpu_irq_53 : 1; 25 | int gpu_irq_54 : 1; 26 | int gpu_irq_55 : 1; 27 | int gpu_irq_56 : 1; 28 | int gpu_irq_57 : 1; 29 | int gpu_irq_62 : 1; 30 | int reserved : 11; 31 | } bits; 32 | } basic_irq_pending_req; 33 | 34 | typedef union { 35 | unsigned int raw; 36 | 37 | struct { 38 | unsigned int reserved0 : 1; 39 | unsigned int reserved1 : 1; 40 | unsigned int reserved2 : 1; 41 | unsigned int system_timer : 1; 42 | unsigned int reserved4 : 1; 43 | unsigned int reserved5 : 1; 44 | unsigned int reserved6 : 1; 45 | unsigned int reserved7 : 1; 46 | unsigned int reserved8 : 1; 47 | unsigned int reserved9 : 1; 48 | unsigned int reserved10 : 1; 49 | unsigned int reserved11 : 1; 50 | unsigned int reserved12 : 1; 51 | unsigned int reserved13 : 1; 52 | unsigned int reserved14 : 1; 53 | unsigned int reserved15 : 1; 54 | unsigned int reserved16 : 1; 55 | unsigned int reserved17 : 1; 56 | unsigned int reserved18 : 1; 57 | unsigned int reserved19 : 1; 58 | unsigned int reserved20 : 1; 59 | unsigned int reserved21 : 1; 60 | unsigned int reserved22 : 1; 61 | unsigned int reserved23 : 1; 62 | unsigned int reserved24 : 1; 63 | unsigned int reserved25 : 1; 64 | unsigned int reserved26 : 1; 65 | unsigned int reserved27 : 1; 66 | unsigned int reserved28 : 1; 67 | unsigned int aux : 1; 68 | unsigned int reserved29 : 1; 69 | unsigned int reserved30 : 1; 70 | } bits; 71 | } irq_table1; 72 | 73 | typedef union { 74 | unsigned int raw; 75 | 76 | struct { 77 | unsigned int reserved0 : 1; 78 | unsigned int reserved1 : 1; 79 | unsigned int reserved2 : 1; 80 | unsigned int reserved3 : 1; 81 | unsigned int reserved4 : 1; 82 | unsigned int reserved5 : 1; 83 | unsigned int reserved6 : 1; 84 | unsigned int reserved7 : 1; 85 | unsigned int reserved8 : 1; 86 | unsigned int reserved9 : 1; 87 | unsigned int reserved10 : 1; 88 | unsigned int i2c_spi_slv_int : 1; 89 | unsigned int reserved11 : 1; 90 | unsigned int pwa0 : 1; 91 | unsigned int pwa1 : 1; 92 | unsigned int reserved12 : 1; 93 | unsigned int smi : 1; 94 | unsigned int gpio0 : 1; 95 | unsigned int gpio1 : 1; 96 | unsigned int gpio2 : 1; 97 | unsigned int gpio3 : 1; 98 | unsigned int i2c : 1; 99 | unsigned int spi : 1; 100 | unsigned int pcm : 1; 101 | unsigned int reserved13 : 1; 102 | unsigned int uart : 1; 103 | unsigned int reserved14 : 1; 104 | unsigned int reserved15 : 1; 105 | unsigned int reserved16 : 1; 106 | unsigned int reserved17 : 1; 107 | unsigned int reserved18 : 1; 108 | unsigned int reserved19 : 1; 109 | } bits; 110 | } irq_table2; 111 | 112 | typedef enum { 113 | unused_interrupt_source0, 114 | unused_interrupt_source1, 115 | unused_interrupt_source2, 116 | interrupt_source_system_timer, 117 | unused_interrupt_source4, 118 | unused_interrupt_source5, 119 | unused_interrupt_source6, 120 | unused_interrupt_source7, 121 | unused_interrupt_source8, 122 | unused_interrupt_source9, 123 | unused_interrupt_source10, 124 | unused_interrupt_source11, 125 | unused_interrupt_source12, 126 | unused_interrupt_source13, 127 | unused_interrupt_source14, 128 | unused_interrupt_source15, 129 | 130 | unused_interrupt_source16, 131 | unused_interrupt_source17, 132 | unused_interrupt_source18, 133 | unused_interrupt_source19, 134 | unused_interrupt_source20, 135 | unused_interrupt_source21, 136 | unused_interrupt_source22, 137 | unused_interrupt_source23, 138 | unused_interrupt_source24, 139 | unused_interrupt_source25, 140 | unused_interrupt_source26, 141 | unused_interrupt_source27, 142 | unused_interrupt_source28, 143 | interrupt_source_aux, 144 | unused_interrupt_source30, 145 | unused_interrupt_source31, 146 | 147 | unused_interrupt_source32, 148 | unused_interrupt_source33, 149 | unused_interrupt_source34, 150 | unused_interrupt_source35, 151 | unused_interrupt_source36, 152 | unused_interrupt_source37, 153 | unused_interrupt_source38, 154 | unused_interrupt_source39, 155 | unused_interrupt_source40, 156 | unused_interrupt_source41, 157 | unused_interrupt_source42, 158 | interrupt_source_i2c_spi_slv, 159 | unused_interrupt_source44, 160 | interrupt_source_pwa0, 161 | interrupt_source_pwa1, 162 | unused_interrupt_source47, 163 | 164 | interrupt_source_smi, 165 | interrupt_source_gpio0, 166 | interrupt_source_gpio1, 167 | interrupt_source_gpio2, 168 | interrupt_source_gpio3, 169 | interrupt_source_i2c, 170 | interrupt_source_spi, 171 | interrupt_source_pcm, 172 | unused_interrupt_source_56, 173 | interrupt_source_uart, 174 | unused_interrupt_source_58, 175 | unused_interrupt_source_59, 176 | unused_interrupt_source_60, 177 | unused_interrupt_source_61, 178 | unused_interrupt_source_62, 179 | unused_interrupt_source_63, 180 | 181 | interrupt_source_ArmTimer, 182 | interrupt_source_ArmMailbox, 183 | interrupt_source_ArmDoorbell0, 184 | interrupt_source_ArmDoorbell1, 185 | interrupt_source_Gpu0Halted, 186 | interrupt_source_Gpu1Halted, 187 | interrupt_source_IllegalAccessType1, 188 | interrupt_source_IllegalAccessType0, 189 | } interrupt_source; 190 | 191 | typedef union { 192 | unsigned int raw; 193 | 194 | struct { 195 | unsigned int source : 7; // see interrupt_source enumeration 196 | unsigned int enable : 1; 197 | unsigned int reserved : 24; 198 | } bits; 199 | } fiq_control_req; 200 | 201 | typedef union{ 202 | unsigned int raw; 203 | 204 | struct{ 205 | unsigned int timer : 1; 206 | unsigned int mailbox : 1; 207 | unsigned int doorbell0 : 1; 208 | unsigned int doorbell1 : 1; 209 | unsigned int gpu0halted : 1; 210 | unsigned int gpu1halted : 1; 211 | unsigned int access_error_type0 : 1; 212 | unsigned int access_error_type1 : 1; 213 | unsigned int reserved : 24; 214 | } bits; 215 | } basic_interrupt_reg; 216 | 217 | #pragma pack(1) 218 | 219 | typedef volatile struct { 220 | basic_irq_pending_req basic_irq_pending; 221 | irq_table1 irq_pending1; 222 | irq_table2 irq_pending2; 223 | fiq_control_req fiq_control; 224 | irq_table1 irq_enable1; 225 | irq_table2 irq_enable2; 226 | basic_interrupt_reg basic_irq_enable; 227 | irq_table1 irq_disable1; 228 | irq_table2 irq_disable2; 229 | basic_interrupt_reg basic_irq_disable; 230 | } ArmInterrupts; 231 | 232 | #pragma pack() 233 | 234 | void Arm_InterruptInitialize(void); 235 | void Arm_IrqEnable(interrupt_source source); 236 | void Arm_IrqDisableall(void); 237 | interrupt_source Arm_IrqGetPending(void); 238 | 239 | void Arm_FiqEnable(interrupt_source source); 240 | void Arm_FiqDisableall(void); 241 | 242 | #endif 243 | -------------------------------------------------------------------------------- /source/hardware/keyboard.c: -------------------------------------------------------------------------------- 1 | //#include "types.h" 2 | //#include "usbd/usbd.h" 3 | //#include "device/hid/keyboard.h" 4 | #include "terminal.h" 5 | #include "types/string.h" 6 | #include "hardware/keyboard.h" 7 | 8 | char* gKeynames[] = 9 | { 10 | "a", // 0 11 | "b", 12 | "c", 13 | "d", 14 | "e", 15 | "f", 16 | "g", 17 | "h", 18 | "i", 19 | "j", 20 | "k", // 10 21 | "l", 22 | "m", 23 | "n", 24 | "o", 25 | "p", 26 | "q", 27 | "r", 28 | "s", 29 | "t", 30 | "u", // 20 31 | "v", 32 | "w", 33 | "x", 34 | "y", 35 | "z", 36 | "1", 37 | "2", 38 | "3", 39 | "4", 40 | "5", // 30 41 | "6", 42 | "7", 43 | "8", 44 | "9", 45 | "0", 46 | "return", 47 | "esc", 48 | "bsp", 49 | "tab", 50 | "space", // 40 51 | "minus", 52 | "equals", 53 | "lsquarebracket", 54 | "rsquarebracket", 55 | "backslash", // NO 56 | "hash", 57 | "semicolon", 58 | "apostrophe", 59 | "grave", 60 | "comma", // 50 61 | "fullstop", 62 | "forwardflash", 63 | "caps-lock", 64 | "f1", 65 | "f2", 66 | "f3", 67 | "f4", 68 | "f5", 69 | "f6", 70 | "f7", // 60 71 | "f8", 72 | "f9", 73 | "f10", 74 | "f11", 75 | "f12", 76 | "prtscn", 77 | "scroll-lock", 78 | "break", 79 | "insert", 80 | "home", // 70 81 | "page-up", 82 | "delete", 83 | "end", 84 | "page-down", 85 | "right", //5 86 | "left", // 6 87 | "down", // 7 88 | "up", // 8 89 | "num-lock", 90 | "numdiv", // 80 91 | "nummul", 92 | "numsub", 93 | "numadd", 94 | "numreturn", 95 | "num1", 96 | "num2", 97 | "num3", 98 | "num4", 99 | "num5", 100 | "num6", // 90 101 | "num7", 102 | "num8", 103 | "num9", 104 | "num0", 105 | "numdelete", 106 | "backslash", 107 | "rmenu" 108 | }; 109 | 110 | const char gVirtualTable_shifted[] = 111 | { 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 'A', 117 | 'B', 118 | 'C', 119 | 'D', 120 | 'E', 121 | 'F', 122 | 'G', 123 | 'H', 124 | 'I', 125 | 'J', 126 | 'K', // 10 127 | 'L', 128 | 'M', 129 | 'N', 130 | 'O', 131 | 'P', 132 | 'Q', 133 | 'R', 134 | 'S', 135 | 'T', 136 | 'U', // 20 137 | 'V', 138 | 'W', 139 | 'X', 140 | 'Y', 141 | 'Z', 142 | '!', 143 | '"', 144 | '*', 145 | '$', // 30 146 | '%', 147 | '^', 148 | '&', 149 | '*', 150 | '(', 151 | ')', 152 | '\n', 153 | /*esc*/0, 154 | /*Bsp*/0, 155 | '\t', 156 | ' ', // 40 157 | '_', 158 | '+', 159 | '{', 160 | '}', 161 | '|', 162 | '~', 163 | ':', 164 | '@', 165 | '*', 166 | '<', // 50 167 | '>', 168 | '?', 169 | 0, 170 | 0, 171 | 0, 172 | 0, 173 | 0, 174 | 0, 175 | 0, 176 | 0, // 60 177 | 0, 178 | 0, 179 | 0, 180 | 0, 181 | 0, 182 | 0, 183 | 0, 184 | 0, 185 | 0, 186 | 0, // 70 187 | 0, 188 | 0, 189 | 0, 190 | 0, 191 | 0, 192 | 0, 193 | 0, 194 | 0, 195 | 0, 196 | '/', // 80 197 | '*', 198 | '-', 199 | '+', 200 | '\n', 201 | '1', 202 | '2', 203 | '3', 204 | '4', 205 | '5', 206 | '6', // 90 207 | '7', 208 | '8', 209 | '9', 210 | '0', 211 | 0, // Numpad delete 212 | '\\' 213 | }; 214 | 215 | const char gVirtualTable[] = 216 | { 217 | 0, 218 | 0, 219 | 0, 220 | 0, 221 | 'a', 222 | 'b', 223 | 'c', 224 | 'd', 225 | 'e', 226 | 'f', 227 | 'g', 228 | 'h', 229 | 'i', 230 | 'j', 231 | 'k', // 10 232 | 'l', 233 | 'm', 234 | 'n', 235 | 'o', 236 | 'p', 237 | 'q', 238 | 'r', 239 | 's', 240 | 't', 241 | 'u', // 20 242 | 'v', 243 | 'w', 244 | 'x', 245 | 'y', 246 | 'z', 247 | '1', 248 | '2', 249 | '3', 250 | '4', // 30 251 | '5', 252 | '6', 253 | '7', 254 | '8', 255 | '9', 256 | '0', 257 | '\n', 258 | /*esc*/0, 259 | /*Bsp*/0, 260 | '\t', 261 | ' ', // 40 262 | '-', 263 | '=', 264 | '[', 265 | ']', 266 | '\\', 267 | '#', 268 | ';', 269 | '\'', 270 | '`', 271 | ',', // 50 272 | '.', 273 | '/', 274 | 0, 275 | 0, 276 | 0, 277 | 0, 278 | 0, 279 | 0, 280 | 0, 281 | 0, // 60 282 | 0, 283 | 0, 284 | 0, 285 | 0, 286 | 0, 287 | 0, 288 | 0, 289 | 0, 290 | 0, 291 | 0, // 70 292 | 0, 293 | 0, 294 | 0, 295 | 0, 296 | 0, 297 | 0, 298 | 0, 299 | 0, 300 | 0, 301 | '/', // 80 302 | '*', 303 | '-', 304 | '+', 305 | '\n', 306 | '1', 307 | '2', 308 | '3', 309 | '4', 310 | '5', 311 | '6', // 90 312 | '7', 313 | '8', 314 | '9', 315 | '0', 316 | 0, // Numpad delete 317 | '\\' 318 | }; 319 | 320 | bool gHaveKeyboard; 321 | unsigned int gKeyboardAddr; 322 | unsigned short gLastKeystate[6]; 323 | //struct KeyboardModifiers gLastModifiers; 324 | 325 | bool KeyboardCtrlDown(void) 326 | { 327 | return -1;//gLastModifiers.LeftControl || gLastModifiers.RightControl; 328 | } 329 | 330 | bool KeyboardShiftDown(void) 331 | { 332 | return -1;//gLastModifiers.LeftShift || gLastModifiers.RightShift; 333 | } 334 | 335 | virtualkey ScanToVirtual(unsigned int scanCode) 336 | { 337 | if(scanCode < 0) return VK_INVALID; 338 | 339 | return (virtualkey)(scanCode - 4); 340 | } 341 | 342 | unsigned char VirtualToAsci(virtualkey vk, bool shifted) 343 | { 344 | if(vk < 0 || vk > (sizeof(gVirtualTable) / sizeof(gVirtualTable[0]))) return -1; 345 | 346 | if(shifted) 347 | return gVirtualTable_shifted[vk + 4]; 348 | else 349 | return gVirtualTable[vk + 4]; 350 | } 351 | 352 | char* GetKeyName(char* buf, unsigned int bufLen, virtualkey vk) 353 | { 354 | char* keyName = gKeynames[vk]; 355 | 356 | if(my_strlen(keyName) < bufLen) 357 | my_strcpy(keyName, buf); 358 | 359 | return buf; 360 | } 361 | 362 | // Retrieves the address of the first attached keyboard 363 | bool EnsureKeyboard(void) 364 | { 365 | // KeyboardUpdate() modifies this 366 | if(gHaveKeyboard) 367 | return true; 368 | 369 | //UsbCheckForChange(); 370 | 371 | if(1)//KeyboardCount() == 0) 372 | { 373 | gHaveKeyboard = false; 374 | return false; 375 | } 376 | 377 | gKeyboardAddr = 0;//KeyboardGetAddress(0); 378 | gHaveKeyboard = true; 379 | 380 | return true; 381 | } 382 | 383 | bool KeyWasDown(unsigned short scanCode) 384 | { 385 | unsigned int i; 386 | for(i = 0; i < 6; i++) 387 | if(gLastKeystate[i] == scanCode) return true; 388 | 389 | return false; 390 | } 391 | 392 | // Gets the scanCode of the first currently pressed key (0 if none) 393 | unsigned short KeyboardGetChar(void) 394 | { 395 | unsigned int i; 396 | for(i = 0; i < 6; i++) 397 | { 398 | unsigned short key = 0;//KeyboardGetKeyDown(gKeyboardAddr, i); 399 | 400 | if(key == 0) return 0; 401 | if(KeyWasDown(key)) continue; 402 | if(key >= 104) continue; 403 | 404 | return key; 405 | } 406 | 407 | return 0; 408 | } 409 | 410 | unsigned int KeyboardInitialise(void) 411 | { 412 | gHaveKeyboard = false; 413 | gKeyboardAddr = 0; 414 | 415 | unsigned int i; 416 | for(i = 0; i < 6; i++) 417 | gLastKeystate[i] = 0; 418 | 419 | return 0; 420 | } 421 | 422 | void KeyboardUpdate(void) 423 | { 424 | if(!EnsureKeyboard()) 425 | { 426 | //print("Failed to update keyboard, could not obtain device.", strlen("Failed to update keyboard, could not obtain device.")); 427 | return; 428 | } 429 | 430 | unsigned int i; 431 | for(i = 0; i < 6; i++) 432 | gLastKeystate[i] = 0;//KeyboardGetKeyDown(gKeyboardAddr, i); 433 | 434 | //gHaveKeyboard = KeyboardPoll(gKeyboardAddr) == 0; 435 | //gLastModifiers = KeyboardGetModifiers(gKeyboardAddr); 436 | } 437 | -------------------------------------------------------------------------------- /include/fs/fs.h: -------------------------------------------------------------------------------- 1 | #include "hardware/device/blockDevice.h" 2 | #define BOOTABLE_FLAG 0x80 3 | 4 | #define E_UNSUPPORTED -2 5 | #define INVALID_HANDLE -1 6 | 7 | #ifndef FS_H 8 | #define FS_H 9 | 10 | typedef enum{ 11 | UnknownFsType = 0x00, 12 | Fat12 = 0x01, 13 | XenixRoot = 0x02, 14 | XenixUser = 0x03, 15 | FAT16LessThan32Mb = 0x04, 16 | ExtendedMsDos = 0x05, 17 | FAT16Over32Mb = 0x06, 18 | Ntfs = 0x07, // Can also be IFS or exFAT 19 | Fat16Ext = 0x06, 20 | FAT32WithCHS = 0x0B, // Partitions up to 2047MB 21 | FAT32XWithLba = 0x0C, // Lba extension 22 | Fat16WithLba = 0xE, 23 | Fat32WithLba3 = 0xF, 24 | Linux = 0x93, 25 | LinuxSwap = 0x42, 26 | LinuxNative = 0x43, 27 | LinuxSwap2 = 0x82, 28 | LinuxNative2 = 0x83, 29 | LinuxExtended = 0x85, 30 | OsxBoot = 0xAB 31 | } fs_type; 32 | 33 | typedef enum { 34 | seek_begin = 0, 35 | seek_relative = 2, 36 | seek_end = 4 37 | } seek_origin; 38 | 39 | typedef enum { 40 | file_closed = 0, 41 | file_read = 2, 42 | file_write = 4 43 | } file_mode; 44 | 45 | typedef enum { 46 | unknown = 0, 47 | file = 2, 48 | directory = 4, 49 | device = 8 50 | } direntry_type; 51 | 52 | typedef union{ 53 | unsigned char raw; 54 | struct { 55 | unsigned char readOnly : 1; 56 | unsigned char hidden : 1; 57 | unsigned char systemFile : 1; 58 | unsigned char volumeId : 1; // This attribute is also used to indicate that the file entry is a Long file name entry 59 | unsigned char directory : 1; // Is a Sub directory (32-byte records) 60 | unsigned char archive : 1; // Has changed since backup 61 | unsigned char unused : 1; // 0 62 | unsigned char unused2 : 1; // 0 63 | } bits; 64 | } direntry_attribute; 65 | 66 | // This is what I want to do, but as I'm too lazy to add a translation between 67 | // FAT32 dir entries and my structure right now, I'll just be using the FAT32 structure for every entry 68 | //typedef struct { 69 | // unsigned int it; 70 | // char* name; 71 | // unsigned int name_len; 72 | // 73 | // // TODO: Right now this is using the FAT32 attribute structure 74 | // // Should use a more generic on in the future 75 | // direntry_attribute attribute; 76 | // // TODO: Remove long file name, should never be using short entries, so this 77 | // // Should be the default, and only entry 78 | // unsigned char hasLongName; 79 | // unsigned char longName[256]; 80 | // 81 | // // Not 100% sure I want to store the size here? 82 | // // Added it so I don't have to rewrite the entire fat32 driver now 83 | // long long size; 84 | // 85 | // // Fat32 Specifics, figure out how to remove 86 | // unsigned int first_cluster_high; 87 | // unsigned int first_cluster_low; 88 | //} direntry; 89 | 90 | typedef struct { 91 | unsigned char name[11]; // Offset; 0x00 - (11 bytes) 92 | direntry_attribute attribute; // Offset: 0x0B 93 | unsigned char reserved; // Reserved for Windows NT (Supposedly this tells us about the casing) 94 | unsigned char creationTimeInTenths; // Creation time in tenths of a second. Note: Only 24 bits used 95 | unsigned short createTime; // 5 bits Hour, 6 bits minutes, 5 bits seconds 96 | unsigned short createDate; // 7 bits year, 4 bits month, 5 bits day 97 | unsigned short lastAccessDate; // 98 | unsigned short first_cluster_high; // High 16 bits is first cluster number 99 | unsigned short lastModifiedTime; 100 | unsigned short lastModifiedDate; 101 | unsigned short first_cluster_low; // Low 16 bits is the first cluster number 102 | unsigned int size; // In bytes 103 | unsigned char hasLongName; 104 | unsigned char longName[256]; 105 | } direntry; 106 | 107 | typedef struct { 108 | direntry* entry; 109 | unsigned int offset; 110 | file_mode mode; 111 | } direntry_open; 112 | 113 | typedef struct { 114 | unsigned char bootable; // BOOTABLE_FLAG 115 | unsigned char cbs_begin[3]; // Don't use 116 | unsigned char type; // see fs_type 117 | unsigned char cbs_end[3]; // Don't use 118 | unsigned char lba_begin[4]; // 119 | unsigned char num_sectors[4]; // Size? 120 | } part_info; 121 | 122 | typedef enum { 123 | storage_read = 0, 124 | storage_write = 2 125 | } storage_device_op; 126 | 127 | typedef enum { 128 | fs_op_read = 0, 129 | fs_op_open = 2, 130 | fs_op_write = 4, 131 | fs_op_close = 8, 132 | fs_op_seek = 16, 133 | fs_op_tell = 32, 134 | fs_op_peek = 64 135 | } fs_op; 136 | 137 | // Note: Stupid forward declare because my editor is using clang to 138 | // provide program-time error checking, and it requires definitions 139 | // To be provided the first time they're used 140 | typedef struct fs_driver_info fs_driver_info; 141 | typedef struct fs_driver fs_driver; 142 | 143 | // This struct represents an initialized file system driver on a specific 144 | // Block device that has been initialized and can be used by Parition*'s to read 145 | // It is created by a drivers factory function that is registered via a call to fs_register_driver_factory 146 | struct fs_driver_info { 147 | char* name; // The name of the device on the system used in fopen("hdd/...") f.ex 148 | unsigned int name_len; 149 | BlockDevice* device; 150 | part_info* info; 151 | 152 | int(*operation)(fs_driver_info* info, fs_op op, void* arg1, void* arg2, void* arg3); 153 | // Driver specific info will be here, but the FS don't care about it 154 | // This just provides the specific filesystems with a place to store 155 | // Initialization information 156 | // The FAT driver for example will return a fat_driver_info struct 157 | // from it's fs_init() call, containing the VBR and first sector to read 158 | }; 159 | 160 | typedef struct { 161 | fs_driver_info* driver; 162 | char* name; 163 | unsigned int name_len; 164 | fs_type type; 165 | unsigned int size; 166 | direntry_open* open_dirs[10]; 167 | unsigned int num_open_dirs; 168 | } partition; 169 | 170 | typedef struct { 171 | int initialized; 172 | BlockDevice* device; 173 | unsigned int size; 174 | partition* partitions[4]; 175 | unsigned int num_partitions; 176 | } storage_device; 177 | 178 | typedef struct { 179 | char bootloader[446]; 180 | part_info partitions[4]; 181 | unsigned short signature; 182 | } mbr_t; 183 | 184 | #define MAX_FS_DRIVER_FACTORIES 4 185 | typedef struct { 186 | storage_device* devices[9]; 187 | unsigned int numDevices; 188 | 189 | int(*factories[MAX_FS_DRIVER_FACTORIES])(BlockDevice* device, part_info* pInfo, fs_driver_info** driver_info); 190 | unsigned int num_factories; 191 | } file_system; 192 | 193 | int fs_initialize(void); 194 | 195 | int fs_register_driver_factory(int(*factory)(BlockDevice* device, part_info* pInfo, fs_driver_info** driver_info)); 196 | int fs_add_device(BlockDevice*); 197 | 198 | int fs_open(char* filename, file_mode mode); 199 | int fs_close(int handle); 200 | int fs_read(int handle, char* buffer, unsigned int bytesToRead); 201 | unsigned int fs_tell(int handle); 202 | int fs_seek(int handle, unsigned int offset, seek_origin origin); 203 | 204 | 205 | #endif -------------------------------------------------------------------------------- /include/myfont.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | __ooooooooo__ 4 | oOOOOOOOOOOOOOOOOOOOOOo 5 | oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo 6 | oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo 7 | oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo 8 | oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo 9 | oOOOOOOOOOOO* *OOOOOOOOOOOOOO* *OOOOOOOOOOOOo 10 | oOOOOOOOOOOO OOOOOOOOOOOO OOOOOOOOOOOOo 11 | oOOOOOOOOOOOOo oOOOOOOOOOOOOOOo oOOOOOOOOOOOOOo 12 | oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo 13 | oOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OOOOo 14 | oOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OOOOOOo 15 | *OOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OOOOO* 16 | *OOOOOO *OOOOOOOOOOOOOOOOOOOOOOOOOOOOO* OOOOOO* 17 | *OOOOOO *OOOOOOOOOOOOOOOOOOOOOOOOOOO* OOOOOO* 18 | *OOOOOOo *OOOOOOOOOOOOOOOOOOOOOOO* oOOOOOO* 19 | *OOOOOOOo *OOOOOOOOOOOOOOOOO* oOOOOOOO* 20 | *OOOOOOOOo *OOOOOOOOOOO* oOOOOOOOO* 21 | *OOOOOOOOo oOOOOOOOO* 22 | *OOOOOOOOOOOOOOOOOOOOO* 23 | ""ooooooooo"" 24 | 25 | - Hello, I'm Lars, I'm here to push the array down far enough 26 | for the line numbers to line up with the ASCI code of the characters (in decimal) 27 | aaaaaand, I'm done! 28 | (0 - 31 is all control characters that aren't printed) 29 | 30 | */ 31 | static const unsigned char gKernelFont[][9] = { 32 | { 0,0,0,0,0,0,0,0,0 }, // space 33 | { 4,4,4,4,4,0,4,0,0 }, // ! 34 | { 10,10,10,0,0,0,0,0,0 }, // " 35 | {10,10,31,10,31,10,10,0,0}, // # 36 | { 14,21,20,14,5,21,14,0,0 }, // $ 37 | { 24,25,2,4,8,19,3,0,0 }, // % 38 | { 8,20,20,8,21,18,13,0,0 }, // & 39 | { 4,4,4,0,0,0,0,0,0 }, // ' 40 | { 2,4,8,8,8,4,2,0,0 }, // ( 41 | { 8,4,2,2,2,4,8,0,0 }, // ) 42 | { 4,21,14,4,14,21,4,0,0 }, // * 43 | { 0,4,4,31,4,4,0,0,0 }, // + 44 | { 0,0,0,0,0,4,4,8,0 }, // , 45 | { 0,0,0,14,0,0,0,0,0 }, // - 46 | { 0,0,0,0,0,0,4,0,0 }, // . 47 | { 0,1,2,4,8,16,0,0,0 }, // / 48 | { 4,10,17,17,17,10,4,0,0 }, // 0 49 | { 4,12,4,4,4,4,14,0,0 }, // 1 50 | { 14,17,1,6,8,16,31,0,0 }, // 2 51 | { 31,1,2,6,1,17,14,0,0 }, // 3 52 | { 2,6,10,18,31,2,2,0,0 }, // 4 53 | { 31,16,30,1,1,17,14,0,0 }, // 5 54 | { 6,8,16,30,17,17,14,0,0 }, // 6 55 | { 31,1,2,4,8,8,8,0,0 }, // 7 56 | { 14,17,17,14,17,17,14,0,0 }, // 8 57 | { 14,17,17,15,1,2,12,0,0 }, // 9 58 | { 0,0,4,0,0,0,4,0,0 }, // : 59 | { 0,0,4,0,0,4,4,8,0 }, // ; 60 | { 2,4,8,16,8,4,2,0,0 }, // < 61 | { 0,0,31,0,31,0,0,0,0 }, // = 62 | { 8,4,2,1,2,4,8,0,0 }, // > 63 | { 14,17,2,4,4,0,4,0,0 }, // ? 64 | { 14,17,23,21,23,16,14,0,0 }, // @ 65 | { 4,10,17,17,31,17,17,0,0 }, // A 66 | { 30,17,17,30,17,17,30,0,0 }, // B 67 | { 14,17,16,16,16,17,14,0,0 }, // C 68 | { 30,17,17,17,17,17,30,0,0 }, // D 69 | { 31,16,16,30,16,16,31,0,0 }, // E 70 | { 31,16,16,30,16,16,16,0,0 }, // F 71 | { 14,17,16,16,19,17,15,0,0 }, // G 72 | { 17,17,17,31,17,17,17,0,0 }, // H 73 | { 14,4,4,4,4,4,14,0,0 }, // I 74 | { 1,1,1,1,1,17,14,0,0 }, // J 75 | { 17,18,20,24,20,18,17,0,0 }, // K 76 | { 16,16,16,16,16,16,31,0,0 }, // L 77 | { 17,27,21,21,17,17,17,0,0 }, // M 78 | { 17,17,25,21,19,17,17,0,0 }, // N 79 | { 14,17,17,17,17,17,14,0,0 }, // O 80 | { 30,17,17,30,16,16,16,0,0 }, // P 81 | { 14,17,17,17,21,18,13,0,0 }, // Q 82 | { 30,17,17,30,20,18,17,0,0 }, // R 83 | { 14,17,16,14,1,17,14,0,0 }, // S 84 | { 31,4,4,4,4,4,4,0,0 }, // T 85 | { 17,17,17,17,17,17,14,0,0 }, // U 86 | { 17,17,17,10,10,4,4,0,0 }, // V 87 | { 17,17,17,21,21,21,10,0,0 }, // W 88 | { 17,17,10,4,10,17,17,0,0 }, // X 89 | { 17,17,10,4,4,4,4,0,0 }, // Y 90 | { 31,1,2,4,8,16,31,0,0 }, // Z 91 | { 31,16,16,16,16,16,16,31,0 }, // [ 92 | { 0,16,8,4,2,1,0,0,0}, // Backslash 93 | { 31,1,1,1,1,1,31,0,0}, // ] 94 | { 8,20,34,0,0,0,0,0 }, // ^ 95 | { 0,0,0,0,0,0,0,255,0 }, // _ 96 | { 64,32,0,0,0,0,0,0,0 }, // ` 97 | { 0,0,14,1,15,17,15,0,0 }, // a 98 | { 16,16,30,17,17,17,30,0,0 }, // b 99 | { 0,0,15,16,16,16,15,0,0 }, // c 100 | { 1,1,15,17,17,17,15,0,0 }, // d 101 | { 0,0,14,17,31,16,14,0,0 }, // e 102 | { 2,4,4,14,4,4,4,0,0 }, // f 103 | { 0,0,15,17,17,17,15,1,14 }, // g 104 | { 16,16,30,17,17,17,17,0,0 }, // h 105 | { 4,0,12,4,4,4,14,0,0 }, // i 106 | { 4,0,4,4,4,4,4,4,8 }, // j 107 | { 8,8,9,10,12,10,9,0,0 }, // k 108 | { 12,4,4,4,4,4,14,0,0 }, // l 109 | { 0,0,26,21,21,21,21,0,0 }, // m 110 | { 0,0,30,17,17,17,17,0,0 }, // n 111 | { 0,0,14,17,17,17,14,0,0 }, // o 112 | { 0,0,30,17,17,17,30,16,16 }, // p 113 | { 0,0,15,17,17,17,15,1,1 }, // q 114 | { 0,0,11,12,8,8,8,0,0 }, // r 115 | { 0,0,15,16,14,1,30,0,0 }, // s 116 | { 4,4,14,4,4,4,2,0,0 }, // t 117 | { 0,0,17,17,17,17,15,0,0 }, // u 118 | { 0,0,17,17,10,10,4,0,0 }, // v 119 | { 0,0,17,17,21,21,10,0,0 }, // w 120 | { 0,0,17,10,4,10,17,0,0 }, // x 121 | { 0,0,17,17,17,17,15,1,14 }, // y 122 | { 0,0,31,2,4,8,31,0,0 }, // z 123 | { 4,8,8,8,16,8,8,8,4}, // { 124 | { 16,16,16,16,16,16,16,16,0 }, // | 125 | { 32,16,16,16,8,16,16,16,32}, // } 126 | { 0,0,0,33,82,140,0,0,0 }, // ~ 127 | { 31,31,31,31,31,31,31,0,0 } // DEL (character-sized block) 128 | // Control Character [xxx] /* TODO: Create bitmap characters for these: */ 129 | // Control Character [xxx] 130 | // Break permitted here [BPH] Zero width space 131 | // NBH 132 | // IND 133 | // NEL 134 | // SSA 135 | // ESA 136 | // HTS 137 | // HTJ 138 | // VTS 139 | // PLD 140 | // PLU 141 | // RI 142 | // SS2 143 | // SS3 144 | // DCS 145 | // PU1 146 | // PU2 147 | // STS 148 | // CCH 149 | // MW 150 | // SPA 151 | // EPA 152 | // SOS 153 | // XXX 154 | // SCI 155 | // CSI 156 | // ST 157 | // OSC 158 | // PM 159 | // APC 160 | // NB SP 161 | // ¡ 162 | // ¢ 163 | // £ 164 | // ¤ 165 | // ¥ 166 | // ¦ 167 | // § 168 | // ¨ 169 | // © 170 | // ª 171 | // « 172 | // ¬ 173 | // SHY 174 | // ® 175 | // ¯ 176 | // ° 177 | // ± 178 | // ² 179 | // ³ 180 | // ´ 181 | // μ 182 | // ¶ 183 | // · 184 | // ¸ 185 | // ¹ 186 | // º 187 | // » 188 | // ¼ 189 | // ½ 190 | // ¾ 191 | // ¿ 192 | // À 193 | // Á 194 | // Â 195 | // Ã 196 | // Ä 197 | // Å 198 | // Æ 199 | // Ç 200 | // È 201 | // É 202 | // Ê 203 | // Ë 204 | // Ì 205 | // Í 206 | // Î 207 | // Ï 208 | // Ð 209 | // Ñ 210 | // Ò 211 | // Ó 212 | // Ô 213 | // Õ 214 | // Ö 215 | // × 216 | // Ø 217 | // Ù 218 | // Ú 219 | // Û 220 | // Ü 221 | // Ý 222 | // Þ 223 | // ß 224 | // à 225 | // á 226 | // â 227 | // ã 228 | // ä 229 | // å 230 | // æ 231 | // ç 232 | // è 233 | // é 234 | // ê 235 | // ë 236 | // ì 237 | // í 238 | // î 239 | // ï 240 | // ð 241 | // ñ 242 | // ò 243 | // ó 244 | // ô 245 | // õ 246 | // ö 247 | // ÷ 248 | // ø 249 | // ù 250 | // ú 251 | // û 252 | // ü 253 | // ý 254 | // þ 255 | // ÿ 256 | }; 257 | // Characters not in use, but they might come in handy later on 258 | // { 0,4,0,31,0,4,0,0,0 }, // divide sign 259 | // { 8,8,8,8,9,3,5,7,1 }, // 1/4 260 | // { 10,10,10,10,10,10,10,0,0 }, // || (Double pipe) 261 | // { 16,16,16,16,22,1,2,4,7 }, // 1/2 262 | // { 6,9,8,28,8,8,31,0,0 }, // £ 263 | // { 0,4,8,31,8,4,0,0,0 }, // left arrow [ in ASCII 264 | // { 0,4,2,31,2,4,0,0,0 }, // right arrow ] in ASCII 265 | // { 10,10,31,10,31,10,10,0,0 }, // # _ in ASCII -------------------------------------------------------------------------------- /visualstudio/PiOSVisualStudio.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | 10 | {C99F3786-0FAF-45D4-B4F9-2B73E4C7AC44} 11 | PiOSVisualStudio 12 | 13 | 14 | 15 | Makefile 16 | true 17 | v120 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | $(ProjectDir)vsbuild.bat PiOS 28 | MyMakefileProj.exe 29 | $(ProjectDir)vsbuild.bat clean 30 | $(ProjectDir)vsbuild.bat rebuild 31 | WIN32;_DEBUG;$(NMakePreprocessorDefinitions) 32 | ..\include;$(NMakeIncludeSearchPath) 33 | ..\include;$(IncludePath) 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /source/hardware/mailbox.c: -------------------------------------------------------------------------------- 1 | #include "hardware/mailbox.h" 2 | #include "memory.h" 3 | #include "memory_map.h" 4 | #include "types/string.h" 5 | #include "hardware/timer.h" 6 | 7 | static volatile unsigned int *gMailbox0Read = (unsigned int *)(PERIPHERAL_VA_MAILBOX_BASE); 8 | static volatile unsigned int *gMailbox0Status = (unsigned int *)(PERIPHERAL_VA_MAILBOX_BASE + 0x18); 9 | static volatile unsigned int *gMailbox0Write = (unsigned int *)(PERIPHERAL_VA_MAILBOX_BASE + 0x20); 10 | 11 | unsigned int Mailbox_Read(unsigned int channel) 12 | { 13 | unsigned int count = 0; 14 | unsigned int data; 15 | 16 | // Loop until something is received on the channel 17 | while(1) 18 | { 19 | while (*gMailbox0Status & MAILBOX_EMPTY) 20 | { 21 | FlushCache(); 22 | 23 | // Arbitrary large number for timeout 24 | if(count++ >(1<<25)) 25 | { 26 | return 0xffffffff; 27 | } 28 | } 29 | DataMemoryBarrier(); 30 | 31 | data = *gMailbox0Read; 32 | 33 | DataMemoryBarrier(); 34 | 35 | if ((data & 15) == channel) 36 | return data; 37 | } 38 | } 39 | 40 | void Mailbox_Write(unsigned int channel, unsigned int data) 41 | { 42 | // Wait until there's space in the mailbox 43 | while (*gMailbox0Status & MAILBOX_FULL) 44 | { 45 | FlushCache(); 46 | } 47 | 48 | DataMemoryBarrier(); 49 | 50 | // 28 MSB is data, 4 LSB = channel 51 | *gMailbox0Write = (data | channel); 52 | } 53 | 54 | unsigned int Mailbox_SdGetBaseFrequency(void) 55 | { 56 | volatile unsigned int mailbuffer[256] __attribute__ ((aligned (16))); 57 | 58 | unsigned int bufSize = 1; 59 | mailbuffer[bufSize++] = 0; // 1. This is a request 60 | mailbuffer[bufSize++] = 0x00030002; // 2. "Get clock rate" tag 61 | mailbuffer[bufSize++] = 8; // 3. Value buffer size 62 | mailbuffer[bufSize++] = 4; // 4. Value length 63 | mailbuffer[bufSize++] = 1; // 5. Clock id + response - Clock id 64 | mailbuffer[bufSize++] = 0; // 6. - Response rate (in Hz) 65 | mailbuffer[bufSize++] = 0; // 7. Closing tag 66 | mailbuffer[0] = bufSize * 4; // 0. Size of the entire buffer (in bytes) 67 | 68 | unsigned int bufferAddr = &mailbuffer; 69 | bufferAddr -= KERNEL_VA_START; 70 | 71 | Mailbox_Write(8, bufferAddr); 72 | 73 | Mailbox_Read(8); 74 | 75 | // Check valid response 76 | if(mailbuffer[1] != RESPONSE_SUCCESS) 77 | { 78 | printf("Failed to retrieve SD base frequency - Invalid mailbox response.\n"); 79 | return -1; 80 | } 81 | 82 | // Check returned clock id 83 | if(mailbuffer[5] != 0x1) 84 | { 85 | printf("Failed to retrieve SD base frequency - Invalid clock id.\n"); 86 | return -1; 87 | } 88 | 89 | // Return the rate 90 | return mailbuffer[6]; 91 | } 92 | 93 | unsigned int Mailbox_GetPowerState(unsigned int deviceId) 94 | { 95 | volatile unsigned int mailbuffer[256] __attribute__ ((aligned (16))); 96 | 97 | unsigned int bufSize = 1; 98 | mailbuffer[bufSize++] = 0; // 1. Request indicator 99 | mailbuffer[bufSize++] = 0x00020001; // 2. Tag - Get power state 100 | mailbuffer[bufSize++] = 0x8; // 3. Value buffer size (in bytes) 101 | mailbuffer[bufSize++] = 0x4; // 4. Value size (in bytes) 102 | mailbuffer[bufSize++] = deviceId; // 5. Value - Device Id 103 | mailbuffer[bufSize++] = 0; // 6. Response - State of device 104 | mailbuffer[bufSize++] = 0; // 7. End of message tag 105 | mailbuffer[0] = bufSize * 4; // 0. Size of entire buffer (in bytes) 106 | 107 | unsigned int bufferAddr = &mailbuffer; 108 | bufferAddr -= KERNEL_VA_START; 109 | 110 | Mailbox_Write(8, bufferAddr); 111 | 112 | Mailbox_Read(8); 113 | 114 | if(mailbuffer[1] != RESPONSE_SUCCESS) 115 | { 116 | printf("Failed to get power state, invalid mailbox response"); 117 | return -1; 118 | } 119 | 120 | return mailbuffer[6]; 121 | } 122 | 123 | int Mailbox_GetClockRate(unsigned int clockId) 124 | { 125 | volatile unsigned int mailbuffer[256] __attribute__((aligned(16))); 126 | 127 | unsigned int bufSize = 1; 128 | mailbuffer[bufSize++] = 0; // 1. Indicates Requests 129 | mailbuffer[bufSize++] = MBT_GET_CLOCKRATE; // 2. Tag 130 | mailbuffer[bufSize++] = 0x8; // 3. Value buffer size 131 | mailbuffer[bufSize++] = 0x4; // 4. Value size 132 | mailbuffer[bufSize++] = clockId; // 5. Value - Clock Id 133 | mailbuffer[bufSize++] = 0; // 6. Response - Rate (in Hz) 134 | mailbuffer[bufSize++] = 0; // 7. End of message tag 135 | mailbuffer[0] = bufSize * 4; // 0. Size o entire buffer (in bytes) 136 | 137 | unsigned int bufferAddr = &mailbuffer; 138 | bufferAddr -= KERNEL_VA_START; 139 | 140 | Mailbox_Write(8, bufferAddr); 141 | 142 | Mailbox_Read(8); 143 | 144 | if (mailbuffer[1] != RESPONSE_SUCCESS) 145 | { 146 | printf("Mailbox: Failed to retrieve clock rate for clock with id %d\n", clockId); 147 | return -1; 148 | } 149 | 150 | return mailbuffer[6]; 151 | } 152 | 153 | unsigned int Mailbox_SetClockRate(unsigned int clockId, unsigned int rate) 154 | { 155 | volatile unsigned int mailbuffer[256] __attribute__((aligned(16))); 156 | 157 | unsigned int bufSize = 1; 158 | mailbuffer[bufSize++] = 0; // 1. Request indicator 159 | mailbuffer[bufSize++] = MBT_SET_CLOCKRATE; // 2. Tag 160 | mailbuffer[bufSize++] = 0x8; // 3. Value buffer size 161 | mailbuffer[bufSize++] = 0x8; // 4. Value size 162 | mailbuffer[bufSize++] = clockId; // 5. Id of clock to change (see mb_clock_id enum) 163 | mailbuffer[bufSize++] = rate; // 6. New clock rate (in Hz) 164 | mailbuffer[bufSize++] = 0; // 7. End of message 165 | mailbuffer[0] = bufSize * 4; // 0. Size of this buffer 166 | 167 | unsigned int bufferAddr = &mailbuffer; 168 | bufferAddr -= KERNEL_VA_START; 169 | 170 | Mailbox_Write(8, bufferAddr); 171 | 172 | if (mailbuffer[1] != RESPONSE_SUCCESS) 173 | { 174 | printf("Failed to set clock rate for clock %d, Invalid mailbox response.\n", clockId); 175 | return -1; 176 | } 177 | 178 | if (mailbuffer[6] == 0) 179 | { 180 | printf("Failed to set clock rate for clock %d, Invalid clock id.\n", clockId); 181 | return -1; 182 | } 183 | 184 | return mailbuffer[6]; 185 | } 186 | 187 | int Mailbox_SetDevicePowerState(unsigned int deviceId, unsigned int powerState) 188 | { 189 | volatile unsigned int mailbuffer[256] __attribute__ ((aligned (16))); 190 | 191 | unsigned int bufSize = 1; 192 | mailbuffer[bufSize++] = 0; // 1. Request indicator 193 | mailbuffer[bufSize++] = 0x00028001; // 2. TAG - Set Power 194 | mailbuffer[bufSize++] = 0x8; // 3. Value buffer size (in bytes) 195 | mailbuffer[bufSize++] = 0x8; // 4. Value size (in bytes) 196 | mailbuffer[bufSize++] = deviceId; // 5. Value - Device id 197 | mailbuffer[bufSize++] = powerState; // 6. Value - State (On, do not wait) 198 | mailbuffer[bufSize++] = 0; // 7. End of message tag 199 | mailbuffer[0] = bufSize * 4; // 0. Size of this buffer (in bytes) 200 | 201 | unsigned int bufferAddr = &mailbuffer; 202 | bufferAddr -= KERNEL_VA_START; 203 | 204 | Mailbox_Write(8, bufferAddr); 205 | 206 | wait(200); // Wait for device to power on (Note we're passing in "don't wait" to power cmd) 207 | 208 | Mailbox_Read(8); 209 | 210 | if(mailbuffer[1] != RESPONSE_SUCCESS) 211 | { 212 | printf("Failed to change power state of device '%d', Invalid mailbox response.\n", deviceId); 213 | return -1; 214 | } 215 | 216 | if(mailbuffer[5] != 0x0) 217 | { 218 | printf("Failed to change power state of device, invalid device id '%d'.\n", deviceId); 219 | return -1; 220 | } 221 | 222 | if((mailbuffer[6] & 0x3) != powerState) 223 | { 224 | printf("Failed to change power state of device, device did not change state successfully, current state: %d.\n", mailbuffer[6]); 225 | return -1; 226 | } 227 | 228 | return 0; 229 | } 230 | --------------------------------------------------------------------------------