| /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) |
| { | { |
| | |