diff --git a/README.md b/README.md index d3251d1..3305ce0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,18 @@ -Raspberry Pi C++ Kernel -==== +## RasPI C++ Kernel (Mindflayer) -This is a project I'm working on dedicated to writing a kernel in C++ specifically targetted towards the Raspberry Pi. This is not a Linux Kernel, it is a bare-metal project completely from scratch. -Included in the main code directory are a few files called "RaspberryLib.cpp"/.h which provide basic functionality necessary for interfacing with the raspberry pi. They have been thoroughly tested and I encourage anyone who is interested to try it out, use my code, whatever. +This bare-metal project was written entirely from scratch and is the product of countless months of research and trial. It was my attempt at learning how to write a kernel, but this project transcends that goal. _Not only do I present to you a reasonably functional kernel, but also a lot of well commented code and a beautiful MIT license._ Use this project to your hearts content, in any way imaginable. It was born out of a search for knowledge, and I hope the blood and sweat of my journey will assist others out there. +### Features + +Mindflayer sports a hearty array of features, functions, helpers, etc. Most of the functionality lies within the framework itself, but here's a rather comprehensive list: + +- Ability to set GPIO pins. +- Super basic drawing library. +- Examples of mapping to the IVT (interrupt vector table). +- Keyboard input (thanks to Alex Chadwick from Baking Pi). +- Memory management (and support for the _new_ keyword). +- Simple threading (no scheduler, also a work-in-progress). + +### Future of This Project + +The sky is the limit! I have some really odd ideas for my kernel, but they will probably go in a separate repository. I hope to keep this project pure and simply dedicated to the nuances of kernel development. diff --git a/code/common.h b/code/common.h index 908192c..d3f9cd6 100755 --- a/code/common.h +++ b/code/common.h @@ -11,11 +11,137 @@ #ifndef __COMMON_H_ #define __COMMON_H_ +#include "./libs/mem.h" + +#define NULL 0 + typedef unsigned long ulong; typedef unsigned int uint32; +typedef volatile unsigned long int uint32_t; typedef unsigned short uint16; typedef unsigned char byte; +// Stack data structure. +template +class iterator { + public: + T val; + iterator* prev; + iterator(iterator* previous, T value ) { + this->val = value; + this->prev = previous; + } + + volatile iterator* next() { + if ( this->prev == NULL ) return NULL; + return this->prev; + } + + T getVal() { + return this->val; + } +}; + +template +class Stack { + private: + iterator* top; + int length; + + public: + void push(T* val) { + iterator* next = new iterator( this->top, val ); + this->top = next; + this->length++; + } + + T* pop( void ) { + // NULL Checking + if ( this->top == NULL ) return NULL; + + // Do the pop + T* result = this->top->getVal(); + this->top = this->top->next(); + this->length--; + + // Return the result + return result; + } + + int getLength() { + return this->length; + } + + iterator* getIterator() { + return this->top; + } +}; + +template +class List { + public: + iterator* first; + uint32 length; + + List() { + this->first = NULL; + this->length = 0; + } + + void add(T val) { + // Allocate it. + void* ptrN = malloc(sizeof(iterator)); + + iterator* newItem = new (ptrN) iterator (NULL, val); + iterator* last = this->first; + if ( last == NULL ) { + this->first = newItem; + } else if ( last->prev == NULL ) { + this->first->prev = newItem; + } else { + do { + last = last->prev; + } while ( last->prev != NULL ); + last->prev = newItem; + } + + this->length++; + } + + T getAt(int index) { + if ( this->first == NULL ) return (T)NULL; + + if ( index == 0 ) { + return this->first->val; + } else { + iterator* last = this->first; + do { + last = last->prev; + index--; + } while ( last->prev != NULL && index > 0 ); + return last->val; + } + } + + T pop() { + volatile iterator* last = this->first; + do { + last = last->prev; + } while ( last->prev != NULL ); + volatile iterator* result = last->prev; + last->prev = NULL; + return result->val; + } + + int getLength() { + return this->length; + } + + iterator* getIterator() { + return this->first; + } +}; + // Linked list structure/class class LinkedList { public: diff --git a/code/console.cpp b/code/console.cpp index 256f204..40258d0 100755 --- a/code/console.cpp +++ b/code/console.cpp @@ -64,6 +64,10 @@ void Console::kprint( const char* string ) { this->kprint( (char*) string ); } +void Console::kprint( char c ) { + this->printChar( c, 0xFFFFFF ); +} + // Clearscreen function. void Console::clear( void ) { this->charx = 0; diff --git a/code/console.h b/code/console.h index 9780e87..0cb093e 100755 --- a/code/console.h +++ b/code/console.h @@ -2,7 +2,8 @@ #define __CONSOLE_H_ #include "common.h" -#include "math.h" +#include "./libs/mem.h" +#include "./libs/math.h" #include "raspberrylib.h" #include "gpu2d.h" @@ -20,6 +21,7 @@ class Console { void kprintf( const char* string, T value ); // Standard printf functions. + void kprint( char c ); void kprint( char* string ); void kprint( const char* string ); void kbase( long value, long base, long size ); diff --git a/code/gpu2d.cpp b/code/gpu2d.cpp index 9db9f8e..d8d7059 100755 --- a/code/gpu2d.cpp +++ b/code/gpu2d.cpp @@ -1,7 +1,7 @@ // ******************************* // FILE: gpu2d.cpp // AUTHOR: SharpCoder -// DATE: 2012-03-28 +// DATE: 2013-03-28 // ABOUT: This is the 2D graphics engine (re written) for my // raspberry pi kernel. I'm trying to implement some // nicer functions and a backbuffer to make everything @@ -29,8 +29,8 @@ gpu2dCanvas::gpu2dCanvas( bool useDoubleBuffer ) { this->fbInfo = (FB_Info*)KERNEL_FB_LOC; // Setup some information about the canvas. - this->fbInfo->screen_width = 1024; - this->fbInfo->screen_height = 768; + this->fbInfo->screen_width = 800; + this->fbInfo->screen_height = 600; this->fbInfo->virtual_width = this->fbInfo->screen_width; // If we're using double buffer... diff --git a/code/gpu2d.h b/code/gpu2d.h index 1e2dd31..714b44a 100755 --- a/code/gpu2d.h +++ b/code/gpu2d.h @@ -15,7 +15,7 @@ // Include the common library. #include "common.h" #include "raspberrylib.h" -#include "mem.h" +#include "./libs/mem.h" class FB_Info { public: diff --git a/code/irq.S b/code/irq.S index 83db74d..5f2d486 100755 --- a/code/irq.S +++ b/code/irq.S @@ -1,7 +1,8 @@ .global init_entry_point +.extern kmain .extern init -.extern irq_handler +.extern interrupt_vector ;@ This is the actual entr point to the application. ;@ I need to look into how to do this another way, but it seems like @@ -44,11 +45,8 @@ init_entry_point: ;@ Next up is a trick to basically force the compiler ;@ to store the branch command as a value ;@ into the respective register. -reset_handler: - .word reset - -basic_handler: - .word arm_interrupt_handler +reset_handler: .word reset +basic_handler: .word arm_interrupt_handler ;@ Then this is our "reset" function ;@ which is what will actually get automatically @@ -66,25 +64,51 @@ reset: ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9} stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9} + ;@ (PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) + mov r0,#0xD2 + msr cpsr_c,r0 + mov sp,#0x8000 + + ;@ (PSR_FIQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) + mov r0,#0xD1 + msr cpsr_c,r0 + mov sp,#0x4000 + + ;@ (PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) + mov r0,#0xD3 + msr cpsr_c,r0 + mov sp,#0x800000 + ;@ And then call the bootstrapper init function. ;@ NOTE: I delegated these two assembly files because I don't ;@ want to marry my kernel to the ivt setup code. - b init - bx lr - + bl kmain + b hang hang: b hang - + +.globl enable_irq +enable_irq: + mrs r0,cpsr + bic r0,r0,#0x80 + msr cpsr_c,r0 + bx lr + ;@ And here is the actual interrupt handler code. arm_interrupt_handler: - - ;@ Store the return link. - sub r14, r14, #4 - stmfd sp!, {r0,r1,r2,r3,r4,r14} + + ;@ Store the return link. + stm sp, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12} + + ;@ Setup the arguments for our method. + mov r0, lr + mov r1, sp ;@ Invoke our C++ irq handler. - bl irq_handler + bl interrupt_vector + ;@ subs pc, r14, #4 + b hang ;@ Restore to the original caller. - ldmfd sp!, {r0,r1,r2,r3,r4,pc}^ - bx lr + ;@ ldmfd sp!, {r0,r1,r2,r3,r4,pc}^ + ;@ bx lr diff --git a/code/irq.cpp b/code/irq.cpp index ff8efd4..bc16851 100755 --- a/code/irq.cpp +++ b/code/irq.cpp @@ -1,37 +1,232 @@ #include "raspberrylib.h" +#include "./libs/mem.h" #include "console.h" -Console* irq_console; -bool use_irq_console; +#define RPI_INTERRUPT_CONTROLLER_BASE 0x2000B200 +#define RPI_ARMTIMER_BASE 0x2000B400 -extern "C" void irq_handler( void ) { +#define RPI_ARMTIMER_CTRL_23BIT ( 1 << 1 ) +#define RPI_ARMTIMER_CTRL_PRESCALE_1 ( 0 << 2 ) +#define RPI_ARMTIMER_CTRL_PRESCALE_16 ( 1 << 2 ) +#define RPI_ARMTIMER_CTRL_PRESCALE_256 ( 2 << 2 ) +#define RPI_ARMTIMER_CTRL_INT_ENABLE ( 1 << 5 ) +#define RPI_ARMTIMER_CTRL_INT_DISABLE ( 0 << 5 ) +#define RPI_ARMTIMER_CTRL_ENABLE ( 1 << 7 ) +#define RPI_ARMTIMER_CTRL_DISABLE ( 0 << 7 ) + +typedef struct { + volatile uint32_t Load; + volatile uint32_t Value; + volatile uint32_t Control; + volatile uint32_t IRQClear; + volatile uint32_t RAWIRQ; + volatile uint32_t MaskedIRQ; + volatile uint32_t Reload; + volatile uint32_t PreDivider; + volatile uint32_t FreeRunningCounter; +} rpi_arm_timer_t; + +typedef struct { + volatile uint32_t IRQ_basic_pending; + volatile uint32_t IRQ_pending_1; + volatile uint32_t IRQ_pending_2; + volatile uint32_t FIQ_control; + volatile uint32_t Enable_IRQs_1; + volatile uint32_t Enable_IRQs_2; + volatile uint32_t Enable_Basic_IRQs; + volatile uint32_t Disable_IRQs_1; + volatile uint32_t Disable_IRQs_2; + volatile uint32_t Disable_Basic_IRQs; +} rpi_irq_controller_t; + +static rpi_irq_controller_t* rpiIRQController = (rpi_irq_controller_t*)RPI_INTERRUPT_CONTROLLER_BASE; +static rpi_arm_timer_t* rpiArmTimer = (rpi_arm_timer_t*)RPI_ARMTIMER_BASE; +rpi_arm_timer_t* RPI_GetArmTimer(void) { return rpiArmTimer; } +rpi_irq_controller_t* RPI_GetIrqController( void ) { return rpiIRQController; } +void irq_deactivate(void); +void irq_init(void); + +extern "C" struct thread { + uint32_t addr; + uint32_t lr; + uint32_t sptr; + uint32 pid; + bool isRun; + bool isDead; + bool isLock; +}; + +// Keep a queue of jobs. +static List threads; + +// These tell the control thread what's up. +static short irqStatus = 0; + +static short ind = 0; +static uint32 guid = 0; +static uint32 turn = 0; +static bool led_on = false; +Console* irqConsole; + +void fork(void (*ptr)(void)) { + thread* t = new thread(); + t->pid = guid++; + t->isRun = false; + t->isDead = false; + t->isLock = false; + t->addr = (uint32_t)ptr; + threads.add(t); +} + +thread* next_task() { + int len = threads.getLength(); + thread* result; - if ( use_irq_console ) - irq_console->kout("INTERRUPT"); - - // Blink once to show we've been here. - RaspberryLib::Wait( 100 ); - return; + // Iterate over the threads an increment until we come to a live thread. + for ( int i = 0; i < len; i++ ) { + if ( ++ind >= len ) + ind = 0; + + // Find the next one that is not dead. + result = threads.getAt(ind); + if ( !result->isDead ) + break; + } + + return result; +} + +void lock() { + irq_deactivate(); + // Set the current thread to locked. + uint32 length = threads.getLength(); + if ( length > 0 ) { + thread* active = threads.getAt(ind); + active->isLock = true; + } + // Resume interrupts. + irq_init(); +} + +void unlock() { + irq_deactivate(); + uint32 length = threads.getLength(); + thread* active = threads.getAt(ind); + active->isLock = false; + irq_init(); } -bool irq_enable( void ) { +extern "C" void interrupt_vector() { + // Clear the arm timer interrupt. + uint32_t ptr_sp; + uint32_t ptr_lr; + + asm volatile("mov %0,r0\n\t" + "mov %1,r1\n\t" + : "=r"(ptr_lr), "=r"(ptr_sp) : : "r0", "r1", "memory"); + + + if ( threads.getLength() == 0 ) { + return; + } + + // Flip the LED each iteration, to show we're actively capturing + // interrupts. + RaspberryLib::SetGPIO(16, !led_on); + led_on = !led_on; + + // We get the active thread (that which last run) and we + // store the return pointer and other related information + // in the thread control block. + thread* t = threads.getAt(ind); + bool resumeThread = false; + + // Check the irqStatus and finish processing if necessary. + if ( irqStatus == 1 ) { + // Enable interrupts again. + irq_init(); + } else if ( irqStatus == 2 ) { + // This is bad... We don't actually want to jump to another thread then. + irq_deactivate(); + resumeThread = true; + } + + // Reset IRQ Status. + irqStatus = 0; - volatile uint32* address = (volatile uint32*)( 0x2000b000 ); + if ( t->isRun ) { + t->sptr = ptr_sp; + t->lr = ptr_lr; + + if ( !resumeThread ) { + thread* next = next_task(); + if (!t->isLock && turn == t->pid) + turn = next->pid; + t = next; + } + } - // ENABLE IRQ 1 - *( address + 0x210 ) = 0xFFFFFFFF; + if ( !t->isRun ) { + // Update the ish. + t->lr = t->addr; + t->sptr = (uint32_t)alloc_stack(128); + t->isRun = true; + RPI_GetArmTimer()->IRQClear = 1; + + // We need to allocate a new stack. + // Then we need to copy the registers over to it. + asm volatile("mov r0,%0\n\t" // new stack pointer + "mov r1,%1\n\t" // old stack pointer + "mov r14,%2\n\t" + "mov sp,r0\n\t" // move the stack pointer + "ldm r1,{r0-r12}\n\t" // load the registers from the old location + "subs pc,r14,#4\n\t" + : : "r"(t->sptr), "r"(ptr_sp), "r"(t->lr) : "memory", "r0", "r1", "sp", "r14", "pc" ); + + // This code gets executed after, theoretically, the thread finishes. + t->isLock = false; + t->isDead = true; + while(true) { } + return; + } - // ENABLE IRQ 2 - *( address + 0x214 ) = 0xFFFFFFFF; + RPI_GetArmTimer()->IRQClear = 1; - // ENABLE BASIC IRQ - *( address + 0x218 ) = 0x000000FF; + // If the thread is locked, spin. + while(t->isLock && turn != t->pid) { } - return true; + // Otherwise, we can execute our ish. + asm volatile("mov r14,%0\n\t" + "mov r0,%1\n\t" + "mov sp,r0\n\t" + "ldm sp,{r0-r12}\n\t" + "subs pc,r14,#4\n\t": : "r"(t->lr), "r"(t->sptr) : "memory","sp", "r14", "r0", "pc" ); + + return; } -void irq_test( void ) { +void irq_init( void ) { + // Tell the control thread what's what. + irqStatus = 1; + RPI_GetIrqController()->Enable_Basic_IRQs = (1<<0); - asm volatile( "SWI #0x0000FF" ); - + /* Timer frequency = Clk/256 * 0x400 */ + RPI_GetArmTimer()->Load = 0x100; // Fast 0xa0 + + /* Setup the ARM Timer */ + RPI_GetArmTimer()->Control = + RPI_ARMTIMER_CTRL_23BIT | + RPI_ARMTIMER_CTRL_ENABLE | + RPI_ARMTIMER_CTRL_INT_ENABLE | + RPI_ARMTIMER_CTRL_PRESCALE_256; + + irqStatus = 0; +} + +void irq_deactivate() { + // Tell the control thread what's what. + irqStatus = 2; + RPI_GetIrqController()->Enable_Basic_IRQs = 0; + RPI_GetIrqController()->Disable_Basic_IRQs = (1<<0); + irqStatus = 0; } diff --git a/code/keyboard.S b/code/keyboard.S new file mode 100755 index 0000000..c34d443 --- /dev/null +++ b/code/keyboard.S @@ -0,0 +1,210 @@ +/****************************************************************************** +* keyboard.s +* by Alex Chadwick +* +* A sample assembly code implementation of the input02 operating system. +* See main.s for details. +* +* keyboard.s contains code to do with the keyboard. +******************************************************************************/ + +.section .text +/* +* The address of the keyboard we're reading from. +* C++ Signautre: u32 KeyboardAddress; +*/ +.align 2 +KeyboardAddress: + .int 0 + +/* +* The scan codes that were down before the current set on the keyboard. +* C++ Signautre: u16* KeyboardOldDown; +*/ +KeyboardOldDown: + .rept 6 + .hword 0 + .endr + +/* +* KeysNoShift contains the ascii representations of the first 104 scan codes +* when the shift key is up. Special keys are ignored. +* C++ Signature: char* KeysNoShift; +*/ +.align 3 +KeysNormal: + .byte 0x0, 0x0, 0x0, 0x0, 'a', 'b', 'c', 'd' + .byte 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l' + .byte 'm', 'n', 'o', 'p', 'q', 'r', 's', 't' + .byte 'u', 'v', 'w', 'x', 'y', 'z', '1', '2' + .byte '3', '4', '5', '6', '7', '8', '9', '0' + .byte '\n', 0x0, '\b', '\t', ' ', '-', '=', '[' + .byte ']', '\\', '#', ';', '\'', '`', ',', '.' + .byte '/', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + .byte 0xFF, 0x0, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0 + .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+' + .byte '\n', '1', '2', '3', '4', '5', '6', '7' + .byte '8', '9', '0', '.', '\\', 0x0, 0x0, '=' + +/* +* KeysShift contains the ascii representations of the first 104 scan codes +* when the shift key is held. Special keys are ignored. +* C++ Signature: char* KeysShift; +*/ +.align 3 +KeysShift: + .byte 0x0, 0x0, 0x0, 0x0, 'A', 'B', 'C', 'D' + .byte 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L' + .byte 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T' + .byte 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"' + .byte '$', '$', '%', '^', '&', '*', '(', ')' + .byte '\n', 0x0, '\b', '\t', ' ', '_', '+', '{' + .byte '}', '|', '~', ':', '@', '$', '<', '>' + .byte '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+' + .byte '\n', '1', '2', '3', '4', '5', '6', '7' + .byte '8', '9', '0', '.', '|', 0x0, 0x0, '=' + +.section .text +/* +* Updates the keyboard pressed and released data. +* C++ Signature: void KeyboardUpdate(); +*/ +.globl KeyboardUpdate +KeyboardUpdate: + push {r4,r5,lr} + + kbd .req r4 + ldr r0,=KeyboardAddress + ldr kbd,[r0] + + teq kbd,#0 + bne haveKeyboard$ + +getKeyboard$: + bl UsbCheckForChange + bl KeyboardCount + teq r0,#0 + ldreq r1,=KeyboardAddress + streq r0,[r1] + beq return$ + + mov r0,#0 + bl KeyboardGetAddress + ldr r1,=KeyboardAddress + str r0,[r1] + teq r0,#0 + beq return$ + mov kbd,r0 + +haveKeyboard$: + mov r5,#0 + + saveKeys$: + mov r0,kbd + mov r1,r5 + bl KeyboardGetKeyDown + + ldr r1,=KeyboardOldDown + add r1,r5,lsl #1 + strh r0,[r1] + add r5,#1 + cmp r5,#6 + blt saveKeys$ + + mov r0,kbd + bl KeyboardPoll + teq r0,#0 + bne getKeyboard$ + +return$: + pop {r4,r5,pc} + .unreq kbd + +/* +* Returns r0=0 if a in r1 key was not pressed before the current scan, and r0 +* not 0 otherwise. +* C++ Signature bool KeyWasDown(u16 scanCode) +*/ +.globl KeyWasDown +KeyWasDown: + ldr r1,=KeyboardOldDown + mov r2,#0 + + keySearch$: + ldrh r3,[r1] + teq r3,r0 + moveq r0,#1 + moveq pc,lr + + add r1,#2 + add r2,#1 + cmp r2,#6 + blt keySearch$ + + mov r0,#0 + mov pc,lr + +/* +* Returns the ascii character last typed on the keyboard, with r0=0 if no +* character was typed. +* C++ Signature char KeyboardGetChar() +*/ +.globl KeyboardGetChar +KeyboardGetChar: + ldr r0,=KeyboardAddress + ldr r1,[r0] + teq r1,#0 + moveq r0,#0 + moveq pc,lr + + push {r4,r5,r6,lr} + + kbd .req r4 + key .req r6 + + mov r4,r1 + mov r5,#0 + + keyLoop$: + mov r0,kbd + mov r1,r5 + bl KeyboardGetKeyDown + + teq r0,#0 + beq keyLoopBreak$ + + mov key,r0 + bl KeyWasDown + teq r0,#0 + bne keyLoopContinue$ + + cmp key,#104 + bge keyLoopContinue$ + + mov r0,kbd + bl KeyboardGetModifiers + + tst r0,#0b00100010 + ldreq r0,=KeysNormal + ldrne r0,=KeysShift + + ldrb r0,[r0,key] + teq r0,#0 + bne keyboardGetCharReturn$ + + keyLoopContinue$: + add r5,#1 + cmp r5,#6 + blt keyLoop$ + + keyLoopBreak$: + mov r0,#0 +keyboardGetCharReturn$: + pop {r4,r5,r6,pc} + .unreq kbd + .unreq key + diff --git a/code/keyboard.h b/code/keyboard.h new file mode 100755 index 0000000..c5c20a4 --- /dev/null +++ b/code/keyboard.h @@ -0,0 +1,23 @@ +#ifndef __KEYBOARD_H_ +#define __KEYBOARD_H_ + +// Include core files. +#include "common.h" + +// List all of the functions that our library exports. +extern "C" { + uint32 KeyboardAddress; + uint16* KeyboardOldDown; + char* KeysNoShift; + char* KeysShift; + void KeyboardUpdate(); + bool KeyWasDown(uint16 scanCode); + char KeyboardGetChar(); + extern void UsbInitialise(); + extern void UsbCheckForChange(); + extern int KeyboardCount(); + extern void KbdLoad(); +}; + + +#endif diff --git a/code/kmain.cpp b/code/kmain.cpp index 4e333df..1019ec4 100755 --- a/code/kmain.cpp +++ b/code/kmain.cpp @@ -11,67 +11,93 @@ #include "raspberrylib.cpp" #include "gpu2d.cpp" #include "console.cpp" +#include "keyboard.h" // Include the meta data generate at compile time -// #include "meta.h" -#include "mem.h" -#include "math.h" +#include "./libs/mem.h" +#include "./libs/math.h" +#include "./libs/string.h" #include "meta.h" using namespace RaspberryLib; +Console* console; + // Define any functions. void print_header( Console* console ); +void printf( const char* c); +void assert( const char* c); +extern "C" void enable_irq(); + +void run1() { + while(true) { + // NOTE: locking mechanism has issues... + lock(); + // NOTE: printf() is not thread safe. + //printf("Hello from thread 1\n"); + unlock(); + Wait(1000); + } +} + +void run2() { + while(true) { + // NOTE: locking mechanism has issues... + lock(); + // NOTE: printf() is not thread safe. + //printf("Hello from thread 2\n"); + unlock(); + Wait(1000); + } +} // Define the entry point for our application. // Note: It must be marked as "extern" in order for the linker // to see it properly. extern "C" void kmain( void ) { - + + // Initialize the irq + irq_init(); + + // Initialize at zero. + sbrk(0); + // Create a canvas. gpu2dCanvas canvas(false); // Create a console. - Console console(&canvas); + console = new Console(&canvas); - // Wire up the interrupts. - irq_console = &console; - use_irq_console = true; + // setup the IRQ console + irqConsole = console; // Draw to the console. - print_header( &console ); - - console.kprint("Waiting: "); - int index; - for(index = 18; index > 0; index-- ) { - console.kprint("."); - Wait( 300 ); - } - console.kprint("\n[STARTING]\n\n"); - - // Initialize memory management first. - init_page_table(); - console.kout("Initialized page table"); - - // Turn on the green light to signify the end - // of our initial kernel code. - irq_enable(); - Wait(500); - console.kout("Interrupt vectors ENABLED"); - console.kprint("About to throw an SWI exception...\n"); + print_header( console ); - Wait( 5000 ); - irq_test(); + //UsbInitialise(); + //assert("Keyboard Initialized"); - Wait(500); - console.kout("SWI Exception Thrown"); + // Queue up a few jobs. + fork(&run1); + fork(&run2); - SetGPIO( 16, 1 ); + // Setup IRQ + assert("IRQ Enabled"); + enable_irq(); - console.kprint("\n\nKernel shutting down..."); + // Hang forever. + while(1) { } return; } +void assert(const char* val) { + console->kout(val); +} + +void printf(const char* val) { + console->kprint(val); +} + void print_header( Console* console ) { meta info = getBuildInfo(); diff --git a/code/libs/math.h b/code/libs/math.h new file mode 100755 index 0000000..b4cab17 --- /dev/null +++ b/code/libs/math.h @@ -0,0 +1,223 @@ +#ifndef __MATH_H_ +#define __MATH_H_ + +#include "../common.h" +#include "./mem.h" +#include "./string.h" + +typedef long mint; +typedef unsigned long umint; + + +namespace Math { + + // Basic methods not bound to anything. + template + T divide( T top, T bottom, T* result, T* remainder ) { + + // Calculate whether or not we need to flip the sign + // afterwards. + bool flipTop = (top < 0 ); + bool flipBottom = (bottom < 0); + + if ( flipTop ) top *= -1; + if ( flipBottom ) bottom *= -1; + + // Test for some edge cases first. + if ( bottom == 0 ) { + *result = -1; + *remainder = -1; + return *result; + } + + if ( top < bottom ) { + *result = 0; + *remainder = top; + return *result; + } + + // Reset the pointer variables and create some temp + // containers. + int topVar = top, bottomVar = bottom; + *result = 0; + *remainder = 0; + + // Do long division (note: everything should be positive now). + for (; topVar >= bottomVar; topVar -= bottomVar ) { + *(result) = *(result) + 1; + } + + // Calculate the remainder. + *(remainder) = top - (*(result) * bottom); + + // Do the flips. + if ( flipTop ) *(result) = *(result) * -1; + if ( flipBottom ) *(result) = *(result) * -1; + + // Return the result. + return *(result); + + } + + template + T pow( T x, T y, bool standard ) { + if ( standard ) { + if ( y == 0 ) return 1; + if ( y == 1 ) return x; + } + + T i = 0, r = x; + for ( ; i < y; i++ ) + r = r * x; + return r; + } + + + template + T pow(T x, T y) { + return pow( x, y, true ); + } + + + char* itoa(uint32 number) { + char digits = 0; + do { } while ( digits < 10 && (number / pow(10, digits++, false)) != 0 ); + + char map[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + char* res = (char*)malloc((digits+1) * sizeof(char)); + res[digits] = '\0'; + int base = 0; + + // Iterate over the digits; + for ( int i = digits - 1; i >= 0; i-- ) { + + int index; + if ( i == 0 ) + index = number - base; + else + index = (number - base) / pow(10,i-1,false); + + if ( index < 10 && index >= 0) + res[digits - i - 1] = map[index]; + + if ( i == 0 ) break; + base += index * pow(10,i-1,false); + } + + // Return the result. + return res; + } + + template + T getDigitCount(T num, T base) { + T top = num, result = 0, remainder = 0, returnVal = 0; + while ( top > 0 ) { + divide( top, base, &result, &remainder ); + top = result; + returnVal++; + } + + return returnVal; + } + + class kfloat { + public: + // Division operator override. + kfloat operator/(const kfloat &target){ + if ( this == &target ) return *this; + + // Do the math. + mint top = this->major, bottom = target.major, result = 0, remainder = 0, i; + + // Now calculate the proper. + divide( top, bottom, &result, &remainder); + + // Store the result. + this->major = result; + this->minor = 0; + + // Calculate the decimal. + for ( i = this->precision; i > 0; i-- ) { + // Do the long division. + divide( remainder * 10, bottom, &result, &remainder ); + this->minor += ( pow( 10, i - 1 ) * result ); + } + + // Return + return *this; + } + + kfloat operator=(const mint &target) { + this->init( target, 0, 2 ); + return *this; + } + + // Constructors + kfloat( void ) { this->init( 0, 0, 0); } + kfloat( mint num ) { this->init( num, 0, 2 ); } + kfloat( mint num, mint dec ) { this->init( num, dec, 2 ); } + kfloat( mint num, mint dec, mint prec) { this->init( num, dec, prec ); } + + // Basic assignment operations. + mint getMajor() { + return this->major; + } + + mint getMinor() { + return this->minor; + } + + mint getPrecision() { + return this->precision; + } + + mint setPrecision(mint p) { + this->precision = p; + } + + mint getBig1() { + return this->big1; + } + + mint getBig2() { + return this->big2; + } + + bool getIsLarge() { + return this->isLarge; + } + + private: + mint major; + mint minor; + mint precision; + + /* Note: this is used exclusivly for very large numbers */ + bool isLarge; + mint big1; + mint big2; + + void init( mint num, mint dec, mint prec ) { + + // Check if we need to incorporate the big major. + if ( num > (umint)0xFFFFFF) { + // Yes. + this->big1 = (num & 0xFFFF0000) >> 16;// >> (4 * 4); + this->big2 = (num & 0x0000FFFF); + this->isLarge = true; + } else { + // No + this->big1 = num; + this->isLarge = false; + } + + this->major = num; + this->minor = dec; + this->precision = prec; + } + }; + +}; + + +#endif diff --git a/code/libs/mem.h b/code/libs/mem.h new file mode 100755 index 0000000..3abbd3f --- /dev/null +++ b/code/libs/mem.h @@ -0,0 +1,79 @@ +// This is a completely blank test arena for memory management. +// The pre-implemented test case functions (defined at the bottom) are +// already wired up to the drawing engine. An array of possible output colors +// are defined which reveal what test(s) passed/failed. + +// The idea is to write up a variety of methods and general +// functionality based around memory management to experiment and see +// what we have available. + +// Please note: I've never written any memory management system, nor have I +// taken a class on it. I'm just winging it with my own ideas. +// Nothing fancy here. + +#ifndef __MEM_H_ +#define __MEM_H_ + +typedef unsigned int uint32; + +#define page_size (uint32)512 +#define MAX_BRK 0xf0000 + +extern char _end; + +uint32 cur_brk = 0; + +uint32 alloc_stack(uint32 bytes) { + cur_brk += bytes; + return cur_brk; +} + +void *sbrk(uint32 increment) +{ + if(cur_brk == 0) + { + cur_brk = (uint32)&_end; + if(cur_brk & 0xfff) + { + cur_brk &= 0xfffff000; + cur_brk += 0x1000; + } + } + + uint32 old_brk = cur_brk; + cur_brk += increment; + + // Align up to 512 + if(cur_brk & 0x1ff) + { + cur_brk &= ~0x1ff; + cur_brk += 0x200; + } + + // Fix if it's too big. + if ( cur_brk > MAX_BRK ) { + cur_brk = old_brk; + return (void*)-1; + } + + // Zero out the memory. + for ( int i = 0; i < increment; i++ ) + *((uint32*)old_brk + i) = 0; + + // return the address. + return (void*)old_brk; +} + +void* malloc(uint32 bytes) { + return sbrk(bytes); +} + +void* operator new( uint32 bytes ) { + return malloc(bytes); +} + +void* operator new( uint32 bytes, void*& ptr ) { + return ptr; +} + +#endif diff --git a/code/libs/string.h b/code/libs/string.h new file mode 100755 index 0000000..0a9ee74 --- /dev/null +++ b/code/libs/string.h @@ -0,0 +1,101 @@ +// ******************************* +// FILE: kstring.h +// AUTHOR: SharpCoder +// DATE: 2015-03-30 +// ABOUT: This is a terrible, horrible, repulsive +// string library I wrote. +// +// LICENSE: Provided "AS IS". USE AT YOUR OWN RISK. +// ******************************* +#ifndef __PI_STRING_H_ +#define __PI_STRING_H_ + +#include "./mem.h" + +int strlen(char* input); + +class string { + private: + char* value; + + public: + int length; + + string(void) { + this->value = (char*)"\0"; + } + string(const char* val) { + this->value = (char*)"\0"; + this->append((char*)val); + } + + void append(const char* c) { + this->append((char*)c); + } + + void append(char* c) { + int a = strlen(this->value); + int b = strlen(c); + int len = a + b; + + char* newVal = (char*)malloc((len + 1) * sizeof(char)); + // Clear it out. + for ( int i = 0; i < len + 1; i++ ) + *(newVal + i) = '\0'; + + for ( int i = 0; i < a; i++ ) + *(newVal + i) = this->value[i]; + + for ( int i = 0; i < b; i++ ) + *(newVal + a + i) = *(c + i); + + this->value = newVal; + this->length = a + b + 1; + } + + void append(char c) { + char vals[] = { c, '\0' }; + this->append(vals); + } + + char getAt(int index) { + if ( index > this->length ) return (char)NULL; + return *(this->value + index); + } + + string* substr(int start, int end) { + string* der = new string(); + for ( int i = start; i < end; i++ ) { + der->append(*(this->value + i)); + } + return der; + } + + char* toString() { + return this->value; + } +}; + +int strlen(char* input) { + int index = 0; + char temp = ' '; + do { + temp = input[index++]; + } while ( temp != '\0' ); + return index - 1; +} + +bool strcmp(string* a, string* b) { + if ( a->length != b->length ) return false; + + const char* one = a->toString(); + const char* two = b->toString(); + + for ( int i = 0; i < a->length; i++ ) { + if ( one[i] != two[i] ) return false; + } + + return true; +} + +#endif diff --git a/code/linker.ld b/code/linker.ld index 2fd77b4..e0ca623 100755 --- a/code/linker.ld +++ b/code/linker.ld @@ -1,13 +1,23 @@ +ENTRY (init_entry_point) MEMORY { - ram : ORIGIN = 0x8000, LENGTH = 0x5000 + ram : ORIGIN = 0x8000, LENGTH = 0x10000 } SECTIONS { - .text : { - irq.o; - bootstrap.o; - kmain.o; - } > ram + .text : { *(.text*) } > ram + . = ALIGN(4096); + + .data : { *(.data*) } > ram + . = ALIGN(4096); + + .bss : { *(.bss*) } > ram + . = ALIGN(4096); + + _bss_end = .; + . = ALIGN(4096); + + . = . + 0x1000; + _end = .; } diff --git a/code/meta.h b/code/meta.h index 5d69bea..fc60d65 100644 --- a/code/meta.h +++ b/code/meta.h @@ -25,11 +25,11 @@ static meta getBuildInfo() { meta properties; properties.AUTHOR="SharpCoder"; properties.EMAIL="Josuha@debuggle.com"; - properties.KERNEL_NAME="0xrpi Kernel"; + properties.KERNEL_NAME="Mindflayer"; properties.KERNEL_NAME_CODE="Mindflayer"; properties.KERNEL_REPO="https://github.com/SharpCoder/rpi-kernel"; - properties.BUILD_DATE="2013-04-02 11:48:47 PM"; - properties.VERSION="0.0.623"; + properties.BUILD_DATE="2015-07-17 02:04:55 PM"; + properties.VERSION="0.0.723"; properties.LOGO_TEXT=""; properties.LOGO_WIDTH= 30; properties.LOGO_HEIGHT= 50; diff --git a/lib/libcsud.a b/lib/libcsud.a new file mode 100755 index 0000000..f76ecd2 Binary files /dev/null and b/lib/libcsud.a differ