Files
bsb2/kernel/syscall/skeleton.cc

329 lines
9.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "../syscall/skeleton.h"
#include "../debug/kernelpanic.h"
#include "../debug/output.h"
#include "../device/textstream.h"
#include "../interrupt/guard.h"
#include "../memory/page.h"
#include "../sync/semaphore.h"
#include "../thread/scheduler.h"
#include "../memory/pageframealloc.h"
#include "../memory/pagetable.h"
#include "../arch/idt.h"
void *operator new(size_t, void *);
//#include "../user/app1/appl.h"
//extern Application apps[];
uint8_t mapNumber = 0;
namespace Syscall {
namespace Skeleton {
void invlpg(uintptr_t virt_addr) {
asm volatile("invlpg (%0)" : : "r" (virt_addr) : "memory");
}
size_t test(Vault &vault, size_t p1, size_t p2, size_t p3, size_t p4,
size_t p5) {
(void)vault;
vault.kout << "test(" << p1 << ", " << p2 << ", " << p3 << ", " << p4
<< ", " << p5 << ");" << endl;
return 0xdeadbeef;
}
int getpid(Vault &vault) {
Thread *me = vault.scheduler.active();
//unsigned id = 0;
//while (&apps[id++] != me); // TODO find better pid source
//return id;
return me->id;
}
size_t write(Vault &vault, uint32_t id, const void *buffer, size_t size, int x, int y) {
(void)id;
TextStream* out;
switch (id) {
case 1:
out = &vault.kout;
break;
case 2:
out = &dout;
break;
default:
out = &vault.kout;
}
int dummy;
if(x == -1 && y != -1)
out->getPos(x, dummy);
if(x != -1 && y == -1)
out->getPos(dummy, y);
if(x == -1 && y == -1)
out->getPos(x, y);
out->setPos(x, y);
for(size_t i = 0; i<size; i++)
*out << ((char*)buffer)[i];
out->flush();
return 0;
}
size_t read(Vault &vault, uint32_t id, void *buf, size_t len) {
(void)id;
size_t read_cnt = 0;
while(read_cnt < len){
Key key;
vault.keys_sem.p(vault);
vault.keys.consume(key);
if(key.valid())
((char*)buf)[read_cnt++] = key.ascii();
else
break;
}
return read_cnt;
}
void sleep(Vault &vault, size_t ms) {
vault.bellringer.sleep(vault, ms);
}
bool sem_init(Vault &vault, size_t id, uint32_t value) {
if (id >= vault.MAX_SEMS) {
return false; // outofrange id
}
if (vault.sems[id].used==1){
return false; //already in use
}
vault.sems[id].counter=value;
return true;
}
bool sem_destroy(Vault &vault, size_t id) {
if (id >= vault.MAX_SEMS) {
return false; // outofrange id
}
if (vault.sems[id].used==0){
return false; //already in free
}
vault.sems[id].used=0;
vault.sems[id].counter=0;
return true;
}
bool sem_signal(Vault &vault, size_t id) {
vault.sems[id].v(vault);
return true;
}
bool sem_wait(Vault &vault, size_t id) {
vault.sems[id].p(vault);
return true;
}
void exit(Vault &vault) {
vault.scheduler.exit();
unmap(vault, (void*) 0x4000000, 512 );
}
void kill(Vault &vault, size_t pid){
//vault.scheduler.kill(&apps[pid]);
}
void* map(Vault *vault, size_t size) {
size_t num_pages = (size + 4096 - 1) / 4096;
//pagetable_t* subbytable = vault->scheduler.active()->subtable;
four_lvl_paging_t* search_table = vault->scheduler.active()->paging_tree;
void* ptr = getFreeVirtSpace(search_table->l4, num_pages);
if (ptr == nullptr) {
return nullptr;
}
// map all used pages
for (size_t i = 0; i < num_pages; ++i) {
// allocate each page with allocator
void* frame = PageFrameAllocator::alloc(false);
setMapping((uintptr_t)ptr, frame, search_table->l4);
}
return ptr;
}
int unmap(Vault &vault, void* start, size_t size) {
uint32_t NumberOfPages = (size/4096);
four_lvl_paging_t* search_table = vault.scheduler.active()->paging_tree;
uint32_t startIndex = ((uintptr_t)start)>>12;
memset(start, 0, size);
for(uint32_t i=startIndex; i<(startIndex+NumberOfPages); i++){
uintptr_t frame = isMapped(i<<12, search_table->l4);
setMapping(i<<12, 0, search_table->l4);
PageFrameAllocator::free(frame);
invlpg(i<<12);
}
return 0;
}
bool copy_from_phys(Vault& vault, uintptr_t src_paddr, void* dest_vaddr, size_t size) {
size_t offset = Page::offset(src_paddr);
size_t total_size = size + offset;
four_lvl_paging_t* search_table = vault.scheduler.active()->paging_tree;
uintptr_t src_vaddr = (uintptr_t)getFreeVirtSpace(search_table->l4, (total_size/4096)+1); // page aligned pointer
if (src_vaddr == 0) {
return false;
}
src_vaddr += offset;
for(uint8_t i =0; i<size/4096 +1; i++){
setMapping(src_vaddr+(uintptr_t)(i*4096), (void*)(src_paddr+(uintptr_t)(i*4096)), search_table->l4);
}
memcpy(dest_vaddr, (void*)src_vaddr, size);
for(uint8_t i =0; i<size/4096 +1; i++){
setMapping((uintptr_t)(src_vaddr), 0, search_table->l4);
}
return true;
}
bool send(Vault& v, int pid, const void* sbuffer, size_t ssize, void* rbuffer, size_t rsize) {
Thread* current_thread = v.scheduler.active();
Thread* target_thread = v.thread_list[pid];
//uintptr_t sbuffer_ptr = isMapped((uintptr_t)sbuffer,v.scheduler.active()->paging_tree->l4) + ((uintptr_t)sbuffer&0xFFF);
IpcStruct msg = {
.ptr = (uintptr_t)sbuffer,
.size = ssize,
.pid = current_thread->id,
.is_answer = false,
.queue_link = nullptr
};
target_thread->ipc_queue.enqueue(msg);
target_thread->ipc_sem.v(v);
while (true) {
current_thread->ipc_sem.p(v);
if (msg.is_answer) {
break;
}
DBG_VERBOSE << "" << endl;
}
uint8_t num_pages = (rsize/4096)+1;
// Kopiere Antwort size kann mehr sein
for(uint8_t i=0;i<num_pages;i++){
uintptr_t paddr = isMapped(msg.ptr, target_thread->paging_tree->l4); //always page aligned
if(rsize-i*4096>4096){ // ganze pages
if (!copy_from_phys(v,paddr,(void*)((uintptr_t) rbuffer+ (4096*i)),4096)) {
return false;
}
} else { //teil von pages
if (!copy_from_phys(v,paddr,(void*)((uintptr_t)rbuffer+ 4096*i), rsize-i*4096)) {
return false;
}
}
}
return true;
}
int receive(Vault& v, void* buffer, size_t size) {
// DBG_VERBOSE << "Receive syscall for thread " << dec << v.scheduler.active()->id << endl;
Thread* thread = v.scheduler.active();
// Warte auf Nachricht
//if (thread->ipc_queue.is_empty()) {
thread->ipc_sem.p(v);
//}
IpcStruct* ipc = thread->ipc_queue.first();
if (ipc == nullptr) return -1;
size_t copy_len = (size < ipc->size) ? size:ipc->size;
size_t total_len = (Page::offset(ipc->ptr)+copy_len);
uint8_t num_pages = (total_len/4096)+1;
for(uint32_t i=0; i<num_pages; i++){
uintptr_t offset = i==0?Page::offset(ipc->ptr):0; //apply offset only on first page
uintptr_t paddr = isMapped((ipc->ptr)+(i*4096), v.thread_list[ipc->pid]->paging_tree->l4);
if(total_len - (i*4096) > 4096)
copy_from_phys(v, paddr+offset,(void*)((uintptr_t)buffer+i*4096), 4096-offset);
else
copy_from_phys(v, paddr, (void*)((uintptr_t)buffer+i*4096), total_len - (i*4096)); //last page
}
return ipc->pid;
}
bool reply(Vault& v, const void* buffer, size_t size) {
Thread* current_thread = v.scheduler.active();
IpcStruct* ipc = current_thread->ipc_queue.dequeue();
//noting to reply to
if(!ipc)
return false;
// if (!ipc || ipc->pid < 0 || static_cast<size_t>(ipc->pid) >= v.thread_count) return false;
Thread* other_thread = v.thread_list[ipc->pid];
if (other_thread == nullptr) return false;
ipc->ptr = (uintptr_t)buffer;
ipc->size = size;
ipc->pid = current_thread->id;
ipc->is_answer = true;
// Sender aufwecken
other_thread->ipc_sem.v(v);
return true;
}
void copy_stack(Thread* parent, Thread* child){
uintptr_t dest_frame = isMapped((uintptr_t)child->StackPointer.user, child->paging_tree->l4);
void* dest_vaddr = getFreeVirtSpace(parent->paging_tree->l4, 1);
setMapping((uintptr_t)dest_vaddr, (void*)dest_frame, parent->paging_tree->l4);
memcpy(dest_vaddr, (void*)0x6000000/*((uintptr_t)parent->StackPointer.user & ~0xFFF)*/, 4096);
setMapping((uintptr_t)dest_vaddr, 0, parent->paging_tree->l4);
}
int fork(Vault &vault, InterruptContext *user_context) {
Thread* parent = vault.scheduler.active();
Thread* child = new Thread(false, (void*)user_context->ip, parent->code_paddr, parent->code_pagenum);
//copy_pagetable(parent->paging_tree, child->paging_tree);
copy_stack(parent, child);
child->StackPointer.user = (void*)user_context->sp;
vault.thread_list[child->id] = child;
//return parent pid to child
prepareContext(child->StackPointer.isr, child->context, Thread::kickoff, reinterpret_cast<uintptr_t>(child), parent->id, 0);
vault.scheduler.ready(child);
// return child pid to parent
return child->id;
}
} // namespace Skeleton
} // namespace Syscall