-Scheduler and context switching added

-Initial syscall infrastructure
This commit is contained in:
2013-07-13 21:09:30 +02:00
parent ba680cccdf
commit 2456d68b00
19 changed files with 629 additions and 266 deletions

View File

@@ -7,9 +7,9 @@ OBJDUMP=arm-none-eabi-objdump
#CFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -Og -flto #CFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -Og -flto
CXXFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=c++11 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -fno-rtti -fstrict-enums -Wabi -Og -flto -D__DYNAMIC_REENT__ CXXFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=c++11 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -fno-rtti -fstrict-enums -Wabi -Og -flto -D__DYNAMIC_REENT__
LDFLAGS=-static LDFLAGS=-static
C_SRCS=syscall.c C_SRCS=
CXX_SRCS=cortexa8.cc drv_omap35x_gpt.cc drv_omap35x_i2c.cc drv_tps65950.cc main.cc mm.cc omap35x.cc omap35x_intc.cc omap35x_prcm.cc phys_mm.cc uart.cc CXX_SRCS=cortexa8.cc drv_omap35x_gpt.cc drv_omap35x_i2c.cc drv_tps65950.cc main.cc mm.cc newlib_syscall.cc omap35x.cc omap35x_intc.cc omap35x_prcm.cc phys_mm.cc scheduler.cc syscall.cc uart.cc
S_SRCS=cortexa8_asm.s syscall_asm.s S_SRCS=cortexa8_asm.s
OBJS=$(addprefix objs/,$(C_SRCS:.c=.o)) $(addprefix objs/,$(CXX_SRCS:.cc=.o)) $(addprefix objs/,$(S_SRCS:.s=.o)) OBJS=$(addprefix objs/,$(C_SRCS:.c=.o)) $(addprefix objs/,$(CXX_SRCS:.cc=.o)) $(addprefix objs/,$(S_SRCS:.s=.o))

View File

