/tmp/sos-code-article9.5/drivers/mem.c (2006-01-22 12:48:28.000000000 +0100 )
sos-code-article9.5/drivers/mem.c (2006-03-19 12:21:04.000000000 +0100 )
Line 91 
Line 91 
     + sos_umem_vmm_get_offset_in_resource(vr);     + sos_umem_vmm_get_offset_in_resource(vr);
  
   /* Don't allow demand paging of non kernel pages */   /* Don't allow demand paging of non kernel pages */
   if (vaddr >= SOS_PAGING_BASE_USER_ADDRESS)   if (! SOS_PAGING_IS_KERNEL_AREA(vaddr, 1))
  
   /* Lookup physical kernel page */   /* Lookup physical kernel page */
  
 

/tmp/sos-code-article9.5/extra/bootsect.S (2006-01-22 12:48:28.000000000 +0100 )
sos-code-article9.5/extra/bootsect.S (2006-03-19 12:21:00.000000000 +0100 )
Line 1 
Line 1 
  
 /* /*
  * @(#) $Id: bootsect.S,v 1.12 2005/08/13 13:47:31 d2 Exp $  * @(#) $Id: bootsect.S 1310 2005-08-13 13:47:31Z d2 $
  * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty  * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty
  *           Jerome Petazzoni & Bernard Cassagne & coffeeman  *           Jerome Petazzoni & Bernard Cassagne & coffeeman
  
 

/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 )
(New file) 
Line 1 
  /* 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 )
(New file) 
Line 1 
  /* 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/hwcore/paging.c (2006-01-22 12:48:30.000000000 +0100 )
sos-code-article9.5/hwcore/paging.c (2006-03-19 12:21:02.000000000 +0100 )
Line 954 
Line 954 
 { {
   SOS_ASSERT_FATAL(SOS_IS_PAGE_ALIGNED(base_address));   SOS_ASSERT_FATAL(SOS_IS_PAGE_ALIGNED(base_address));
   SOS_ASSERT_FATAL(SOS_IS_PAGE_ALIGNED(length));   SOS_ASSERT_FATAL(SOS_IS_PAGE_ALIGNED(length));
   SOS_ASSERT_FATAL(SOS_PAGING_BASE_USER_ADDRESS <= base_address);   SOS_ASSERT_FATAL(SOS_PAGING_IS_USER_AREA(base_address, length));
   /* Mark all the pages read-only, when already mapped in physical   /* Mark all the pages read-only, when already mapped in physical
      memory */      memory */
  
 

/tmp/sos-code-article9.5/hwcore/paging.h (2006-01-22 12:48:30.000000000 +0100 )
sos-code-article9.5/hwcore/paging.h (2006-03-19 12:21:02.000000000 +0100 )
Line 40 
Line 40 
  
 /** /**
  * Basic SOS virtual memory organization  * Basic SOS virtual memory organization
  */  *
 /** Frontier between kernel and user space virtual addresses */  * - Kernel space starts at the lower 4kB address (first page is not
 #define SOS_PAGING_BASE_USER_ADDRESS (0x40000000) /* 1GB (must be 4MB-aligned) */  *   mapped in order to catch invalid pointers)
 #define SOS_PAGING_TOP_USER_ADDRESS  (0xFFFFFFFF) /* 4GB - 1B */  * - User space starts at the 1GB address
 #define SOS_PAGING_USER_SPACE_SIZE   (0xc0000000) /* 3GB */  */
  #define SOS_PAGING_BASE_USER_ADDRESS   (0x40000000) /* 1GB (must be 4MB-aligned) */
  #define SOS_PAGING_UPPER_USER_ADDRESS  (0xFFFFFFFF) /* 4GB - 1B */
  #define SOS_PAGING_USER_SPACE_SIZE     (SOS_PAGING_UPPER_USER_ADDRESS - \
                                          SOS_PAGING_BASE_USER_ADDRESS + 1) /* 3GB */
  #define SOS_PAGING_IS_USER_AREA(base_addr, length) \
    ( (SOS_PAGING_BASE_USER_ADDRESS <= (base_addr))  \
        && ((length) <= SOS_PAGING_USER_SPACE_SIZE) )
 /** Length of the space reserved for the mirroring in the kernel /** Length of the space reserved for the mirroring in the kernel
     virtual space */     virtual space */
