├── 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 |
--------------------------------------------------------------------------------