@@ -38,6 +38,11 @@ uint32_t cortexa8::read_cpuid(int reg) noexcept {
return rval; return rval;
} }
void cortexa8::init_mode() {
__asm__ __volatile__ ("mov r0, r13; mov r1, r14; cps #0x1f; mov r13, r0; mov r14, r1"
: : : "r0", "r1");
}
void cortexa8::enable_icache() noexcept { void cortexa8::enable_icache() noexcept {
uint32_t reg; uint32_t reg;
@@ -407,7 +412,7 @@ extern "C" {
void _cortexa8_excp_data_abt() __attribute__((interrupt ("ABORT"))); void _cortexa8_excp_data_abt() __attribute__((interrupt ("ABORT")));
void _cortexa8_excp_pf_abt() __attribute__((interrupt ("ABORT"))); void _cortexa8_excp_pf_abt() __attribute__((interrupt ("ABORT")));
void _cortexa8_excp_undef() __attribute__((interrupt ("UNDEF"))); void _cortexa8_excp_undef() __attribute__((interrupt ("UNDEF")));
void _cortexa8_syscall() __attribute__((interrupt ("SWI"))); void cortexa8_syscall();
void _cortexa8_unhandled_fiq() __attribute__((interrupt ("FIQ"))); void _cortexa8_unhandled_fiq() __attribute__((interrupt ("FIQ")));
} }
@@ -443,7 +448,7 @@ void _cortexa8_excp_undef() {
while(1) {} while(1) {}
} }
void _cortexa8_syscall() { void cortexa8_syscall() {
printf("Syscall NYI\n"); printf("Syscall NYI\n");
} }
@@ -453,6 +458,29 @@ void _cortexa8_unhandled_fiq() {
// Context switching stuff // Context switching stuff
cortexa8::thread_cb initial_thread_cb; static cortexa8::thread_cb initial_thread_cb;
cortexa8::thread_cb *_current_thread_cb = &initial_thread_cb; cortexa8::thread_cb *_current_thread_cb = &initial_thread_cb;
cortexa8::thread_cb *cortexa8::get_cur_thread() {
return _current_thread_cb;
}
void cortexa8::set_cur_thread(thread_cb* tcb) {
_current_thread_cb = tcb;
}
void cortexa8::exit_svc() {
__asm__ __volatile__ ("svc 0" : : : "r0");
}
void cortexa8::yield_svc() {
__asm__ __volatile__ ("svc 1" : : : "r0");
}
bool cortexa8::in_handler() {
uint32_t mode = cortexa8_get_cpsr() & 0x1f;
if((mode == 0x10) || (mode == 0x1f))
return false;
return true;
}

View File

@@ -9,7 +9,24 @@
#define CORTEXA8_CPUID_PFR0 3 #define CORTEXA8_CPUID_PFR0 3
#define CORTEXA8_CPUID_PFR1 4 #define CORTEXA8_CPUID_PFR1 4
// Implemented in cortexa8_asm.s
extern "C" {
void cortexa8_ena_int();
void cortexa8_dis_int();
bool cortexa8_get_int();
void cortexa8_set_usr_sp(void *sp);
void cortexa8_set_abt_sp(void *sp);
void cortexa8_set_und_sp(void *sp);
void cortexa8_set_irq_sp(void *sp);
void cortexa8_set_fiq_sp(void *sp);
uint32_t cortexa8_get_spsr();
uint32_t cortexa8_get_cpsr();
}
namespace cortexa8 { namespace cortexa8 {
void init_mode();
uint32_t read_cpuid(int reg) noexcept; uint32_t read_cpuid(int reg) noexcept;
@@ -26,26 +43,42 @@ namespace cortexa8 {
void unmap_pages(uintptr_t virt, unsigned count); void unmap_pages(uintptr_t virt, unsigned count);
struct thread_cb { struct thread_cb {
uint32_t regs[15]; thread_cb()
: regs{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, cpsr{0} {
}
uint32_t regs[16];
uint32_t cpsr; uint32_t cpsr;
}; };
thread_cb *get_cur_thread();
void set_cur_thread(thread_cb* tcb);
void exit_svc();
void yield_svc();
bool in_handler();
// Wrapper to handle safe disabling/enabling of interrupts
class ScopedSetIF {
public:
ScopedSetIF(bool enableInts = false) : savedIF_{cortexa8_get_int()} {
if(enableInts)
cortexa8_ena_int();
else
cortexa8_dis_int();
}
~ScopedSetIF() {
if(savedIF_)
cortexa8_ena_int();
else
cortexa8_dis_int();
}
private:
bool savedIF_;
};
} }
// Implemented in cortexa8_asm.s
extern "C" {
void cortexa8_ena_int();
void cortexa8_dis_int();
bool cortexa8_get_int();
void cortexa8_set_usr_sp(void *sp);
void cortexa8_set_abt_sp(void *sp);
void cortexa8_set_und_sp(void *sp);
void cortexa8_set_irq_sp(void *sp);
void cortexa8_set_fiq_sp(void *sp);
uint32_t cortexa8_get_spsr();
}
#endif #endif

View File

@@ -1,15 +1,11 @@
.global cortexa8_ena_int .global cortexa8_ena_int
cortexa8_ena_int: cortexa8_ena_int:
mrs r0, cpsr cpsie i
bic r0, r0, #0x80
msr cpsr, r0
bx lr bx lr
.global cortexa8_dis_int .global cortexa8_dis_int
cortexa8_dis_int: cortexa8_dis_int:
mrs r0, cpsr cpsid i
orr r0, r0, #0x80
msr cpsr, r0
bx lr bx lr
.global cortexa8_get_int .global cortexa8_get_int
@@ -20,37 +16,16 @@ cortexa8_get_int:
movne r0, #0 movne r0, #0
bx lr bx lr
.global cortexa8_set_usr_sp
cortexa8_set_usr_sp:
/* Read and save CPSR */
mrs r1, cpsr
mov r2, r1
/* Set mode to USR */
bfc r1, #0, #5
orr r1, r1, #0x10
/* Write CPSR */
msr cpsr, r1
/* Set SP in USR mode */
mov sp, r0
/* Restore original CPSR */
msr cpsr, r2
/* Return */
bx lr
.global cortexa8_set_abt_sp .global cortexa8_set_abt_sp
cortexa8_set_abt_sp: cortexa8_set_abt_sp:
/* Read and save CPSR */ /* Read and save CPSR */
mrs r1, cpsr mrs r1, cpsr
mov r2, r1
/* Set mode to ABT */ /* Set mode to ABT */
bfc r1, #0, #5 cps #0x17
orr r1, r1, #0x17
/* Write CPSR */
msr cpsr, r1
/* Set SP in ABT mode */ /* Set SP in ABT mode */
mov sp, r0 mov sp, r0
/* Restore original CPSR */ /* Restore original CPSR */
msr cpsr, r2 msr cpsr, r1
/* Return */ /* Return */
bx lr bx lr
@@ -58,16 +33,12 @@ cortexa8_set_abt_sp:
cortexa8_set_und_sp: cortexa8_set_und_sp:
/* Read and save CPSR */ /* Read and save CPSR */
mrs r1, cpsr mrs r1, cpsr
mov r2, r1
/* Set mode to UND */ /* Set mode to UND */
bfc r1, #0, #5 cps #0x1b
orr r1, r1, #0x1b
/* Write CPSR */
msr cpsr, r1
/* Set SP in UND mode */ /* Set SP in UND mode */
mov sp, r0 mov sp, r0
/* Restore original CPSR */ /* Restore original CPSR */
msr cpsr, r2 msr cpsr, r1
/* Return */ /* Return */
bx lr bx lr
@@ -75,16 +46,12 @@ cortexa8_set_und_sp:
cortexa8_set_irq_sp: cortexa8_set_irq_sp:
/* Read and save CPSR */ /* Read and save CPSR */
mrs r1, cpsr mrs r1, cpsr
mov r2, r1
/* Set mode to IRQ */ /* Set mode to IRQ */
bfc r1, #0, #5 cps #0x12
orr r1, r1, #0x12
/* Write CPSR */
msr cpsr, r1
/* Set SP in IRQ mode */ /* Set SP in IRQ mode */
mov sp, r0 mov sp, r0
/* Restore original CPSR */ /* Restore original CPSR */
msr cpsr, r2 msr cpsr, r1
/* Return */ /* Return */
bx lr bx lr
@@ -92,16 +59,12 @@ cortexa8_set_irq_sp:
cortexa8_set_fiq_sp: cortexa8_set_fiq_sp:
/* Read and save CPSR */ /* Read and save CPSR */
mrs r1, cpsr mrs r1, cpsr
mov r2, r1
/* Set mode to FIQ */ /* Set mode to FIQ */
bfc r1, #0, #5 cps #0x11
orr r1, r1, #0x11
/* Write CPSR */
msr cpsr, r1
/* Set SP in FIQ mode */ /* Set SP in FIQ mode */
mov sp, r0 mov sp, r0
/* Restore original CPSR */ /* Restore original CPSR */
msr cpsr, r2 msr cpsr, r1
/* Return */ /* Return */
bx lr bx lr
@@ -110,6 +73,11 @@ cortexa8_get_spsr:
mrs r0, spsr mrs r0, spsr
bx lr bx lr
.global cortexa8_get_cpsr
cortexa8_get_cpsr:
mrs r0, cpsr
bx lr
/* /*
The irq sp (r13) register is loaded with a pointer to the current thread control block. The irq sp (r13) register is loaded with a pointer to the current thread control block.
All registers are saved there, the sp is loaded with __stack_int and the All registers are saved there, the sp is loaded with __stack_int and the
@@ -135,7 +103,31 @@ _cortexa8_int:
msr spsr, r1 msr spsr, r1
ldm r13, {r0-r15}^ ldm r13, {r0-r15}^
.global _cortexa8_syscall
_cortexa8_syscall:
ldr r13, = _current_thread_cb
ldr r13, [r13]
stm r13, {r0-r14}^
str lr, [r13, #60]
mrs r0, spsr
str r0, [r13, #64]
ldr r13, = __stack_syscall
/* Determine if the calling thread was executing ARM or Thumb code */
tst r0, #0x20
/* For Thumb, read syscall no. from LR-2, for ARM from LR-4 */
ldreq r0, [lr, #-4]
biceq r0, #0xff000000
ldrneh r0, [lr, #-2]
andne r0, #0x000000ff
bl syscall_handler
ldr r13, = _current_thread_cb
ldr r13, [r13]
ldr r1, [r13, #64]
msr spsr, r1
ldm r13, {r0-r15}^
.global _vect_table .global _vect_table
.align 5 .align 5

View File

@@ -6,6 +6,7 @@
#include "omap35x_intc.hh" #include "omap35x_intc.hh"
#include "util.hh" #include "util.hh"
#include "mmio.hh" #include "mmio.hh"
#include "globals.hh"
#include "drv_omap35x_gpt.hh" #include "drv_omap35x_gpt.hh"
#define TIOCP_CFG 4 #define TIOCP_CFG 4
@@ -24,7 +25,7 @@ public:
} }
~OMAP35x_GPT_impl() { ~OMAP35x_GPT_impl() {
OMAP35x_intc::get().disable_int(irq_); global::intc->disable_int(irq_);
} }
void ticktimer(int_handler_t handler) { void ticktimer(int_handler_t handler) {
@@ -35,14 +36,14 @@ public:
r_tnir() = -680000; r_tnir() = -680000;
handler_ = handler; handler_ = handler;
OMAP35x_intc::get().register_handler(irq_, std::bind(&OMAP35x_GPT_impl::irqhandler, this), 0); global::intc->register_handler(irq_, std::bind(&OMAP35x_GPT_impl::irqhandler, this), 0);
r_tclr() = 0x3; // autoreload = 1, start = 1 r_tclr() = 0x3; // autoreload = 1, start = 1
r_tier() = 0x2; // Overflow int = enable r_tier() = 0x2; // Overflow int = enable
r_twer() = 0x2; // Overflow wakeup = enable r_twer() = 0x2; // Overflow wakeup = enable
OMAP35x_intc::get().enable_int(irq_); global::intc->enable_int(irq_);
} }
private: private:

View File

@@ -184,11 +184,13 @@ SECTIONS
_bss_end__ = . ; __bss_end__ = . ; _bss_end__ = . ; __bss_end__ = . ;
. = ALIGN(64); . = ALIGN(64);
. = . + 0x4000; /* 64KiB exception stack */ . = . + 0x4000; /* 16KiB exception stack */
__stack_excp = .; __stack_excp = .;
. = . + 0x4000; /* 64KiB interrupt stack */ . = . + 0x4000; /* 16KiB interrupt stack */
__stack_int = .; __stack_int = .;
. = . + 0x4000; /* 64KiB kernel startup stack */ . = . + 0x4000; /* 16KiB syscall stack */
__stack_syscall = .;
. = . + 0x4000; /* 16KiB kernel startup stack */
__stack = .; __stack = .;
__end__ = . ; __end__ = . ;

19
globals.hh Normal file
View File

@@ -0,0 +1,19 @@
#ifndef _GLOBALS_HH_
#define _GLOBALS_HH_
#include "interfaces.hh"
class OMAP35x_prcm;
class OMAP35x_intc;
class Scheduler;
namespace global {
extern OMAP35x_prcm* prcm;
extern OMAP35x_intc* intc;
extern ICharacterDevice* console;
extern Scheduler* scheduler;
}
#endif

49
main.cc
View File

@@ -12,22 +12,35 @@
#include "omap35x_prcm.hh" #include "omap35x_prcm.hh"
#include "phys_mm.hh" #include "phys_mm.hh"
#include "mm.hh" #include "mm.hh"
#include "scheduler.hh"
#include "cortexa8.hh" #include "cortexa8.hh"
#include "uart.hh" #include "uart.hh"
#include "globals.hh"
namespace global {
OMAP35x_prcm* prcm = nullptr;
OMAP35x_intc* intc = nullptr;
ICharacterDevice* console = nullptr;
Scheduler* scheduler = nullptr;
}
void sbrk_stats(); void sbrk_stats();
static volatile uint32_t tickctr = 0; static volatile uint32_t tickctr = 0;
static OMAP35x_prcm* _prcm = nullptr;
void tickfunc() noexcept { void tickfunc() noexcept {
++tickctr; ++tickctr;
_prcm->clear_wake_per(3); if(global::scheduler)
global::scheduler->timeslice();
global::prcm->clear_wake_per(3);
} }
void setConsole(ICharacterDevice* newConsole); void setConsole(ICharacterDevice* newConsole);
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
cortexa8::init_mode(); // Enter system mode
// Initialize memory // Initialize memory
cortexa8::enable_dcache(); cortexa8::enable_dcache();
cortexa8::enable_icache(); cortexa8::enable_icache();
@@ -35,7 +48,7 @@ int main(int argc, char* argv[]) {
// Enable early console // Enable early console
EarlyUART earlyUART{}; EarlyUART earlyUART{};
setConsole(&earlyUART); global::console = &earlyUART;
// Install handlers // Install handlers
cortexa8::init_handlers(); cortexa8::init_handlers();
@@ -50,18 +63,14 @@ int main(int argc, char* argv[]) {
phys_mm::print_state(); phys_mm::print_state();
// Configure PRCM // Configure PRCM
OMAP35x_prcm prcm {0x48004000, 0x48306000}; global::prcm = new OMAP35x_prcm{0x48004000, 0x48306000};
_prcm = &prcm;
//while(1) {__asm__ __volatile__ ("wfi"); }
// Configure interrrupt & exception handling // Configure interrrupt & exception handling
OMAP35x_intc intc {0x48200000}; global::intc = new OMAP35x_intc{0x48200000};
prcm.enable_peripherals(); global::prcm->enable_peripherals();
UART consoleUART {0x49020000, 74, prcm}; global::console = new UART{0x49020000, 74};
setConsole(&consoleUART);
// Enable interrupts // Enable interrupts
cortexa8_ena_int(); cortexa8_ena_int();
@@ -82,10 +91,15 @@ int main(int argc, char* argv[]) {
TPS65950 tps65950{i2c1}; TPS65950 tps65950{i2c1};
if(!chipInfo.running_on_qemu()) { if(!chipInfo.running_on_qemu()) {
prcm.set_cpu_opp(3); global::prcm->set_cpu_opp(3);
tps65950.set_cpu_opp(3); tps65950.set_cpu_opp(3);
} }
{
cortexa8::ScopedSetIF disint{};
global::scheduler = new Scheduler{};
}
while(1) { while(1) {
char buf[256]; char buf[256];
if(fgets(buf, 256, stdin)) if(fgets(buf, 256, stdin))
@@ -100,13 +114,10 @@ int main(int argc, char* argv[]) {
sbrk_stats(); sbrk_stats();
phys_mm::print_state(); phys_mm::print_state();
while(1) { global::scheduler->exit();
__asm__ __volatile__ ("wfi");
if(tickctr%100 == 0) { // We shouldn't get here
printf("."); __asm__ __volatile__ ("svc #42");
fflush(stdout);
}
}
return 0; return 0;
} }

143
newlib_syscall.cc Normal file
View File

@@ -0,0 +1,143 @@
#include <sys/stat.h>
#include <stdlib.h>
#include "cortexa8.hh"
#include "mm.hh"
#include "globals.hh"
#include "scheduler.hh"
#include <errno.h>
#undef errno
extern int errno;
extern "C" {
int _close(int file) __attribute__((used));
int _close(int file) {
return -1;
}
int _lseek(int file, int ptr, int dir) __attribute__((used));
int _lseek(int file, int ptr, int dir) {
return 0;
}
int _fstat(int file, struct stat *st) __attribute__((used));
int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file) __attribute__((used));
int _isatty(int file) {
return 1;
}
int _read(int file, char *ptr, int len) __attribute__((used));
int _read(int file, char *ptr, int len) {
if(file != 0)
return 0;
if(global::console)
return global::console->read(ptr, len);
else {
errno = EIO;
return -1;
}
}
int _write(int file, const char *ptr, int len) __attribute__((used));
int _write(int file, const char *ptr, int len) {
if(file != 1 && file != 2) // Only stdout supported
return 0;
if(global::console) {
global::console->write(ptr, len);
return len;
} else {
errno = EIO;
return -1;
}
}
extern uint32_t __heap_start;
static uintptr_t heap_end = 0;
static uintptr_t brk;
caddr_t _sbrk(int incr) __attribute__((used));
caddr_t _sbrk(int incr) {
if(heap_end == 0) {
heap_end = mm::get_heap_end();
brk = (uintptr_t)&__heap_start;
}
if(incr > 0) {
if(brk + incr >= heap_end) {
// Allocate additional RAM for heap
try {
unsigned pages = (brk+incr-heap_end+1)/4096;
if((brk+incr-heap_end+1)%4096 != 0)
++pages;
heap_end = mm::grow_heap(pages);
} catch (ex::bad_alloc &ex) {
_write(1, "Heap allocation failure\n", 24);
abort();
}
}
}
caddr_t prev_brk = (caddr_t)brk;
brk += incr;
return prev_brk;
}
int _kill(int pid, int sig) __attribute__((used));
int _kill(int pid, int sig) {
errno = EINVAL;
return -1;
}
int _getpid(void) __attribute__((used));
int _getpid(void) {
return 1;
}
int _open(const char *name, int flags, int mode) __attribute__((used));
int _open(const char *name, int flags, int mode) {
return -1;
}
void _exit(int status) __attribute__((used));
void _exit(int status) {
// If scheduler is initialized
if(global::scheduler)
global::scheduler->exit(); // End current thread
// Otherwise, endless wait loop
while(true)
__asm__ __volatile__ ("wfi");
}
/* struct _reent* __getreent() __attribute__((used)); */
/* struct _reent* __getreent() { */
/* _write(1,"!", 1); */
/* return nullptr; */
/* } */
}
#include <cstdio>
void sbrk_stats() {
if(heap_end == 0) {
_write(1, "Heap not initialized\n", 21);
return;
}
uintptr_t save_heap_end = heap_end, save_brk = brk;
printf("Heap: %u bytes allocated, %u bytes used\n",
save_heap_end-(uintptr_t)&__heap_start,
save_brk-(uintptr_t)&__heap_start);
}

View File

@@ -103,11 +103,8 @@ void _omap35x_intc_handler() {
} }
OMAP35x_intc* OMAP35x_intc::instance_ = nullptr;
OMAP35x_intc::OMAP35x_intc(uintptr_t base) : impl_{new OMAP35x_intc_impl{base}} { OMAP35x_intc::OMAP35x_intc(uintptr_t base) : impl_{new OMAP35x_intc_impl{base}} {
assert(!instance_);
instance_ = this;
} }
OMAP35x_intc::~OMAP35x_intc() { OMAP35x_intc::~OMAP35x_intc() {
@@ -124,8 +121,3 @@ void OMAP35x_intc::enable_int(int irq) {
void OMAP35x_intc::disable_int(int irq) { void OMAP35x_intc::disable_int(int irq) {
impl_->disable_int(irq); impl_->disable_int(irq);
} }
OMAP35x_intc& OMAP35x_intc::get() {
assert(instance_);
return *instance_;
}

View File

@@ -18,11 +18,8 @@ public:
void enable_int(int irq); void enable_int(int irq);
void disable_int(int irq); void disable_int(int irq);
static OMAP35x_intc& get();
private: private:
std::unique_ptr<OMAP35x_intc_impl> impl_; std::unique_ptr<OMAP35x_intc_impl> impl_;
static OMAP35x_intc* instance_;
}; };
#endif #endif

88
scheduler.cc Normal file
View File

@@ -0,0 +1,88 @@
#include <memory>
#include <cstdio>
#include "cortexa8.hh"
#include "scheduler.hh"
static void idle_task(void *) {
static int count = 0;
while(true) {
++count;
if(count%100 == 0) {
// printf(".");
// fflush(stdout);
}
__asm__ __volatile__("wfi");
}
}
Scheduler::Scheduler() {
// Create kernel process object
procs_.emplace_back(new Process());
kernelProc_ = procs_.back().get();
// Capture the initial (=current) kernel thread and wrap in in a Thread
threads_.emplace_back(new Thread(*kernelProc_));
kernelThread_ = threads_.back().get();
kernelThread_->setState(ThreadState::running);
currentThread_ = kernelThread_;
// Create the idle thread
threads_.emplace_back(new Thread(*kernelProc_, &idle_task, nullptr));
idleThread_ = threads_.back().get();
idleThread_->setPriority(65535);
{
cortexa8::ScopedSetIF disint{};
// Schedule kernel and idle threads
runQueue_.push(idleThread_);
}
}
Scheduler::~Scheduler() {
}
void Scheduler::timeslice() {
if(currentThread_->getState() == ThreadState::running)
currentThread_->setState(ThreadState::ready);
runQueue_.push(currentThread_);
currentThread_ = runQueue_.top();
runQueue_.pop();
currentThread_->setState(ThreadState::running);
cortexa8::set_cur_thread(currentThread_->get_tcb());
}
void Scheduler::update() {
cortexa8::ScopedSetIF disint{};
// If the current thread has become un-ready, or a higher priority thread has become ready, reschedule
if(!currentThread_->ready() || (runQueue_.top()->getPriority() < currentThread_->getPriority())) {
auto newThread_ = runQueue_.top();
runQueue_.pop();
if(currentThread_->getState() == ThreadState::running || currentThread_->getState() == ThreadState::yield) {
currentThread_->setState(ThreadState::ready);
runQueue_.push(currentThread_);
}
currentThread_ = newThread_;
currentThread_->setState(ThreadState::running);
cortexa8::set_cur_thread(currentThread_->get_tcb());
}
}
void Scheduler::yield() {
cortexa8::ScopedSetIF disint{};
if(currentThread_->getState() == ThreadState::running)
currentThread_->setState(ThreadState::yield);
}
void Scheduler::exit() {
cortexa8::ScopedSetIF disint{};
if(cortexa8::in_handler()) {
currentThread_->setState(ThreadState::terminated);
} else {
cortexa8::exit_svc();
}
}

156
scheduler.hh Normal file
View File

@@ -0,0 +1,156 @@
#ifndef _SCHEDULER_HH_
#define _SCHEDULER_HH_
#include <cstdint>
#include <cstdlib>
#include <vector>
#include <cassert>
#include <queue>
#include <functional>
#include <memory>
#include "exceptions.hh"
#include "cortexa8.hh"
using thread_entry_t = void(void*);
class Scheduler {
public:
class Process;
enum class ThreadState {
ready,
running,
waiting,
terminated,
yield
};
class Thread {
public:
~Thread() {
assert(!neverDestruct_);
}
cortexa8::thread_cb* get_tcb() {
return tcb_.get();
}
Thread(Thread const& copy) = delete;
// Priority compare (here, higher = higher priority)
// Result is only meaningful for runnable, scheduled threads
bool operator<(Thread const& other) const {
// Check for higher priority
if(priority_ > other.priority_)
return true; // I am lower prio
else if(priority_ < other.priority_)
return false; // Other thread is lower prio
else {
// TODO: Compare by waiting time
return true;
}
}
unsigned getPriority() const {
return priority_;
}
// Set this threads priority. The lower the number the higher the priority
void setPriority(unsigned priority) {
priority_ = priority;
}
bool ready() const {
return (state_ == ThreadState::ready) || (state_ == ThreadState::running);
}
ThreadState getState() const {
return state_;
}
private:
Thread(Process& proc) : proc_(proc), neverDestruct_{true}, priority_(0), state_{ThreadState::ready} {
tcb_.reset(cortexa8::get_cur_thread());
}
Thread(Process& proc, thread_entry_t entry, void *arg, size_t stacksize = 4096)
: tcb_{new cortexa8::thread_cb}, proc_(proc), stack_{new uint32_t[stacksize/4]}, neverDestruct_{false},
priority_(0), state_{ThreadState::ready} {
tcb_->regs[15] = (uint32_t)entry;
tcb_->regs[13] = (uint32_t)stack_.get();
tcb_->regs[1] = (uint32_t)arg;
tcb_->cpsr = 0x0000015f;
}
void setState(ThreadState state) {
state_ = state;
}
std::unique_ptr<cortexa8::thread_cb> tcb_;
Process& proc_;
std::unique_ptr<uint32_t> stack_;
bool neverDestruct_;
unsigned priority_;
ThreadState state_;
friend class Scheduler;
};
class Process {
private:
Process() : ttable0_phys_(0), ttable0_(nullptr) {
}
uint32_t ttable0_phys_;
uint32_t *ttable0_;
std::vector<Thread> threads_;
friend class Scheduler;
};
Scheduler();
~Scheduler();
// Called by timer interrupt
// Selects a new thread to run after a time slice has elapsed
void timeslice();
// Set tcb of new current thread if necessary
// This may only be called when inside an exception/interrupt handler
void update();
// Cease execution of current thread for this timeslice
// This may only be called when inside an exception/interrupt handler
void yield();
// Exit current thread. If this is the last thread of a process, the process terminates
void exit();
Thread& getCurrentThread() {
return *currentThread_;
}
private:
struct ThreadCompare {
bool operator()(Thread* const& lhs, Thread* const& rhs) const {
return *lhs<*rhs;
}
};
std::vector<std::unique_ptr<Process>> procs_;
std::vector<std::unique_ptr<Thread>> threads_;
std::priority_queue<Thread*, std::vector<Thread*>, ThreadCompare> runQueue_;
// Process for kernel threads (no ttable0)
Process *kernelProc_;
// Initial thread and the idle thread
Thread *kernelThread_, *idleThread_;
Thread *currentThread_;
};
#endif

140
syscall.c
View File

@@ -1,140 +0,0 @@
#include <sys/stat.h>
#include <stdlib.h>
#include "cortexa8.hh"
#include "mm.hh"
#include <errno.h>
#undef errno
extern int errno;
#include "uart.hh"
static ICharacterDevice* console = nullptr;
void setConsole(ICharacterDevice* newConsole) {
console = newConsole;
}
#ifdef __cplusplus
extern "C" {
#endif
int _close(int file) __attribute__((used));
int _close(int file) {
return -1;
}
int _lseek(int file, int ptr, int dir) __attribute__((used));
int _lseek(int file, int ptr, int dir) {
return 0;
}
int _fstat(int file, struct stat *st) __attribute__((used));
int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file) __attribute__((used));
int _isatty(int file) {
return 1;
}
int _read(int file, char *ptr, int len) __attribute__((used));
int _read(int file, char *ptr, int len) {
/* if(file != 0) */
/* return 0; */
if(console)
return console->read(ptr, len);
else {
errno = EIO;
return -1;
}
}
int _write(int file, const char *ptr, int len) __attribute__((used));
int _write(int file, const char *ptr, int len) {
// if(file != 1 && file != 2) // Only stdout supported
//return 0;
if(console) {
console->write(ptr, len);
return len;
} else {
errno = EIO;
return -1;
}
}
extern uint32_t __heap_start;
static uintptr_t heap_end = 0;
static uintptr_t brk;
caddr_t _sbrk(int incr) __attribute__((used));
caddr_t _sbrk(int incr) {
if(heap_end == 0) {
heap_end = mm::get_heap_end();
brk = (uintptr_t)&__heap_start;
}
if(brk + incr >= heap_end) {
// Allocate additional RAM for heap
try {
unsigned pages = (brk+incr-heap_end+1)/4096;
if((brk+incr-heap_end+1)%4096 != 0)
++pages;
heap_end = mm::grow_heap(pages);
} catch (ex::bad_alloc &ex) {
_write(1, "Heap allocation failure\n", 24);
abort();
}
}
caddr_t prev_brk = (caddr_t)brk;
brk += incr;
return prev_brk;
}
int _kill(int pid, int sig) __attribute__((used));
int _kill(int pid, int sig) {
errno = EINVAL;
return -1;
}
int _getpid(void) __attribute__((used));
int _getpid(void) {
return 1;
}
int _open(const char *name, int flags, int mode) __attribute__((used));
int _open(const char *name, int flags, int mode) {
return -1;
}
/* struct _reent* __getreent() __attribute__((used)); */
/* struct _reent* __getreent() { */
/* _write(1,"!", 1); */
/* return nullptr; */
/* } */
#ifdef __cplusplus
}
#endif
#include <cstdio>
void sbrk_stats() {
if(heap_end == 0) {
_write(1, "Heap not initialized\n", 21);
return;
}
uintptr_t save_heap_end = heap_end, save_brk = brk;
printf("Heap: %u bytes allocated, %u bytes used\n",
save_heap_end-(uintptr_t)&__heap_start,
save_brk-(uintptr_t)&__heap_start);
}

34
syscall.cc Normal file
View File

@@ -0,0 +1,34 @@
#include <cstdint>
#include <cstdio>
#include <errno.h>
#include "scheduler.hh"
#include "globals.hh"
#include "cortexa8.hh"
#include "syscall.hh"
extern cortexa8::thread_cb *_current_thread_cb;
void syscall_handler(int num) {
int32_t rval = 0;
//printf("Syscall %d PC: %.8lx SP: %.8lx\n", num, _current_thread_cb->regs[15], _current_thread_cb->regs[13]);
switch(num) {
case SYSCALL_EXIT:
global::scheduler->exit();
break;
case SYSCALL_YIELD:
global::scheduler->yield();
break;
default:
printf("WARNING: Unknown syscall %d\n", num);
printf("PC: %.8lx SP: %.8lx\n", _current_thread_cb->regs[15], _current_thread_cb->regs[13]);
rval = -EINVAL;
}
// Write return value
_current_thread_cb->regs[0] = rval;
global::scheduler->update();
}

9
syscall.hh Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _SYSCALL_HH_
#define _SYSCALL_HH_
#define SYSCALL_EXIT 0
#define SYSCALL_YIELD 1
extern "C" void syscall_handler(int num);
#endif

View File

@@ -1,6 +0,0 @@
.global _exit
_exit:
mrs r1, CPSR
wfi
b _exit

20
uart.cc
View File

@@ -5,15 +5,16 @@
#include "cortexa8.hh" #include "cortexa8.hh"
#include "omap35x_intc.hh" #include "omap35x_intc.hh"
#include "omap35x_prcm.hh" #include "omap35x_prcm.hh"
#include "globals.hh"
#include "util.hh" #include "util.hh"
#include "mmio.hh" #include "mmio.hh"
#include "uart.hh" #include "uart.hh"
class UART_impl { class UART_impl {
public: public:
UART_impl(uintptr_t base, int irq, OMAP35x_prcm& prcm) : base_{base}, irq_(irq), prcm_(prcm) { UART_impl(uintptr_t base, int irq) : base_{base}, irq_(irq) {
OMAP35x_intc::get().register_handler(irq_, std::bind(&UART_impl::recv_handler, this), 1); global::intc->register_handler(irq_, std::bind(&UART_impl::recv_handler, this), 1);
OMAP35x_intc::get().enable_int(irq_); global::intc->enable_int(irq_);
r_lcr() = 0xBF; // Configuration mode B r_lcr() = 0xBF; // Configuration mode B
uint8_t dllsave = r_dll(), dlhsave = r_dlh(); uint8_t dllsave = r_dll(), dlhsave = r_dlh();
@@ -31,7 +32,7 @@ UART_impl(uintptr_t base, int irq, OMAP35x_prcm& prcm) : base_{base}, irq_(irq),
} }
~UART_impl() { ~UART_impl() {
OMAP35x_intc::get().disable_int(irq_); global::intc->disable_int(irq_);
} }
void write(char const* data, int const& len) { void write(char const* data, int const& len) {
@@ -86,10 +87,14 @@ UART_impl(uintptr_t base, int irq, OMAP35x_prcm& prcm) : base_{base}, irq_(irq),
if(pos > 0) if(pos > 0)
return pos; return pos;
while(!newdata_) while(!newdata_) {
if(global::scheduler)
cortexa8::yield_svc();
else
__asm__ __volatile__ ("wfi"); // If we didn't get any data, wait __asm__ __volatile__ ("wfi"); // If we didn't get any data, wait
} }
} }
}
private: private:
void recv_handler() { void recv_handler() {
@@ -107,12 +112,11 @@ private:
} }
newdata_ = true; newdata_ = true;
prcm_.clear_wake_per(11); global::prcm->clear_wake_per(11);
} }
MMIO_alloc base_; MMIO_alloc base_;
int irq_; int irq_;
OMAP35x_prcm& prcm_;
uint8_t volatile& r_data() { uint8_t volatile& r_data() {
return _reg8(base_.get_virt(), 0); return _reg8(base_.get_virt(), 0);
@@ -184,7 +188,7 @@ private:
} }
}; };
UART::UART(uintptr_t base, int irq, OMAP35x_prcm& prcm) : impl_(new UART_impl(base, irq, prcm)) { UART::UART(uintptr_t base, int irq) : impl_(new UART_impl(base, irq)) {
} }
UART::~UART() { UART::~UART() {

View File

@@ -12,7 +12,7 @@ class UART_impl;
class UART : public ICharacterDevice { class UART : public ICharacterDevice {
public: public:
UART(uintptr_t base, int irq, OMAP35x_prcm& prcm); UART(uintptr_t base, int irq);
~UART(); ~UART();
virtual void write(char const* data, int const& len); virtual void write(char const* data, int const& len);