Line 54 
Line 61 
 #define SOS_PAGING_MIRROR_VADDR \ #define SOS_PAGING_MIRROR_VADDR \
    (SOS_PAGING_BASE_USER_ADDRESS - SOS_PAGING_MIRROR_SIZE)    (SOS_PAGING_BASE_USER_ADDRESS - SOS_PAGING_MIRROR_SIZE)
  
  #define SOS_PAGING_BASE_KERNEL_ADDRESS  (0x00004000) /* 16kB */
  #define SOS_PAGING_UPPER_KERNEL_ADDRESS (SOS_PAGING_MIRROR_VADDR - 1) /* 1GB - 4MB - 1B */
  #define SOS_PAGING_KERNEL_SPACE_SIZE    (SOS_PAGING_UPPER_KERNEL_ADDRESS - \
                                           SOS_PAGING_BASE_KERNEL_ADDRESS + 1) /* 1GB - 4MB - 16kB */
  #define SOS_PAGING_IS_KERNEL_AREA(base_addr, length) \
    ( (SOS_PAGING_BASE_KERNEL_ADDRESS <= (base_addr))  \
        && ((length) <= SOS_PAGING_KERNEL_SPACE_SIZE) )
  
  
 /** /**
  * sos_paging_map flags  * sos_paging_map flags
  
 

/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 )
Line 22 
Line 22 
 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/binfmt_elf32.c (2006-01-22 12:48:30.000000000 +0100 )
sos-code-article9.5/sos/binfmt_elf32.c (2006-03-19 12:21:03.000000000 +0100 )
Line 386 
Line 386 
           continue;           continue;
         }         }
              
       if (elf_phdrs[i].p_vaddr < SOS_PAGING_BASE_USER_ADDRESS)       if (! SOS_PAGING_IS_USER_AREA(elf_phdrs[i].p_vaddr,
                                      elf_phdrs[i].p_memsz) )
           sos_display_fatal_error("User program has an incorrect address");           sos_display_fatal_error("User program has an incorrect address");
         }         }
  
 

/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 )
Line 31 
Line 31 
 #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/fs.c (2006-01-22 12:48:30.000000000 +0100 )
sos-code-article9.5/sos/fs.c (2006-03-19 12:21:03.000000000 +0100 )
Line 22 
Line 22 
 #include <sos/list.h> #include <sos/list.h>
 #include <sos/kmem_slab.h> #include <sos/kmem_slab.h>
 #include <sos/kmalloc.h> #include <sos/kmalloc.h>
  #include <sos/syscall.h> /* For the FCNTL commands */
 #include "chardev.h" #include "chardev.h"
  
 #include "fs.h" #include "fs.h"
Line 1221 
Line 1222 
                        sos_ui32_t req_arg /* Usually: sos_uaddr_t */)                        sos_ui32_t req_arg /* Usually: sos_uaddr_t */)
 { {
   if (! of->ops_file->fcntl)   if (! of->ops_file->fcntl)
     return -SOS_ENOSYS;     return sos_fs_basic_fcntl_helper(of, req_id, req_arg);
   return of->ops_file->fcntl(of, req_id, req_arg);   return of->ops_file->fcntl(of, req_id, req_arg);
 } }
Line 1950 
Line 1951 
 } }
  
  
  /* *************************************************************
   * client FS helper functions
   */
  sos_ret_t sos_fs_basic_fcntl_helper(struct sos_fs_opened_file * of,
                                      int req_id, sos_ui32_t req_arg)
  {
    sos_ret_t result = -SOS_ENOSUP;
  
    switch(req_id)
      {
      case SOS_FCNTL_DUPFD:
        {
          result = sos_fs_ref_opened_file(of);
          if (SOS_OK != result)
            break;
  
          result = sos_process_register_opened_file((struct sos_process*)of->owner,
                                                    of, req_arg);
        }
        break;
  
      case SOS_FCNTL_GETFD:
        {
          result = of->open_flags & SOS_FS_OPEN_CLOSEONEXEC;
        }
        break;
  
      case SOS_FCNTL_SETFD:
        {
          of->open_flags &= ~SOS_FS_OPEN_CLOSEONEXEC;
          of->open_flags |= (req_arg & SOS_FS_OPEN_CLOSEONEXEC);
          result = SOS_OK;
        }
        break;
  
      case SOS_FCNTL_GETFL:
        {
          result = of->open_flags;
        }
        break;
  
      case SOS_FCNTL_SETFL:
        {
          /* Not supported */
        }
        break;
  
      default:
        break;
      }
  
    return result;
  }
  
  
 /* ************************************************************* /* *************************************************************
  * mount/umount stuff  * mount/umount stuff
  
 

/tmp/sos-code-article9.5/sos/fs.h (2006-01-22 12:48:30.000000000 +0100 )
sos-code-article9.5/sos/fs.h (2006-03-19 12:21:03.000000000 +0100 )
Line 1123 
Line 1123 
                                        const struct sos_process * dst_proc,                                        const struct sos_process * dst_proc,
                                        struct sos_fs_opened_file ** result_of);                                        struct sos_fs_opened_file ** result_of);
  
  /**
   * Generic fcntl function that can be called from inside the FS's
   * fcntl method. It will handle the following fcntl commands:
   *    - F_DUPFD
   *    - F_GETFD
   *    - F_SETFD
   *    - F_GETFL
   *    - F_SETFL
   * Any other command will lead to a -SOS_ENOSUP return value.
   * It will take care not to change anything besides the fs.h structures.
   */
  sos_ret_t sos_fs_basic_fcntl_helper(struct sos_fs_opened_file * src_of,
                                      int req_id, sos_ui32_t req_arg);
 #endif /* _SOS_FS_H_ */ #endif /* _SOS_FS_H_ */
  
 

