Add RPC support
This commit is contained in:
parent
18ca6e49e6
commit
d9a01fdbda
15
README.md
15
README.md
@ -1,39 +1,48 @@
|
||||
# os
|
||||
|
||||
This is a hobby OS based on a microkernel.
|
||||
It currently supports:
|
||||
|
||||
1. Basic preemptive multitasking with task states & exiting.
|
||||
2. Physical & virtual memory management
|
||||
3. Interrupts.
|
||||
4. The PIT, used to do preemption.
|
||||
5. The serial port, used as an output for logs. (driver in kernel, will eventually be moved out)
|
||||
6. RPC for IPC
|
||||
|
||||
## Building (on Linux or Mac)
|
||||
|
||||
To build the OS, you will need a custom patched GCC cross-compiler targeted for my OS, and GRUB.
|
||||
Installing GRUB on:
|
||||
|
||||
1. Ubuntu. GRUB is already installed.
|
||||
2. Another linux distro. GRUB is likely already installed, but if it is not, you will need to use your distribution's package manager to install GRUB.
|
||||
3. Mac. You will need to install Homebrew, then install the formula i386-elf-grub.
|
||||
|
||||
### Building the cross-compiler
|
||||
|
||||
The instructions for building a cross compiler are [here](https://wiki.osdev.org/GCC_Cross-Compiler), though a few changes need to be made.
|
||||
First, you **must** download GCC 9.2.0 and Binutils 2.32, or the patches may not apply correctly.
|
||||
Next, you need to apply the patches located in the patches/ directory.
|
||||
Set $TARGET to i386-myos, not i686-elf.
|
||||
When running configure for both Binutils and GCC, you must pass --sysroot=<path to cloned github repo>/sysroot as an extra argument,
|
||||
When running configure for both Binutils and GCC, you must pass --sysroot=\<path to cloned github repo\>/sysroot as an extra argument,
|
||||
otherwse the compiler will not be able to find the libc headers.
|
||||
Otherwise, the build is as normal.
|
||||
|
||||
Once the cross-compiler is built, the OS can be built by simply typing `make`.
|
||||
|
||||
## Additional setup for development
|
||||
|
||||
To properly develop the OS, you willl need to install QEMU and GDB.
|
||||
|
||||
Installing QEMU on
|
||||
Installing QEMU on
|
||||
|
||||
1. Ubuntu. Run `sudo apt get install qemu`
|
||||
2. Another linux distro. Use your distribution's package manager to install QEMU.
|
||||
3. Mac. Run `brew install qemu`
|
||||
|
||||
Installing GDB on
|
||||
Installing GDB on
|
||||
|
||||
1. Ubuntu. Run `sudo apt get install gdb`
|
||||
2. Another linux distro. Use your distribution's package manager to install GDB.
|
||||
3. Mac. Run `brew install gdb` (Note: It will warn about an unsigned binary, but this will have no impact on debugging the OS)
|
||||
|
31
init/main.c
31
init/main.c
@ -7,6 +7,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tasking.h>
|
||||
#include <rpc.h>
|
||||
|
||||
typedef struct {
|
||||
char filename[100];
|
||||
@ -128,21 +129,31 @@ char load_proc(size_t datapos,char* initrd) {
|
||||
// }
|
||||
|
||||
void* thread_func(void* arg) {
|
||||
for (;;) yield();
|
||||
for (;;);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
serial_print("IN INIT\n");
|
||||
pthread_t thread;
|
||||
pthread_create(&thread,NULL,thread_func,NULL);
|
||||
block_thread(THREAD_BLOCKED);
|
||||
for (int i=0;i<5;i++) {
|
||||
serial_print("YIELDING\n");
|
||||
yield();
|
||||
serial_print("YIELDED\n");
|
||||
}
|
||||
serial_print("EXITING\n");
|
||||
long size=initrd_sz();
|
||||
char* initrd=malloc(size);
|
||||
initrd_get(initrd);
|
||||
size_t datapos=find_loc("rpctest",initrd);
|
||||
load_proc(datapos,initrd);
|
||||
void* retbuf=rpc_call(2,"rpctestfunc","Buffer test\n",strlen("Buffer test\n")+1);
|
||||
serial_print(retbuf);
|
||||
rpc_deallocate_buf(retbuf,strlen(retbuf)+1);
|
||||
serial_print(retbuf);
|
||||
// yield();
|
||||
// pthread_t thread;
|
||||
// pthread_create(&thread,NULL,thread_func,NULL);
|
||||
// blockThread(THREAD_BLOCKED);
|
||||
// for (int i=0;i<5;i++) {
|
||||
// serial_print("YIELDING\n");
|
||||
// yield();
|
||||
// serial_print("YIELDED\n");
|
||||
// }
|
||||
// serial_print("EXITING\n");
|
||||
exit(0);
|
||||
// long size=initrd_sz();
|
||||
// char* initrd=malloc(size);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "../isr.h"
|
||||
#include "../paging.h"
|
||||
#include "../serial.h"
|
||||
//#include "../../rpc.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "isr.h"
|
||||
@ -248,6 +249,7 @@ void isr_handler(registers_t* r) {
|
||||
} else {
|
||||
r->ebx=(uint32_t)address_spaces_put_data((void*)r->ebx,(void*)r->ecx,r->edx);
|
||||
}
|
||||
serial_printf("sycall done\n");
|
||||
break;
|
||||
case SYSCALL_SERIAL_PRINT:
|
||||
serial_write_string((char*)r->ebx);
|
||||
@ -267,6 +269,27 @@ void isr_handler(registers_t* r) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SYSCALL_THREAD_EXIT:
|
||||
tasking_thread_exit();
|
||||
break;
|
||||
case SYSCALL_CALL_RPC:
|
||||
r->edi=(uint32_t)kernel_rpc_call((pid_t)r->ebx,(char*)r->ecx,(void*)r->edx,(size_t)r->esi);
|
||||
break;
|
||||
case SYSCALL_REGISTER_RPC:
|
||||
kernel_rpc_register_func((char*)r->ebx,(rpc_func)r->ecx);
|
||||
break;
|
||||
case SYSCALL_DEALLOCTATE_RPC_RET:
|
||||
kernel_rpc_deallocate_buf((void*)r->ebx,(size_t)r->ecx);
|
||||
break;
|
||||
case SYSCALL_RPC_RET:
|
||||
kernel_rpc_return((void*)r->ebx,(size_t)r->ecx);
|
||||
break;
|
||||
case SYSCALL_CHECK_PROC_EXISTS:
|
||||
r->ecx=tasking_check_proc_exists((pid_t)r->ebx);
|
||||
break;
|
||||
case SYSCALL_RPC_MARK_AS_INIT:
|
||||
kernel_rpc_mark_as_init();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ void unmap_pages(void* start_virt,int num_pages) {
|
||||
if (page_table_map[dir_entry].pres) {
|
||||
pg_struct_entry* entry=&page_table_map[table_entry+1024*dir_entry];
|
||||
entry->pres=0;
|
||||
invl_page(start_virt+(i*1024));
|
||||
invl_page(start_virt+(i*4096));
|
||||
table_entry++;
|
||||
if (table_entry==1024) {
|
||||
dir_entry++;
|
||||
|
@ -68,8 +68,8 @@ void setup_kstack(Thread* thread,void* param1,void* param2,char kmode,void* eip)
|
||||
RUN_IN_ADDRESS_SPACE(thread->address_space,{
|
||||
user_stack=(void**)(((char*)alloc_pages(2))+0x2000);
|
||||
user_stack-=2;
|
||||
user_stack[0]=param1;
|
||||
user_stack[1]=param2;
|
||||
user_stack[0]=param2;
|
||||
user_stack[1]=param1;
|
||||
});
|
||||
kstacks[top_idx-3]=(void*)task_init;
|
||||
kstacks[top_idx-2]=(void*)user_stack;
|
||||
|
@ -67,7 +67,7 @@ void kmain(struct multiboot_boot_header_tag* hdr) {
|
||||
asm volatile("sti");
|
||||
tasking_init();
|
||||
vga_init((char*)0xC00B8000);
|
||||
timer_init(1000);
|
||||
timer_init(100);
|
||||
read_initrd(tags);
|
||||
int pos=0;
|
||||
size_t datapos;
|
||||
|
212
kernel/rpc.c
212
kernel/rpc.c
@ -1,48 +1,168 @@
|
||||
// #include "cpu/halt.h"
|
||||
// #include "cpu/i386/address_spaces.h"
|
||||
// #include "cpu/i386/serial.h"
|
||||
// #include "cpu/tasking.h"
|
||||
// #include "rpc.h"
|
||||
// #include <string.h>
|
||||
// void rpc_init_struct(ThreadRPCStruct* info) {
|
||||
// for (size_t i = 0; i < 32; i++) {
|
||||
// info->funcs[i].code=NULL;
|
||||
// memset(info->funcs[i].name,'\0',32);
|
||||
// }
|
||||
// info->rpc_response=NULL;
|
||||
// info->num_funcs=0;
|
||||
// }
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
// void rpc_reg_func(void* (*code)(void*),char* name) {
|
||||
// if (strlen(name)>31) {
|
||||
// serial_printf("Max length for RPC function name is 31!\n");
|
||||
// halt();
|
||||
// }
|
||||
// ThreadRPCStruct* info=tasking_get_rpc_struct(0);
|
||||
// if (info->num_funcs==32) {
|
||||
// serial_printf("Maximum # of RPC functions registered\n");
|
||||
// halt();
|
||||
// }
|
||||
// info->funcs[info->num_funcs].code=code;
|
||||
// strcpy(info->funcs[info->num_funcs].name,name);
|
||||
// info->num_funcs++;
|
||||
// }
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
#include "tasking.h"
|
||||
#include "rpc.h"
|
||||
#include "pmem.h"
|
||||
#include "cpu/paging.h"
|
||||
#include "cpu/arch_consts.h"
|
||||
#include "kmalloc.h"
|
||||
#include <string.h>
|
||||
#include "cpu/serial.h"
|
||||
|
||||
/**
|
||||
* Represents a thread waiting for a process to finish RPC init
|
||||
*/
|
||||
typedef struct rpc_waiting_thread {
|
||||
pid_t waiting_pid; //!< The PID of the thread that is waiting for RPC init
|
||||
pid_t waiting_tid; //!< The TID of the thread that is waiting for RPC init
|
||||
pid_t process_waiting_on; //!< The process being waited on
|
||||
struct rpc_waiting_thread* next; //!< The next entry in the linked list
|
||||
} rpc_waiting_thread;
|
||||
|
||||
rpc_func_info* process_funcs[32768]={NULL}; //!< Pointers to a list of registered functions for each process
|
||||
size_t process_num_funcs[32768]={0}; //!< The number of functions each process has registered
|
||||
char process_ready_bmap[32768/8]={0}; //!< A bitmap of processes that have completed RPC init
|
||||
rpc_waiting_thread* waiting_thread_list=NULL; //!< A linked list of threads waiting for a process to finish RPC init
|
||||
|
||||
/**
|
||||
* Mark a process as ready to accept RPC calls
|
||||
* \param pid The pid to mark
|
||||
*/
|
||||
static void mark_init(pid_t pid) {
|
||||
size_t byte=pid/8;
|
||||
size_t bit=pid%8;
|
||||
process_ready_bmap[byte]=process_ready_bmap[byte]|(1<<bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a process as not ready to accept RPC calls
|
||||
* \param pid The pid to mark
|
||||
*/
|
||||
static void clear_init(pid_t pid) {
|
||||
size_t byte=pid/8;
|
||||
size_t bit=pid%8;
|
||||
process_ready_bmap[byte]=process_ready_bmap[byte]&(~(1<<bit));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a process is ready to accept RPC calls
|
||||
* \param pid The pid to check
|
||||
* \return whether the process is ready
|
||||
*/
|
||||
static char is_init(pid_t pid) {
|
||||
size_t byte=pid/8;
|
||||
size_t bit=pid%8;
|
||||
char entry=process_ready_bmap[byte];
|
||||
return (entry&(1<<bit))>0;
|
||||
}
|
||||
|
||||
void* kernel_rpc_call(pid_t pid,char* name,void* buf,size_t size) {
|
||||
if (is_init(pid)==0) {
|
||||
rpc_waiting_thread* waiting_thread=kmalloc(sizeof(rpc_waiting_thread));
|
||||
if (waiting_thread==NULL) {
|
||||
serial_printf("Kmalloc unable to allocate waiting_thread\n");
|
||||
halt();
|
||||
}
|
||||
waiting_thread->process_waiting_on=pid;
|
||||
waiting_thread->waiting_pid=tasking_get_PID();
|
||||
waiting_thread->waiting_tid=tasking_get_TID();
|
||||
waiting_thread->next=waiting_thread_list;
|
||||
waiting_thread_list=waiting_thread;
|
||||
tasking_block(THREAD_WAITING_FOR_RPC_INIT);
|
||||
}
|
||||
rpc_func_info* func=NULL;
|
||||
rpc_func_info* funcs=process_funcs[pid];
|
||||
for (size_t i = 0; i < process_num_funcs[pid]; i++){
|
||||
if (strcmp(funcs[i].name,name)==0) {
|
||||
func=&funcs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (func==NULL) {
|
||||
serial_printf("No function %s for PID %d\n",name,pid);
|
||||
return NULL;
|
||||
}
|
||||
void* virtaddr=NULL;
|
||||
if (buf) {
|
||||
virtaddr=alloc_pages((size/PAGE_SZ)+1);
|
||||
void* physaddr=virt_to_phys(virtaddr);
|
||||
memcpy(virtaddr,buf,size);
|
||||
unmap_pages(virtaddr,(size/PAGE_SZ)+1);
|
||||
RUN_IN_ADDRESS_SPACE(tasking_get_address_space(pid),{
|
||||
virtaddr=find_free_pages((size/PAGE_SZ)+1);
|
||||
map_pages(virtaddr,physaddr,(size/PAGE_SZ)+1,0,1);
|
||||
});
|
||||
}
|
||||
pid_t tid=tasking_new_thread(func->code,pid,virtaddr);
|
||||
tasking_set_rpc_calling_thread(pid,tid);
|
||||
// Block the thread and wait for an unblock from rpc_return
|
||||
tasking_block(THREAD_WAITING_FOR_RPC);
|
||||
// Now that RPC call has returned, pass the return buffer back to the caller
|
||||
return tasking_get_rpc_ret_buf();
|
||||
}
|
||||
|
||||
void kernel_rpc_register_func(char* name,rpc_func code) {
|
||||
pid_t pid=tasking_get_PID();
|
||||
if (process_funcs[pid]==NULL) {
|
||||
process_funcs[pid]=kmalloc(sizeof(rpc_func_info)*32);
|
||||
}
|
||||
if (process_num_funcs[pid]==32) {
|
||||
serial_printf("Already registered 32 functions!");
|
||||
return;
|
||||
}
|
||||
rpc_func_info* info=&process_funcs[pid][process_num_funcs[pid]];
|
||||
strcpy(&info->name[0],name);
|
||||
info->code=code;
|
||||
process_num_funcs[pid]++;
|
||||
}
|
||||
|
||||
void kernel_rpc_deallocate_buf(void* buf,size_t size) {
|
||||
if (buf==NULL) return;
|
||||
dealloc_pages((size/PAGE_SZ)+1,buf);
|
||||
}
|
||||
|
||||
void kernel_rpc_return(void* buf,size_t size) {
|
||||
pid_t tid;
|
||||
pid_t pid=tasking_get_rpc_calling_thread(&tid);
|
||||
void* virtaddr=NULL;
|
||||
if (buf) {
|
||||
virtaddr=alloc_pages((size/PAGE_SZ)+1);
|
||||
void* physaddr=virt_to_phys(virtaddr);
|
||||
memcpy(virtaddr,buf,size);
|
||||
unmap_pages(virtaddr,(size/PAGE_SZ)+1);
|
||||
RUN_IN_ADDRESS_SPACE(tasking_get_address_space(pid),{
|
||||
virtaddr=find_free_pages((size/PAGE_SZ)+1);
|
||||
map_pages(virtaddr,physaddr,(size/PAGE_SZ)+1,1,1);
|
||||
});
|
||||
}
|
||||
tasking_set_rpc_ret_buf(virtaddr);
|
||||
tasking_unblock(pid,tid);
|
||||
}
|
||||
|
||||
size_t kernel_get_num_rpc_funcs(pid_t pid) {
|
||||
return process_num_funcs[pid];
|
||||
}
|
||||
|
||||
void kernel_rpc_mark_as_init() {
|
||||
mark_init(tasking_get_PID());
|
||||
if (waiting_thread_list) {
|
||||
rpc_waiting_thread* prev=NULL;
|
||||
for (rpc_waiting_thread* waiting_thread=waiting_thread_list;waiting_thread!=NULL;waiting_thread=waiting_thread->next) {
|
||||
if (waiting_thread->process_waiting_on==tasking_get_PID()) {
|
||||
tasking_unblock(waiting_thread->waiting_pid,waiting_thread->waiting_tid);
|
||||
if (waiting_thread==waiting_thread_list) {
|
||||
waiting_thread_list=waiting_thread_list->next;
|
||||
} else {
|
||||
prev->next=waiting_thread->next;
|
||||
}
|
||||
prev=waiting_thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// void rpc_call(char* name,pid_t pid,void* data,size_t size) {
|
||||
// if (strlen(name)>31) {
|
||||
// serial_printf("Max length for RPC function name is 31!\n");
|
||||
// halt();
|
||||
// }
|
||||
// ThreadRPCStruct* info=tasking_get_rpc_struct(pid);
|
||||
// int func_idx=-1;
|
||||
// for (size_t i=0;i<info->num_funcs;i++) {
|
||||
// if (strcmp(info->funcs[i].name,name)==0) {
|
||||
// func_idx=i;
|
||||
// }
|
||||
// }
|
||||
// if (func_idx==-1) {
|
||||
// serial_printf("No such rpc function %s for PID %d",name,pid);
|
||||
// }
|
||||
// void* copieddata=address_spaces_put_data(current_thread->address_space,data,size);
|
||||
// tasking_new_thread(info->funcs[func_idx].code,pid,1,copieddata);
|
||||
// }
|
||||
|
58
kernel/rpc.h
58
kernel/rpc.h
@ -2,15 +2,61 @@
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef RPC_H
|
||||
#define RPC_H
|
||||
#ifndef KERN_RPC_H
|
||||
#define KERN_RPC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void* (*rpc_func)(void*); //!< Type of an RPC function
|
||||
|
||||
/**
|
||||
* Represents an RPC fumctiom
|
||||
* Represents an RPC fumctiom with name
|
||||
*/
|
||||
typedef struct RPCFuncInfo {
|
||||
typedef struct rpc_func_info {
|
||||
char name[32]; //!< THe name of the function
|
||||
void* (*code)(void*); //!< A pointer to the code that implements the funtcion
|
||||
} RPCFuncInfo;
|
||||
rpc_func code; //!< A pointer to the code that implements the funtcion
|
||||
} rpc_func_info;
|
||||
|
||||
|
||||
/**
|
||||
* Call an RPC function
|
||||
* \param pid The PID of the process with the RPC function
|
||||
* \param name The name of the function to call
|
||||
* \param buf The argument buffer to provide
|
||||
* \param size The size of the argument buffer
|
||||
* \return the return buffer of the RPC functiom
|
||||
*/
|
||||
void* kernel_rpc_call(pid_t pid,char* name,void* buf,size_t size);
|
||||
/**
|
||||
* Register an RPC function
|
||||
* \param name The name of the function
|
||||
* \param code The code of the function
|
||||
*/
|
||||
void kernel_rpc_register_func(char* name,rpc_func code);
|
||||
/**
|
||||
* Deallocate an RPC return buffer
|
||||
* \param buf The buffer to deallocate
|
||||
* \param size The size of the buffer to deallocate
|
||||
*/
|
||||
void kernel_rpc_deallocate_buf(void* buf,size_t size);
|
||||
|
||||
/**
|
||||
* Set the RPC return buffer for the calling thread & unblock the calling thread
|
||||
* \param buf The return buffer
|
||||
* \param size The size of the return buffer
|
||||
* \note This function must only be called from an RPC thread
|
||||
*/
|
||||
void kernel_rpc_return(void* buf,size_t size);
|
||||
|
||||
/**
|
||||
* Get the number of RPC functions a process has registers
|
||||
* \param pid The PID of the process
|
||||
* \return the number of RPC functions the process has registered
|
||||
*/
|
||||
size_t kernel_get_num_rpc_funcs(pid_t pid);
|
||||
|
||||
/**
|
||||
* Mark the current process as ready to accept RPC calls
|
||||
*/
|
||||
void kernel_rpc_mark_as_init();
|
||||
#endif
|
||||
|
@ -99,7 +99,7 @@ void tasking_create_task(void* eip,void* address_space,char kmode,void* param1,v
|
||||
thread->prev_ready_to_run=NULL;
|
||||
thread->next_ready_to_run=NULL;
|
||||
thread->prev_thread_in_process=NULL;
|
||||
|
||||
thread->state=THREAD_READY;
|
||||
if (isThread) {
|
||||
thread->address_space=proc->first_thread->address_space;
|
||||
thread->next_thread_in_process=proc->first_thread;
|
||||
@ -133,6 +133,10 @@ pid_t tasking_get_PID() {
|
||||
return current_thread->process->pid;
|
||||
}
|
||||
|
||||
pid_t tasking_get_TID() {
|
||||
return current_thread->tid;
|
||||
}
|
||||
|
||||
int* tasking_get_errno_address() {
|
||||
return ¤t_thread->errno;
|
||||
}
|
||||
@ -194,26 +198,28 @@ void switch_to_thread(Thread* thread) {
|
||||
Thread* current_thread_next_ready=get_next_ready_thread(current_thread,thread);
|
||||
if (!current_thread_next_ready) {
|
||||
//This process is fully blocked, try the process of the thread we're yielding to
|
||||
Thread* current_thread_next_ready=get_next_ready_thread(thread,thread);
|
||||
current_thread_next_ready=get_next_ready_thread(thread,thread);
|
||||
}
|
||||
if (current_thread_next_ready) {
|
||||
if (current_thread_next_ready) {
|
||||
schedule_thread(current_thread_next_ready);
|
||||
}
|
||||
thread->state=THREAD_RUNNING;
|
||||
serial_printf("Switching to PID %d TID %d.\n",thread->process->pid,thread->tid);
|
||||
switch_to_thread_asm(thread);
|
||||
}
|
||||
|
||||
void tasking_yield() {
|
||||
serial_printf("Attempting to yield\n");
|
||||
if (ready_to_run_head) {
|
||||
serial_printf("Attempting to switch to PID %d TID %d\n",ready_to_run_head->process->pid,ready_to_run_head->tid);
|
||||
switch_to_thread(ready_to_run_head);
|
||||
} else {
|
||||
if (NUM_UNBLOCKED_THREADS(current_thread->process)>1) {
|
||||
// Thread* thread=get_next_ready_thread(current_thread,current_thread);
|
||||
// schedule_thread(thread);
|
||||
// yield();
|
||||
serial_printf("The ready to run list is empty, and the current process has other unblocked threads? This is an invalid state! Halting!\n");
|
||||
halt();
|
||||
} else if (NUM_UNBLOCKED_THREADS(current_thread->process)==1) {
|
||||
serial_printf("Yield failed, no other ready processes\n");
|
||||
return;
|
||||
} else {
|
||||
if (num_procs==0) {
|
||||
@ -259,6 +265,9 @@ void tasking_block(thread_state newstate) {
|
||||
thread->state=newstate;
|
||||
}
|
||||
}
|
||||
current_thread->process->num_threads_blocked++;
|
||||
unmark_proc_scheduled(current_thread->process->pid);
|
||||
tasking_yield();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -300,6 +309,7 @@ void tasking_unblock(pid_t pid,pid_t tid) {
|
||||
return;
|
||||
}
|
||||
thread->state=THREAD_READY;
|
||||
thread->process->num_threads_blocked--;
|
||||
schedule_thread(thread);
|
||||
}
|
||||
|
||||
@ -342,3 +352,45 @@ void* tasking_get_address_space(pid_t pid) {
|
||||
return processes[pid].first_thread->address_space;
|
||||
}
|
||||
|
||||
void tasking_set_rpc_calling_thread(pid_t pid,pid_t tid) {
|
||||
Thread* thread=get_thread(pid,tid);
|
||||
thread->rpc_calling_pid=current_thread->process->pid;
|
||||
thread->rpc_calling_tid=current_thread->tid;
|
||||
}
|
||||
|
||||
pid_t tasking_get_rpc_calling_thread(pid_t* tid) {
|
||||
*tid=current_thread->rpc_calling_tid;
|
||||
return current_thread->rpc_calling_pid;
|
||||
}
|
||||
|
||||
void tasking_set_rpc_ret_buf(void* buf) {
|
||||
pid_t tid;
|
||||
pid_t pid=tasking_get_rpc_calling_thread(&tid);
|
||||
Thread* thread=get_thread(pid,tid);
|
||||
thread->rpc_ret_buf=buf;
|
||||
}
|
||||
|
||||
void* tasking_get_rpc_ret_buf() {
|
||||
return current_thread->rpc_ret_buf;
|
||||
}
|
||||
|
||||
void tasking_thread_exit() {
|
||||
tasking_block(THREAD_EXITED);
|
||||
}
|
||||
|
||||
char tasking_check_proc_exists(pid_t pid) {
|
||||
if (processes[pid].num_threads==0) {
|
||||
return 0;
|
||||
}
|
||||
char num_exited_threads=0;
|
||||
for (Thread* thread=processes[pid].first_thread;thread!=NULL;thread=thread->next_thread_in_process) {
|
||||
if (thread->state==THREAD_EXITED) {
|
||||
num_exited_threads++;
|
||||
}
|
||||
}
|
||||
if ((num_exited_threads=processes[pid].num_threads)&&kernel_get_num_rpc_funcs(pid)==0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include "rpc.h"
|
||||
|
||||
#ifndef TASKING_H
|
||||
|
||||
@ -17,7 +18,9 @@ typedef enum thread_state {
|
||||
THREAD_RUNNING, //!< The state of a running thread
|
||||
THREAD_READY, //!< The state of a ready to run thread
|
||||
THREAD_EXITED, //!< The state of an exited thread
|
||||
THREAD_BLOCKED //!< The state of a generically blocked thread
|
||||
THREAD_BLOCKED, //!< The state of a generically blocked thread
|
||||
THREAD_WAITING_FOR_RPC, //!< The state of a thread waiting for an RPC call to return
|
||||
THREAD_WAITING_FOR_RPC_INIT //!< The state of a thread waiting for a process to fully initilaize it's RPC functions
|
||||
} thread_state;
|
||||
|
||||
#endif
|
||||
@ -51,6 +54,9 @@ typedef struct Thread {
|
||||
struct Thread* next_ready_to_run; //!< If the thread is in the ready to run list, this is the next ready to run thread. (potentially in a different process)
|
||||
struct Thread* prev_ready_to_run; //!< If the thread is in the ready to run list, this is the previous ready to run thread. (potentially in a different process)
|
||||
Process* process; //!< The thread's process.
|
||||
pid_t rpc_calling_pid; //!< The PID of the thread that called this RPC (only used for RPC handler threads)
|
||||
pid_t rpc_calling_tid; //!< The TID of the thread that called this RPC (only used for RPC handler threads)
|
||||
void* rpc_ret_buf; //!< The return buffer of the RPC call that the thread made
|
||||
} Thread;
|
||||
|
||||
extern Thread* current_thread;
|
||||
@ -79,6 +85,11 @@ char tasking_is_privleged();
|
||||
* \return The current thread's PID
|
||||
*/
|
||||
pid_t tasking_get_PID();
|
||||
/**
|
||||
* Get the TID of the current thread.
|
||||
* \return The current thread's TID
|
||||
*/
|
||||
pid_t tasking_get_TID();
|
||||
/**
|
||||
* Get the adddress of errno for the current thread
|
||||
* \return The address of errno
|
||||
@ -122,4 +133,42 @@ void tasking_yield();
|
||||
*/
|
||||
void* tasking_get_address_space(pid_t pid);
|
||||
|
||||
/**
|
||||
* Set the RPC calling thread for an RPC handler thread to the current threasd
|
||||
* \param pid The PID of the handler thread
|
||||
* \param tid The TID of the handler thread
|
||||
*/
|
||||
void tasking_set_rpc_calling_thread(pid_t pid,pid_t tid);
|
||||
|
||||
/**
|
||||
* Get the RPC calling thread for the current thread
|
||||
* \param tid A pointer to a pid_t to store the return TID
|
||||
* \return the return PID
|
||||
* \note This is only applicable for an RPC handler thread
|
||||
*/
|
||||
pid_t tasking_get_rpc_calling_thread(pid_t* tid);
|
||||
/**
|
||||
* Set the RPC return buffer for the calling thread
|
||||
* \param buf The return buffer
|
||||
*/
|
||||
void tasking_set_rpc_ret_buf(void* buf);
|
||||
|
||||
/**
|
||||
* Get the RPC return buffer for the current thread
|
||||
* \return the return buffer
|
||||
*/
|
||||
void* tasking_get_rpc_ret_buf();
|
||||
|
||||
/**
|
||||
* Terminate the current thread
|
||||
*/
|
||||
void tasking_thread_exit();
|
||||
|
||||
/**
|
||||
* Check if a process exists
|
||||
* \param pid The param of the process to check
|
||||
* \return Whether the process exists
|
||||
*/
|
||||
char tasking_check_proc_exists(pid_t pid);
|
||||
|
||||
#endif
|
||||
|
@ -15,3 +15,9 @@ int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict at
|
||||
"::"b"(start_routine),"c"(thread),"d"(arg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pthread_exit(void *value_ptr) {
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_THREAD_EXIT) ", %eax; \
|
||||
int $80;");
|
||||
}
|
||||
|
@ -21,4 +21,11 @@ typedef int pthread_attr_t; //!< Created as dummy
|
||||
int pthread_create(pthread_t *restrict thread,
|
||||
const pthread_attr_t *restrict attr,
|
||||
void *(*start_routine)(void*), void *restrict arg);
|
||||
|
||||
/**
|
||||
* Terminate the current thread
|
||||
* \param value_ptr A pointer that when other threads in the process join on the current thread, they will recieve. (not implemented)
|
||||
*/
|
||||
void pthread_exit(void *value_ptr);
|
||||
|
||||
#endif
|
||||
|
43
libc/rpc.c
Normal file
43
libc/rpc.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include <rpc.h>
|
||||
#include <sys/syscalls.h>
|
||||
|
||||
#define QUAUX(X) #X
|
||||
#define QU(X) QUAUX(X)
|
||||
|
||||
|
||||
void* rpc_call(pid_t pid,char* name,void* buf,size_t size) {
|
||||
void* retbuf;
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_CALL_RPC) ", %%eax; \
|
||||
int $80; \
|
||||
":"=D"(retbuf):"b"(pid),"c"(name),"d"(buf),"S"(size));
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
void rpc_register_func(char* name,rpc_func code) {
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_REGISTER_RPC) ", %%eax; \
|
||||
int $80; \
|
||||
"::"b"(name),"c"(code));
|
||||
}
|
||||
|
||||
void rpc_deallocate_buf(void* buf,size_t size) {
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_DEALLOCTATE_RPC_RET) ", %%eax; \
|
||||
int $80; \
|
||||
"::"b"(buf),"c"(size));
|
||||
}
|
||||
|
||||
void rpc_return(void* buf,size_t size) {
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_RPC_RET) ", %%eax; \
|
||||
int $80; \
|
||||
"::"b"(buf),"c"(size));
|
||||
}
|
||||
|
||||
void rpc_mark_as_init() {
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_RPC_MARK_AS_INIT) ", %%eax; \
|
||||
int $80; \
|
||||
"::);
|
||||
}
|
46
libc/rpc.h
Normal file
46
libc/rpc.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef RPC_H
|
||||
#define RPC_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void* (*rpc_func)(void*); //!< Type of an RPC function
|
||||
|
||||
/**
|
||||
* Call an RPC function
|
||||
* \param pid The PID of the process with the RPC function
|
||||
* \param name The name of the function to call
|
||||
* \param buf The argument buffer to provide
|
||||
* \param size The size of the argument buffer
|
||||
* \return the return buffer of the RPC functiom
|
||||
*/
|
||||
void* rpc_call(pid_t pid,char* name,void* buf,size_t size);
|
||||
|
||||
/**
|
||||
* Register an RPC function
|
||||
* \param name The name of the function
|
||||
* \param code The code of the function
|
||||
*/
|
||||
void rpc_register_func(char* name,rpc_func code);
|
||||
/**
|
||||
* Deallocate an RPC return buffer
|
||||
* \param buf The buffer to deallocate
|
||||
* \param size The size of the buffer to deallocate
|
||||
*/
|
||||
void rpc_deallocate_buf(void* buf,size_t size);
|
||||
|
||||
/**
|
||||
* Set the RPC return buffer for the calling thread & unblock the calling thread
|
||||
* \param buf The return buffer
|
||||
* \param size The size of the return buffer
|
||||
* \note This function must only be called from an RPC thread
|
||||
*/
|
||||
void rpc_return(void* buf,size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Mark the current process as ready to accept RPC calls
|
||||
*/
|
||||
void rpc_mark_as_init();
|
||||
|
||||
#endif
|
@ -10,6 +10,8 @@
|
||||
#define SYSCALL_GET_ERRNO_ADDR 5
|
||||
#define SYSCALL_GET_PID 6
|
||||
#define SYSCALL_NEW_THREAD 14
|
||||
#define SYSCALL_THREAD_EXIT 19
|
||||
#define SYSCALL_CHECK_PROC_EXISTS 20
|
||||
|
||||
#define SYSCALL_ALLOC_MEM 7
|
||||
#define SYSCALL_PRIV_MAP_PAGES 8
|
||||
@ -20,4 +22,11 @@
|
||||
#define SYSCALL_GET_INITRD_SZ 12
|
||||
#define SYSCALL_COPY_INITRD 13
|
||||
|
||||
#define SYSCALL_CALL_RPC 15
|
||||
#define SYSCALL_REGISTER_RPC 16
|
||||
#define SYSCALL_DEALLOCTATE_RPC_RET 17
|
||||
#define SYSCALL_RPC_RET 18
|
||||
#define SYSCALL_RPC_MARK_AS_INIT 21
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -42,3 +42,12 @@ void unblock_thread(pid_t pid,pid_t tid) {
|
||||
int $80; \
|
||||
"::"b"(pid),"c"(tid));
|
||||
}
|
||||
|
||||
char check_proc_exists(pid_t pid) {
|
||||
char exists;
|
||||
asm volatile(" \
|
||||
mov $" QU(SYSCALL_CHECK_PROC_EXISTS) ", %%eax; \
|
||||
int $80; \
|
||||
":"=c"(exists):"b"(pid));
|
||||
return exists;
|
||||
}
|
||||
|
@ -46,5 +46,11 @@ void block_thread(thread_state state);
|
||||
*/
|
||||
void unblock_thread(pid_t pid,pid_t tid);
|
||||
|
||||
/**
|
||||
* Check if a process exists
|
||||
* \param pid The param of the process to check
|
||||
* \return Whether the process exists
|
||||
*/
|
||||
char check_proc_exists(pid_t pid);
|
||||
|
||||
#endif
|
||||
|
13
rpctest/Makefile
Normal file
13
rpctest/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
C_SOURCES = $(wildcard *.c)
|
||||
OBJ = $(C_SOURCES:.c=.o )
|
||||
CFLAGS = -Wall -g
|
||||
CC = i386-myos-gcc
|
||||
|
||||
rpctest: $(OBJ) ../libc/*
|
||||
@$(CC) -o $@ $(CFLAGS) $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
@rm -rf *.o init
|
20
rpctest/main.c
Normal file
20
rpctest/main.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <dbg.h>
|
||||
#include <rpc.h>
|
||||
#include <tasking.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
void rpcfunc(void* buf) {
|
||||
if(buf) {
|
||||
serial_print(buf);
|
||||
} else {
|
||||
serial_print("RPC test func\n");
|
||||
}
|
||||
rpc_return("return value\n",strlen("return value\n")+1);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
rpc_register_func("rpctestfunc",&rpcfunc);
|
||||
rpc_mark_as_init();
|
||||
}
|
BIN
rpctest/rpctest
Executable file
BIN
rpctest/rpctest
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user