Userspace with a syscall
This commit is contained in:
parent
a02167ad88
commit
4ad5b58787
@ -335,7 +335,7 @@ int cpu_ustate_init(struct cpu_state **ctx, uaddr_t startPC, uint32_t arg1, uint
|
||||
uctx->regs.cs = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UCODE); // Code
|
||||
uctx->regs.ds = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Data
|
||||
uctx->regs.es = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Data
|
||||
uctx->regs.cpl0_ss = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Kernel Stack
|
||||
uctx->regs.cpl0_ss = BUILD_SEGMENT_REG_VALUE(0, FALSE, SEG_KDATA); // Kernel Stack
|
||||
uctx->cpl3_ss = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // User Stack
|
||||
|
||||
uctx->cpl3_esp = startSP;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "assert.h"
|
||||
#include "swintr.h"
|
||||
#include "irq.h"
|
||||
#include "idt.h"
|
||||
@ -8,9 +9,10 @@ int syscallSetup(){
|
||||
uint32_t flags, ret;
|
||||
|
||||
disable_IRQs(flags);
|
||||
ret = idt_set_handler(SYSCALL_INTR_NB, (vaddr_t)syscallHandler, 3);
|
||||
ret = idt_set_handler(SYSCALL_INTR_NB, (vaddr_t)syscallHandler, 3);
|
||||
restore_IRQs(flags);
|
||||
|
||||
assert(ret == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -201,6 +201,9 @@ void cpu_state_detect_kernel_stack_overflow(const struct cpu_state *ctxt,
|
||||
#define cpu_state_detect_kernel_stack_overflow(ctxt, stkbottom, stksize) ({/* nop */})
|
||||
#endif
|
||||
|
||||
int cpu_ustate_init(struct cpu_state **ctx, uaddr_t startPC, uint32_t arg1, uint32_t arg2,
|
||||
uaddr_t startSP, vaddr_t kernelStackBottom, size_t kernelStackSize);
|
||||
|
||||
int syscallGet3args(const struct cpu_state *user_ctxt,
|
||||
/* out */ unsigned int *arg1,
|
||||
/* out */ unsigned int *arg2,
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "serial.h"
|
||||
#include "stack.h"
|
||||
#include "stdarg.h"
|
||||
#include "swintr.h"
|
||||
#ifdef RUN_TEST
|
||||
#include "test.h"
|
||||
#endif
|
||||
@ -172,6 +173,7 @@ void kmain(unsigned long magic, unsigned long addr)
|
||||
threadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1));
|
||||
threadCreate("idle ", idleThread, NULL);
|
||||
processSetup();
|
||||
syscallSetup();
|
||||
|
||||
irqSetRoutine(IRQ_TIMER, pit_handler);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "list.h"
|
||||
#include "mmuContext.h"
|
||||
#include "time.h"
|
||||
#include "types.h"
|
||||
#include "vga.h"
|
||||
|
||||
static struct thread *currentThread;
|
||||
@ -59,15 +60,15 @@ struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, v
|
||||
return NULL;
|
||||
|
||||
thread->stackAddr = (vaddr_t)malloc(THREAD_DEFAULT_STACK_SIZE);
|
||||
if (!thread->stackAddr)
|
||||
if (!thread->stackAddr){
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("Alloc stack at 0x%x struct at 0x%x\n", thread->stackAddr, thread);
|
||||
#endif
|
||||
thread->stackSize = THREAD_DEFAULT_STACK_SIZE;
|
||||
|
||||
if (!thread->stackAddr)
|
||||
goto free_mem;
|
||||
|
||||
if (name)
|
||||
strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH);
|
||||
@ -91,12 +92,53 @@ free_mem:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t startPc,
|
||||
uint32_t arg1, uint32_t arg2, uaddr_t startSP)
|
||||
{
|
||||
struct thread *thread = malloc(sizeof(struct thread));
|
||||
|
||||
if (thread == NULL)
|
||||
return NULL;
|
||||
|
||||
thread->stackAddr = (vaddr_t)malloc(THREAD_DEFAULT_STACK_SIZE);
|
||||
if (!thread->stackAddr) {
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
thread->stackSize = THREAD_DEFAULT_STACK_SIZE;
|
||||
|
||||
if (name)
|
||||
strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH);
|
||||
else
|
||||
strzcpy(thread->name, "[UNKNOW]", THREAD_NAME_MAX_LENGTH);
|
||||
|
||||
if (cpu_ustate_init(&thread->cpuState, startPc, arg1, arg2, startSP, thread->stackAddr,
|
||||
thread->stackSize)) {
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
if(processAddThread(proc, thread))
|
||||
goto free_mem;
|
||||
|
||||
thread->state = READY;
|
||||
uint32_t flags;
|
||||
disable_IRQs(flags);
|
||||
list_add_tail(currentThread, thread);
|
||||
restore_IRQs(flags);
|
||||
return thread;
|
||||
free_mem:
|
||||
free((void *)thread->stackAddr);
|
||||
free((void *)thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void threadDelete(struct thread *thread)
|
||||
{
|
||||
uint32_t flags;
|
||||
disable_IRQs(flags);
|
||||
list_delete(currentThread, thread);
|
||||
restore_IRQs(flags);
|
||||
assert(thread->state == EXITING);
|
||||
|
||||
if (thread->squattedContext) {
|
||||
threadChangeCurrentContext(NULL);
|
||||
@ -135,6 +177,7 @@ struct cpu_state *threadSwitch(struct cpu_state *prevCpu)
|
||||
currentThread->cpuState = prevCpu;
|
||||
if (nextThread != currentThread) {
|
||||
currentThread->state = READY;
|
||||
// printf(" Switch from %s to %s\n", currentThread->name, nextThread->name);
|
||||
currentThread = nextThread;
|
||||
currentThread->state = RUNNING;
|
||||
threadPrepareContext(nextThread);
|
||||
@ -145,6 +188,17 @@ struct cpu_state *threadSwitch(struct cpu_state *prevCpu)
|
||||
return nextThread->cpuState;
|
||||
}
|
||||
|
||||
int threadCount()
|
||||
{
|
||||
struct thread *nextThread;
|
||||
int idx;
|
||||
uint32_t flags;
|
||||
disable_IRQs(flags);
|
||||
list_foreach(currentThread, nextThread, idx){
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
int threadOnJieffiesTick()
|
||||
{
|
||||
struct thread *nextThread;
|
||||
@ -224,7 +278,7 @@ int threadYield()
|
||||
|
||||
if (current->state == RUNNING)
|
||||
current->state = READY;
|
||||
|
||||
// printf(" Yield from %s to %s\n", currentThread->name, next->name);
|
||||
currentThread = next;
|
||||
currentThread->state = RUNNING;
|
||||
threadPrepareContext(next);
|
||||
|
@ -72,6 +72,8 @@ int threadSetup(vaddr_t mainStack, size_t mainStackSize);
|
||||
void threadExit();
|
||||
|
||||
struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args);
|
||||
struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t startPc,
|
||||
uint32_t arg1, uint32_t arg2, uaddr_t startSP);
|
||||
void threadDelete(struct thread *thread);
|
||||
|
||||
struct thread *threadSelectNext();
|
||||
@ -85,3 +87,4 @@ int threadOnJieffiesTick();
|
||||
struct thread *getCurrentThread();
|
||||
int threadAddThread(struct thread *th);
|
||||
int threadChangeCurrentContext(struct mmu_context *ctx);
|
||||
int threadCount();
|
||||
|
53
tests/test.c
53
tests/test.c
@ -3,6 +3,7 @@
|
||||
#include "ata.h"
|
||||
#include "assert.h"
|
||||
#include "cpu_context.h"
|
||||
#include "kernel.h"
|
||||
#include "klibc.h"
|
||||
#include "thread.h"
|
||||
#include "list.h"
|
||||
@ -13,6 +14,8 @@
|
||||
#include "serial.h"
|
||||
#include "stack.h"
|
||||
#include "synchro.h"
|
||||
#include "syscall.h"
|
||||
#include "swintr.h"
|
||||
#include "time.h"
|
||||
|
||||
void testMemcpyPerf()
|
||||
@ -213,6 +216,7 @@ static void reclaim_stack(void *stack_vaddr)
|
||||
|
||||
static void exit_hello12(void *stack_vaddr)
|
||||
{
|
||||
printf("Stopping hello\n");
|
||||
cpu_context_exit_to(ctxt_main, (cpu_kstate_function_arg1_t *)reclaim_stack,
|
||||
(vaddr_t)stack_vaddr);
|
||||
}
|
||||
@ -348,6 +352,7 @@ void testKthread()
|
||||
threadCreate("mtest1", mutThread, "mut1");
|
||||
threadCreate("mtest2", mutThread, "mut2");
|
||||
threadCreate("mtest3", mutThread, "mut3");
|
||||
threadMsleep(2000);
|
||||
}
|
||||
|
||||
void testATAThread(){
|
||||
@ -382,6 +387,29 @@ static void testMMUContext()
|
||||
mmuContextUnref(new);
|
||||
}
|
||||
|
||||
static void userProgramm()
|
||||
{
|
||||
int ret;
|
||||
|
||||
asm volatile("movl %1,%%eax \n"
|
||||
"movl %2,%%ebx \n"
|
||||
"movl %3,%%ecx \n"
|
||||
"movl %4,%%edx \n"
|
||||
"int %5\n"
|
||||
"movl %%eax, %0"
|
||||
: "=g"(ret)
|
||||
: "g"(SYSCALL_ID_WRITE), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB)
|
||||
: "eax", "ebx", "ecx", "edx");
|
||||
asm volatile("movl %1,%%eax \n"
|
||||
"movl %2,%%ebx \n"
|
||||
"movl %3,%%ecx \n"
|
||||
"movl %4,%%edx \n"
|
||||
"int %5\n"
|
||||
"movl %%eax, %0"
|
||||
: "=g"(ret)
|
||||
: "g"(SYSCALL_ID_EXIT), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB)
|
||||
: "eax", "ebx", "ecx", "edx");
|
||||
}
|
||||
|
||||
static void testProcess(){
|
||||
struct process *proc= processCreate("TESTPROCESS");
|
||||
@ -397,6 +425,29 @@ static void testProcess(){
|
||||
processUnref(proc);
|
||||
printf("Next process list should be empty\n");
|
||||
processListPrint();
|
||||
printf("Running user space app\n");
|
||||
struct process *proc2= processCreate("TESTPROCESS2");
|
||||
|
||||
threadChangeCurrentContext(processGetMMUContext(proc2));
|
||||
uaddr_t stackTop = 0xfffffffc;
|
||||
uaddr_t stackBottom = ALIGN_DOWN(stackTop, PAGE_SIZE);
|
||||
paddr_t stackPhy = allocPhyPage(1);
|
||||
assert(pageMap(stackBottom, stackPhy, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0);
|
||||
unrefPhyPage(stackPhy);
|
||||
|
||||
uaddr_t mem = PAGING_BASE_USER_ADDRESS;
|
||||
paddr_t memPhy = allocPhyPage(1);
|
||||
assert(pageMap(mem, memPhy, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0);
|
||||
unrefPhyPage(memPhy);
|
||||
|
||||
memcpy((void *)mem, userProgramm, PAGE_SIZE);
|
||||
|
||||
threadCreateUser("UserProg", proc2, mem, 0, 0, stackTop);
|
||||
threadYield();
|
||||
processUnref(proc2);
|
||||
threadChangeCurrentContext(NULL);
|
||||
|
||||
printf("Running user space app DONE\n");
|
||||
}
|
||||
|
||||
void run_test(void)
|
||||
@ -436,7 +487,9 @@ void run_test(void)
|
||||
printf("Testing backtrace\n");
|
||||
test_backtrace();
|
||||
testCoroutine();
|
||||
int nbThread = threadCount();
|
||||
testKthread();
|
||||
assert(nbThread + 1 == threadCount());//For sleep Thread
|
||||
testMMUContext();
|
||||
testProcess();
|
||||
memGetStat(&afterFreemem, &afterUsedmem);
|
||||
|
Loading…
Reference in New Issue
Block a user