/tmp/sos-code-article9.5/sos/hash.c (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/sos/hash.c (2006-03-19 12:21:03.000000000 +0100 )
Line 66 
Line 66 
  
   /** Number of buckets in this hash table */   /** Number of buckets in this hash table */
   sos_count_t              nbuckets;   sos_count_t              nbuckets;
  
    /** Number of elements currently in the hash */
    sos_count_t              nb_elems;
      
   struct bucket bucket[0];   struct bucket bucket[0];
 }; };
Line 118 
Line 121 
 } }
  
  
  sos_count_t sos_hash_get_nb_elts(const struct sos_hash_table * h)
  {
    return h->nb_elems;
  }
  
  
 sos_ret_t sos_hash_dispose(struct sos_hash_table *h) sos_ret_t sos_hash_dispose(struct sos_hash_table *h)
 { {
   unsigned int i;   unsigned int i;
Line 156 
Line 165 
  
   list_add_head_named(h->bucket[bucket].list, h_elt, h_prev, h_next);   list_add_head_named(h->bucket[bucket].list, h_elt, h_prev, h_next);
   h->bucket[bucket].nb_elems ++;   h->bucket[bucket].nb_elems ++;
    h->nb_elems ++;
  
   return SOS_OK;   return SOS_OK;
 } }
Line 215 
Line 225 
  
   list_delete_named(h->bucket[bucket].list, h_elt, h_prev, h_next);   list_delete_named(h->bucket[bucket].list, h_elt, h_prev, h_next);
   h->bucket[bucket].nb_elems --;   h->bucket[bucket].nb_elems --;
    h->nb_elems --;
  
   return SOS_OK;   return SOS_OK;
 } }
  
  
  sos_bool_t sos_hash_walk(const struct sos_hash_table *h,
                           sos_hash_map_func_t * iter_func,
                           void * custom_data)
  {
    unsigned int i;
    for (i = 0 ; i < h->nbuckets ; i++)
      {
        sos_count_t nelts;
        struct sos_hash_linkage * elt;
  
        list_foreach_forward_named(h->bucket[i].list, elt,
                                   nelts, h_prev, h_next)
          {
            if (! iter_func(custom_data,
                            elt_for_h_linkage(h, elt)))
              return FALSE;
          }
      }
  
    return TRUE;
  }
  
  
 unsigned long sos_hash_ui64(const void * ptr_key) unsigned long sos_hash_ui64(const void * ptr_key)
 { {
   const sos_ui64_t * keyval = ptr_key;   const sos_ui64_t * keyval = ptr_key;
  
 

/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 )
Line 41 
Line 41 
 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;
  
Line 57 
Line 62 
  *  *
  * @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),     \
  
  
Line 90 
Line 97 
                       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);
  
Line 116 
Line 127 
                           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/kmem_vmm.h (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/sos/kmem_vmm.h (2006-03-19 12:21:03.000000000 +0100 )
Line 30 
Line 30 
 #include <hwcore/paging.h> #include <hwcore/paging.h>
  
 /* The base and top virtual addresses covered by the kernel allocator */ /* The base and top virtual addresses covered by the kernel allocator */
 #define SOS_KMEM_VMM_BASE 0x4000 /* 16kB */ #define SOS_KMEM_VMM_BASE SOS_PAGING_BASE_KERNEL_ADDRESS      /* 16kB */
 #define SOS_KMEM_VMM_TOP  SOS_PAGING_MIRROR_VADDR /* 1GB - 4MB */ #define SOS_KMEM_VMM_TOP  (SOS_PAGING_UPPER_KERNEL_ADDRESS+1) /* 1GB - 4MB */
 /** Opaque structure used internally and declared here for physmem.h */ /** Opaque structure used internally and declared here for physmem.h */
 struct sos_kmem_range; struct sos_kmem_range;
  
 

/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 )
Line 110 
Line 110 
       || (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 ==
Line 136 
Line 137 
           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",
Line 148 
Line 149 
       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;
     }     }
