$(LD) -nostartfiles -Map $(BIN)/$@.MAP -T link.ld -o $(BIN)/$@.ELF start.o $^ --print-memory-usage
@echo "Creating binary..."
@mkdir -p $(BIN)
- $(MKIMG) -Obinary -R .data $(BIN)/$@.ELF $(BIN)/$@.bin
+ $(MKIMG) -Obinary $(BIN)/$@.ELF $(BIN)/$@.bin
# Run in Qemu; note this is a patched version for stm32-f103c8
run:
/* syscall.h */
-extern void theos_test();
+extern int theos_test(int, int, int);
+extern int theos_init(uint32_t *);
+extern int theos_switch(uint32_t *, uint32_t *);
+extern int theos_uptime();
/* Safety macro's to get the address or value */
#define MEM_VALUE(addr) *((volatile uint32_t(*) (addr))
#define MEM_ADDR(addr) ((volatile uint32_t *) (addr))
+#define HW_ADDR(addr) (*((volatile unsigned long *)(addr)))
/* SYSTEM INFO AND DEBUG */
#define MCU_ID MEM_ADDR(0xE000ED00)
#define FLASH_MEM MEM_ADDR(0x1FFFF000)
+/* MEMORY PROTECTION UNIT */
+#define MPU_TYPER MEM_ADDR(0xE000ED90)
+#define MPU_CR MEM_ADDR(0xE000ED94)
+#define MPU_RNR MEM_ADDR(0xE000ED98)
+#define MPU_RBAR MEM_ADDR(0xE000ED9C)
+
/* POWER CONTROL REGISTERS */
#define PWR_CR MEM_ADDR(0x40007000)
/* SYSTEM CONTROL BLOCK REGISTER */
#define SCB_VTOR MEM_ADDR(0xE000ED08) // VECTOR TABLE
-#define SCB_VTOR_ST MEM_ADDR(0xE000ED04) // STATUS OF VECTOR
+#define SCB_ICSR MEM_ADDR(0xE000ED04) // STATUS OF VECTOR
#define SCB_CCR MEM_ADDR(0xE000ED14) // SET SOFTWARE TRAPS
+#define SCB_SHCSR MEM_ADDR(0xE000ED24) // ENABLE VARIOUS FAULTS EXCEPTIONS
+#define SCB_CFSR MEM_ADDR(0xE000ED28) // GEN. USAGE FAULT STATUS REGISTER
+#define SCB_HFSR MEM_ADDR(0xE000ED2C) // HARD FAULT STATUS REGISTER
+#define SCB_BFAR MEM_ADDR(0xE000ED38) // BUS FAULT ADDRESS REGISTER
/* NESTED VECTOR INTERRUPT CONTROL REGISTER */
#define NVIC_ISER0 MEM_ADDR(0xE000E100) // interrupt set enable register
#define NVIC_ISER1 MEM_ADDR(0xE000E104) // interrupt set enable register
#define NVIC_ISER2 MEM_ADDR(0xE000E108) // interrupt set enable register
+#define NVIC_STIR MEM_ADDR(0xE000EF00) // Software trigger interrupt
/* SYSTICK REGISTER */
#define STK_CTRL MEM_ADDR(0xE000E010)
--- /dev/null
+typedef struct process process_t;
+struct process {
+ uint32_t id;
+ uint32_t * stackptr;
+ uint32_t reserved;
+};
#define __SYSTEM_H
+/* Return CONSTANTS */
+
+#define OK 1
+#define MMKAY 0
+#define NOTOK -1
+
+/* RETURN TYPES */
+
+typedef int32_t SYSCALL;
+typedef int32_t PROCESS;
+
/* CLOCK.C
* Board specific clock settings. These boards often come with two
* external oscillators: one high speed (8MHz) and one low speed (~30kHz).
memcpy(&frame, current_sp, sizeof(struct interrupt_frame));
- uint8_t nr = *SCB_VTOR_ST & 0xFF;
+ uint8_t nr = *SCB_ICSR & 0xFF;
printf("EXCEPTION: %s\n", exception_message(nr));
printf("STACKFRAME:\n");
printf("R0:%p\n",frame.r0);
printf("R3:%p\n",frame.r3);
printf("R12:%p\n",frame.r12);
printf("LR:%p\n",frame.lr);
- printf("PC:%p\n",frame.pc);
+ printf("PC:%p (<-- last function call)\n",frame.pc);
printf("PSR:%p\n",frame.psr);
+ printf("CPU STATUS:");
+ printf("%x\n", *SCB_CFSR);
for(;;);
}
* */
extern void * reset, * nmi, * hardfault;
- // set dummy handlers
+ /* set dummy handlers */
for (int i = 1; i <= 64 ; i++) {
ivt_set_gate(i, dummy_isr, 0);
}
+
+ /* Enable memory management, bus and usage fault exceptions handlers
+ * If these are not enabled, the processor treats them as a hard
+ * faults. Unpriviliged access will cause a busfault in case no MPU */
+ rsetbit(SCB_SHCSR, 16); // MPU violation
+ rsetbit(SCB_SHCSR, 17); // Bus faults
+ rsetbit(SCB_SHCSR, 18); // Usage faults
+
+ /* Enable various other faults */
+ // rsetbit(SCB_CCR, 4); // division by zero, (needed if you write a lot
+ // of assembly, otherwise the compiler probably leave these divisions out
+
+
/* The vector table is intially at 0x0. The vector table can be
* relocated to other memory locations. We can do this by setting
* a register in the NVIC called the vector table offset register */
* 0xFFFF * (1/8,000,000) * 3 = 24.58ms
* 0xFFFFFFFF * (1/8MHz) * 3 = 1610ms
* */
-static void __block(uint32_t count) {
+/* static void __block(uint32_t count) {
- asm volatile("b1: subs %0, %1, #1" "\n\t"
- "bne b1" : "=r" (count) : "r" (count));
-}
+} */
/* Delay us microsecond
* Note: delay includes setup time (about 4 clockcycles), so is quite
void _block(uint32_t us) {
uint32_t count = (us/3) * CLKSPEED_MHZ; // x cycles
- __block(count);
+ asm volatile("b1: subs %0, %1, #1" "\n\t"
+ "bne b1" : "=r" (count) : "r" (count));
+ //__block(count);
}
-
/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
*
* $LOG$
#include <lib/syscall.h>
+/* Arguments are placed in r0, r1, r2 by convention
+ * And "parsed" to the the kernel
+ * Right after the svc call, r0 contains status
+ * of call (ie. OK, NOTOK */
-//__attribute__ ((naked))
-static int theos_syscall(int SYSCALL_N, int SYSCALL_N2) {
+int theos_uptime() {
- asm volatile ("svc 11");
-
- return 0;
+ asm volatile("svc 6");
+ int ret;
+ asm volatile("mov %0, r0" : "=r" (ret));
+ return ret;
}
-//__attribute__ ((naked))
-void theos_test(int dummy, int dummy2) {
+
+int theos_init(uint32_t * p) {
+ asm volatile("svc 1");
- theos_syscall(0xB1, 0xB2);
+ return -1;
}
-/* void theos_cputs(const char * str, size_t len) {
+__attribute__ ((naked))
+int theos_switch(uint32_t * p1, uint32_t * p2) {
+
+ asm volatile("push {lr}");
+ asm volatile("svc 4");
+ asm volatile("pop {lr}");
+ asm volatile("bx lr");
+ // should not be here
+ for(;;);
+
+}
- //syscall(#, 0, 0, 0 ..);
- theos_syscall(22, 44);
-} */
+int theos_test(int arg1, int arg2, int arg3) {
+
+ asm volatile("svc 11");
+ int ret;
+ asm volatile("mov %0, r0" : "=r" (ret));
+ return ret;
+}
{
/* (.vector_table */
*(.text)
- *(.rodata)
+ *(.rodata)
+ data_lma = .;
}
. = 0x20000000;
- .data :
+ data_vma = .;
+ .data : AT (data_lma)
{
*(.data)
}
+ data_end = .;
.bss : ALIGN(4)
{
*(.bss)
#include <sys/robsys.h>
#include <sys/mmap.h>
+#include <sys/process.h>
#include <lib/regfunc.h>
#include <lib/pool.h>
//#include <drivers/mk450_joystick.h>
#include <drivers/st7735s.h>
-
#include <lib/syscall.h>
+process_t p1;
+process_t p2;
+
+uint32_t stackp1[500];
+uint32_t stackp2[500];
+
+extern int count;
+
+void switch_usermode() {
+
+ // user mode
+ //asm volatile ("mov r0, 0x1" "\n\t"
+ //"msr control, r0" "\n\t"
+ //"isb" "\n\t");
+
+ // system init call
+
+}
+
+void process1(void) {
+
+ while(1) {
+ //uint32_t control = 0xFFFFFFFF;
+ printf("process 1\n");
+ //asm volatile("msr control, %0" "\n\t"
+ // "dsb" : : "r" (control));
+ //printf("control: %x", control);
+ //for(;;);
+ _block(100);
+ theos_switch(&p1, &p2);
+ }
+
+}
+void process2(void) {
+ while(1) {
+ printf("process 2\n");
+ _block(100);
+ theos_switch(&p2, &p1);
+ }
+
+}
+
+int test_data_segment = 99;
+
void main()
{
+ /* Load .data segment into SRAM */
+ extern uint32_t * data_lma, data_vma, data_end;
+ int size = (&data_end - &data_vma) * 4;
+ memcpy(&data_vma, &data_lma, size);
+
/* Initialize the clock system, */
clock_init();
/* TFT screen */
// tft_init();
- /* Cortex M* integrated systick, can be replaced
- * by the more accurate RTC.
- systick_init();
- */
-
/* Set up a very small libc library */
init_printf(NULL, putc);
/* On board LEDs*/
led_init();
+
/* Real time clock */
- //rtc_init();
+ rtc_init();
+
// printf("press any key to start\n");
-// asm volatile ("wfi");
+// asm volatile ("cpsid f"); // doesn't work in qemu
syscall_init();
- theos_test(0xA1, 0xA2);
+
+ //int ret;
+ //ret = theos_test(0x1, 0x2, 0x3);
+ //ret = theos_uptime();
+
+ //printf("ret: %d\n", ret);
+
+ int size_stack = sizeof(stackp1);
+
+ p1.stackptr = ((unsigned int) stackp1) + size_stack - 0x1C;
+ p1.stackptr[6] = (uint32_t) process1;
+ p1.stackptr[7] = 0x01000000;
+ p2.stackptr = ((unsigned int) stackp2) + size_stack - 0x1C;
+ p2.stackptr[6] = (uint32_t) process2;
+ p2.stackptr[7] = 0x01000000;
+
+ theos_init(&p1);
+
+ /* Cortex M* integrated systick, can be replaced
+ * by the more accurate RTC. */
+
+// systick_init();
+
+ // switch_usermode();
+
+ //printf("without system call");
+// theos_test(0xA1, 0xA2);
/* Eeprom Driver
eeprom_at24c_init();
.text
.global _start
.global reset, nmi, hardfault
- .global _svc_handler
+ .global pendsv_handler
.code 16
.syntax unified
_start:
(machine somehow has a failure). That's why they are included here.
Later the interrupt vector will be relocated to SRAM and modified. */
+
nmi:
b nmi
* |----------------------------|
* | SYSTEM CALL | # |
* |--------------------|-------|
- * | THEOS_getenv | |
- * | THEOS_killenv | |
- * | THEOS_setenv | |
- * | THEOS_newenv | |
- * | THEOS_cputs | |
- * | THEOS_omnigod | |
- * | THEOS_brk | |
- * | THEOS_time | |
- * | THEOS_magic | |
+ * | THEOS_INIT | 1 |
+ * | THEOS_DESTROY | 2 |
+ * | THEOS_RESCHED | 3 |
+ * | THEOS_GETC | 4 |
+ * | THEOS_CPUTS | 5 |
+ * | THEOS_UPTIME | 6 |
+ * | THEOS_OMNIGOD | 7 |
+ * | THEOS_TIME | 8 |
+ * | THEOS_MAGIC | 99 |
* |----------------------------|
*
* TODO: include in header enum
* */
-
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/robsys.h>
#include <sys/mmap.h>
+#include <sys/process.h>
#include <lib/stdio.h>
#include <lib/string.h>
#include <lib/regfunc.h>
#include <lib/tinyprintf.h>
+enum {
+ THEOS_INIT = 1,
+ THEOS_CREATE,
+ THEOS_DESTROY,
+ THEOS_SWITCH,
+ THEOS_GETC,
+ THEOS_CPUTS,
+ THEOS_UPTIME
+};
+
+
+static int sys_uptime() {
+
+ int uptime = *RTC_CNTL;
+ return uptime;
+}
+
+/* Context switch routine, saves stack pointer of
+ * the current process, loads the stack pointer
+ * of the next.
+ *
+ * Other registers and flags (i.e. PSR, PC are popped
+ * by exit of this system call.
+ * Precondition: Usage of PSP */
+int sys_switch(process_t * currp, process_t * newp) {
+
+ uint32_t tmp_stackptr = 0xFFFFFFFF;
+ asm volatile("mrs %0, psp" : "=r" (tmp_stackptr));
+ currp->stackptr = tmp_stackptr;
+
+ asm volatile("msr psp, %0" : : "r" (newp->stackptr) ); // load new pointer
+ uint32_t chk_stackptr;
+ asm volatile("mrs %0, psp" : "=r" (chk_stackptr));
+ //asm volatile("isb");
+ printf("OLD: %x\n", currp->stackptr);
+ printf("NEW: %x\n", newp->stackptr);
+ printf("CHK: %x\n", chk_stackptr);
+ //for(;;);
+
+ return 0;
+
+}
+
+int sys_init(process_t * p) {
+
+ asm volatile("msr psp, %0" : : "r" (p->stackptr));
+ return 0;
+}
+
+static int sys_stub() {
+
+ return 0;
+
+}
/*
* This is a so-called first interrupt handler
* The naked attribute makes sure the compiler doesn't
- * places registers on the stack. */
+ * places registers on the stack */
+
+/*
+ * SVC is similar to an exception or interrupt
+ * A stack frame is pushed on entry and popped
+ * on exit BY PROCESSOR. Please see in-function command */
__attribute__ ((naked))
void * _svc_handler(void) {
- uint32_t * current_sp;
+ uint32_t * callee_sp;
/* Test whether system call was invoked from supervisor (use MSP) or
* user (use PSP) mode */
"tst lr, #4" "\n\t"
"ite eq" "\n\t"
"mrseq %0, msp" "\n\t"
- "mrsne %0, psp" : "=r" (current_sp));
+ "mrsne %0, psp" "\n\t"
+ "push {lr}" "\n\t"
+ "push {r4-r11}" : "=r" (callee_sp));
/* An exception (or interrupt) before entering this handler
* places the following on the stack
*
- * R0
- * R1
- * R2
+ * R0 <- args[0]
+ * R1 <- args[1]
+ * R2
* R3
* R12
- * LR
- * PC <- placed at current_sp[6]
- * PSR
+ * LR <- Not a real LR, A certain 'mask'
+ * PC <- placed at callee_sp[6], see description below
+ * PSR <- Status of processor before call
*
* PC contains the return address that will continue after this SVC handler
* is finised. The previous address (the svc # call) is at PC - 2, the
* first byte contains the svc number.
* */
- uint8_t svc_nr = ((char *) current_sp[6])[-2];
-
- printf("SYSTEM CALL NR: %d", svc_nr);
+ uint8_t svc_nr = ((char *) callee_sp[6])[-2];
+ int ret = -1;
- for (;;);
+ switch(svc_nr) {
+ case THEOS_INIT:
+ sys_init((process_t *) callee_sp[0]);
+ asm volatile (
+ "ldr r0, =0xFFFFFFFD" "\n\t"
+ "mov lr, r0" "\n\t"
+ "bx lr");
+ break;
+ case THEOS_SWITCH:
+ sys_switch((process_t *) callee_sp[0], (process_t *) callee_sp[1]);
+ //asm volatile (
+ // "ldr r0, =0xFFFFFFFD" "\n\t"
+ // "mov lr, r0" "\n\t"
+ // "bx lr");
+
+ break;
+ case THEOS_CPUTS:
+ break;
+ case THEOS_GETC:
+ break;
+ case THEOS_UPTIME:
+ ret = sys_uptime();
+ break;
+ default:
+ break;
+ }
-}
+ //printf("SYSTEM CALL NR: %d\n", svc_nr);
+ /* Check arguments, placed in r0, r1, r2
+ * (can get more if you save the stack) */
+ //uint32_t arg1 = callee_sp[0];
+ //uint32_t arg2 = callee_sp[1];
+ //uint32_t arg3 = callee_sp[2];
+ //printf("ARGUMENTS: %x, %x, %x\n", arg1, arg2, arg3);
-void syscall(unsigned int * args) {
+ /* Return value in r0 for callee */
+ callee_sp[0] = ret;
- uint32_t svc_number = 99;
- printf("SYSCALL NR: %x", svc_number);
+ asm volatile ("pop {r4-r11}");
+ /* exception return, 0xFFFFFFFX (<-- last value is flag
+ * and gives the processor information to return to what */
+ asm volatile ("pop {lr}");
+ asm volatile ("bx lr");
- for(;;);
- /* switch(SYSCALL_NO) {
- case THEOS_cputs:
- kernel_cputs(a1, a2);
- break;
- default:
- for (;;);
- } */
}
void syscall_init() {
-
/* SVC is located at position 11 in the interrupt vector table */
ivt_set_gate(11, _svc_handler, 0);
-
}
-static void kernel_cputs(char * s, size_t l) {
-
- // TODO
-}
-
-
-void kernel_omnigod() {
-
- /* */
-
-}
-
-
#include <lib/regfunc.h>
#include <lib/tinyprintf.h>
+#define NUMB_TASKS 3
+
+int count;
+int next_task;
+int curr_task;
+uint32_t currentp;
+uint32_t nextp;
+
+//struct proces {
+// int32_t nr;
+// uint32_t *stack_ptr;
+// uint32_t mask;
+//};
+//
+//struct proces p1, p2, p3;
+//
+//
+// uint32_t oldpsp;
+// uint32_t newpsp;
+//
+//uint32_t task0_stack[50];
+//uint32_t task1_stack[50];
+//uint32_t task2_stack[50];
+//uint32_t PSP_array[3];
+
struct interrupt_frame {
uint32_t r0; // N-32
//__attribute__ ((interrupt))
void * systick_handler(/* struct interrupt_frame * frame */) {
- printf("Ticking...\n");
+ //printf("Ticking...\n");
+ //printf("Current task: %d", curr_task);
+ //count++;
+
+
+
+
+ //switch(curr_task) {
+ // case(0): next_task = 1; break;
+ // case(1): next_task = 2; break;
+ // case(2): next_task = 0; break;
+ // default: next_task = 0; break;
+ //}
+
+ //if (curr_task != next_task) {
+
+
+
+ //}
+
}
+__attribute__ ((naked))
+ void * pendsv_handler_c(void) {
+//
+// asm volatile ("push {r0-r11, lr}");
+// asm volatile ("mrs %0, psp" : "=r" (oldpsp));
+// asm volatile ("push {lr}");
+//
+// //asm volatile ("push {lr}");
+//
+// //printf("FROM MSP %x", oldpsp);
+// //PSP_array[curr_task] = oldpsp;
+// //curr_task = next_task;
+// //newpsp = PSP_array[next_task];
+//
+// asm volatile ("msr psp, %0" : : "r" (newpsp));
+//
+// asm volatile("pop {lr}");
+// //asm volatile ("pop {r0-r12}");
+// asm volatile("bx lr"); // return
+}
+
+uint32_t set_psp(uint32_t) __attribute__( ( naked ) );
+uint32_t set_psp(uint32_t stackie) {
+
+ asm volatile ("msr psp, r0" "\n\t"
+ "bx lr");
+}
+
void systick_init() {
+// count = 0;
+// curr_task = 0;
+// next_task = 1;
+
/* Every time the counter counts down to zero
* a systick exception is invoked. Systick has
* exception number 15. in the vector table */
/* Get calibration and set this to 1 sec
* !Most boards have a 1 ms or 10 ms
* calibration value */
- int calib = (*STK_CALIB << 0) * 500;
+ int calib = (*STK_CALIB << 0) * 200;
/* The counter reload registers counts down to zero
* and then it is restores the value */
rsetbit(STK_CTRL, 0);
rsetbit(STK_CTRL, 1);
+// extern void task0(void), task1(void), task2(void);
+//
+// int size_stack = sizeof(task0_stack);
+//
+// p1.stack_ptr = ((unsigned int) task0_stack) + size_stack - 0x1C;
+// p1.stack_ptr[6] = (uint32_t) task0;
+// p1.stack_ptr[7] = 0x01000000;
+// p2.stack_ptr = ((unsigned int) task0_stack) + size_stack - 0x1C;
+// p2.stack_ptr[6] = (uint32_t) task1;
+// p2.stack_ptr[7] = 0x01000000;
+// p3.stack_ptr = ((unsigned int) task0_stack) + size_stack - 0x1C;
+// p3.stack_ptr[6] = (uint32_t) task2;
+// p3.stack_ptr[7] = 0x01000000;
+//
+// set_psp(p1.stack_ptr[-7]);
+//
+// for(;;);
+
+ /* Initialize processes */
+ //PSP_array[0] = ((unsigned int) task0_stack) + sizeof(task0_stack) - 32*4;
+ //HW_ADDR(PSP_array[0] + 0x18) = (unsigned long) task0;
+ //HW_ADDR(PSP_array[0] + 0x1C) = 0x01000000;
+ //PSP_array[1] = ((unsigned int) task1_stack) + sizeof(task1_stack) - 32*4;
+ //HW_ADDR(PSP_array[1] + 0x18) = (unsigned long) task1;
+ //HW_ADDR(PSP_array[1] + 0x1C) = 0x01000000;
+ //PSP_array[2] = ((unsigned int) task2_stack) + sizeof(task2_stack) - 32*4;
+ //HW_ADDR(PSP_array[2] + 0x18) = (unsigned long) task2;
+ //HW_ADDR(PSP_array[2] + 0x1C) = 0x01000000;
+
+ //extern void pendsv_handler;
+
+ ivt_set_gate(14, pendsv_handler_c, 0);
+
+ //set_psp((PSP_array[curr_task] + 32*4 ));
+
+ //int startpsp = PSP_array[curr_task] + 16*4;
+
+ //asm volatile ("msr psp, %0" : : "r" (startpsp));
+
+
+ //asm volatile ("mov r0, 0x3" "\n\t"
+ //"msr control, r0" "\n\t"
+ //"isb" "\n\t");
+
+ //for(;;);
+
+ //set current PSP
+ //printf("0: %x\n", PSP_array[0]);
+ //printf("1: %x", PSP_array[0]);
+
+ //task0();
}