/tmp/sos-code-article9.5/hwcore/bitmap.c (1970-01-01 01:00:00.000000000 +0100
) |
|
sos-code-article9.5/hwcore/bitmap.c (2006-03-19 12:21:02.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2006 David Decotigny |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| |
| #include <sos/macros.h> |
| |
| #include "bitmap.h" |
| |
| |
| /** |
| * ffs: find first bit set (1 = LSb, 32 = MSb). |
| * |
| * @return 0 when none found |
| * |
| * @note: License is GPLv2, origin is Linux Kernel 2.6.14.3 |
| * (@see include/asm-i386/bitops.h) |
| */ |
| static inline int word_ffs(sos_ui32_t x) |
| { |
| if (!x) |
| return 0; |
| |
| __asm__("bsfl %1,%0" |
| :"=r" (x) |
| :"rm" (x)); |
| return x+1; |
| } |
| |
| |
| /** Set a 32bits mask of nbits '1' starting at LSb */ |
| static inline sos_ui32_t generate_lsb_mask(int nbits) |
| { |
| return (1 << nbits) - 1; |
| } |
| |
| |
| sos_size_t sos_bitmap_ffs(const void * area, |
| sos_size_t bit_length, |
| sos_size_t _start_bit_index) |
| { |
| sos_size_t start_bit_index = _start_bit_index - 1; |
| sos_size_t word_index = start_bit_index >> 5; |
| const sos_ui32_t * word = (const sos_ui32_t*)area; |
| sos_ui32_t mask = ~ generate_lsb_mask(start_bit_index & 31); |
| |
| while (start_bit_index < bit_length) |
| { |
| sos_size_t fsb = word_ffs(word[word_index] & mask); |
| |
| if (fsb > 0) |
| { |
| sos_size_t bit_index = SOS_ALIGN_INF(start_bit_index, 32) + fsb; |
| if (bit_index > bit_length) |
| return 0; |
| |
| return bit_index; |
| } |
| |
| start_bit_index = SOS_ALIGN_INF(start_bit_index, 32) + 32; |
| word_index ++; |
| mask = ~0; |
| } |
| |
| return 0; |
| } |
| |
| |
| sos_size_t sos_bitmap_ffc(const void * area, |
| sos_size_t bit_length, |
| sos_size_t _start_bit_index) |
| { |
| sos_size_t start_bit_index = _start_bit_index - 1; |
| sos_size_t word_index = start_bit_index >> 5; |
| const sos_ui32_t * word = (const sos_ui32_t*)area; |
| sos_ui32_t mask = ~ generate_lsb_mask(start_bit_index & 31); |
| |
| while (start_bit_index < bit_length) |
| { |
| sos_size_t fcb = word_ffs((~ word[word_index]) & mask); |
| |
| if (fcb > 0) |
| { |
| sos_size_t bit_index = SOS_ALIGN_INF(start_bit_index, 32) + fcb; |
| if (bit_index > bit_length) |
| return 0; |
| |
| return bit_index; |
| } |
| |
| start_bit_index = SOS_ALIGN_INF(start_bit_index, 32) + 32; |
| word_index ++; |
| mask = ~0; |
| } |
| |
| return 0; |
| } |
| |
| |
| #undef ADDR |
| #define ADDR (*(volatile long *) addr) |
| |
| /** |
| * test_and_set_bit - Set a bit and return its old value |
| * @param nr Bit to set (starting at 0 !) |
| * @param addr Address to count from |
| * |
| * @note: License is GPLv2, origin is Linux Kernel 2.6.14.3 |
| * (@see include/asm-i386/bitops.h) |
| */ |
| static inline int test_and_set_bit(int nr, volatile unsigned long * addr) |
| { |
| int oldbit; |
| |
| __asm__ __volatile__( |
| "btsl %2,%1\n\tsbbl %0,%0" |
| :"=r" (oldbit),"=m" (ADDR) |
| :"Ir" (nr) : "memory"); |
| return oldbit; |
| } |
| |
| |
| /** |
| * test_and_clear_bit - Clear a bit and return its old value |
| * @param nr Bit to clear (starting at 0 !) |
| * @param addr Address to count from |
| * |
| * @note: License is GPLv2, origin is Linux Kernel 2.6.14.3 |
| * (@see include/asm-i386/bitops.h) |
| */ |
| static inline int test_and_clear_bit(int nr, volatile unsigned long * addr) |
| { |
| int oldbit; |
| |
| __asm__ __volatile__( |
| "btrl %2,%1\n\tsbbl %0,%0" |
| :"=r" (oldbit),"=m" (ADDR) |
| :"Ir" (nr) : "memory"); |
| return oldbit; |
| } |
| |
| |
| sos_bool_t sos_bitmap_test_and_set(void * area, |
| sos_size_t _bit_index) |
| { |
| sos_ui32_t * word = (sos_ui32_t*)area; |
| sos_size_t bit_index = _bit_index - 1; |
| sos_size_t word_index = bit_index >> 5; |
| |
| bit_index &= 31; |
| return test_and_set_bit(bit_index, word + word_index); |
| } |
| |
| |
| sos_bool_t sos_bitmap_test_and_clear(void * area, |
| sos_size_t _bit_index) |
| { |
| sos_ui32_t * word = (sos_ui32_t*)area; |
| sos_size_t bit_index = _bit_index - 1; |
| sos_size_t word_index = bit_index >> 5; |
| |
| bit_index &= 31; |
| return test_and_clear_bit(bit_index, word + word_index); |
| } |
| |
/tmp/sos-code-article9.5/hwcore/bitmap.h (1970-01-01 01:00:00.000000000 +0100
) |
|
sos-code-article9.5/hwcore/bitmap.h (2006-03-19 12:21:02.000000000 +0100
) |
|
|
|
| /* Copyright (C) 2006 David Decotigny |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. |
| */ |
| #ifndef _SOS_BITMAP_H_ |
| #define _SOS_BITMAP_H_ |
| |
| |
| /** |
| * @file bitmap.h |
| * |
| * Bitmap manipulation. The implementation of this API is |
| * architecture-dependent, hence its location in hwcore/ |
| */ |
| |
| #include <sos/types.h> |
| #include <sos/errno.h> |
| |
| |
| /** |
| * Return index (start at start_bit_index) of first bit set |
| * @return 0 < x <= bit_length when found, 0 when none found |
| * @note in-memory size of area MUST be a multiple of 4B (32bits) ! |
| * |
| * @note not atomic |
| */ |
| sos_size_t sos_bitmap_ffs(const void * area, |
| sos_size_t bit_length, |
| sos_size_t start_bit_index /* start at 1 */); |
| |
| |
| /** |
| * Return index (start at start_bit_index) of first bit clear |
| * @return 0 < x <= bit_length when found, 0 when none found |
| * @note in-memory size of area MUST be a multiple of 4B (32bits) ! |
| * |
| * @note not atomic |
| */ |
| sos_size_t sos_bitmap_ffc(const void * area, |
| sos_size_t bit_length, |
| sos_size_t start_bit_index /* start at 1 */); |
| |
| |
| /** |
| * Set bit at index (start at 1) |
| * @return old value of the bit |
| * |
| * @note atomic |
| */ |
| sos_bool_t |
| sos_bitmap_test_and_set(void * area, |
| sos_size_t bit_index /* start at 1 */); |
| |
| |
| /** |
| * Clear bit at index (start at 1) |
| * @return old value of the bit |
| * |
| * @note atomic |
| */ |
| sos_bool_t |
| sos_bitmap_test_and_clear(void * area, |
| sos_size_t bit_index /* start at 1 */); |
| |
| |
| #endif /* _SOS_BITMAP_H_ */ |
| |
/tmp/sos-code-article9.5/Makefile (2006-01-22 12:48:32.000000000 +0100
) |
|
sos-code-article9.5/Makefile (2006-03-19 12:21:04.000000000 +0100
) |
|
|
|
CFLAGS = -Wall -nostdinc -ffreestanding -DKERNEL_SOS -O -g | CFLAGS = -Wall -nostdinc -ffreestanding -DKERNEL_SOS -O -g |
LIBGCC = $(shell $(CC) -print-libgcc-file-name) # To benefit from FP/64bits artihm. | LIBGCC = $(shell $(CC) -print-libgcc-file-name) # To benefit from FP/64bits artihm. |
LDFLAGS = --warn-common -nostdlib | LDFLAGS = --warn-common -nostdlib |
OBJECTS = bootstrap/multiboot.o \ | OBJECTS = bootstrap/multiboot.o \ |
hwcore/idt.o hwcore/gdt.o \ | hwcore/idt.o hwcore/gdt.o \ |
hwcore/swintr.o hwcore/swintr_wrappers.o \ | hwcore/swintr.o hwcore/swintr_wrappers.o \ |
hwcore/exception.o hwcore/exception_wrappers.o \ | hwcore/exception.o hwcore/exception_wrappers.o \ |
hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o \ | hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o \ |
hwcore/paging.o hwcore/i8254.o \ | hwcore/paging.o hwcore/i8254.o \ |
hwcore/cpu_context.o hwcore/cpu_context_switch.o \ | hwcore/cpu_context.o hwcore/cpu_context_switch.o \ |
hwcore/mm_context.o \ | hwcore/mm_context.o hwcore/bitmap.o \ |
sos/kmem_vmm.o sos/kmem_slab.o sos/kmalloc.o \ | sos/kmem_vmm.o sos/kmem_slab.o sos/kmalloc.o \ |
sos/physmem.o sos/klibc.o \ | sos/physmem.o sos/klibc.o \ |
sos/thread.o sos/kwaitq.o \ | sos/thread.o sos/kwaitq.o \ |
sos/time.o sos/sched.o sos/ksynch.o \ | sos/time.o sos/sched.o sos/ksynch.o \ |
sos/process.o sos/syscall.o \ | sos/process.o sos/syscall.o \ |
sos/assert.o sos/main.o sos/mouse_sim.o \ | sos/assert.o sos/main.o sos/mouse_sim.o \ |
sos/uaccess.o sos/calcload.o \ | sos/uaccess.o sos/calcload.o \ |
sos/umem_vmm.o sos/binfmt_elf32.o \ | sos/umem_vmm.o sos/binfmt_elf32.o \ |
drivers/x86_videomem.o drivers/bochs.o \ | drivers/x86_videomem.o drivers/bochs.o \ |
drivers/zero.o drivers/mem.o \ | drivers/zero.o drivers/mem.o \ |
drivers/ide.o drivers/kbd.o drivers/kbdmapfr.o \ | drivers/ide.o drivers/kbd.o drivers/kbdmapfr.o \ |
drivers/serial.o drivers/tty.o drivers/part.o \ | drivers/serial.o drivers/tty.o drivers/part.o \ |
drivers/console.o \ | drivers/console.o \ |
sos/hash.o sos/fs.o sos/fs_nscache.o \ | sos/hash.o sos/fs.o sos/fs_nscache.o \ |
drivers/fs_virtfs.o sos/chardev.o sos/blkdev.o \ | drivers/fs_virtfs.o sos/chardev.o sos/blkdev.o \ |
sos/blkcache.o sos/fs_pagecache.o \ | sos/blkcache.o sos/fs_pagecache.o \ |
| |
KERNEL_OBJ = sos.elf | KERNEL_OBJ = sos.elf |
| |
/tmp/sos-code-article9.5/sos/errno.h (2006-01-22 12:48:30.000000000 +0100
) |
|
sos-code-article9.5/sos/errno.h (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
#define SOS_ENOMEM 3 /* No available memory */ | #define SOS_ENOMEM 3 /* No available memory */ |
#define SOS_EBUSY 4 /* Object or device still in use */ | #define SOS_EBUSY 4 /* Object or device still in use */ |
#define SOS_EINTR 5 /* Wait/Sleep has been interrupted */ | #define SOS_EINTR 5 /* Wait/Sleep has been interrupted */ |
#define SOS_EPERM 6 /* Mutex/files ownership error */ | #define SOS_EAGAIN 6 /* Temporary resource exhaustion */ |
#define SOS_EFAULT 7 /* Unresolved virtual memory fault */ | #define SOS_EPERM 7 /* Mutex/files ownership error */ |
#define SOS_ENOENT 8 /* No such file or directory */ | #define SOS_EFAULT 8 /* Unresolved virtual memory fault */ |
#define SOS_ELOOP 9 /* symlink resolution loop / too recursive */ | #define SOS_ENOENT 9 /* No such file or directory */ |
#define SOS_EEXIST 10 /* File already exists */ | #define SOS_ELOOP 10 /* symlink resolution loop / too recursive */ |
#define SOS_EACCES 11 /* Permission denied */ | #define SOS_EEXIST 11 /* File already exists */ |
#define SOS_ENOTDIR 12 /* Dir does not exist */ | #define SOS_EACCES 12 /* Permission denied */ |
#define SOS_ENAMETOOLONG 13 | #define SOS_ENOTDIR 13 /* Dir does not exist */ |
#define SOS_EXDEV 14 /* Cannot link entries across different FS */ | #define SOS_ENAMETOOLONG 14 |
#define SOS_EISDIR 15 /* Directories not allowed in operation */ | #define SOS_EXDEV 15 /* Cannot link entries across different FS */ |
#define SOS_ENOTEMPTY 16 | #define SOS_EISDIR 16 /* Directories not allowed in operation */ |
#define SOS_ENODEV 17 /* No such device */ | #define SOS_ENOTEMPTY 17 |
#define SOS_EBADF 18 /* Bad file descriptor */ | #define SOS_ENODEV 18 /* No such device */ |
#define SOS_EMFILE 19 /* Reached maximal opened file for process */ | #define SOS_EBADF 19 /* Bad file descriptor */ |
#define SOS_ENOSYS 20 /* Operation not implemented */ | #define SOS_EMFILE 20 /* Reached maximal opened file for process */ |
#define SOS_EIO 21 /* Input/output error */ | #define SOS_ENOSYS 21 /* Operation not implemented */ |
| #define SOS_EIO 22 /* Input/output error */ |
| |
/* A negative value means that an error occured. For | /* A negative value means that an error occured. For |
| |
/tmp/sos-code-article9.5/sos/hash.h (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/hash.h (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
typedef sos_bool_t (sos_hash_key_eq_func_t)(const void * ptr_key1, | typedef sos_bool_t (sos_hash_key_eq_func_t)(const void * ptr_key1, |
const void * ptr_key2); | const void * ptr_key2); |
| |
| /** Prototype of a key/value iteration function: when FALSE = stop now ! */ |
| typedef sos_bool_t (sos_hash_map_func_t)(void * custom_data, |
| void * elt_with_key); |
| |
| |
/** Opaque structure */ | /** Opaque structure */ |
struct sos_hash_table; | struct sos_hash_table; |
| |
|
|
* | * |
* @param name The name of the hash table (debug) | * @param name The name of the hash table (debug) |
* @param elt_type The type of the elements | * @param elt_type The type of the elements |
* @param hfunc The hash function (@see sos_hash_func_t) | * @param hfunc The hash function (@see sos_hash_func_t). When NULL: |
* @param hfunc The element comparaison function (@see | * identity (native unsigned long keys assumed) |
* sos_hash_key_eq_func_t) | * @param eqfunc The element comparaison function (@see |
| * sos_hash_key_eq_func_t). When NULL: native |
| * unsigned long comparison |
* @param name_key_field The name of the field in the element type | * @param name_key_field The name of the field in the element type |
* that holds the key | * that holds the key |
* @param name_key_field The name of the field in the element type | * @param name_key_field The name of the field in the element type |
* that hold the prev/next hash linkage data | * that hold the prev/next hash linkage data |
*/ | */ |
#define sos_hash_create(name,elt_type,hfunc,eqfunc,nbuckets,\ | #define sos_hash_create(name,elt_type,hfunc,eqfunc,nbuckets, \ |
name_key_field,name_h_linkage) \ | name_key_field,name_h_linkage) \ |
_sos_hash_create_FULL(name, hfunc, eqfunc, nbuckets, \ | _sos_hash_create_FULL(name, hfunc, eqfunc, nbuckets, \ |
offsetof(elt_type, name_key_field), \ | offsetof(elt_type, name_key_field), \ |
| |
| |
|
|
sos_uoffset_t offset_h_linkage); | sos_uoffset_t offset_h_linkage); |
| |
| |
| /** Return the number of elements in the hash table */ |
| sos_count_t sos_hash_get_nb_elts(const struct sos_hash_table * h); |
| |
| |
/** Does not free the elements themselves ! */ | /** Does not free the elements themselves ! */ |
sos_ret_t sos_hash_dispose(struct sos_hash_table *h); | sos_ret_t sos_hash_dispose(struct sos_hash_table *h); |
| |
|
|
void *elt); | void *elt); |
| |
| |
| /** |
| * Call iter_func on each of the elements in the hash table |
| * Stop when iter_func returns 0 (and returns FALSE). Otherwise return |
| * TRUE. |
| * |
| * @note iter_func must NOT block ! |
| * @note No particular locking |
| */ |
| sos_bool_t sos_hash_walk(const struct sos_hash_table *h, |
| sos_hash_map_func_t * iter_func, |
| void * custom_data); |
| |
| |
/* | /* |
* Common hash functions | * Common hash functions |
*/ | */ |
| |
/tmp/sos-code-article9.5/sos/main.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/main.c (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
|| (cur_thr->fixup_uaccess.return_vaddr)) | || (cur_thr->fixup_uaccess.return_vaddr)) |
{ | { |
__label__ unforce_address_space; | __label__ unforce_address_space; |
sos_bool_t need_to_setup_mmu; | sos_bool_t need_to_prepare_user_space_access; |
| |
/* Make sure to always stay in the interrupted thread's MMU | /* Do we already try to access an address space ? */ |
configuration */ | need_to_prepare_user_space_access |
need_to_setup_mmu = (cur_thr->squatted_mm_context | = (sos_thread_get_current()->squatted_address_space == NULL); |
!= sos_process_get_mm_context(cur_thr->process)); | |
if (need_to_setup_mmu) | if (need_to_prepare_user_space_access) |
| /* No: Need to configure the interrupted thread user space */ |
| |
if (SOS_OK == | if (SOS_OK == |
|
|
goto unforce_address_space; | goto unforce_address_space; |
} | } |
| |
if (need_to_setup_mmu) | if (need_to_prepare_user_space_access) |
| |
sos_bochs_printf("\e[35mTHR %p: Unresolved USER page Fault at instruction 0x%x on access to address 0x%x (info=%x)!\e[m\n", | sos_bochs_printf("\e[35mTHR %p: Unresolved USER page Fault at instruction 0x%x on access to address 0x%x (info=%x)!\e[m\n", |
|
|
sos_thread_exit(); | sos_thread_exit(); |
| |
unforce_address_space: | unforce_address_space: |
if (need_to_setup_mmu) | if (need_to_prepare_user_space_access) |
return; | return; |
} | } |
|
|
struct sos_process *proc_init; | struct sos_process *proc_init; |
struct sos_thread *new_thr; | struct sos_thread *new_thr; |
sos_uaddr_t ustack, start_uaddr; | sos_uaddr_t ustack, start_uaddr; |
| int fake_args[32]; /* Must be large enough to contain argv/envp for init */ |
| sos_ret_t ret; |
struct sos_fs_opened_file * init_root, * init_cwd, * unused_of; | struct sos_fs_opened_file * init_root, * init_cwd, * unused_of; |
| |
/* Create the new process */ | /* Create the new process */ |
|
|
} | } |
| |
| |
| |
start_uaddr = sos_binfmt_elf32_map(as_init, "init"); | start_uaddr = sos_binfmt_elf32_map(as_init, "init"); |
if (0 == start_uaddr) | if (0 == start_uaddr) |
|
|
} | } |
| |
/* Allocate the user stack */ | /* Allocate the user stack */ |
ustack = (SOS_PAGING_TOP_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE) + 1; | ustack = (SOS_PAGING_UPPER_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE) + 1; |
SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE, | SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE, |
/* PRIVATE */ 0); | /* PRIVATE */ 0); |
|
|
return -SOS_ENOMEM; | return -SOS_ENOMEM; |
} | } |
| |
| /* Compute the address of the stack that will be used to initialize |
| the user thread */ |
| ustack = SOS_ALIGN_INF((ustack + SOS_DEFAULT_USER_STACK_SIZE |
| - sizeof(fake_args)), 4); |
| |
| /* Build fake argv/envp arguments for the init process. See |
| userland/crt.c for the format. */ |
| fake_args[0] = 0x1; /* argc */ |
| fake_args[1] = 4 * sizeof(fake_args[0]); /* offset of argv[0] */ |
| fake_args[2] = 0x0; /* delimiter between argv and envp */ |
| fake_args[3] = 0x0; /* end of envp */ |
| strzcpy ((char *) & fake_args[4], /* argv[0] contents */ |
| "init", 5); |
| |
| /* Copy the arguments to the user thread stack */ |
| ret = sos_memcpy_to_specified_userspace (as_init, |
| ustack, |
| (sos_vaddr_t) fake_args, |
| sizeof(fake_args)); |
| if (sizeof(fake_args) != ret) |
| { |
| sos_bochs_printf ("sos_memcpy_to_specified_userspace() failed, returned %d\n", ret); |
| sos_process_unref(proc_init); |
| return ret; |
| } |
| |
/* Now create the user thread */ | /* Now create the user thread */ |
new_thr = sos_create_user_thread(NULL, | new_thr = sos_create_user_thread(NULL, |
proc_init, | proc_init, |
start_uaddr, | start_uaddr, |
0, 0, | 0, 0, |
ustack + SOS_DEFAULT_USER_STACK_SIZE - 4, | ustack, |
if (! new_thr) | if (! new_thr) |
{ | { |
| |
/tmp/sos-code-article9.5/sos/process.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/process.c (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
#include <sos/kmem_slab.h> | #include <sos/kmem_slab.h> |
#include <hwcore/irq.h> | #include <hwcore/irq.h> |
#include <drivers/bochs.h> | #include <drivers/bochs.h> |
| #include <hwcore/bitmap.h> |
| #include <sos/physmem.h> /* for SOS_PAGE_SIZE */ |
| |
#include <sos/umem_vmm.h> | #include <sos/umem_vmm.h> |
| |
|
|
{ | { |
char name[SOS_PROCESS_MAX_NAMELEN]; | char name[SOS_PROCESS_MAX_NAMELEN]; |
| |
| /** Process identifier */ |
| sos_pid_t pid; |
| |
/** First important resource: the address space */ | /** First important resource: the address space */ |
struct sos_umem_vmm_as *address_space; | struct sos_umem_vmm_as *address_space; |
| |
|
|
/** Where the current working dir of the process is */ | /** Where the current working dir of the process is */ |
struct sos_fs_opened_file * cwd; | struct sos_fs_opened_file * cwd; |
| |
struct sos_process *prev, *next; | /** To chain the processes in the global list of active processes |
| and PIDs */ |
| struct sos_hash_linkage hlink_pidtable; |
| |
| |
/** The list of processes in the system */ | /** The list of processes in the system */ |
static struct sos_process *process_list = NULL; | static struct sos_hash_table * process_hash; |
| |
| |
| /** The bitmap for PID allocation */ |
| static void * bitmap_pid; |
| |
| |
| /** Number of bits in the PID bitmap */ |
| #define SOS_PROCESS_PID_BITMAP_NBITS \ |
| (8 * SOS_PROCESS_PID_BITMAP_NPAGES * SOS_PAGE_SIZE) |
| |
| |
| /** The PID where we start looking for a free slot */ |
| static sos_pid_t next_base_pid; |
| |
/** The cache for the sos_process structures */ | /** The cache for the sos_process structures */ |
|
|
void sos_process_dumplist(void) | void sos_process_dumplist(void) |
{ | { |
struct sos_thread * cur_thr = sos_thread_get_current(); | struct sos_thread * cur_thr = sos_thread_get_current(); |
struct sos_process * proc; | int nb_procs = 0; |
int nb_procs; | |
sos_bochs_printf("<ps>\n"); | /* Internal function used to dump infos about a single process */ |
list_foreach(process_list, proc, nb_procs) | sos_bool_t process_iterator(void* custom_data, |
| struct sos_process * proc) |
struct sos_thread * thr; | struct sos_thread * thr; |
int nb_thrs; | int nb_thrs; |
| |
sos_bochs_printf(" proc@%p: '%s', %d threads, %d refs\n", | nb_procs ++; |
proc, proc->name?proc->name:"(none)", | sos_bochs_printf(" proc %d @%p: '%s', %d threads, %d refs\n", |
| proc->pid, proc, proc->name?proc->name:"(none)", |
| |
list_foreach_forward_named(proc->thread_list, thr, nb_thrs, | list_foreach_forward_named(proc->thread_list, thr, nb_thrs, |
|
|
thr->state, | thr->state, |
(void*)sos_cpu_context_get_PC(thr->cpu_state)); | (void*)sos_cpu_context_get_PC(thr->cpu_state)); |
} | } |
| |
| return TRUE; |
} | } |
| |
| sos_bochs_printf("<ps>\n"); |
| sos_hash_walk(process_hash, (sos_hash_map_func_t*)process_iterator, NULL); |
sos_bochs_printf(" ======= %d processes =======\n", nb_procs); | sos_bochs_printf(" ======= %d processes =======\n", nb_procs); |
sos_bochs_printf("</ps>\n"); | sos_bochs_printf("</ps>\n"); |
} | } |
|
|
| |
sos_ret_t sos_process_subsystem_setup() | sos_ret_t sos_process_subsystem_setup() |
{ | { |
| |
/* Create the cache for the process structures */ | /* Create the cache for the process structures */ |
cache_struct_process = sos_kmem_cache_create("struct_process", | cache_struct_process = sos_kmem_cache_create("struct_process", |
sizeof(struct sos_process), | sizeof(struct sos_process), |
|
|
0, | 0, |
SOS_KSLAB_CREATE_MAP | SOS_KSLAB_CREATE_MAP |
| SOS_KSLAB_CREATE_ZERO); | | SOS_KSLAB_CREATE_ZERO); |
if (! cache_struct_process) | if (NULL == cache_struct_process) |
| |
| /* Allocate pages for the PID bitmap */ |
| bitmap_pid = (void*) sos_kmem_vmm_alloc(SOS_PROCESS_PID_BITMAP_NPAGES, |
| SOS_KMEM_VMM_MAP); |
| if (NULL == bitmap_pid) |
| { |
| sos_kmem_cache_destroy(cache_struct_process); |
| return -SOS_ENOMEM; |
| } |
| |
| /* The next process might (and actually will !) have PID 1 */ |
| next_base_pid = 1; |
| |
| /* Create the hash for the process list */ |
| process_hash = sos_hash_create("pidtable", struct sos_process, |
| NULL, NULL, 37, |
| pid, hlink_pidtable); |
| if (NULL == process_hash) |
| { |
| sos_kmem_cache_destroy(cache_struct_process); |
| sos_kmem_vmm_free((sos_vaddr_t)bitmap_pid); |
| return -SOS_ENOMEM; |
| } |
| |
| return SOS_OK; |
| } |
| |
| |
| /** Helper function to allocate a PID entry and bind it to the given process */ |
| static sos_ret_t register_process(struct sos_process * proc) |
| { |
| sos_ret_t retval; |
| sos_pid_t pid; |
| |
| /* First of all: look for a free PID */ |
| while (TRUE) |
| { |
| pid = sos_bitmap_ffc(bitmap_pid, |
| SOS_PROCESS_PID_BITMAP_NBITS, |
| next_base_pid); |
| if (pid <= 0) |
| { |
| if (next_base_pid > 1) |
| { |
| /* try again from the beginning */ |
| next_base_pid = 1; |
| continue; |
| } |
| else |
| /* Bad news: no PID left at all ! */ |
| return -SOS_EAGAIN; |
| } |
| |
| if (! sos_bitmap_test_and_set(bitmap_pid, pid)) |
| /* Could allocate it ! */ |
| break; |
| } |
| |
| /* Set the base PID for next process */ |
| if (pid < SOS_PROCESS_PID_BITMAP_NBITS) |
| next_base_pid = pid + 1; |
| else |
| next_base_pid = 1; |
| |
| /* Now bind the process into the process hash */ |
| proc->pid = pid; |
| |
| retval = sos_hash_insert(process_hash, proc); |
| if (SOS_OK != retval) |
| { |
| /* Bad news: cannot register in hash */ |
| SOS_ASSERT_FATAL(sos_bitmap_test_and_clear(bitmap_pid, pid)); |
| return retval; |
| } |
| |
| return SOS_OK; |
| } |
| |
| |
| /** Helper function to deallocate a PID entry and unbind it to the given process */ |
| static sos_ret_t unregister_process(struct sos_process * proc) |
| { |
| SOS_ASSERT_FATAL(SOS_OK == sos_hash_remove(process_hash, proc)); |
| SOS_ASSERT_FATAL(sos_bitmap_test_and_clear(bitmap_pid, proc->pid)); |
| proc->pid = 0; |
return SOS_OK; | return SOS_OK; |
} | } |
| |
|
|
sos_ui32_t flags; | sos_ui32_t flags; |
struct sos_process *proc; | struct sos_process *proc; |
| |
| |
if (! proc) | if (! proc) |
return NULL; | return NULL; |
|
|
} | } |
| |
if (do_copy_current_process) | if (do_copy_current_process) |
proc->address_space = sos_umem_vmm_duplicate_current_thread_as(proc); | { |
| struct sos_process * myself = sos_thread_get_current()->process; |
| proc->address_space |
| = sos_umem_vmm_duplicate_as(sos_process_get_address_space(myself), |
| proc); |
| } |
proc->address_space = sos_umem_vmm_create_empty_as(proc); | proc->address_space = sos_umem_vmm_create_empty_as(proc); |
| |
|
|
| |
/* Add it to the global list of processes */ | /* Add it to the global list of processes */ |
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
list_add_tail(process_list, proc); | retval = register_process(proc); |
| if (SOS_OK == retval) |
| proc->ref_cnt = 1; /* Mark the process as referenced */ |
| |
/* Mark the process as referenced */ | |
proc->ref_cnt = 1; | |
| |
if (SOS_OK != retval) | if (SOS_OK != retval) |
{ | { |
|
|
} | } |
| |
| |
| sos_pid_t sos_process_get_pid(const struct sos_process *proc) |
| { |
| return proc->pid; |
| } |
| |
| |
sos_count_t sos_process_get_nb_threads(const struct sos_process *proc) | sos_count_t sos_process_get_nb_threads(const struct sos_process *proc) |
{ | { |
sos_count_t retval; | sos_count_t retval; |
|
|
| |
sos_ret_t | sos_ret_t |
sos_process_register_opened_file(struct sos_process *proc, | sos_process_register_opened_file(struct sos_process *proc, |
struct sos_fs_opened_file * of) | struct sos_fs_opened_file * of, |
| int start_search_at_fd) |
int i; | int i; |
for (i = 0 ; i < SOS_PROCESS_MAX_OPENED_FILES ; i++) | for (i = start_search_at_fd ; |
| i < SOS_PROCESS_MAX_OPENED_FILES ; |
| i++) |
{ | { |
proc->fds[i] = of; | proc->fds[i] = of; |
|
|
sos_restore_IRQs(flags); | sos_restore_IRQs(flags); |
return -SOS_EBUSY; | return -SOS_EBUSY; |
} | } |
list_delete(process_list, proc); | unregister_process(proc); |
| |
/* Close the file descriptors */ | /* Close the file descriptors */ |
| |
/tmp/sos-code-article9.5/sos/syscall.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/syscall.c (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
#include <sos/kmalloc.h> | #include <sos/kmalloc.h> |
#include <sos/klibc.h> | #include <sos/klibc.h> |
#include <drivers/bochs.h> | #include <drivers/bochs.h> |
#include <hwcore/paging.h> | |
#include <sos/umem_vmm.h> | #include <sos/umem_vmm.h> |
#include <drivers/zero.h> | #include <drivers/zero.h> |
|
|
{ | { |
sos_ret_t retval; | sos_ret_t retval; |
| |
| |
switch(syscall_id) | switch(syscall_id) |
{ | { |
case SOS_SYSCALL_ID_EXIT: | case SOS_SYSCALL_ID_EXIT: |
|
|
sos_duplicate_user_thread(NULL, new_proc, | sos_duplicate_user_thread(NULL, new_proc, |
cur_thr, | cur_thr, |
user_ctxt, | user_ctxt, |
0); | 0 /* fork return value for child ! */); |
{ | { |
sos_process_unref(new_proc); | sos_process_unref(new_proc); |
|
|
/* Return to the "parent" thread with a value different from | /* Return to the "parent" thread with a value different from |
0. Unix says it should be the "PID" of the child. We don't | 0. Unix says it should be the "PID" of the child. We don't |
have such a "PID" notion for now */ | have such a "PID" notion for now */ |
retval = (sos_ui32_t)new_proc; | retval = (sos_ui32_t)sos_process_get_pid(new_proc); |
| } |
| break; |
| |
| case SOS_SYSCALL_ID_GETPID: |
| { |
| struct sos_thread *cur_thr; |
| struct sos_process * proc; |
| |
| cur_thr = sos_thread_get_current(); |
| proc = cur_thr->process; |
| |
| retval = (sos_ui32_t) sos_process_get_pid(proc); |
break; | break; |
| |
|
|
struct sos_process * proc; | struct sos_process * proc; |
struct sos_umem_vmm_as *new_as; | struct sos_umem_vmm_as *new_as; |
sos_uaddr_t user_str, ustack, start_uaddr; | sos_uaddr_t user_str, ustack, start_uaddr; |
| sos_uaddr_t src_argaddr; |
| sos_size_t len_args; |
sos_size_t len; | sos_size_t len; |
char * str; | char * str; |
| |
|
|
} | } |
| |
/* Get the user arguments */ | /* Get the user arguments */ |
retval = sos_syscall_get2args(user_ctxt, & user_str, & len); | retval = sos_syscall_get4args(user_ctxt, & user_str, & len, |
| & src_argaddr, & len_args); |
break; | break; |
| |
| /* Don't go any further if the arg/env array is obviously too |
| large */ |
| if (SOS_DEFAULT_USER_STACK_SIZE <= len_args) |
| { |
| retval = -SOS_EINVAL; |
| break; |
| } |
| |
/* Copy the program name into kernel sppace */ | /* Copy the program name into kernel sppace */ |
retval = sos_strndup_from_user(& str, user_str, len + 1, 0); | retval = sos_strndup_from_user(& str, user_str, len + 1, 0); |
if (SOS_OK != retval) | if (SOS_OK != retval) |
|
|
| |
/* Allocate space for the user stack (8MB) */ | /* Allocate space for the user stack (8MB) */ |
#define SOS_DEFAULT_USER_STACK_SIZE (8 << 20) | #define SOS_DEFAULT_USER_STACK_SIZE (8 << 20) |
ustack = (SOS_PAGING_TOP_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE) | ustack = (SOS_PAGING_UPPER_USER_ADDRESS |
+ 1; | - SOS_DEFAULT_USER_STACK_SIZE) |
| + 1; |
SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE, | SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE, |
/* PRIVATE */ 0); | /* PRIVATE */ 0); |
|
|
break; | break; |
} | } |
| |
| /* ustack now refers to the initial stack pointer of the new |
| user thread: update it here */ |
| ustack = SOS_ALIGN_INF((ustack + SOS_DEFAULT_USER_STACK_SIZE |
| - len_args), 4); |
| |
| if (len_args != sos_usercpy(new_as, ustack, |
| NULL, src_argaddr, |
| len_args)) |
| { |
| sos_umem_vmm_delete_as(new_as); |
| sos_kfree((sos_vaddr_t)str); |
| retval = -SOS_EFAULT; |
| break; |
| } |
| |
/* Now create the user thread */ | /* Now create the user thread */ |
new_thr = sos_create_user_thread(NULL, | new_thr = sos_create_user_thread(NULL, |
proc, | proc, |
start_uaddr, | start_uaddr, |
0, 0, | 0, 0, |
ustack + SOS_DEFAULT_USER_STACK_SIZE | ustack, |
- 4, | |
if (! new_thr) | if (! new_thr) |
{ | { |
sos_umem_vmm_delete_as(new_as); | sos_umem_vmm_delete_as(new_as); |
sos_kfree((sos_vaddr_t)str); | sos_kfree((sos_vaddr_t)str); |
retval = -SOS_ENOMEM; | retval = -SOS_ENOMEM; |
break; | break; |
| |
sos_process_set_name(proc, str); | sos_process_set_name(proc, str); |
|
|
{ | { |
sos_umem_vmm_delete_as(new_as); | sos_umem_vmm_delete_as(new_as); |
sos_kfree((sos_vaddr_t)str); | sos_kfree((sos_vaddr_t)str); |
break; | break; |
| |
/* The current thread must exit now */ | /* The current thread must exit now */ |
|
|
} | } |
break; | break; |
| |
| |
case SOS_SYSCALL_ID_MSYNC: | case SOS_SYSCALL_ID_MSYNC: |
{ | { |
sos_uaddr_t start_uaddr; | sos_uaddr_t start_uaddr; |
|
|
} | } |
break; | break; |
| |
| |
case SOS_SYSCALL_ID_NEW_THREAD: | case SOS_SYSCALL_ID_NEW_THREAD: |
{ | { |
sos_uaddr_t start_func; | sos_uaddr_t start_func; |
|
|
if (SOS_OK != retval) | if (SOS_OK != retval) |
break; | break; |
| |
retval = sos_process_register_opened_file(proc, of); | retval = sos_process_register_opened_file(proc, of, 0); |
{ | { |
sos_fs_close(of); | sos_fs_close(of); |
|
|
sos_bochs_printf("Syscall: UNKNOWN[%d]\n", syscall_id); | sos_bochs_printf("Syscall: UNKNOWN[%d]\n", syscall_id); |
retval = -SOS_ENOSUP; | retval = -SOS_ENOSUP; |
} | } |
| |
} | } |
| |
/tmp/sos-code-article9.5/sos/syscall.h (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/syscall.h (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
/** | /** |
* The user services offered by the SOS kernel | * The user services offered by the SOS kernel |
*/ | */ |
#define SOS_SYSCALL_ID_EXIT 256 /**< Args: retval, retval=NONE */ | #define SOS_SYSCALL_ID_EXIT 67 /**< Args: retval, retval=NONE */ |
| |
/** | /** |
|
|
/** | /** |
* User memory mappings management | * User memory mappings management |
*/ | */ |
| #define SOS_SYSCALL_ID_GETPID 256 /**< Args: NONE, retval=cur. proc. PID */ |
#define SOS_SYSCALL_ID_FORK 257 /**< Args: NONE, retval={father:child_pd, child:0} */ | #define SOS_SYSCALL_ID_FORK 257 /**< Args: NONE, retval={father:child_pd, child:0} */ |
#define SOS_SYSCALL_ID_EXEC 258 /**< Args: ptr_exec_path strlen_exec_path, retval=errno */ | #define SOS_SYSCALL_ID_EXEC 258 /**< Args: ptr_exec_path strlen_exec_path addr_args len_args, retval=errno */ |
#define SOS_SYSCALL_ID_MPROTECT 261 /**< Args: start_uaddr size access_rights, retval=errno */ | #define SOS_SYSCALL_ID_MPROTECT 261 /**< Args: start_uaddr size access_rights, retval=errno */ |
#define SOS_SYSCALL_ID_MRESIZE 262 /**< Args: old_uaddr old_size ptr_new_uaddr new_size flags, retval=errno */ | #define SOS_SYSCALL_ID_MRESIZE 262 /**< Args: old_uaddr old_size ptr_new_uaddr new_size flags, retval=errno */ |
|
|
#define SOS_SYSCALL_ID_FSMMAP 566 /**< Args: &hint len prot flags fd uoffs64_hi uoffs64_lo, retval=errno */ | #define SOS_SYSCALL_ID_FSMMAP 566 /**< Args: &hint len prot flags fd uoffs64_hi uoffs64_lo, retval=errno */ |
#define SOS_SYSCALL_ID_FSYNC 567 /**< Args: fd, retval=errno */ | #define SOS_SYSCALL_ID_FSYNC 567 /**< Args: fd, retval=errno */ |
#define SOS_SYSCALL_ID_FCNTL 568 /**< Args: fd cmd arg, retval=errno */ | #define SOS_SYSCALL_ID_FCNTL 568 /**< Args: fd cmd arg, retval=errno */ |
| /* fcntl possible commands */ |
| # define SOS_FCNTL_DUPFD 0x4201 |
| # define SOS_FCNTL_GETFD 0x4202 |
| # define SOS_FCNTL_SETFD 0x4203 |
| # define SOS_FCNTL_GETFL 0x4204 |
| # define SOS_FCNTL_SETFL 0x4205 |
#define SOS_SYSCALL_ID_IOCTL 569 /**< Args: fd cmd arg, retval=errno */ | #define SOS_SYSCALL_ID_IOCTL 569 /**< Args: fd cmd arg, retval=errno */ |
| |
#define SOS_SYSCALL_ID_CREAT 570 /**< Args: uaddr_path pathlen access_rights, retval=errno */ | #define SOS_SYSCALL_ID_CREAT 570 /**< Args: uaddr_path pathlen access_rights, retval=errno */ |
| |
/tmp/sos-code-article9.5/sos/thread.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/thread.c (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
static struct sos_kslab_cache *cache_thread; | static struct sos_kslab_cache *cache_thread; |
| |
| |
/** | |
* (Forwad declaration) Helper function to change the MMU config of | |
* the current executing thread. Analogous to function | |
* sos_thread_change_current_mm_context() of article 7 | |
*/ | |
static sos_ret_t change_current_mm_context(struct sos_mm_context *mm_ctxt); | |
| |
| |
{ | { |
SOS_ASSERT_FATAL(current_thread->state == SOS_THR_RUNNING); | SOS_ASSERT_FATAL(current_thread->state == SOS_THR_RUNNING); |
|
|
SOS_ASSERT_FATAL(the_thread->process != NULL); | SOS_ASSERT_FATAL(the_thread->process != NULL); |
| |
/* It should not squat any other's address space */ | /* It should not squat any other's address space */ |
SOS_ASSERT_FATAL(the_thread->squatted_mm_context == NULL); | SOS_ASSERT_FATAL(the_thread->squatted_address_space == NULL); |
/* Perform an MMU context switch if needed */ | /* Perform an MMU context switch if needed */ |
sos_mm_context_switch_to(sos_process_get_mm_context(the_thread->process)); | sos_umem_vmm_set_current_as(sos_process_get_address_space(the_thread->process)); |
| |
/* the_thread is a kernel thread squatting a precise address | /* Restore the address space currently in use */ |
space ? */ | else |
else if (the_thread->squatted_mm_context != NULL) | sos_umem_vmm_set_current_as(the_thread->squatted_address_space); |
sos_mm_context_switch_to(the_thread->squatted_mm_context); | |
| |
| |
|
|
| |
sos_kfree((sos_vaddr_t) thr->kernel_stack_base_addr); | sos_kfree((sos_vaddr_t) thr->kernel_stack_base_addr); |
| |
/* If the thread squats an address space, release it */ | /* Not allowed to squat any user space at deletion time */ |
if (thr->squatted_mm_context) | SOS_ASSERT_FATAL(NULL == thr->squatted_address_space); |
SOS_ASSERT_FATAL(SOS_OK == change_current_mm_context(NULL)); | |
/* For a user thread: remove the thread from the process threads' list */ | /* For a user thread: remove the thread from the process threads' list */ |
if (thr->process) | if (thr->process) |
|
|
*/ | */ |
| |
| |
static sos_ret_t | |
change_current_mm_context(struct sos_mm_context *mm_ctxt) | |
{ | |
/* Retrieve the previous mm context */ | |
struct sos_mm_context * prev_mm_ctxt | |
= current_thread->squatted_mm_context; | |
| |
/* Update current thread's squatted mm context */ | |
current_thread->squatted_mm_context = mm_ctxt; | |
| |
/* Update the reference counts and switch the MMU configuration if | |
needed */ | |
if (mm_ctxt != NULL) | |
{ | |
sos_mm_context_ref(mm_ctxt); /* Because it is now referenced as | |
the squatted_mm_context field of | |
the thread */ | |
sos_mm_context_switch_to(mm_ctxt); | |
} | |
else | |
sos_mm_context_unref(prev_mm_ctxt); /* Because it is not referenced as | |
the squatted_mm_context field of | |
the thread any more */ | |
| |
return SOS_OK; | |
} | |
| |
| |
sos_thread_prepare_user_space_access(struct sos_umem_vmm_as * dest_as, | sos_thread_prepare_user_space_access(struct sos_umem_vmm_as * dest_as, |
sos_vaddr_t fixup_retvaddr) | sos_vaddr_t fixup_retvaddr) |
|
|
| |
dest_as = sos_process_get_address_space(current_thread->process); | dest_as = sos_process_get_address_space(current_thread->process); |
} | } |
else | |
/* Don't allow to access to an address space different than that | |
of the current thread if the page fault are allowed ! */ | |
SOS_ASSERT_FATAL(! fixup_retvaddr); | |
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
SOS_ASSERT_FATAL(NULL == current_thread->squatted_mm_context); | SOS_ASSERT_FATAL(NULL == current_thread->squatted_address_space); |
| |
/* Change the MMU configuration and init the fixup return address */ | /* Change the MMU configuration and init the fixup return address */ |
retval = change_current_mm_context(sos_umem_vmm_get_mm_context(dest_as)); | retval = sos_umem_vmm_set_current_as(dest_as); |
{ | { |
| current_thread->squatted_address_space = dest_as; |
current_thread->fixup_uaccess.return_vaddr = fixup_retvaddr; | current_thread->fixup_uaccess.return_vaddr = fixup_retvaddr; |
current_thread->fixup_uaccess.faulted_uaddr = 0; | current_thread->fixup_uaccess.faulted_uaddr = 0; |
| |
sos_restore_IRQs(flags); | sos_restore_IRQs(flags); |
|
|
sos_ui32_t flags; | sos_ui32_t flags; |
| |
sos_disable_IRQs(flags); | sos_disable_IRQs(flags); |
SOS_ASSERT_FATAL(NULL != current_thread->squatted_mm_context); | SOS_ASSERT_FATAL(NULL != current_thread->squatted_address_space); |
/* Don't impose anything regarding the current MMU configuration anymore */ | /* Don't impose anything regarding the current MMU configuration anymore */ |
retval = change_current_mm_context(NULL); | |
current_thread->fixup_uaccess.faulted_uaddr = 0; | current_thread->fixup_uaccess.faulted_uaddr = 0; |
| |
| retval = sos_umem_vmm_set_current_as(NULL); |
| current_thread->squatted_address_space = NULL; |
| |
sos_restore_IRQs(flags); | sos_restore_IRQs(flags); |
return retval; | return retval; |
} | } |
| |
/tmp/sos-code-article9.5/sos/uaccess.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/uaccess.c (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
({ if (__uaccess_zero_fool_gcc) goto lbl; }) | ({ if (__uaccess_zero_fool_gcc) goto lbl; }) |
| |
| |
static sos_ret_t nocheck_user_memcpy(sos_vaddr_t dest, | /** |
| * @param user_as The user address space we want to transfer from/to |
| * |
| * @return >=0 : number of bytes successfully transferred, <0 an error code |
| */ |
| static sos_ret_t nocheck_user_memcpy(struct sos_umem_vmm_as * user_as, |
| sos_vaddr_t dest, |
sos_size_t size, | sos_size_t size, |
sos_bool_t transfer_from_user) | sos_bool_t transfer_from_user) |
|
|
if (size <= 0) | if (size <= 0) |
return 0; | return 0; |
| |
retval = sos_thread_prepare_user_space_access(NULL, | retval = sos_thread_prepare_user_space_access(user_as, |
if (SOS_OK != retval) | if (SOS_OK != retval) |
return retval; | return retval; |
|
|
sos_size_t size) | sos_size_t size) |
{ | { |
/* Make sure user is trying to access user space */ | /* Make sure user is trying to access user space */ |
if (user_from < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(user_from, size) ) |
| |
if (user_from > SOS_PAGING_TOP_USER_ADDRESS - size) | /* Make sure the copy totally resides inside kernel space */ |
| if (! SOS_PAGING_IS_KERNEL_AREA(kernel_to, size) ) |
| |
return nocheck_user_memcpy(kernel_to, user_from, size, TRUE); | return nocheck_user_memcpy(NULL, kernel_to, user_from, size, TRUE); |
| |
| |
|
|
sos_vaddr_t kernel_from, | sos_vaddr_t kernel_from, |
sos_size_t size) | sos_size_t size) |
{ | { |
| /* Make sure the source totally resides inside kernel space */ |
| if (! SOS_PAGING_IS_KERNEL_AREA(kernel_from, size) ) |
| return -SOS_EPERM; |
| |
/* Make sure user is trying to access user space */ | /* Make sure user is trying to access user space */ |
if (user_to < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(user_to, size) ) |
| |
if (user_to > SOS_PAGING_TOP_USER_ADDRESS - size) | return nocheck_user_memcpy(NULL, user_to, kernel_from, size, FALSE); |
| } |
| |
| |
| sos_ret_t sos_memcpy_from_specified_userspace(sos_vaddr_t kernel_to, |
| struct sos_umem_vmm_as * src_as, |
| sos_uaddr_t user_from, |
| sos_size_t size) |
| { |
| if (NULL == src_as) |
| return -SOS_EINVAL; |
| |
| /* Make sure user is trying to access user space */ |
| if (! SOS_PAGING_IS_USER_AREA(user_from, size) ) |
| return -SOS_EPERM; |
| |
| /* Make sure the copy totally resides inside kernel space */ |
| if (! SOS_PAGING_IS_KERNEL_AREA(kernel_to, size) ) |
| return -SOS_EPERM; |
| |
| return nocheck_user_memcpy(src_as, kernel_to, user_from, size, TRUE); |
| } |
| |
| |
| sos_ret_t sos_memcpy_to_specified_userspace(struct sos_umem_vmm_as * dst_as, |
| sos_uaddr_t user_to, |
| sos_vaddr_t kernel_from, |
| sos_size_t size) |
| { |
| if (NULL == dst_as) |
| return -SOS_EINVAL; |
| |
| /* Make sure the source totally resides inside kernel space */ |
| if (! SOS_PAGING_IS_KERNEL_AREA(kernel_from, size) ) |
| return -SOS_EPERM; |
| |
| /* Make sure user is trying to access user space */ |
| if (! SOS_PAGING_IS_USER_AREA(user_to, size) ) |
| return -SOS_EPERM; |
| |
| return nocheck_user_memcpy(dst_as, user_to, kernel_from, size, FALSE); |
| } |
| |
| |
| sos_ret_t sos_usercpy(struct sos_umem_vmm_as * dst_as, |
| sos_uaddr_t dst_uaddr, |
| struct sos_umem_vmm_as * src_as, |
| sos_uaddr_t src_uaddr, |
| sos_size_t size) |
| { |
| sos_vaddr_t kern_addr; |
| sos_ret_t retval; |
| |
| if (size <= 0) |
| return 0; |
| |
| /* Make sure user is trying to access user space */ |
| if (! SOS_PAGING_IS_USER_AREA(src_uaddr, size) ) |
| return -SOS_EPERM; |
| if (! SOS_PAGING_IS_USER_AREA(dst_uaddr, size) ) |
| |
return nocheck_user_memcpy(user_to, kernel_from, size, FALSE); | kern_addr = sos_kmalloc(size, 0); |
| if (! kern_addr) |
| return -SOS_ENOMEM; |
| |
| retval = nocheck_user_memcpy(src_as, kern_addr, src_uaddr, |
| size, TRUE); |
| if (retval <= 0) |
| { |
| sos_kfree((sos_vaddr_t)kern_addr); |
| return retval; |
| } |
| |
| retval = nocheck_user_memcpy(dst_as, dst_uaddr, kern_addr, |
| retval, FALSE); |
| |
| sos_kfree((sos_vaddr_t)kern_addr); |
| |
| return retval; |
| |
| |
|
|
return 0; | return 0; |
| |
/* Make sure user is trying to access user space */ | /* Make sure user is trying to access user space */ |
if (user_str < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(user_str, max_len) ) |
| |
/* Don't allow invalid max_len */ | |
if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) ) | |
return -SOS_EINVAL; | |
| |
(sos_vaddr_t) && catch_pgflt); | (sos_vaddr_t) && catch_pgflt); |
if (SOS_OK != retval) | if (SOS_OK != retval) |
|
|
sos_ret_t sos_strzcpy_from_user(char *kernel_to, sos_uaddr_t user_from, | sos_ret_t sos_strzcpy_from_user(char *kernel_to, sos_uaddr_t user_from, |
sos_size_t max_len) | sos_size_t max_len) |
{ | { |
| if (max_len <= 0) |
| return -SOS_EINVAL; |
| |
/* Make sure user is trying to access user space */ | /* Make sure user is trying to access user space */ |
if ((sos_uaddr_t)user_from < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(user_from, max_len) ) |
| |
/* Don't allow invalid max_len */ | /* Make sure the copy totally resides inside kernel space */ |
if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) ) | if (! SOS_PAGING_IS_KERNEL_AREA((sos_vaddr_t)kernel_to, max_len) ) |
return -SOS_EINVAL; | return -SOS_EPERM; |
return nocheck_user_strzcpy(kernel_to, (const char*)user_from, max_len); | return nocheck_user_strzcpy(kernel_to, (const char*)user_from, max_len); |
} | } |
|
|
sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user_to, const char *kernel_from, | sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user_to, const char *kernel_from, |
sos_size_t max_len) | sos_size_t max_len) |
{ | { |
/* Make sure user is trying to access user space */ | if (max_len <= 0) |
if ((sos_uaddr_t)user_to < SOS_PAGING_BASE_USER_ADDRESS) | return -SOS_EINVAL; |
| |
| /* Make sure the source totally resides inside kernel space */ |
| if (! SOS_PAGING_IS_KERNEL_AREA((sos_vaddr_t)kernel_from, max_len) ) |
| |
/* Don't allow invalid max_len */ | /* Make sure user is trying to access user space */ |
if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) ) | if (! SOS_PAGING_IS_USER_AREA(user_to, max_len) ) |
return -SOS_EINVAL; | return -SOS_EPERM; |
return nocheck_user_strzcpy((char*)user_to, kernel_from, max_len); | return nocheck_user_strzcpy((char*)user_to, kernel_from, max_len); |
} | } |
| |
/tmp/sos-code-article9.5/sos/uaccess.h (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/uaccess.h (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
| |
#include <sos/types.h> | #include <sos/types.h> |
#include <sos/errno.h> | #include <sos/errno.h> |
| #include <sos/umem_vmm.h> |
/** | /** |
* Retrieve a bunch of data from the user space of the | * Retrieve a bunch of data from the user space of the |
|
|
| |
| |
/** | /** |
* Transfer a bunch of data to the user space of the | * Transfer a bunch of data from kernel space into the user space of |
* current_thread->process | * the current_thread->process |
* @return <0 n error ! Return the number of bytes successfully copied | * @return <0 n error ! Return the number of bytes successfully copied |
* otherwise. | * otherwise. |
|
|
| |
| |
/** | /** |
| * Variant of sos_memcpy_from_user() |
| * Retrieve a bunch of data from the user space of the given src_as |
| * address space into kernel space |
| * |
| * @return NULL on error (including unresolved page fault during |
| * transfer) |
| * |
| * @note src_as MUST NOT be NULL |
| */ |
| sos_ret_t sos_memcpy_from_specified_userspace(sos_vaddr_t kernel_to, |
| struct sos_umem_vmm_as * src_as, |
| sos_uaddr_t user_from, |
| sos_size_t size); |
| |
| |
| /** |
| * Variant of sos_memcpy_to_user() |
| * Transfer a bunch of data from kernel space into the user space of |
| * the given dst_as address space |
| * |
| * @return <0 n error ! Return the number of bytes successfully copied |
| * otherwise. |
| * |
| * @note dst_as MUST NOT be NULL |
| */ |
| sos_ret_t sos_memcpy_to_specified_userspace(struct sos_umem_vmm_as * dst_as, |
| sos_uaddr_t user_to, |
| sos_vaddr_t kernel_from, |
| sos_size_t size); |
| |
| /** |
| * Copy data from an user space into another |
| * @return The number of bytes successfuly copied |
| * @note dst_as and src_as may be NULL, in which case the current |
| * thread->process address space is used for the copy |
| */ |
| sos_ret_t sos_usercpy(struct sos_umem_vmm_as * dst_as, |
| sos_uaddr_t dst_uaddr, |
| struct sos_umem_vmm_as * src_as, |
| sos_uaddr_t src_uaddr, |
| sos_size_t size); |
| |
| |
| /** |
* @return the length of the given user space string user_str | * @return the length of the given user space string user_str |
* (excluding the trailing \0), up to max_len bytes. <0 on error | * (excluding the trailing \0), up to max_len bytes. <0 on error |
* (unresolved page fault, etc.) | * (unresolved page fault, etc.) |
| |
/tmp/sos-code-article9.5/sos/umem_vmm.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/umem_vmm.c (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
#include <drivers/bochs.h> | #include <drivers/bochs.h> |
#include <hwcore/mm_context.h> | #include <hwcore/mm_context.h> |
#include <hwcore/paging.h> | #include <hwcore/paging.h> |
| #include <hwcore/irq.h> |
#include <drivers/zero.h> | #include <drivers/zero.h> |
| |
#include "umem_vmm.h" | #include "umem_vmm.h" |
|
|
} | } |
| |
| |
| static struct sos_umem_vmm_as * current_address_space = NULL; |
| struct sos_umem_vmm_as * sos_umem_vmm_get_current_as(void) |
| { |
| return current_address_space; |
| } |
| |
| |
| sos_ret_t sos_umem_vmm_set_current_as(struct sos_umem_vmm_as * as) |
| { |
| sos_ui32_t flags; |
| struct sos_umem_vmm_as *prev_as = current_address_space; |
| |
| if (current_address_space == as) |
| return SOS_OK; |
| |
| if (NULL != as) |
| { |
| sos_disable_IRQs(flags); |
| sos_process_ref(sos_umem_vmm_get_process(as)); |
| sos_mm_context_switch_to(sos_umem_vmm_get_mm_context(as)); |
| current_address_space = as; |
| sos_restore_IRQs(flags); |
| } |
| else |
| current_address_space = as; |
| |
| if (prev_as) |
| sos_process_unref(sos_umem_vmm_get_process(prev_as)); |
| |
| return SOS_OK; |
| } |
| |
| |
struct sos_umem_vmm_as * | struct sos_umem_vmm_as * |
sos_umem_vmm_create_empty_as(struct sos_process *owner) | sos_umem_vmm_create_empty_as(struct sos_process *owner) |
{ | { |
|
|
| |
| |
struct sos_umem_vmm_as * | struct sos_umem_vmm_as * |
sos_umem_vmm_duplicate_current_thread_as(struct sos_process *owner) | sos_umem_vmm_duplicate_as(struct sos_umem_vmm_as * model_as, |
| struct sos_process *for_owner) |
__label__ undo_creation; | __label__ undo_creation; |
struct sos_umem_vmm_as * my_as; | |
int nb_vr; | int nb_vr; |
| |
|
|
if (! new_as) | if (! new_as) |
return NULL; | return NULL; |
| |
my_as = sos_process_get_address_space(sos_thread_get_current()->process); | new_as->process = for_owner; |
new_as->process = owner; | |
| |
/* | /* |
|
|
* COW) | * COW) |
*/ | */ |
SOS_ASSERT_FATAL(SOS_OK | SOS_ASSERT_FATAL(SOS_OK |
== sos_thread_prepare_user_space_access(my_as, | == sos_thread_prepare_user_space_access(model_as, |
NULL)); | NULL)); |
| |
/* Copy the virtual regions */ | /* Copy the virtual regions */ |
list_foreach_named(my_as->list_vr, model_vr, nb_vr, prev_in_as, next_in_as) | list_foreach_named(model_as->list_vr, model_vr, nb_vr, prev_in_as, next_in_as) |
struct sos_umem_vmm_vr * vr; | struct sos_umem_vmm_vr * vr; |
| |
|
|
} | } |
| |
/* Now copy the current MMU configuration */ | /* Now copy the current MMU configuration */ |
new_as->mm_context = sos_mm_context_duplicate(my_as->mm_context); | new_as->mm_context = sos_mm_context_duplicate(model_as->mm_context); |
goto undo_creation; | goto undo_creation; |
| |
/* Correct behavior */ | /* Correct behavior */ |
new_as->heap_start = my_as->heap_start; | new_as->heap_start = model_as->heap_start; |
new_as->heap_size = my_as->heap_size; | new_as->heap_size = model_as->heap_size; |
new_as->phys_total = my_as->phys_total; | new_as->phys_total = model_as->phys_total; |
memcpy(& new_as->vm_total, & my_as->vm_total, sizeof(struct vm_usage)); | memcpy(& new_as->vm_total, & model_as->vm_total, sizeof(struct vm_usage)); |
memcpy(& new_as->vm_shrd, & my_as->vm_shrd, sizeof(struct vm_usage)); | memcpy(& new_as->vm_shrd, & model_as->vm_shrd, sizeof(struct vm_usage)); |
return new_as; | return new_as; |
| |
|
|
*/ | */ |
| |
/* Make sure the hint_uaddr hint is valid */ | /* Make sure the hint_uaddr hint is valid */ |
if (hint_uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(hint_uaddr, size) ) |
{ retval = -SOS_EINVAL; goto return_mmap; } | |
if (hint_uaddr > SOS_PAGING_TOP_USER_ADDRESS - size) | |
| |
/* Unmap any overlapped VR */ | /* Unmap any overlapped VR */ |
|
|
sos_uaddr_t uaddr, sos_size_t size) | sos_uaddr_t uaddr, sos_size_t size) |
{ | { |
struct sos_umem_vmm_vr *vr, *preallocated_vr; | struct sos_umem_vmm_vr *vr, *preallocated_vr; |
sos_bool_t need_to_setup_mmu; | |
| sos_bool_t need_to_change_address_space = FALSE; |
| |
if (! SOS_IS_PAGE_ALIGNED(uaddr)) | if (! SOS_IS_PAGE_ALIGNED(uaddr)) |
return -SOS_EINVAL; | return -SOS_EINVAL; |
|
|
size = SOS_PAGE_ALIGN_SUP(size); | size = SOS_PAGE_ALIGN_SUP(size); |
| |
/* Make sure the uaddr is valid */ | /* Make sure the uaddr is valid */ |
if (uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(uaddr, size) ) |
return -SOS_EINVAL; | |
if (uaddr > SOS_PAGING_TOP_USER_ADDRESS - size) | |
| |
/* In some cases, the unmapping might imply a VR to be split into | /* In some cases, the unmapping might imply a VR to be split into |
|
|
uaddr, size, vr->start, vr->size); | uaddr, size, vr->start, vr->size); |
} | } |
| |
need_to_setup_mmu = (sos_thread_get_current()->squatted_mm_context | /* When called from mresize, the address space is already squatted, |
!= as->mm_context); | so we don't have to change it again */ |
if (need_to_setup_mmu) | need_to_change_address_space |
| = (as != sos_thread_get_current()->squatted_address_space); |
| |
| if (need_to_change_address_space) |
== sos_thread_prepare_user_space_access(as, | == sos_thread_prepare_user_space_access(as, |
(sos_vaddr_t) | (sos_vaddr_t) |
NULL)); | NULL)); |
| |
| |
| /* Begin independent sub-block */ |
sos_ret_t sz_unmapped = sos_paging_unmap_interval(uaddr, size); | sos_ret_t sz_unmapped = sos_paging_unmap_interval(uaddr, size); |
SOS_ASSERT_FATAL(sz_unmapped >= 0); | SOS_ASSERT_FATAL(sz_unmapped >= 0); |
as->phys_total -= sz_unmapped; | as->phys_total -= sz_unmapped; |
} | } |
if (need_to_setup_mmu) | /* End independent sub-block */ |
| |
| if (need_to_change_address_space) |
| |
if (! used_preallocated_vr) | if (! used_preallocated_vr) |
|
|
size = SOS_PAGE_ALIGN_SUP(size); | size = SOS_PAGE_ALIGN_SUP(size); |
| |
/* Make sure the uaddr is valid */ | /* Make sure the uaddr is valid */ |
if (uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(uaddr, size) ) |
return -SOS_EINVAL; | |
if (uaddr > SOS_PAGING_TOP_USER_ADDRESS - size) | |
| |
/* Pre-allocate 2 new VRs (same reason as for unmap). Because chprot | /* Pre-allocate 2 new VRs (same reason as for unmap). Because chprot |
|
|
size = SOS_PAGE_ALIGN_SUP(size); | size = SOS_PAGE_ALIGN_SUP(size); |
| |
/* Make sure the uaddr is valid */ | /* Make sure the uaddr is valid */ |
if (uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(uaddr, size) ) |
return -SOS_EINVAL; | |
if (uaddr > SOS_PAGING_TOP_USER_ADDRESS - size) | |
| |
/* Go from page to page, and for each dirty page in the region, call | /* Go from page to page, and for each dirty page in the region, call |
|
|
struct sos_umem_vmm_vr *vr, *prev_vr, *next_vr; | struct sos_umem_vmm_vr *vr, *prev_vr, *next_vr; |
| |
/* Make sure the new uaddr is valid */ | /* Make sure the new uaddr is valid */ |
if (*new_uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(*new_uaddr, new_size) ) |
return -SOS_EINVAL; | |
if (*new_uaddr > SOS_PAGING_TOP_USER_ADDRESS - new_size) | |
| |
old_uaddr = SOS_PAGE_ALIGN_INF(old_uaddr); | old_uaddr = SOS_PAGE_ALIGN_INF(old_uaddr); |
|
|
must_move_vr |= TRUE; | must_move_vr |= TRUE; |
| |
/* If VR would be out-of-user-space, it must be moved */ | /* If VR would be out-of-user-space, it must be moved */ |
if (*new_uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(*new_uaddr, new_size) ) |
must_move_vr |= TRUE; | |
if (*new_uaddr > SOS_PAGING_TOP_USER_ADDRESS - new_size) | |
| |
/* The VR must be moved but the user forbids it */ | /* The VR must be moved but the user forbids it */ |
|
|
sos_bool_t write_access, | sos_bool_t write_access, |
sos_bool_t user_access) | sos_bool_t user_access) |
{ | { |
struct sos_process *process = sos_thread_get_current()->process; | |
struct sos_umem_vmm_vr *vr; | struct sos_umem_vmm_vr *vr; |
| |
if (! process) | as = current_address_space; |
return -SOS_EFAULT; | |
| |
as = sos_process_get_address_space(process); | |
return -SOS_EFAULT; | return -SOS_EFAULT; |
| |
|
|
struct sos_umem_vmm_vr *vr; | struct sos_umem_vmm_vr *vr; |
int nb_vr; | int nb_vr; |
| |
if (uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (! SOS_PAGING_IS_USER_AREA(uaddr, 1) ) |
return NULL; | |
if (uaddr > SOS_PAGING_TOP_USER_ADDRESS) | |
| |
list_foreach_named(as->list_vr, vr, nb_vr, prev_in_as, next_in_as) | list_foreach_named(as->list_vr, vr, nb_vr, prev_in_as, next_in_as) |
|
|
if (hint_uaddr < SOS_PAGING_BASE_USER_ADDRESS) | if (hint_uaddr < SOS_PAGING_BASE_USER_ADDRESS) |
hint_uaddr = SOS_PAGING_BASE_USER_ADDRESS; | hint_uaddr = SOS_PAGING_BASE_USER_ADDRESS; |
| |
if (hint_uaddr > SOS_PAGING_TOP_USER_ADDRESS - size + 1) | if (hint_uaddr > SOS_PAGING_UPPER_USER_ADDRESS - size + 1) |
| |
initial_vr = vr = find_enclosing_or_next_vr(as, hint_uaddr); | initial_vr = vr = find_enclosing_or_next_vr(as, hint_uaddr); |
|
|
/* No: wrapping up */ | /* No: wrapping up */ |
| |
/* Is there any space before the end of user space ? */ | /* Is there any space before the end of user space ? */ |
if (hint_uaddr <= SOS_PAGING_TOP_USER_ADDRESS - size) | if (hint_uaddr <= SOS_PAGING_UPPER_USER_ADDRESS - size) |
| |
hint_uaddr = SOS_PAGING_BASE_USER_ADDRESS; | hint_uaddr = SOS_PAGING_BASE_USER_ADDRESS; |
| |
/tmp/sos-code-article9.5/sos/umem_vmm.h (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/sos/umem_vmm.h (2006-03-19 12:21:03.000000000 +0100
) |
|
|
|
| |
| |
/** | /** |
| * Get the current effective address space. This may be the "normal" |
| * address space of the current thread, but not necessarilly: this |
| * might be the address space of just another process ! This may |
| * happen if a kernel thread of process P wants to access the address |
| * space of another process P2. This might also be NULL (no access to |
| * user space needed). |
| */ |
| struct sos_umem_vmm_as * sos_umem_vmm_get_current_as(void); |
| |
| |
| /** |
| * Change the current effective address space, eventually |
| * reconfiguring the MMU. This will increase the owning process's |
| * reference count of the given AS, and decrease that of the previous |
| * AS (when different). |
| * |
| * @param as may be NULL (no need to access user space) |
| */ |
| sos_ret_t sos_umem_vmm_set_current_as(struct sos_umem_vmm_as * as); |
| |
| |
| /** |
* Create a new, empty, address space | * Create a new, empty, address space |
* | * |
* @param owner The process that will own the new address space | * @param owner The process that will own the new address space |
|
|
| |
| |
/** | /** |
* Create a new address space, copy of the current thread's address | * Create a new address space, copy of the model_as address |
* marked 'read-only' to activate the "copy-on-write" semantics. | * marked 'read-only' to activate the "copy-on-write" semantics. |
* | * |
* @param owner The process that will hold the new address space | * @param model_as The address space to copy |
| * @param for_owner The process that will hold the new address space |
* @note automatically calls | * @note automatically calls |
* sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() | * sos_thread_prepare_user_space_access()/sos_thread_end_user_space_access() |
*/ | */ |
struct sos_umem_vmm_as * | struct sos_umem_vmm_as * |
sos_umem_vmm_duplicate_current_thread_as(struct sos_process *owner); | sos_umem_vmm_duplicate_as(struct sos_umem_vmm_as * model_as, |
| struct sos_process *for_owner); |
| |
/** | /** |
| |
/tmp/sos-code-article9.5/userland/crt.c (2006-01-22 12:48:31.000000000 +0100
) |
|
sos-code-article9.5/userland/crt.c (2006-03-19 12:21:04.000000000 +0100
) |
|
|
|
| |
#include <hwcore/swintr.h> | #include <hwcore/swintr.h> |
#include <string.h> | #include <string.h> |
| |
| #include "libc.h" /* putenv */ |
#include "crt.h" | #include "crt.h" |
| |
/** | /** |
| * Macro used to retrieve the 2 parameters passed to any new thread |
| * (architecture-dependent) |
| */ |
| #define GET_THREAD_PARAMETERS(param1, param2) \ |
| asm volatile ("movl %%eax, %0 ; movl %%ebx, %1" \ |
| : "=g"(param1), "=g"(param2) : : "%eax", "%ebx" ) |
| |
| |
| /** |
| * Helper function to retrieve the arg array from the parameter area |
| * sent by the parent. |
| * |
| * Format of the parent's args area: |
| * Number of arguments |
| * Offset of arg 0 (program's name) |
| * Offset of arg 1 |
| * ... |
| * Offset of arg N (last argument) |
| * NULL |
| * Offset of environnement variable 0 |
| * Offset of environnement variable 1 |
| * ... |
| * Offset of environnement variable N |
| * NULL |
| * Contents of arg 0 with terminal \0 |
| * Contents of arg 1 with terminal \0 |
| * ... |
| * Contents of arg N with terminal \0 |
| * Contents of env 0 with terminal \0 |
| * Contents of env 1 with terminal \0 |
| * ... |
| * Contents of env N with terminal \0 |
| * |
| * This function simply transforms the N offsets into the real |
| * addresses of the arg X contents (ie it simply adds the base address |
| * of the area). |
| */ |
| static void unmarshall_argv_envp(void * args, |
| int * argc, |
| const char ** * argv, |
| const char ** * envp) |
| { |
| addr_t * offset = (addr_t*) args; |
| *argc = 0; |
| *argv = NULL; |
| |
| offset = args; |
| |
| /* Get argc */ |
| *argc = * (int*) offset; |
| offset ++; |
| |
| /* Get base of argv */ |
| *argv = (const char **) offset; |
| |
| /* Walk the offsets array and transform these offsets into memory |
| addresses */ |
| for ( ; 0 != *offset ; offset ++) |
| *offset += (addr_t) args; |
| |
| /* Skip the NULL separating argv from envp */ |
| offset ++; |
| |
| /* Get base of envp */ |
| *envp = (const char **) offset; |
| |
| /* Walk the offsets array and transform these offsets into memory |
| addresses */ |
| for ( ; 0 != *offset ; offset ++) |
| { |
| *offset += (addr_t) args; |
| |
| /* Register this environment variable */ |
| putenv((char*) *offset); |
| } |
| } |
| |
| |
| /** |
* Starter function ! | * Starter function ! |
*/ | */ |
void _start(void) __attribute__((noreturn)); | /** Function called by crt_asm.S:_start to start user program */ |
void _start(void) | void _cmain(const char* arg_env_area[]) __attribute__((noreturn)); |
| void _cmain(const char* arg_env_area[]) |
| |
| /* Will hold the parameters that will be passed to main */ |
| const char** argv; |
| const char** envp; |
| int argc; |
| |
| |
/* This starter function expects a main() function somewhere */ | /* This starter function expects a main() function somewhere */ |
extern int main(void); | extern int main(int argc, char const* argv[], |
| char const* envp[]); |
/* Reset the bss section */ | /* Setup the arguments list and the environment variables */ |
extern char _bbss, _ebss; | unmarshall_argv_envp (arg_env_area, & argc, & argv, & envp); |
memset(& _bbss, 0x0, (& _ebss) - (& _bbss)); | |
_sos_exit(main()); | _sos_exit(main(argc, argv, envp)); |
| |
| |
|
|
} | } |
| |
| |
int _sos_exec(const char * prog) | int _sos_getpid() |
| { |
| return _sos_syscall0(SOS_SYSCALL_ID_GETPID); |
| } |
| |
| |
| int _sos_exec(const char * prog, |
| void const* args, |
| size_t arglen) |
return _sos_syscall2(SOS_SYSCALL_ID_EXEC, (unsigned int)prog, | return _sos_syscall4(SOS_SYSCALL_ID_EXEC, (unsigned int)prog, |
(unsigned int)strlen(prog)); | (unsigned int)strlen(prog), |
| (unsigned int)args, |
| (unsigned int)arglen); |
| |
| |
|
|
*/ | */ |
static void thread_routine(void) | static void thread_routine(void) |
{ | { |
/* NOTE: variables as named registers is a gcc extension */ | sos_thread_func_t * func; |
register unsigned long int reg_arg1 asm("%eax"); | unsigned long int arg; |
register unsigned long int reg_arg2 asm("%ebx"); | |
sos_thread_func_t * func = (sos_thread_func_t*)reg_arg1; | GET_THREAD_PARAMETERS(func, arg); |
unsigned long int arg = reg_arg2; | |
func(arg); | func(arg); |
_sos_exit(0); | _sos_exit(0); |
| |
/tmp/sos-code-article9.5/userland/libc.c (2006-01-22 12:48:32.000000000 +0100
) |
|
sos-code-article9.5/userland/libc.c (2006-03-19 12:21:04.000000000 +0100
) |
|
|
|
} | } |
| |
| |
int exec(const char *progname) | pid_t getpid() |
return _sos_exec(progname); | return _sos_getpid(); |
| } |
| |
| |
| /** |
| * Helper to transform the array of argv and envp into an area |
| * suitable for the crt.c:unmarshall_argv_envp() function. |
| * @see crt.c for the format of this array. |
| */ |
| static void const* marshall_execve_parameters(char* const argv[], |
| char* const envp[], |
| /*out*/size_t * sz) |
| { |
| size_t i, i_offset, count_argv, count_envp, size; |
| char * str; |
| void * result; |
| addr_t * offset; |
| |
| *sz = 0; |
| |
| /* Count the number of argv parameters and the size to allocate */ |
| for (count_argv = 0, size = 0 ; argv && argv[count_argv] != NULL ; count_argv ++) |
| size += strlen(argv[count_argv]) + 1 /* trailing \0 */; |
| |
| /* Count the number of envp parameters and the size to allocate */ |
| for (count_envp = 0 ; envp && envp[count_envp] != NULL ; count_envp ++) |
| size += strlen(envp[count_envp]) + 1 /* trailing \0 */; |
| |
| size += (count_argv + count_envp + 3) * sizeof(addr_t); |
| result = malloc(size); |
| if (NULL == result) |
| return NULL; |
| |
| /* Build the array of offsets and the string contents */ |
| offset = (addr_t*)result; |
| str = (char*) & offset[count_argv + count_envp + 3]; |
| i_offset = 0; |
| |
| /* First element of the array is the number of argv entries */ |
| offset [i_offset++] = count_argv; |
| |
| /* Marshall the argv array */ |
| for (i = 0 ; i < count_argv ; i ++, i_offset ++) |
| { |
| char const* c; |
| |
| offset[i_offset] = (void*)str - result; |
| |
| for (c = argv[i] ; *c ; c ++, str ++) |
| *str = *c; |
| *str = '\0'; str ++; |
| } |
| |
| /* The NULL between argv and envp */ |
| offset [i_offset++] = 0; |
| |
| for (i = 0 ; i < count_envp ; i ++, i_offset ++) |
| { |
| char const* c; |
| |
| offset[i_offset] = (void*)str - result; |
| |
| for (c = envp[i] ; *c ; c ++, str ++) |
| *str = *c; |
| *str = '\0'; str ++; |
| } |
| |
| /* Final NULL */ |
| offset[count_argv + count_envp + 2] = 0; |
| *sz = size; |
| |
| return result; |
| } |
| |
| |
| int execve(const char *filename, |
| char *const argv [], |
| char *const envp[]) |
| { |
| void const* args_area; |
| size_t args_sz; |
| int retval; |
| |
| args_area = marshall_execve_parameters(argv, envp, & args_sz); |
| |
| retval = _sos_exec(filename, |
| args_area, args_sz); |
| |
| if (NULL != args_area) |
| free((void*)args_area); |
| |
| return retval; |
| } |
| |
| |
| int execv(const char * filename, |
| char * const argv []) |
| { |
| return execve(filename, argv, environ); |
| } |
| |
| |
| static int compute_nargs(va_list ap) |
| { |
| int nargs = 0; |
| while (va_arg(ap, char*)) |
| nargs ++; |
| return nargs; |
| } |
| |
| |
| static int vexec(const char *path, va_list ap, int envp_in_list) |
| { |
| int retval; |
| char ** vector, **entry; |
| char *str; |
| char ** envp; |
| |
| size_t nargs = compute_nargs(ap); |
| |
| /* Allocate the char* vector */ |
| vector = malloc((nargs + 1)*sizeof(char*)); |
| if (! vector) |
| return -1; |
| |
| /* Fill it */ |
| entry = vector; |
| while ((str = va_arg(ap, char*)) != NULL) |
| { |
| *entry = str; |
| entry ++; |
| } |
| *entry = NULL; |
| |
| if (envp_in_list) |
| envp = (char**)va_arg(ap, char*); |
| else |
| envp = environ; |
| |
| retval = execve(path, vector, envp); |
| free(vector); |
| return retval; |
| } |
| |
| |
| int execl(const char *path, ...) |
| { |
| int retval; |
| va_list ap; |
| va_start(ap, path); |
| retval = vexec(path, ap, FALSE); |
| va_end(ap); |
| return retval; |
| } |
| |
| |
| int execle(const char *path, ...) |
| { |
| int retval; |
| va_list ap; |
| va_start(ap, path); |
| retval = vexec(path, ap, TRUE); |
| va_end(ap); |
| return retval; |
| } |
| |
| |
| int exec(char * const filename) |
| { |
| return execl(filename, filename, NULL); |
| |
| |
|
|
} | } |
| |
| |
| /** |
| * Max number of environment variables |
| */ |
| #define SOS_MAX_ENVVARS 1024 |
| |
| char **environ = NULL; |
| |
| |
| /** |
| * Compare the keys of two strings of the form "key=val" |
| */ |
| static int equal_key(const char *e1, |
| const char *e2) |
| { |
| for ( ; e1 && (*e1) && e2 && (*e2) && (*e1 == *e2) ; e1++, e2++) |
| if (*e1 == '=') |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| |
| /** |
| * Helper function to register an environment variable |
| */ |
| static int registerenv(char * string, int can_overwrite) |
| { |
| int i; |
| char ** overwritten; |
| |
| /* The first time: allocate the environ table */ |
| if (! environ) |
| { |
| environ = malloc(SOS_MAX_ENVVARS * sizeof(char*)); |
| if (! environ) |
| return 0; |
| |
| memset(environ, 0x0, SOS_MAX_ENVVARS * sizeof(char*)); |
| } |
| |
| /* Walk the environment variables */ |
| overwritten = NULL; |
| for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) |
| { |
| /* Reached end of list ? */ |
| if (! environ[i]) |
| break; |
| |
| /* Variable already present ? */ |
| if (equal_key(environ[i], string)) |
| overwritten = & environ[i]; |
| } |
| |
| if (overwritten) |
| { |
| /* Not allowed to overwrite it ! */ |
| if (! can_overwrite) |
| return -1; |
| |
| /* Overwrite allowed: do it now */ |
| free(*overwritten); |
| *overwritten = string; |
| return 0; |
| } |
| |
| /* Must add the variable */ |
| |
| /* No place left ? */ |
| if (i >= SOS_MAX_ENVVARS) |
| return -1; |
| |
| /* Ok, add it at the end */ |
| environ[i] = string; |
| return 0; |
| } |
| |
| |
| /** |
| * @return TRUE when the key of the "keyvalpair" pair is "key" |
| */ |
| static int key_is(char * keyvalpair, const char * key, |
| char ** /*out*/value) |
| { |
| for ( ; keyvalpair && *keyvalpair && key && *key ; keyvalpair ++, key ++) |
| if (*key != *keyvalpair) |
| break; |
| |
| if (value) |
| *value = keyvalpair + 1; |
| |
| return (keyvalpair && (*keyvalpair == '=') && key && (*key == '\0')); |
| } |
| |
| |
| int putenv(char * string) |
| { |
| char * str; |
| if (! string) |
| return -1; |
| |
| str = strdup(string); |
| if (! str) |
| return -1; |
| |
| return registerenv(string, TRUE); |
| } |
| |
| |
| int setenv(const char *name, const char *value, int overwrite) |
| { |
| char * str, * c; |
| size_t sz_name, sz_value; |
| |
| if (!name || !value) |
| return -1; |
| |
| /* Allocate space for the "name=value" string */ |
| sz_name = strlen(name); |
| sz_value = strlen(value); |
| str = malloc(sz_name + 1 + sz_value + 1); |
| if (! str) |
| return -1; |
| |
| /* sprintf(str, "%s=%s", name, value); */ |
| c = str; |
| *c = '\0'; |
| strzcpy(c, name, sz_name+1); c += sz_name; |
| strzcpy(c, "=", 2); c += 1; |
| strzcpy(c, value, sz_value+1); |
| |
| return registerenv(str, overwrite); |
| } |
| |
| |
| char *getenv(const char *name) |
| { |
| int i; |
| |
| if (! environ) |
| return NULL; |
| |
| for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) |
| { |
| char *value; |
| |
| /* Reached end of list ? */ |
| if (! environ[i]) |
| return NULL; |
| |
| /* Variable already present ? */ |
| if (key_is(environ[i], name, & value)) |
| return value; |
| } |
| |
| return NULL; |
| } |
| |
| |
| void unsetenv(const char *name) |
| { |
| int i; |
| char ** entry, ** last_entry; |
| |
| if (! environ) |
| return; |
| |
| /* Walk the environment variables */ |
| entry = last_entry = NULL; |
| for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) |
| { |
| /* Reached end of list ? */ |
| if (! environ[i]) |
| break; |
| |
| /* Variable already present ? */ |
| if (key_is(environ[i], name, NULL)) |
| entry = & environ[i]; |
| else if (entry) |
| last_entry = & environ[i]; |
| } |
| |
| /* Found nothing ! */ |
| if (! entry) |
| return; |
| |
| /* Found it: erase it... */ |
| free(*entry); |
| *entry = NULL; |
| |
| /* ... and replace it with the last entry */ |
| if (last_entry) |
| { |
| *entry = *last_entry; |
| *last_entry = NULL; |
| } |
| } |
| |
| |
| int clearenv(void) |
| { |
| int i; |
| |
| if (! environ) |
| return 0; |
| |
| for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) |
| { |
| if (! environ[i]) |
| break; |
| |
| free(environ[i]); |
| environ[i] = NULL; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
int munmap(void * start, size_t length) | int munmap(void * start, size_t length) |
{ | { |
| |