Line 292 
Line 293 
   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 */
Line 339 
Line 342 
     }     }
  
  
  
   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)
Line 349 
Line 351 
     }     }
  
   /* 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);
Line 359 
Line 361 
       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 )
Line 21 
Line 21 
 #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>
  
Line 40 
Line 42 
 { {
   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;
  
Line 60 
Line 65 
   /** 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 */
Line 78 
Line 98 
 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,
Line 103 
Line 124 
                              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");
 } }
Line 111 
Line 137 
  
 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),
Line 118 
Line 145 
                                                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;
 } }
  
Line 132 
Line 243 
   sos_ui32_t flags;   sos_ui32_t flags;
   struct sos_process *proc;   struct sos_process *proc;
  
  
   if (! proc)   if (! proc)
     return NULL;     return NULL;
Line 170 
Line 280 
     }     }
  
   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);
  
Line 194 
Line 309 
  
   /* 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)
     {     {
Line 238 
Line 352 
 } }
  
  
  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;
Line 339 
Line 459 
  
 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;
Line 417 
Line 540 
       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/process.h (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/sos/process.h (2006-03-19 12:21:03.000000000 +0100 )
Line 52 
Line 52 
 #define SOS_DEFAULT_USER_STACK_SIZE (8 << 20) #define SOS_DEFAULT_USER_STACK_SIZE (8 << 20)
  
  
  /** Number of pages for the pid bitmap (1 page = 32k PIDs) */
  #define SOS_PROCESS_PID_BITMAP_NPAGES  1
  
  
 /** /**
  * Initialization of the process subsystem  * Initialization of the process subsystem
  */  */
Line 93 
Line 97 
  
  
 /** /**
   * Return the PID of the process
   */
  sos_pid_t sos_process_get_pid(const struct sos_process *proc);
  
  
  /**
  * Return the number of threads currently registered in the process  * Return the number of threads currently registered in the process
  */  */
 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);
Line 169 
Line 179 
  */  */
 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);
  
 /** /**
  
 

/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 )
Line 20 
Line 20 
 #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>
Line 46 
Line 45 
 { {
   sos_ret_t retval;   sos_ret_t retval;
  
  
   switch(syscall_id)   switch(syscall_id)
     {     {
     case SOS_SYSCALL_ID_EXIT:     case SOS_SYSCALL_ID_EXIT:
Line 82 
Line 82 
           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);
Line 95 
Line 95 
         /* 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;
  
Line 105 
Line 117 
         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;
  
Line 119 
Line 133 
           }           }
  
         /* 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)
Line 151 
Line 174 
  
         /* 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);
Line 163 
Line 187 
             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);
Line 188 
Line 226 
           {           {
             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 */
Line 297 
Line 335 
       }       }
       break;       break;
  
  
     case SOS_SYSCALL_ID_MSYNC:     case SOS_SYSCALL_ID_MSYNC:
       {       {
         sos_uaddr_t start_uaddr;         sos_uaddr_t start_uaddr;
Line 322 
Line 361 
       }       }
       break;       break;
  
  
     case SOS_SYSCALL_ID_NEW_THREAD:     case SOS_SYSCALL_ID_NEW_THREAD:
       {       {
         sos_uaddr_t start_func;         sos_uaddr_t start_func;
Line 593 
Line 633 
         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);
Line 1437 
Line 1477 
       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 )
Line 29 
Line 29 
 /** /**
  * 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 */
  
 /** /**
Line 42 
Line 42 
 /** /**
  * 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 */
Line 72 
Line 73 
 #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 )
Line 70 
Line 70 
 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);
Line 361 
Line 353 
       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); 
  
  
Line 386 
Line 377 
  
   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)
Line 780 
Line 770 
  */  */
  
  
 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)
Line 823 
Line 785 
  
       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);
