Add RPC support

This commit is contained in:
pjht 2020-08-02 14:37:23 -05:00
parent 18ca6e49e6
commit d9a01fdbda
20 changed files with 544 additions and 75 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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++;

View File

@ -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;

View File

@ -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;

View File

@ -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);
// }

View File

@ -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

View File

@ -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 &current_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;
}
}

View File

@ -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

View File

@ -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;");
}

View File

@ -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
View 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
View 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

View File

@ -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

View File

@ -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;
}

View File

@ -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
View 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
View 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

Binary file not shown.