diff --git a/headers/os/kernel/arch/x86/commpage.h b/headers/os/kernel/arch/x86/commpage.h new file mode 100644 index 0000000000..a68ef23def --- /dev/null +++ b/headers/os/kernel/arch/x86/commpage.h @@ -0,0 +1,23 @@ +/* + * Copyright 2007, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef __OS_KERNEL_ARCH_x86_COMMPAGE_H +#define __OS_KERNEL_ARCH_x86_COMMPAGE_H + +/* some systemwide commpage constants, used in the kernel and libroot */ + +/* be careful what you put here, this file is included from assembly */ +#define COMMPAGE_ENTRY_MAGIC 0 +#define COMMPAGE_ENTRY_VERSION 1 +#define COMMPAGE_ENTRY_SYSCALL 2 + +#define USER_COMMPAGE_ADDR (0xffff0000) +#define COMMPAGE_SIZE (0x8000) +#define TABLE_ENTRIES 64 + +#define COMMPAGE_SIGNATURE 'COMM' +#define COMMPAGE_VERSION 1 + +#endif + diff --git a/headers/private/kernel/arch/x86/commpage.h b/headers/private/kernel/arch/x86/commpage.h new file mode 100644 index 0000000000..8a13d74354 --- /dev/null +++ b/headers/private/kernel/arch/x86/commpage.h @@ -0,0 +1,12 @@ +/* + * Copyright 2007, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_x86_COMMPAGE_H +#define _KERNEL_ARCH_x86_COMMPAGE_H + + +status_t commpage_init(void); + +#endif + diff --git a/src/system/kernel/arch/x86/Jamfile b/src/system/kernel/arch/x86/Jamfile index d8c9f3135a..d09d1409fb 100644 --- a/src/system/kernel/arch/x86/Jamfile +++ b/src/system/kernel/arch/x86/Jamfile @@ -31,6 +31,8 @@ KernelStaticLibrary libx86 : apm.cpp bios.cpp cpuid.S + commpage.c + syscall.S generic_vm_physical_page_mapper.cpp : diff --git a/src/system/kernel/arch/x86/arch_cpu.c b/src/system/kernel/arch/x86/arch_cpu.c index 8684db96b5..ff12cda9c4 100644 --- a/src/system/kernel/arch/x86/arch_cpu.c +++ b/src/system/kernel/arch/x86/arch_cpu.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "interrupts.h" @@ -505,6 +506,9 @@ arch_cpu_init_post_vm(kernel_args *args) // setup SSE2/3 support init_sse(); + // initialize the commpage support + commpage_init(); + return B_OK; } diff --git a/src/system/kernel/arch/x86/commpage.c b/src/system/kernel/arch/x86/commpage.c new file mode 100644 index 0000000000..42cfb167d7 --- /dev/null +++ b/src/system/kernel/arch/x86/commpage.c @@ -0,0 +1,74 @@ +/* + * Copyright 2007, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#include +#include + +#include +#include + +#include + +static area_id comm_area; +static area_id user_comm_area; +static unsigned long *comm_ptr; +static unsigned long *user_comm_ptr; +static void *next_comm_addr; + +// user syscall assembly stub +extern void _user_syscall_int(void); +extern unsigned int _user_syscall_int_end; + +static inline +addr_t commpage_ptr_to_user_ptr(const void *ptr) +{ + return ((addr_t)ptr) + ((addr_t)user_comm_ptr - (addr_t)comm_ptr); +} + +static +status_t initialize_commpage_syscall(void) +{ + size_t len; + + // for now, we're hard coded to use the legacy method (int 99) + len = (size_t)((void *)&_user_syscall_int_end - (void *)&_user_syscall_int); + memcpy(next_comm_addr, &_user_syscall_int, len); + + // fill in the table entry + comm_ptr[COMMPAGE_ENTRY_SYSCALL] = commpage_ptr_to_user_ptr(next_comm_addr); + next_comm_addr = (void *)((addr_t)next_comm_addr + ROUNDUP(len, 4)); + + return B_OK; +} + +status_t +commpage_init(void) +{ + int i; + + // create a read/write kernel area + comm_area = create_area("commpage", (void **)&comm_ptr, B_ANY_ADDRESS, COMMPAGE_SIZE, B_FULL_LOCK, + B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA); + + // clone it at a fixed address with user read/only permissions + user_comm_ptr = (void *)USER_COMMPAGE_ADDR; + user_comm_area = clone_area("user_commpage", (void **)&user_comm_ptr, B_EXACT_ADDRESS, + B_READ_AREA | B_EXECUTE_AREA, comm_area); + + // zero it out + memset(comm_ptr, 0, COMMPAGE_SIZE); + + // fill in some of the table + comm_ptr[0] = COMMPAGE_SIGNATURE; + comm_ptr[1] = COMMPAGE_VERSION; + + // the next slot to allocate space is after the table + next_comm_addr = (void *)&comm_ptr[TABLE_ENTRIES]; + + // select the optimum syscall mechanism and patch the commpage + initialize_commpage_syscall(); + + return B_OK; +} + diff --git a/src/system/kernel/arch/x86/syscall.S b/src/system/kernel/arch/x86/syscall.S new file mode 100644 index 0000000000..2b359dfb7c --- /dev/null +++ b/src/system/kernel/arch/x86/syscall.S @@ -0,0 +1,19 @@ +/* + * Copyright 2007, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#define FUNCTION(x) .global x; .type x,@function; x +#define SYM(x) .global x; x + +.text + +/* user space half of the syscall mechanism, to be copied into the commpage */ +FUNCTION(_user_syscall_int): + int $99 + ret +SYM(_user_syscall_int_end): + + + + diff --git a/src/system/libroot/os/arch/x86/syscalls.inc b/src/system/libroot/os/arch/x86/syscalls.inc index 87154ec695..4f8748cae6 100644 --- a/src/system/libroot/os/arch/x86/syscalls.inc +++ b/src/system/libroot/os/arch/x86/syscalls.inc @@ -1,3 +1,7 @@ +/* + * Copyright 2007, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ /* ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. @@ -7,16 +11,18 @@ * syscall interface works as such: * eax has syscall # * esp + 4 points to the syscall parameters + * branch to the syscall vector in the commpage */ +#include + #define _SYSCALL(name, n) \ .globl name; \ .type name,@function; \ .align 8; \ name: \ movl $n,%eax; \ - int $99; \ - ret + jmp *(USER_COMMPAGE_ADDR + COMMPAGE_ENTRY_SYSCALL * 4) #define SYSCALL0(name, n) _SYSCALL(name, n) #define SYSCALL1(name, n) _SYSCALL(name, n) @@ -35,3 +41,4 @@ name: \ #define SYSCALL14(name, n) _SYSCALL(name, n) #define SYSCALL15(name, n) _SYSCALL(name, n) #define SYSCALL16(name, n) _SYSCALL(name, n) +