Line 852 
Line 811 
   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/thread.h (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/sos/thread.h (2006-03-19 12:21:03.000000000 +0100 )
Line 126 
Line 126 
    * This is the SOS implementation of the Linux "Lazy TLB" and    * This is the SOS implementation of the Linux "Lazy TLB" and
    * address-space loaning.    * address-space loaning.
    */    */
   struct sos_mm_context *squatted_mm_context;   struct sos_umem_vmm_as *squatted_address_space;
   /* Data specific to each state */   /* Data specific to each state */
   union   union
Line 349 
Line 349 
  * @param dest_as The address space we want to access, or NULL to  * @param dest_as The address space we want to access, or NULL to
  * access current thread's address space  * access current thread's address space
  *  *
  * @param fixup_retvaddr When != 0, then dest_as MUST BE NULL (we  * @param fixup_retvaddr When != 0, the page fault handler should
  * don't allow controlled access from kernel into user space from a  * accept page faults from the kernel in user space, and resolve them
  * foreign thread). In this case, the page fault handler should accept  * in the usual way. The value in retvaddr is where the page fault
  * page faults from the kernel in user space, and resolve them in the  * handler has to return to in case the page fault remains
  * usual way. The value in retvaddr is where the page fault handler  * unresolved. The address of the faulting address is kept in
  * has to return to in case the page fault remains unresolved. The 
  * address of the faulting address is kept in 
  *  *
  * @note typical values for fixup_retvaddr are obtained by "Labels as  * @note typical values for fixup_retvaddr are obtained by "Labels as
  
 

/tmp/sos-code-article9.5/sos/types.h (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/sos/types.h (2006-03-19 12:21:03.000000000 +0100 )
Line 49 
Line 49 
 /** Generic count of objects (LARGE) */ /** Generic count of objects (LARGE) */
 typedef unsigned long long int sos_lcount_t; typedef unsigned long long int sos_lcount_t;
  
  /** Process identifiers */
  typedef unsigned int           sos_pid_t;
  
 /* Low-level sizes */ /* Low-level sizes */
 typedef unsigned long long int sos_ui64_t; /**< 32b unsigned */ typedef unsigned long long int sos_ui64_t; /**< 32b unsigned */
 typedef unsigned long int      sos_ui32_t; /**< 32b unsigned */ typedef unsigned long int      sos_ui32_t; /**< 32b unsigned */
  
 

/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 )
Line 34 
Line 34 
  ({ 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)
Line 50 
Line 56 
   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;
Line 103 
Line 109 
                                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);
  
  
Line 144 
Line 151 
                              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;
  
  
Line 167 
Line 254 
     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)
Line 252 
Line 335 
 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);
 } }
Line 267 
Line 353 
 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 )
Line 27 
Line 27 
  
 #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
Line 55 
Line 55 
  
  
 /** /**
  * 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.
Line 67 
Line 67 
  
  
 /** /**
   * 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 )
Line 23 
Line 23 
 #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"
Line 230 
Line 231 
 } }
  
  
  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)
 { {
Line 252 
Line 286 
  
  
 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;
  
Line 264 
Line 298 
   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; 
  
   /*   /*
Line 274 
Line 307 
    * 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;
  
Line 315 
Line 348 
     }     }
  
   /* 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;
  
Line 555 
Line 588 
        */        */
  
       /* 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 */
Line 712 
Line 743 
                    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;
Line 722 
Line 753 
   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
Line 875 
Line 904 
                               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)
Line 913 
Line 950 
   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
Line 1224 
Line 1259 
   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
Line 1287 
Line 1320 
   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);
Line 1347 
Line 1378 
     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 */
Line 1464 
Line 1493 
                                               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;
  
Line 1590 
Line 1615 
   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)
Line 1632 
Line 1655 
   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);
Line 1658 
Line 1681 
           /* 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 )
Line 285 
Line 285 
  
  
 /** /**
   * 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
Line 297 
Line 319 
  
  
 /** /**
  * 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_asm.S (1970-01-01 01:00:00.000000000 +0100 )
sos-code-article9.5/userland/crt_asm.S (2006-03-19 12:21:04.000000000 +0100 )
(New file) 
Line 1 
  /* 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.
  */
  #define ASM_SOURCE 1
  
  .file "crt_asm.S"
  
  .text
  
  /* The function to call: "C" code start routine (defined in crt.c) */
  .extern _cmain
  
  /* User program entry point */
  .globl _start
          .type   _start, @function
  _start:
          pushl %esp
          call _cmain /* Hello "C" world ! */
          addl $4, %esp
  
          /* We should never reach this line */
          lcall *0 /* Crash the process */
  
 

/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 )
Line 27 
Line 27 
  
 #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));
  
  
Line 189 
Line 278 
 } }
  
  
 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);
  
  
Line 244 
Line 343 
  */  */
 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/crt.h (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/userland/crt.h (2006-03-19 12:21:04.000000000 +0100 )
Line 105 
Line 105 
  */  */
 int _sos_bochs_write(const char *str, unsigned length); int _sos_bochs_write(const char *str, unsigned length);
  
  
 /** /**
  * Syscall to duplicate the current running process  * Syscall to duplicate the current running process
  */  */
Line 112 
Line 113 
  
  
 /** /**
   * Syscall to retrieved the current process's PID
   */
  int _sos_getpid(void);
  
  
  /**
  * Syscall to re-initialize the address space of the current process  * Syscall to re-initialize the address space of the current process
  * with that of the program 'progname'  * with that of the program 'progname'
  */  *
 int _sos_exec(const char * prog);  * The args argument is the address of an array that contains the
   * arguments and environnement variables for the new process.
   */
  int _sos_exec(const char * prog,
                void const* args,
                size_t arglen);
  
 /** /**
  
 

/tmp/sos-code-article9.5/userland/envtest.c (1970-01-01 01:00:00.000000000 +0100 )
sos-code-article9.5/userland/envtest.c (2006-03-19 12:21:04.000000000 +0100 )
(New file) 
Line 1 
  #include <libc.h>
  
  int main(int argc, char * argv[], char *envp[])
  {
    int i;
    char **e;
  
    printf("Nargs: %d\n", argc);
    for (i = 0 ; i < argc ; i ++)
      printf("  arg[%d] = |%s|\n", i, argv[i]);
  
    for (e = envp ; e && *e ; e ++)
      printf("  ENV |%s|\n", *e);
  
    return 0;
  }
  
 

/tmp/sos-code-article9.5/userland/fstest.c (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/userland/fstest.c (2006-03-19 12:21:04.000000000 +0100 )
Line 24 
Line 24 
  
 #include "fstest_utils.h" #include "fstest_utils.h"
  
 #define OPEN_BASE_FD 3 static const int OPEN_BASE_FD = 3;
 /** /**
  * @file fstest.c  * @file fstest.c
  
 

/tmp/sos-code-article9.5/userland/ldscript.lds (2006-01-22 12:48:32.000000000 +0100 )
sos-code-article9.5/userland/ldscript.lds (2006-03-19 12:21:04.000000000 +0100 )
Line 56 
Line 56 
     }     }
  
     /* Beginning of the BSS section (global uninitialized data) */     /* Beginning of the BSS section (global uninitialized data) */
     .bss SIZEOF(.rodata) + ADDR(.rodata) :     .bss ALIGN(SIZEOF(.rodata) + ADDR(.rodata), 4096) :
         PROVIDE(_bbss = .);         PROVIDE(_bbss = .);
         *(.bss)         *(.bss)
  
 

/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 )
Line 34 
Line 34 
 } }
  
  
 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);
  
  
Line 53 
Line 222 
 } }
  
  
  /**
   * 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)
 { {
  
 

/tmp/sos-code-article9.5/userland/libc.h (2006-01-22 12:48:32.000000000 +0100 )
sos-code-article9.5/userland/libc.h (2006-03-19 12:21:04.000000000 +0100 )
Line 40 
Line 40 
  
  
 /** /**
   * Retrieves the current process's PID
   */
  pid_t getpid(void);
  
  
  /**
  * Function to re-initialize the address space of the current process  * Function to re-initialize the address space of the current process
  * with that of the program 'progname'  * with that of the program 'progname'
  */  */
 int exec(const char *progname); int execve(const  char  *filename,
             char  *const argv [],
             char *const envp[]);
  int execv(const char  * filename,
            char  * const argv []);
  int execl(const  char  *path, ...);
  int execle(const  char  *path, ...);
  
  
  /**
   * Equivalent to execl(filename, filename);
   */
  int exec(char * const filename);
  
 int nanosleep(unsigned long int sec, int nanosleep(unsigned long int sec,
Line 54 
Line 72 
  
  
 /** /**
   * Environment variables management API
   */
  extern char **environ; /** Needed by execl */
  
  int putenv(char * string);
  int setenv(const char *name, const char *value, int overwrite);
  char *getenv(const char *name);
  void unsetenv(const char *name);
  int clearenv(void);
  
  
  /**
  * These flags (for mmap API) MUST be consistent with those defined in  * These flags (for mmap API) MUST be consistent with those defined in
  * paging.h and umem_vmm.h  * paging.h and umem_vmm.h
  */  */
  
 

/tmp/sos-code-article9.5/userland/Makefile (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/userland/Makefile (2006-03-19 12:21:04.000000000 +0100 )
Line 29 
Line 29 
  
 -include .mkvars -include .mkvars
  
 PROGS := init myprog1 myprog2 myprog3 myprog4 myprog5 myprog6 \ PROGS := init myprog1 myprog2 myprog3 myprog4 myprog5 myprog6           \
          myprog7 myprog8 myprog9 myprog10 myprog11 myprog12   \          envtest myprog7 myprog8 myprog9 myprog10 myprog11 myprog12     \
  
 # Build dependencies of the programs # Build dependencies of the programs
Line 39 
Line 39 
 chartest: fstest_utils.o chartest: fstest_utils.o
 blktest: fstest_utils.o blktest: fstest_utils.o
 shell: fstest_utils.o shell: fstest_utils.o
 $(PROGS) : % : %.o crt.o libc.a $(PROGS) : % : %.o crt.o crt_asm.o libc.a
 PWD := $(shell pwd | sed 's/"/\\\"/g;s/\$$/\\\$$/g') PWD := $(shell pwd | sed 's/"/\\\"/g;s/\$$/\\\$$/g')
  
  
 

/tmp/sos-code-article9.5/userland/shell.c (2006-01-22 12:48:31.000000000 +0100 )
sos-code-article9.5/userland/shell.c (2006-03-19 12:21:04.000000000 +0100 )
Line 303 
Line 303 
       printf("Could not fork (%d)\n", retval);       printf("Could not fork (%d)\n", retval);
       return -1;       return -1;
     }     }
   retval = exec(argv[1]);   printf("Created new process %d\n", getpid());
    retval = execv(argv[1], & argv[1]);
    exit(0);
   return 0;   return 0;
 } }
  
Line 605 
Line 607 
   char **argv;   char **argv;
  
   for (c = cmd; *c != '\0'; c++)   for (c = cmd; *c != '\0'; c++)
     if (*c == ' ')     {
       argc++;       if (*c == ' ')
          {
            /* Skip all spaces */
            while (*c && *c == ' ')
              c++;
  
            /* Reached the end of the command line ? */
            if (! *c)
              break;
  
            argc++;
          }
      }
   argv = malloc (argc * sizeof(char*));   argv = malloc ((argc+1) * sizeof(char*));
    argv[argc] = NULL; /* To be compatible with execv(e) */
     return;     return;
  
Line 619 
Line 634 
         c++;         c++;
       *c = '\0';       *c = '\0';
       c++;       c++;
        /* Skip spaces */
        while (*c && *c == ' ')
          c++;
     }     }
  
   if (! strcmp (argv[0], "uname"))   if (! strcmp (argv[0], "uname"))
Line 676 
Line 694 
     {     {
       shell_partdump (argc, argv);       shell_partdump (argc, argv);
     }     }
    else if (! strcmp(argv[0], "getenv"))
      {
        if (argc > 1)
          printf("%s\n", getenv(argv[1]));
        else
          printf("Variable name missing\n");
      }
    else if (! strcmp(argv[0], "setenv"))
      {
        if (argc > 2)
          printf("retval=%d\n",
                 setenv(argv[1], argv[2], TRUE));
        else
          printf("Variable name/value missing\n");
      }
    else if (! strcmp(argv[0], "unsetenv"))
      {
        if (argc > 1)
          unsetenv(argv[1]);
        else
          printf("Variable name missing\n");
      }
     printf ("Command not found\n");     printf ("Command not found\n");
  
  
 

/tmp/sos-code-article9.5/userland/string.c (2006-01-22 12:48:32.000000000 +0100 )
sos-code-article9.5/userland/string.c (2006-03-19 12:21:04.000000000 +0100 )
Line 18 
Line 18 
    USA.     USA. 
 */ */
 #include "string.h" #include "string.h"
  #include "libc.h"
  
 /* For an optimized version, see BSD sources ;) */ /* For an optimized version, see BSD sources ;) */
 void *memcpy(void *dst0, const void *src0, register unsigned int size) void *memcpy(void *dst0, const void *src0, register unsigned int size)
Line 115 
Line 116 
   return res;   return res;
 } }
  
  
  char *strndup(const char *s, size_t n)
  {
    char * result;
    n = strnlen(s, n);
    result = malloc(n+1);
    if (! result)
      return NULL;
  
    strzcpy(result, s, n+1);
    return result;
  }
  
  
  char *strdup(const char *s)
  {
    char * result;
    size_t n = strlen(s);
  
    result = malloc(n+1);
    if (! result)
      return NULL;
  
    strzcpy(result, s, n+1);
    return result;
  }
  
  
 int strcmp(register const char *s1, register const char *s2) int strcmp(register const char *s1, register const char *s2)
 { {
   while (*s1 == *s2++)   while (*s1 == *s2++)
Line 208 
Line 237 
 { {
   return strtol(nptr, NULL, 10);   return strtol(nptr, NULL, 10);
 } }
  
  
 

/tmp/sos-code-article9.5/userland/string.h (2006-01-22 12:48:32.000000000 +0100 )
sos-code-article9.5/userland/string.h (2006-03-19 12:21:04.000000000 +0100 )
Line 53 
Line 53 
  */  */
 char *strzcat (char *dest, const char *src, char *strzcat (char *dest, const char *src,
                const size_t len);                const size_t len);
  
  char *strndup(const char *s, size_t n);
  char *strdup(const char *s);
    
 int strcmp(register const char *s1, register const char *s2 ); int strcmp(register const char *s1, register const char *s2 );
 int strncmp(register const char *s1, register const char *s2, int strncmp(register const char *s1, register const char *s2,
             register int len );             register int len );
  
  
 #define isupper(c)  (('A' <= (c)) && ((c) <= 'Z')) #define isupper(c)  (('A' <= (c)) && ((c) <= 'Z'))
 #define isdigit(c)  (('0' <= (c)) && ((c) <= '9')) #define isdigit(c)  (('0' <= (c)) && ((c) <= '9'))
Line 72 
Line 74 
 long long atoll(const char *nptr); long long atoll(const char *nptr);
 long atol(const char *nptr); long atol(const char *nptr);
  
  
  
 

/tmp/sos-code-article9.5/userland/types.h (2006-01-22 12:48:32.000000000 +0100 )
sos-code-article9.5/userland/types.h (2006-03-19 12:21:04.000000000 +0100 )
Line 25 
Line 25 
  
 typedef unsigned int size_t; typedef unsigned int size_t;
  
 typedef int pid_t; typedef unsigned int addr_t;
  typedef int pid_t;
 typedef signed long int off_t; typedef signed long int off_t;
 typedef signed long long int loff_t; typedef signed long long int loff_t;
  


Legend:
 
identical lines
Removed from old 
changed lines
 Added in new

File list:
    
sos-code-article9.5/drivers/mem.c
    sos-code-article9.5/extra/bootsect.S
    sos-code-article9.5/hwcore/bitmap.c
    sos-code-article9.5/hwcore/bitmap.h
    sos-code-article9.5/hwcore/paging.c
    sos-code-article9.5/hwcore/paging.h
    sos-code-article9.5/Makefile
    sos-code-article9.5/sos/binfmt_elf32.c
    sos-code-article9.5/sos/errno.h
    sos-code-article9.5/sos/fs.c
    sos-code-article9.5/sos/fs.h
    sos-code-article9.5/sos/hash.c
    sos-code-article9.5/sos/hash.h
    sos-code-article9.5/sos/kmem_vmm.h
    sos-code-article9.5/sos/main.c
    sos-code-article9.5/sos/process.c
    sos-code-article9.5/sos/process.h
    sos-code-article9.5/sos/syscall.c
    sos-code-article9.5/sos/syscall.h
    sos-code-article9.5/sos/thread.c
    sos-code-article9.5/sos/thread.h
    sos-code-article9.5/sos/types.h
    sos-code-article9.5/sos/uaccess.c
    sos-code-article9.5/sos/uaccess.h
    sos-code-article9.5/sos/umem_vmm.c
    sos-code-article9.5/sos/umem_vmm.h
    sos-code-article9.5/userland/crt_asm.S
    sos-code-article9.5/userland/crt.c
    sos-code-article9.5/userland/crt.h
    sos-code-article9.5/userland/envtest.c
    sos-code-article9.5/userland/fstest.c
    sos-code-article9.5/userland/ldscript.lds
    sos-code-article9.5/userland/libc.c
    sos-code-article9.5/userland/libc.h
    sos-code-article9.5/userland/Makefile
    sos-code-article9.5/userland/shell.c
    sos-code-article9.5/userland/string.c
    sos-code-article9.5/userland/string.h
    sos-code-article9.5/userland/types.h