/tmp/sos-code-article8/drivers/bochs.c (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/bochs.c (2005-12-28 11:44:55.000000000 +0100 )
Line 24 
Line 24 
    operating system under the Bochs emulator.  */    operating system under the Bochs emulator.  */
 #define SOS_BOCHS_IOPORT 0xe9 #define SOS_BOCHS_IOPORT 0xe9
  
 sos_ret_t sos_bochs_setup(void) sos_ret_t sos_bochs_subsystem_setup(void)
   return SOS_OK;   return SOS_OK;
 } }
  
 

/tmp/sos-code-article8/drivers/bochs.h (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/bochs.h (2005-12-28 11:44:55.000000000 +0100 )
Line 31 
Line 31 
 #include <sos/errno.h> #include <sos/errno.h>
 #include <sos/types.h> #include <sos/types.h>
  
 sos_ret_t sos_bochs_setup(void); sos_ret_t sos_bochs_subsystem_setup(void);
 sos_ret_t sos_bochs_putchar(char c); sos_ret_t sos_bochs_putchar(char c);
  
  
 

/tmp/sos-code-article8/drivers/console.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/console.c (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005  Thomas Petazzoni
  
     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 <drivers/x86_videomem.h>
  #include <drivers/kbd.h>
  #include <drivers/tty.h>
  #include <drivers/devices.h>
  
  #include "console.h"
  
  sos_ret_t
  sos_console_subsystem_setup (void)
  {
    sos_ret_t ret;
    struct tty_device *tty;
  
    ret = sos_screen_init();
    if (SOS_OK != ret)
      return ret;
  
    ret = tty_create (SOS_CHARDEV_CONSOLE_MINOR,
                      sos_screen_putchar, & tty);
    if (SOS_OK != ret)
      return ret;
  
    return sos_kbd_subsystem_setup (tty);
  }
  
 

/tmp/sos-code-article8/drivers/console.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/console.h (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005  Thomas Petazzoni
  
     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_DRV_CONSOLE_H_
  #define _SOS_DRV_CONSOLE_H_
  
  /**
   * @file console.h
   *
   * Simple tty device binding together the physical keyboard (@see
   * kbd.h) and the text-mode screen (@see x86_videomem.h)
   */
  
  #include <sos/errno.h>
  
  
  /**
   * Create a new TTY device (minor CHARDEV_CONSOLE_MINOR) that controls
   * the keyboard/screen
   */
  sos_ret_t sos_console_subsystem_setup (void);
  
  #endif /* _SOS_DRV_CONSOLE_H_ */
  
 

/tmp/sos-code-article8/drivers/devices.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/devices.h (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005      David Decotigny, Thomas Petazzoni
  
     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_DEVICES_H_
  #define _SOS_DEVICES_H_
  
  /**
   *@file devices.h
   *
   * This file contains definitions concerning device drivers that must
   * be shared between userspace applications and the kernel. They are
   * mostly major numbers, IOCTL commands and parameters.
   *
   * This file must be built so that it can be safely included both from
   * user applications and the kernel.
   */
  
  /* For /dev/zero & /dev/null devices */
  #define SOS_CHARDEV_ZERO_MAJOR            1
  #define SOS_CHARDEV_ZERO_MINOR            0
  #define SOS_CHARDEV_NULL_MINOR            1
  
  /* For memory char devices (/dev/mem and /dev/kmem) */
  #define SOS_CHARDEV_MEM_MAJOR             2
  #define SOS_CHARDEV_KMEM_MINOR            0 /* /dev/kmem */
  #define SOS_CHARDEV_PHYSMEM_MINOR         1 /* /dev/mem */
  
  /* TTY major and minor*/
  #define SOS_CHARDEV_TTY_MAJOR             3
  #define SOS_CHARDEV_CONSOLE_MINOR         0
  #define SOS_CHARDEV_SERIAL_MINOR          1
  
  /* TTY IOCTL commands */
  #define SOS_IOCTL_TTY_SETPARAM            1
  #define SOS_IOCTL_TTY_RESETPARAM          2
  
  /* TTY IOCTL command parameters for SOS_IOCTL_TTY_SETPARAM and
     SOS_IOCTL_TTY_RESETPARAM */
  #define SOS_IOCTLPARAM_TTY_CANON          1
  #define SOS_IOCTLPARAM_TTY_ECHO           2
  
  #endif /* _SOS_DEVICE_H_ */
  
 

/tmp/sos-code-article8/drivers/fs_virtfs.c (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/fs_virtfs.c (2005-12-28 11:44:55.000000000 +0100 )
Line 507 
Line 507 
                                   struct sos_fs_stat * result)                                   struct sos_fs_stat * result)
 { {
   struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;   struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
   result->st_type             = this->type; 
   result->st_storage_location = this->storage_location;   /* Establish the major/minor fields */
   result->st_access_rights    = this->access_rights;   result->st_rdev.device_class    = 0;
   result->st_nlink            = this->ondisk_lnk_cnt;   result->st_rdev.device_instance = 0;
    if (this->type == SOS_FS_NODE_DEVICE_CHAR)
      {
        /* If the current node is a special device: get the major/minor
           directly from it */
        result->st_rdev.device_class    = this->dev_id.device_class;
        result->st_rdev.device_instance = this->dev_id.device_instance;
      }
    else
      {
        /* Otherwise, retrieve it from the device that it is mounted
           on (might not exist...) */
        struct sos_fs_node * rootdev = this->fs->device;
        if (rootdev)
          {
            result->st_rdev.device_class    = rootdev->dev_id.device_class;
            result->st_rdev.device_instance = rootdev->dev_id.device_instance;
          }
      }
  
    result->st_type                 = this->type;
    result->st_storage_location     = this->storage_location;
    result->st_access_rights        = this->access_rights;
    result->st_nlink                = this->ondisk_lnk_cnt;
     result->st_size           = virtfsnode->file.size;     result->st_size               = virtfsnode->file.size;
     result->st_size           = 0;     result->st_size               = 0;
 } }
  
Line 579 
Line 602 
   (struct sos_fs_node_ops_file){   (struct sos_fs_node_ops_file){
     .truncate = virtfs_truncate,     .truncate = virtfs_truncate,
     .stat     = virtfs_stat_node,     .stat     = virtfs_stat_node,
     .sync     = virtfs_sync_node, 
   };   };
  
Line 765 
Line 787 
 { {
   struct virtfs_node * virtfsnode;   struct virtfs_node * virtfsnode;
  
   /* Allow only DIRs or FILEs */   /* Allow only DIRs, FILEs or special device files */
       && (type != SOS_FS_NODE_SYMLINK)       && (type != SOS_FS_NODE_SYMLINK)
       && (type != SOS_FS_NODE_DIRECTORY))       && (type != SOS_FS_NODE_DIRECTORY)
        && (type != SOS_FS_NODE_DEVICE_CHAR))
  
   virtfsnode = (struct virtfs_node*) sos_kmalloc(sizeof(*virtfsnode), 0);   virtfsnode = (struct virtfs_node*) sos_kmalloc(sizeof(*virtfsnode), 0);
Line 785 
Line 808 
   (*result)->type              = type;   (*result)->type              = type;
   (*result)->access_rights     = access_rights;   (*result)->access_rights     = access_rights;
   (*result)->destructor        = virtfs_node_destructor;   (*result)->destructor        = virtfs_node_destructor;
   (*result)->new_opened_file   = virtfs_new_opened_file; 
   (*result)->close_opened_file = virtfs_close_opened_file; 
  
    /* The "file" functions are defined by the FS code only for
       non-special device files */
    if (type != SOS_FS_NODE_DEVICE_CHAR)
      {
        (*result)->sync              = virtfs_sync_node;
        (*result)->new_opened_file   = virtfs_new_opened_file;
        (*result)->close_opened_file = virtfs_close_opened_file;
      }
  
   if (type == SOS_FS_NODE_SYMLINK)   if (type == SOS_FS_NODE_SYMLINK)
     (*result)->ops_symlink = & virtfs_ops_symlink;     (*result)->ops_symlink = & virtfs_ops_symlink;
   else if (type == SOS_FS_NODE_DIRECTORY)   else if (type == SOS_FS_NODE_DIRECTORY)
  
 

/tmp/sos-code-article8/drivers/kbd.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/kbd.c (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005  Thomas Petazzoni
  
     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/types.h>
  #include <sos/errno.h>
  #include <sos/assert.h>
  #include <hwcore/irq.h>
  #include <hwcore/ioports.h>
  
  #include "tty.h"
  
  /*
   * Keyboard ports and commands.
   * 
   * @see Ralf Brown's interrupt (and port) list   
   * http://www-2.cs.cmu.edu/~ralf/files.html      
   */
  
  #define KBD_DATA_PORT               0x60
  
  #define KBD_BREAKCODE_LIMIT         0x80
  #define KBD_EXTENDED_SCANCODE       0xE0
  
  #define KBD_IS_MAKECODE(c)          ((c) < KBD_BREAKCODE_LIMIT)
  #define KBD_IS_BREAKCODE(c)         ((c) >= KBD_BREAKCODE_LIMIT)
  #define KBD_BREAKCODE_2_MAKECODE(c) ((c) ^ KBD_BREAKCODE_LIMIT)
  
  #define KBD_LEFTSHIFT_SCANCODE      0x2a
  #define KBD_RIGHTSHIFT_SCANCODE     0x36
  
  typedef sos_ui8_t scancode_t;
  
  extern const char *kbd_regular_translate_table [];
  extern const char *kbd_shift_translate_table [];
  
  static const char **kbd_current_translate_table = kbd_regular_translate_table;
  static int is_ext = FALSE;
  
  static struct tty_device *tty;
  
  static void kbd_irq_handler (int irq_level)
  {
    scancode_t scancode;
    const char *key = NULL;
  
    scancode = inb (KBD_DATA_PORT);
  
    /* Mark that next interrupt wil give an extended scancode */
    if (scancode == KBD_EXTENDED_SCANCODE)
      {
        is_ext = TRUE;
      }
  
    /* Handle extended scancode */
    else if (is_ext)
      {
        is_ext = FALSE;
      }
  
    /* Normal scancode */
    else
      {
        /* Keypressed */
        if (KBD_IS_MAKECODE(scancode))
          {
            /* If shift, change translation table */
            if ((scancode == KBD_LEFTSHIFT_SCANCODE) ||
                (scancode == KBD_RIGHTSHIFT_SCANCODE))
              kbd_current_translate_table = kbd_shift_translate_table;
  
            /* If normal key, compute the result using the translation
               tables and the booleans */
            else if (kbd_current_translate_table[scancode])
              {
                key = kbd_current_translate_table[scancode];
              }
          }
  
        /* Key released */
        else
          {
            scancode_t makecode = KBD_BREAKCODE_2_MAKECODE(scancode);
  
            if ((makecode == KBD_LEFTSHIFT_SCANCODE) ||
                (makecode == KBD_RIGHTSHIFT_SCANCODE))
              kbd_current_translate_table = kbd_regular_translate_table;
          }
      }
  
    if (key)
      tty_add_chars (tty, key);
  }
  
  
  sos_ret_t sos_kbd_subsystem_setup(struct tty_device *t)
  {
    tty = t;
  
    sos_irq_set_routine (SOS_IRQ_KEYBOARD, kbd_irq_handler);
  
    return SOS_OK;
  }
  
  
 

/tmp/sos-code-article8/drivers/kbd.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/kbd.h (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005  Thomas Petazzoni
  
     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_DRV_KBD_H_
  #define _SOS_DRV_KBD_H_
  
  /**
   * @file kbd.h
   *
   * Basic keyboard driver for SOS. Handles normal, shift and function
   * keys, does not handle alt/altgr/ctrl combinations.
   */
  
  #include <sos/errno.h>
  #include <drivers/tty.h>
  
  
  /**
   * Bind the physical keyboard to the given TTY device
   */
  sos_ret_t sos_kbd_subsystem_setup(struct tty_device *tty);
  
  #endif /* _SOS_DRV_KBD_H_ */
  
 

/tmp/sos-code-article8/drivers/kbdmapfr.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/kbdmapfr.c (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005  Thomas Petazzoni
  
     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/types.h>
  
  const char *kbd_regular_translate_table [128] = {
    /* 0 */ 0,
    /* 1 */ "\e",
    /* 2 */ "&",
    /* 3 */ "é",
    /* 4 */ "\"",
    /* 5 */ "'",
    /* 6 */ "(",
    /* 7 */ "-",
    /* 8 */ "è",
    /* 9 */ "_",
    /* 10 */ "ç",
    /* 11 */ "à",
    /* 12 */ ")",
    /* 13 */ "=",
    /* 14 */ "\b", /* Backspace */
    /* 15 */ "\t", /* Tab */
    /* 16 */ "a",
    /* 17 */ "z",
    /* 18 */ "e",
    /* 19 */ "r",
    /* 20 */ "t",
    /* 21 */ "y",
    /* 22 */ "u",
    /* 23 */ "i",
    /* 24 */ "o",
    /* 25 */ "p",
    /* 26 */ "^",
    /* 27 */ "$",
    /* 28 */ "\n",
    /* 29 */ 0, /* left control */
    /* 30 */ "q",
    /* 31 */ "s",
    /* 32 */ "d",
    /* 33 */ "f",
    /* 34 */ "g",
    /* 35 */ "h",
    /* 36 */ "j",
    /* 37 */ "k",
    /* 38 */ "l",
    /* 39 */ "m",
    /* 40 */ "ù",
    /* 41 */ 0,
    /* 42 */ 0, /* left shift */
    /* 43 */ "*",
    /* 44 */ "w",
    /* 45 */ "x",
    /* 46 */ "c",
    /* 47 */ "v",
    /* 48 */ "b",
    /* 49 */ "n",
    /* 50 */ ",",
    /* 51 */ ";",
    /* 52 */ ":",
    /* 53 */ "!",
    /* 54 */ 0,
    /* 55 */ 0,
    /* 56 */ 0,
    /* 57 */ " ",
    /* 58 */ 0,
    /* 59 */ "\eOP",   /* F1 */
    /* 60 */ "\eOQ",   /* F2 */
    /* 61 */ "\eOR",   /* F3 */
    /* 62 */ "\eOS",   /* F4 */
    /* 63 */ "\e[15~", /* F5 */
    /* 64 */ "\e[17~", /* F6 */
    /* 65 */ "\e[18~", /* F7 */
    /* 66 */ "\e[19~", /* F8 */
    /* 67 */ "\e[20~", /* F9 */
    /* 68 */ "\e[21~", /* F10 */
    /* 69 */ 0,
    /* 70 */ 0,
    /* 71 */ 0,
    /* 72 */ 0,
    /* 73 */ 0,
    /* 74 */ 0,
    /* 75 */ 0,
    /* 76 */ 0,
    /* 77 */ 0,
    /* 78 */ 0,
    /* 79 */ 0,
    /* 80 */ 0,
    /* 81 */ 0,
    /* 82 */ 0,
    /* 83 */ 0,
    /* 84 */ 0,
    /* 85 */ 0,
    /* 86 */ "<",
    /* 87 */ "\e[23~", /* F11 */
    /* 88 */ "\e[24~", /* F12 */
    /* 89 */ 0,
    /* 90 */ 0,
    /* 91 */ 0,
    /* 92 */ 0,
    /* 93 */ 0,
    /* 94 */ 0,
    /* 95 */ 0,
    /* 96 */ 0,
    /* 97 */ 0,
    /* 98 */ 0,
    /* 99 */ 0,
    /* 100 */ 0,
    /* 101 */ 0,
    /* 102 */ 0,
    /* 103 */ 0,
    /* 104 */ 0,
    /* 105 */ 0,
    /* 106 */ 0,
    /* 107 */ 0,
    /* 108 */ 0,
    /* 109 */ 0,
    /* 110 */ 0,
    /* 111 */ 0,
    /* 112 */ 0,
    /* 113 */ 0,
    /* 114 */ 0,
    /* 115 */ 0,
    /* 116 */ 0,
    /* 117 */ 0,
    /* 118 */ 0,
    /* 119 */ 0,
    /* 120 */ 0,
    /* 121 */ 0,
    /* 122 */ 0,
    /* 123 */ 0,
    /* 124 */ 0,
    /* 125 */ 0,
    /* 126 */ 0,
    /* 127 */ 0
  };
  
  const char *kbd_shift_translate_table [128] = {
    /* 0 */ 0,
    /* 1 */ "\e",
    /* 2 */ "1",
    /* 3 */ "2",
    /* 4 */ "3",
    /* 5 */ "4",
    /* 6 */ "5",
    /* 7 */ "6",
    /* 8 */ "7",
    /* 9 */ "8",
    /* 10 */ "9",
    /* 11 */ "0",
    /* 12 */ "°",
    /* 13 */ "+",
    /* 14 */ "\b",   /* Shift-Backspace */
    /* 15 */ "\e[Z", /* Shift-Tab */
    /* 16 */ "A",
    /* 17 */ "Z",
    /* 18 */ "E",
    /* 19 */ "R",
    /* 20 */ "T",
    /* 21 */ "Y",
    /* 22 */ "U",
    /* 23 */ "I",
    /* 24 */ "O",
    /* 25 */ "P",
    /* 26 */ "\"",
    /* 27 */ "£",
    /* 28 */ "\n",
    /* 29 */ 0, /* left control */
    /* 30 */ "Q",
    /* 31 */ "S",
    /* 32 */ "D",
    /* 33 */ "F",
    /* 34 */ "G",
    /* 35 */ "H",
    /* 36 */ "J",
    /* 37 */ "K",
    /* 38 */ "L",
    /* 39 */ "M",
    /* 40 */ "%",
    /* 41 */ 0,
    /* 42 */ 0,
    /* 43 */ "µ",
    /* 44 */ "W",
    /* 45 */ "X",
    /* 46 */ "C",
    /* 47 */ "V",
    /* 48 */ "B",
    /* 49 */ "N",
    /* 50 */ "?",
    /* 51 */ ".",
    /* 52 */ "/",
    /* 53 */ "§",
    /* 54 */ 0,
    /* 55 */ 0,
    /* 56 */ 0,
    /* 57 */ 0,
    /* 58 */ 0,
    /* 59 */ "\eOP",     /* Shift-F1 */
    /* 60 */ "\eOQ",     /* Shift-F2 */
    /* 61 */ "\eOR",     /* Shift-F3 */
    /* 62 */ "\eOS",     /* Shift-F4 */
    /* 63 */ "\e[15;2~", /* Shift-F5 */
    /* 64 */ "\e[17;2~", /* Shift-F6 */
    /* 65 */ "\e[18;2~", /* Shift-F7 */
    /* 66 */ "\e[19;2~", /* Shift-F8 */
    /* 67 */ "\e[20:2~", /* Shift-F9 */
    /* 68 */ "\e[21:2~", /* Shift-F10 */
    /* 69 */ 0,
    /* 70 */ 0,
    /* 71 */ 0,
    /* 72 */ 0,
    /* 73 */ 0,
    /* 74 */ 0,
    /* 75 */ 0,
    /* 76 */ 0,
    /* 77 */ 0,
    /* 78 */ 0,
    /* 79 */ 0,
    /* 80 */ 0,
    /* 81 */ 0,
    /* 82 */ 0,
    /* 83 */ 0,
    /* 84 */ 0,
    /* 85 */ 0,
    /* 86 */ ">",
    /* 87 */ "\e[23;2~", /* Shift-F11 */
    /* 88 */ "\e[24;2~", /* Shift-F12 */
    /* 89 */ 0,
    /* 90 */ 0,
    /* 91 */ 0,
    /* 92 */ 0,
    /* 93 */ 0,
    /* 94 */ 0,
    /* 95 */ 0,
    /* 96 */ 0,
    /* 97 */ 0,
    /* 98 */ 0,
    /* 99 */ 0,
    /* 100 */ 0,
    /* 101 */ 0,
    /* 102 */ 0,
    /* 103 */ 0,
    /* 104 */ 0,
    /* 105 */ 0,
    /* 106 */ 0,
    /* 107 */ 0,
    /* 108 */ 0,
    /* 109 */ 0,
    /* 110 */ 0,
    /* 111 */ 0,
    /* 112 */ 0,
    /* 113 */ 0,
    /* 114 */ 0,
    /* 115 */ 0,
    /* 116 */ 0,
    /* 117 */ 0,
    /* 118 */ 0,
    /* 119 */ 0,
    /* 120 */ 0,
    /* 121 */ 0,
    /* 122 */ 0,
    /* 123 */ 0,
    /* 124 */ 0,
    /* 125 */ 0,
    /* 126 */ 0,
    /* 127 */ 0
  };
  
  
 

/tmp/sos-code-article8/drivers/mem.c (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/mem.c (2005-12-28 11:44:56.000000000 +0100 )
Line 23 
Line 23 
 #include <sos/kmem_slab.h> #include <sos/kmem_slab.h>
 #include <sos/list.h> #include <sos/list.h>
 #include <hwcore/paging.h> #include <hwcore/paging.h>
  #include <drivers/devices.h>
  #include <sos/kmem_vmm.h>
  #include <sos/uaccess.h>
  #include <sos/chardev.h>
  
 #include "mem.h" #include "mem.h"
  
Line 125 
Line 129 
  
 /** The function responsible for mapping the /dev/kmem resource in /** The function responsible for mapping the /dev/kmem resource in
     user space */     user space */
  static
 sos_ret_t sos_dev_kmem_map(struct sos_umem_vmm_as * dest_as, sos_ret_t sos_dev_kmem_map(struct sos_umem_vmm_as * dest_as,
                            sos_uaddr_t *uaddr,                            sos_uaddr_t *uaddr,
                            sos_size_t size,                            sos_size_t size,
Line 204 
Line 209 
  
 /** The function responsible for mapping the /dev/mem resource in /** The function responsible for mapping the /dev/mem resource in
     user space */     user space */
  static
 sos_ret_t sos_dev_physmem_map(struct sos_umem_vmm_as * dest_as, sos_ret_t sos_dev_physmem_map(struct sos_umem_vmm_as * dest_as,
                               sos_uaddr_t *uaddr,                               sos_uaddr_t *uaddr,
                               sos_size_t size,                               sos_size_t size,
Line 239 
Line 245 
  
   return SOS_OK;   return SOS_OK;
 } }
  
  
  /*
   * /dev/mem and /dev/kmem character device operations
   *
   * the "custom_data" field of the FS node is used to store the total
   * number of pages available
   */
  #define GET_DEV_SIZE(fsnode) \
    ((sos_size_t)(fsnode)->custom_data)
  
  static sos_ret_t dev_mem_fs_open(struct sos_fs_node        * fsnode,
                                   struct sos_fs_opened_file * of,
                                   void * chardev_class_custom_data)
  {
    /* Make sure the device is supported by this driver and compute its
       "size" (use the custom_data field to store it) */
    switch (fsnode->dev_id.device_instance)
      {
        /* For /dev/kmem, go to the end of the kernel mapping */
      case SOS_CHARDEV_KMEM_MINOR:
        fsnode->custom_data = (void*)SOS_PAGING_BASE_USER_ADDRESS;
        return SOS_OK;
        break;
  
        /* For /dev/mem, go to the end of physical memory */
      case SOS_CHARDEV_PHYSMEM_MINOR:
        {
          sos_size_t ram_pages = 0;
          sos_physmem_get_state(& ram_pages, NULL);
          fsnode->custom_data = (void*)(ram_pages << SOS_PAGE_SHIFT);
        }
        return SOS_OK;
        break;
  
      default:
        break;
      }
  
    return -SOS_ENODEV;
  }
  
  
  static sos_ret_t dev_mem_fs_seek(struct sos_fs_opened_file *this,
                                   sos_lsoffset_t offset,
                                   sos_seek_whence_t whence,
                                   /* out */ sos_lsoffset_t * result_position)
  {
    /* Make sure the device is supported by this driver */
    struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry);
  
    /* Artificiallly update the position in the "file" */
    sos_lsoffset_t ref_offs;
    sos_lsoffset_t dev_size = GET_DEV_SIZE(fsnode);
  
    *result_position = this->position;
    switch (whence)
      {
      case SOS_SEEK_SET:
        ref_offs = 0;
        break;
  
      case SOS_SEEK_CUR:
        ref_offs = this->position;
        break;
  
      case SOS_SEEK_END:
        ref_offs = dev_size;
        break;
  
      default:
        return -SOS_EINVAL;
      }
  
    /* Forbid accesses "before" the start of the device */
    if (offset < -ref_offs)
      return -SOS_EINVAL;
  
    /* Forbid accesses "after" the end of the device */
    else if (ref_offs + offset > dev_size)
      return -SOS_EINVAL;
    
    this->position = ref_offs + offset;
    *result_position = this->position;
    return SOS_OK;
  }
  
  
  typedef enum { DO_READ, DO_WRITE } dev_mem_access_type_t;
  static sos_ret_t dev_mem_fs_access(struct sos_fs_opened_file *this,
                                     sos_uaddr_t user_buf,
                                     sos_size_t * /* in/out */len,
                                     dev_mem_access_type_t access_type)
  {
    struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry);
    sos_vaddr_t   physmem_transfer_kernel_page = 0; /* Used for /dev/mem only */
    sos_uoffset_t offs;
    sos_size_t    accesslen = 0;
  
    /* Readjust copy length to match the size of the device */
    if (this->position + *len >= GET_DEV_SIZE(fsnode))
      *len = GET_DEV_SIZE(fsnode) - this->position;
  
    /* Ignore zero-size requests */
    if (*len <= 0)
      return SOS_OK;
  
    /* For /dev/mem device, prepare a kernel page to copy the physical
       pages before transferring to user space */
    if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance)
      {
        physmem_transfer_kernel_page = sos_kmem_vmm_alloc(1, 0);
        if (! physmem_transfer_kernel_page)
          return -SOS_ENOMEM;
      }
  
    /* Try to copy the data in page-size chunks */
    offs = this->position;
    while (offs < this->position + *len)
      {
        /* Retrieve page address of data in kernel memory */
        sos_uoffset_t page_boundary = SOS_PAGE_ALIGN_INF(offs);
        sos_vaddr_t   page_vaddr;
        sos_uoffset_t offset_in_page;
        sos_uoffset_t accesslen_in_page;
        sos_ret_t retval;
  
        /* For /dev/mem device, we need to map the page in kernel memory
           before */
        if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance)
          {
            retval = sos_paging_map(page_boundary,
                                    physmem_transfer_kernel_page,
                                    FALSE,
                                    (access_type==DO_WRITE)?
                                      SOS_VM_MAP_PROT_WRITE
                                      :SOS_VM_MAP_PROT_READ);
            if (SOS_OK != retval)
              break;
  
            page_vaddr = physmem_transfer_kernel_page;
          }
        /* For /dev/kmem device, the page should already be in kernel space */
        else if (! sos_kmem_vmm_is_valid_vaddr(page_boundary))
          break; /* No: page is not mapped in kernel space ! */
        else
          page_vaddr = page_boundary; /* Yes, page is mapped */
  
        /* Now copy the data from kernel to user space */
        offset_in_page = offs - page_boundary;
        accesslen_in_page  = SOS_PAGE_SIZE - offset_in_page;
        if (accesslen + accesslen_in_page > *len)
          accesslen_in_page = *len - accesslen;
  
        if (access_type==DO_WRITE)
          retval = sos_memcpy_from_user(page_vaddr + offset_in_page,
                                        user_buf + accesslen,
                                        accesslen_in_page);
        else
          retval = sos_memcpy_to_user(user_buf + accesslen,
                                      page_vaddr + offset_in_page,
                                      accesslen_in_page);
        
        /* Now, for /dev/mem, unmap the page from kernel */
        if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance)
          sos_paging_unmap(physmem_transfer_kernel_page);
        
        /* Go to next page if possible */
        if (retval < 0)
          break;
  
        accesslen += retval;
        /* If transfer was interrupted, stop here */
        if (retval < accesslen_in_page)
          break;
  
        /* Go on to next page */
        offs = page_boundary + SOS_PAGE_SIZE;
      }
  
    /* Release the temporary page for physical mem transfers */
    if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance)
      sos_kmem_vmm_free(physmem_transfer_kernel_page);
  
    /* Update the position in the "file" */
    *len = accesslen;
    this->position += accesslen;
    return SOS_OK;
  }
  
  
  static sos_ret_t dev_mem_fs_read(struct sos_fs_opened_file *this,
                                     sos_uaddr_t dest_buf,
                                     sos_size_t * /* in/out */len)
  {
    return dev_mem_fs_access(this, dest_buf, len, DO_READ);
  }
  
  
  static sos_ret_t dev_mem_fs_write(struct sos_fs_opened_file *this,
                                    sos_uaddr_t src_buf,
                                    sos_size_t * /* in/out */len)
  {
    return dev_mem_fs_access(this, src_buf, len, DO_WRITE);
  }
  
  
  static sos_ret_t dev_mem_fs_mmap(struct sos_fs_opened_file *this,
                                   sos_uaddr_t *uaddr, sos_size_t size,
                                   sos_ui32_t access_rights,
                                   sos_ui32_t flags,
                                   sos_luoffset_t offset)
  {
    struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry);
    if (SOS_CHARDEV_PHYSMEM_MINOR == fsnode->dev_id.device_instance)
      return sos_dev_physmem_map(sos_process_get_address_space(this->owner),
                                 uaddr, size, offset, access_rights, flags);
  
    return sos_dev_kmem_map(sos_process_get_address_space(this->owner),
                            uaddr, size, offset, access_rights, flags);
  }
  
  
  static struct sos_chardev_ops dev_mem_fs_ops
    = (struct sos_chardev_ops) {
      .open  = dev_mem_fs_open,
      .close = NULL,
      .seek  = dev_mem_fs_seek,
      .read  = dev_mem_fs_read,
      .write = dev_mem_fs_write,
      .mmap  = dev_mem_fs_mmap,
      .fcntl = NULL,
      .ioctl = NULL
    };
  
  
  sos_ret_t sos_dev_mem_chardev_setup()
  {
    return sos_chardev_register_class(SOS_CHARDEV_MEM_MAJOR,
                                      & dev_mem_fs_ops,
                                      NULL);
  }
  
 

/tmp/sos-code-article8/drivers/mem.h (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/mem.h (2005-12-28 11:44:56.000000000 +0100 )
Line 27 
Line 27 
  
 #include <sos/umem_vmm.h> #include <sos/umem_vmm.h>
  
 /** 
  * Map /dev/kmem into user space 
  */ 
 sos_ret_t sos_dev_kmem_map(struct sos_umem_vmm_as * dest_as, 
                            sos_uaddr_t *uaddr, 
                            sos_size_t size, 
                            sos_vaddr_t offset, 
                            sos_ui32_t access_rights, 
                            sos_ui32_t flags); 
  
 /** /**
  * Map /dev/mem into user space  * Bind to the /dev/kmem and /dev/mem character devices
 sos_ret_t sos_dev_physmem_map(struct sos_umem_vmm_as * dest_as, sos_ret_t sos_dev_mem_chardev_setup();
                               sos_uaddr_t *uaddr, 
                               sos_size_t size, 
                               sos_paddr_t offset, 
                               sos_ui32_t access_rights, 
                               sos_ui32_t flags); 
 #endif /* _SOS_EXEC_ELF32_H_ */ #endif /* _SOS_EXEC_ELF32_H_ */
  
 

/tmp/sos-code-article8/drivers/serial.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/serial.c (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2000  David Decotigny, The KOS Team
  
     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/errno.h>
  #include <hwcore/ioports.h>
  #include <sos/klibc.h>
  #include <hwcore/irq.h>
  #include <drivers/devices.h>
  
  #include "tty.h"
  
  #define SERIAL_BAUDRATE_MAX 115200
  
  /* Default parameters */
  #ifndef DEBUG_SERIAL_PORT
  # define DEBUG_SERIAL_PORT 0
  #endif
  #ifndef DEBUG_SERIAL_SPEED
  # define DEBUG_SERIAL_SPEED 9600
  #endif
  
  /* The offsets of UART registers.  */
  #define UART_TX         0
  #define UART_RX         0
  #define UART_DLL        0
  #define UART_IER        1
  #define UART_DLH        1
  #define UART_IIR        2
  #define UART_FCR        2
  #define UART_LCR        3
  #define UART_MCR        4
  #define UART_LSR        5
  #define UART_MSR        6
  #define UART_SR         7
  
  /* For LSR bits.  */
  #define UART_DATA_READY         0x01
  #define UART_EMPTY_TRANSMITTER  0x20
  
  /* The type of parity.  */
  #define UART_NO_PARITY          0x00
  #define UART_ODD_PARITY         0x08
  #define UART_EVEN_PARITY        0x18
  
  /* The type of word length.  */
  #define UART_5BITS_WORD 0x00
  #define UART_6BITS_WORD 0x01
  #define UART_7BITS_WORD 0x02
  #define UART_8BITS_WORD 0x03
  
  /* The type of the length of stop bit.  */
  #define UART_1_STOP_BIT         0x00
  #define UART_2_STOP_BITS        0x04
  
  /* the switch of DLAB.  */
  #define UART_DLAB               0x80
  
  /* Enable the FIFO.  */
  #define UART_ENABLE_FIFO        0xC7
  
  /* Turn on DTR, RTS, and OUT2.  */
  #define UART_ENABLE_MODEM       0x0B
  
  
  static struct
  {
    unsigned short iobase;
    unsigned short is_enabled;
    struct tty_device *tty;
  } _serial_config [] = { { 0x3f8, FALSE },
                          { 0x2f8, FALSE },
                          { 0x3e8, FALSE },
                          { 0x2e8, FALSE } };
  
  #define SERIAL_PORT_MAX 4
  
  #define serial_inb inb
  #define serial_outb(port,val) outb(val,port)
  
  inline static int
  serial_isready (unsigned short port)
  {
    unsigned char status;
  
    status = serial_inb (port + UART_LSR);
    return (status & UART_DATA_READY) ? : -1;
  }
  
  
  static char
  serial_getchar (unsigned short unit)
  {
    if(unit >= SERIAL_PORT_MAX
       || _serial_config[unit].is_enabled == FALSE)
      return -1;
  
    /* Wait until data is ready.  */
    while ((serial_inb (_serial_config[unit].iobase + UART_LSR)
            & UART_DATA_READY) == 0)
      ;
  
    /* Read and return the data.  */
    return serial_inb (_serial_config[unit].iobase + UART_RX);
  }
  
  
  /* 0 on success */
  static int
  serial_putchar (unsigned short port, char c)
  {
    /* Perhaps a timeout is necessary.  */
    int timeout = 10000;
  
    /* Wait until the transmitter holding register is empty.  */
    while ((serial_inb (port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
      if (--timeout == 0)
        /* There is something wrong. But what can I do?  */
        return -1;
  
    serial_outb (port + UART_TX, c);
    return 0;
  }
  
  static char serial_printk_buf[1024];
  
  inline static int serial_prints(unsigned short unit, const char *str)
  {
    const char *c;
    unsigned short port;
  
    if(unit >= SERIAL_PORT_MAX
       || _serial_config[unit].is_enabled == FALSE)
      return -1;
  
    port = _serial_config[unit].iobase;
  
    for (c = str; *c != '\0'; c++)
      serial_putchar(port, *c);
  
  
    return (int) (c-str);
  }
  
  int sos_serial_printf(unsigned short unit, const char *format, ...)
  {
    va_list args;
    int len;
  
    va_start(args, format);
    len=vsnprintf(serial_printk_buf,sizeof(serial_printk_buf),format,args);
  
    return serial_prints(unit, serial_printk_buf);
  }
  
  
  static void serial_irq_handler (int irq_level)
  {
    unsigned char chr;
  
    if (irq_level == SOS_IRQ_COM1)
      {
        char c[2];
        chr = serial_inb (_serial_config[0].iobase + UART_RX);
  
        /* Little hacks to get it to work with Qemu serial port
           emulation. */
        if (chr == '\r')
          chr = '\n';
        else if (chr == 127)
          chr = '\b';
  
        /* Build a null-terminated string */
        c[0] = chr;
        c[1] = '\0';
  
        tty_add_chars (_serial_config[0].tty, c);
      }
  }
  
  static sos_ret_t sos_serial_putchar (char c)
  {
    sos_ret_t ret;
    int i;
  
    /* The serial port doesn't understand '\b', but requires ANSI
       commands instead. So we emulate '\b' by outputing "\e[D \e[D"
       which basically goes backward one character, prints a space and
       goes backward one character again. */
    if (c == '\b')
      {
        const char *str = "\e[D \e[D";
  
        for (i = 0; i < strlen(str); i++)
          {
            ret = serial_putchar (_serial_config[0].iobase, str[i]);
            if (ret != SOS_OK)
              return ret;
          }
  
        return SOS_OK;
      }
  
    return serial_putchar (_serial_config[0].iobase, c);
  }
  
  
  /* OK On success */
  sos_ret_t sos_serial_subsystem_setup (sos_bool_t enable)
  {
    unsigned short div = 0;
    unsigned char status = 0;
    unsigned short serial_port;
  
    unsigned short unit = 0;
    unsigned int speed = 115200;
    int word_len = UART_8BITS_WORD;
    int parity = UART_NO_PARITY;
    int stop_bit_len = UART_1_STOP_BIT;
  
    if (unit >= SERIAL_PORT_MAX)
      return -1;
  
    serial_port = _serial_config[unit].iobase;
  
    /* Turn off the interrupt.  */
    serial_outb (serial_port + UART_IER, 0);
  
    /* Set DLAB.  */
    serial_outb (serial_port + UART_LCR, UART_DLAB);
  
    /* Set the baud rate.  */
    if (speed > SERIAL_BAUDRATE_MAX)
      return -1;
  
    div = SERIAL_BAUDRATE_MAX / speed;
  
    serial_outb (serial_port + UART_DLL, div & 0xFF);
    serial_outb (serial_port + UART_DLH, div >> 8);
  
    /* Set the line status.  */
    status |= parity | word_len | stop_bit_len;
    serial_outb (serial_port + UART_LCR, status);
  
    /* Enable the FIFO.  */
    serial_outb (serial_port + UART_FCR, UART_ENABLE_FIFO);
  
    /* Turn on DTR, RTS, and OUT2.  */
    serial_outb (serial_port + UART_MCR, UART_ENABLE_MODEM);
  
    /* Drain the input buffer.  */
    while (serial_isready (serial_port) != -1)
      (void) serial_getchar (unit);
  
    _serial_config[unit].is_enabled = TRUE;
  
    return SOS_OK;
  }
  
  
  /* Cannot be placed in sos_serial_subsystem_init() because when it
     gets called, the IRQ handling subsystem is not yet initialized */
  sos_ret_t sos_ttyS0_subsystem_setup (void)
  {
    sos_ret_t ret;
  
    /* FIXME */
    ret = tty_create (SOS_CHARDEV_SERIAL_MINOR, sos_serial_putchar,
                      & _serial_config[0].tty);
    if (SOS_OK != ret)
      return ret;
  
    sos_irq_set_routine (SOS_IRQ_COM1, serial_irq_handler);
  
    /* Enable interrupts */
    serial_outb (_serial_config[0].iobase + UART_IER, 1);
  
    return SOS_OK;
  }
  
 

/tmp/sos-code-article8/drivers/serial.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/serial.h (2005-12-28 11:44:55.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2000  David Decotigny, Thomas Petazzoni, The KOS Team
  
     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_SERIAL_H_
  #define _SOS_SERIAL_H_
  
  /**
   * @file serial.h
   *
   * 16550 Serial driver for SOS. This is a two-layers driver:
   *   - low-level layer: polling-style read/write functions
   *   - higher-level layer: interrupt-driver read function bound to a TTY device
   */
  
  #include <sos/errno.h>
  #include <sos/types.h>
  
  
  /**
   * Create a new TTY device (minor SOS_CHARDEV_SERIAL_MINOR)
   * controlling the first serial line
   */
  sos_ret_t sos_ttyS0_subsystem_setup (void);
  
  
  #endif
  
 

/tmp/sos-code-article8/drivers/tty.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/tty.c (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005  Thomas Petazzoni, 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/types.h>
  #include <sos/assert.h>
  #include <sos/errno.h>
  #include <sos/fs.h>
  #include <sos/ksynch.h>
  #include <sos/kwaitq.h>
  #include <sos/uaccess.h>
  #include <sos/kmalloc.h>
  #include <sos/list.h>
  #include <sos/chardev.h>
  #include <drivers/devices.h>
  
  #include "tty.h"
  
  #define TTY_BUFFER_LEN 64
  #define TTY_NAME_LEN   16
  
  struct tty_device {
    sos_ui32_t        instance;
    unsigned int      open_count;
    char              buffer[TTY_BUFFER_LEN];
    unsigned int      buffer_read;
    unsigned int      buffer_write;
    struct sos_ksema  sem;
    struct sos_kwaitq wq;
    sos_ret_t         (*write)(char c);
    unsigned int      param;
    struct tty_device *next, *prev;
  };
  
  static struct tty_device *tty_device_list;
  
  static struct tty_device *
  tty_device_find (sos_ui32_t instance)
  {
    struct tty_device *t;
    int n;
  
    list_foreach (tty_device_list, t, n)
      {
        if (t->instance == instance)
          return t;
      }
  
    return NULL;
  }
  
  static sos_ret_t tty_read(struct sos_fs_opened_file *this,
                            sos_uaddr_t dest_buf, sos_size_t *len)
  {
    sos_size_t count = 0;
    struct tty_device *t;
    sos_ret_t ret;
  
    t = (struct tty_device *) this->custom_data;
  
    if (*len == 0)
      return SOS_OK;
  
    while (1)
      {
        char c;
  
        /* Take the semaphore */
        sos_ksema_down (& t->sem, NULL);
  
        /* No keys available in the ring buffer, wait until the
           add_chars callback wakes us up */
        if (t->buffer_read == t->buffer_write)
          {
            sos_ksema_up (& t->sem);
            sos_kwaitq_wait (& t->wq, NULL);
  
            /* Go back to begining of loop: maybe someone else stole the
               semaphore */
            continue;
          }
  
        c = t->buffer[t->buffer_read];
  
        /* Copy the received character from the ring buffer to the
           destination buffer */
        ret = sos_memcpy_to_user (dest_buf,
                                  (sos_vaddr_t) & t->buffer[t->buffer_read],
                                  sizeof (char));
        if (sizeof(char) != ret)
          {
            *len = count;
            sos_ksema_up (& t->sem);
            return ret;
          }
  
        dest_buf++;
  
        /* Update the ring buffer read pointer */
        t->buffer_read++;
        if (t->buffer_read == TTY_BUFFER_LEN)
          t->buffer_read = 0;
  
        count++;
  
        if (t->param & SOS_IOCTLPARAM_TTY_ECHO)
          t->write (c);
  
        sos_ksema_up (& t->sem);
  
        /* Did we read enough bytes ? */
        if (count == *len
            || (c == '\n' && t->param & SOS_IOCTLPARAM_TTY_CANON))
          break;
      }
  
    *len = count;
    return SOS_OK;
  }
  
  
  static sos_ret_t tty_write(struct sos_fs_opened_file *this,
                             sos_uaddr_t src_buf, sos_size_t *len)
  {
    struct tty_device *t;
    char c;
    int i;
    sos_ret_t ret;
  
    t = (struct tty_device *) this->custom_data;
  
    for (i = 0; i < *len; i++)
      {
        ret = sos_memcpy_from_user ((sos_vaddr_t) & c, src_buf, sizeof(char));
        if (sizeof(char) != ret)
          {
            *len = i;
            return ret;
          }
  
        sos_ksema_down (& t->sem, NULL);
        t->write (c);
        sos_ksema_up (& t->sem);
  
        src_buf++;
      }
  
    return SOS_OK;
  }
  
  
  static sos_ret_t tty_ioctl(struct sos_fs_opened_file *this, int req_id,
                             sos_ui32_t req_arg)
  {
    struct tty_device *t;
  
    if (req_arg != SOS_IOCTLPARAM_TTY_ECHO
        && req_arg != SOS_IOCTLPARAM_TTY_CANON)
      return -SOS_EINVAL;
  
    t = (struct tty_device *) this->custom_data;
  
    sos_ksema_down (& t->sem, NULL);
  
    switch (req_id)
      {
      case SOS_IOCTL_TTY_SETPARAM:
        t->param |= req_arg;
        break;
  
      case SOS_IOCTL_TTY_RESETPARAM:
        t->param &= ~req_arg;
        break;
  
      default:
        sos_ksema_up (& t->sem);
        return -SOS_EINVAL;
      }
  
    sos_ksema_up (& t->sem);
  
    return SOS_OK;
  }
  
  static sos_ret_t tty_open(struct sos_fs_node        * fsnode,
                            struct sos_fs_opened_file * of,
                            void * chardev_class_custom_data)
  {
    struct tty_device *t;
  
    t = tty_device_find (fsnode->dev_id.device_instance);
    if (t == NULL)
      return -SOS_ENOENT;
  
    sos_ksema_down (& t->sem, NULL);
    of->custom_data = t;
    t->open_count ++;
    sos_ksema_up (& t->sem);
  
    return SOS_OK;
  }
  
  
  static sos_ret_t tty_close(struct sos_fs_opened_file *of,
                             void *custom_data)
  {
    struct tty_device *t;
  
    t = (struct tty_device *) of->custom_data;
  
    sos_ksema_down (& t->sem, NULL);
    t->open_count --;
    sos_ksema_up (& t->sem);
  
    return SOS_OK;
  }
  
  void tty_add_chars (struct tty_device *t, const char *s)
  {
    sos_ksema_down (& t->sem, NULL);
    while (*s)
      {
        /* Add all characters to the ring buffer */
        t->buffer[t->buffer_write] = *s;
        t->buffer_write++;
        if (t->buffer_write == TTY_BUFFER_LEN)
          t->buffer_write = 0;
        s++;
      }
    sos_ksema_up (& t->sem);
  
    /* Wake up a possibly waiting thread */
    sos_kwaitq_wakeup (& t->wq, SOS_KWQ_WAKEUP_ALL, SOS_OK);
  }
  
  struct sos_chardev_ops tty_ops = {
    .read    = tty_read,
    .write   = tty_write,
    .open    = tty_open,
    .close   = tty_close,
    .ioctl   = tty_ioctl
  };
  
  sos_ret_t tty_create (sos_ui32_t device_instance,
                        sos_ret_t (*write_func) (char c),
                        struct tty_device **tty_out)
  {
    struct tty_device *tty;
  
    if (tty_device_find (device_instance) != NULL)
      return -SOS_EBUSY;
  
    tty = (struct tty_device *) sos_kmalloc (sizeof(struct tty_device), 0);
    if (tty == NULL)
      return -SOS_ENOMEM;
  
    memset (tty->buffer, 0, sizeof(tty->buffer));
    tty->open_count   = 0;
    tty->instance     = device_instance;
    tty->write        = write_func;
    tty->buffer_read  = 0;
    tty->buffer_write = 0;
    tty->param        = SOS_IOCTLPARAM_TTY_CANON;
    sos_kwaitq_init(& tty->wq, "tty", SOS_KWQ_ORDER_FIFO);
    sos_ksema_init(& tty->sem, "tty", 1, SOS_KWQ_ORDER_FIFO);
  
    list_add_tail (tty_device_list, tty);
  
    *tty_out = tty;
  
    return SOS_OK;
  }
  
  sos_ret_t tty_remove (struct tty_device *tty)
  {
    if (tty == NULL)
      return -SOS_EINVAL;
  
    if (SOS_OK != sos_ksema_trydown (& tty->sem))
      return -SOS_EBUSY;
  
    if (tty->open_count != 0)
      return -SOS_EBUSY;
  
    sos_kwaitq_dispose (& tty->wq);
    list_delete (tty_device_list, tty);
  
    sos_kfree ((sos_vaddr_t) tty);
  
    return SOS_OK;
  }
  
  sos_ret_t tty_subsystem_setup (void)
  {
    list_init (tty_device_list);
    return sos_chardev_register_class (SOS_CHARDEV_TTY_MAJOR,
                                       & tty_ops, NULL);
  }
  
  sos_ret_t tty_subsystem_cleanup (void)
  {
    return sos_chardev_unregister_class (SOS_CHARDEV_TTY_MAJOR);
  }
  
  
 

/tmp/sos-code-article8/drivers/tty.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/drivers/tty.h (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005      David Decotigny, Thomas Petazzoni
  
     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_TTY_H_
  #define _SOS_TTY_H_
  
  #include <sos/types.h>
  
  struct tty_device;
  
  sos_ret_t tty_subsystem_setup (void);
  sos_ret_t tty_subsystem_cleanup (void);
  
  sos_ret_t tty_create (sos_ui32_t device_instance,
                        sos_ret_t (*write_func) (char c),
                        struct tty_device **tty_out);
  sos_ret_t tty_remove (struct tty_device *tty);
  
  /**
   * @note Function called without synchronization
   */
  void tty_add_chars (struct tty_device *t, const char *s);
  
  #endif
  
  
 

/tmp/sos-code-article8/drivers/x86_videomem.c (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/x86_videomem.c (2005-12-28 11:44:56.000000000 +0100 )
Line 4 
Line 4 
    modify it under the terms of the GNU General Public License    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.    of the License, or (at your option) any later version.
     
    but WITHOUT ANY WARRANTY; without even the implied warranty of    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.    GNU General Public License for more details.
     
    along with this program; if not, write to the Free Software    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
    USA.     USA.
 #include <sos/klibc.h> #include <sos/klibc.h>
 #include <hwcore/ioports.h> #include <hwcore/ioports.h>
Line 30 
Line 30 
 #define LINES   25 #define LINES   25
 #define COLUMNS 80 #define COLUMNS 80
  
  /*
   * VGA ports and commands.
   * 
   * @see Ralf Brown's interrupt (and port) list   
   * http://www-2.cs.cmu.edu/~ralf/files.html      
   */
  
  /* VGA ports */
  #define VGA_COMMAND_PORT 0x3D4
  #define VGA_DATA_PORT    0x3D5
  
  /* VGA commands */
  #define VGA_SET_CURSOR_START 0xA
  #define VGA_SET_CURSOR_END   0xB
  #define VGA_SET_CURSOR_HIGH  0xE
  #define VGA_SET_CURSOR_LOW   0xF
  
 /** The structure of a character element in the video memory. @see /** The structure of a character element in the video memory. @see
     http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */     http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */
Line 45 
Line 61 
  
 sos_ret_t sos_x86_videomem_setup(void) sos_ret_t sos_x86_videomem_setup(void)
 { {
   /* 
    * Hide cursor. @see Ralf Brown's interrupt (and port) list 
    * http://www-2.cs.cmu.edu/~ralf/files.html 
    */ 
 #define CRT_REG_INDEX 0x3d4 
 #define CRT_REG_DATA  0x3d5 
  
      start") */      start") */
   outb(0x0a, CRT_REG_INDEX);   outb(0x0a, VGA_COMMAND_PORT);
   /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */   /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */
   outb(1 << 5, CRT_REG_DATA);   outb(1 << 5, VGA_DATA_PORT);
   return SOS_OK;   return SOS_OK;
 } }
Line 73 
Line 82 
       (*video)[i].attribute = attribute;       (*video)[i].attribute = attribute;
     }     }
  
   return SOS_OK;     return SOS_OK;
  
  
Line 85 
Line 94 
  
   if (video_offs >= LINES*COLUMNS)   if (video_offs >= LINES*COLUMNS)
     return -SOS_EINVAL;     return -SOS_EINVAL;
    
     {     {
       (*video)[video_offs].character = (unsigned char)*str;       (*video)[video_offs].character = (unsigned char)*str;
Line 104 
Line 113 
  
   if (video_offs >= LINES*COLUMNS)   if (video_offs >= LINES*COLUMNS)
     return -SOS_EINVAL;     return -SOS_EINVAL;
    
   (*video)[video_offs].attribute = attribute;   (*video)[video_offs].attribute = attribute;
  
Line 118 
Line 127 
 { {
   char buff[256];   char buff[256];
   va_list ap;   va_list ap;
    
   vsnprintf(buff, sizeof(buff), format, ap);   vsnprintf(buff, sizeof(buff), format, ap);
   va_end(ap);   va_end(ap);
    
 } }
  
  
  /*
   * Console that supports scrolling, based on the low-level code
   * above. This console only takes part of the screen, starting at row
   * CONSOLE_ROW_START. The rows before that one are free for use by the
   * kernel debugging messages.
   */
  
  /* Current row in the high-level console. Must be signed, because of
     computations inside sos_screen_putchar() */
  static int row;
  
  /* Current column in the high-level console. Must be signed, because
     of computations inside sos_screen_putchar() */
  static int col;
  
  /* The limit between the low-level console, accessible to the kernel,
     and the high-level console, accessible to the user applications
     through the sos_screen_putchar() function. */
  #define CONSOLE_ROW_START 12
  
  static void sos_screen_set_cursor (unsigned int row, unsigned int col)
  {
    unsigned int pos;
  
    pos = (row * COLUMNS + col);
  
    outb(VGA_SET_CURSOR_HIGH, VGA_COMMAND_PORT);
    outb( (pos >> 8), VGA_DATA_PORT);
    outb(VGA_SET_CURSOR_LOW, VGA_COMMAND_PORT);
    outb( (pos & 0xFF), VGA_DATA_PORT);
  }
  
  sos_ret_t sos_screen_putchar (char c)
  {
    if (c == '\r')
      {
        /* Go to first row */
        col = 0;
      }
  
    /* New line */
    else if (c == '\n')
      {
        /* Go to next line */
        col = 0;
        row ++;
      }
  
    /* Remove the last character */
    else if (c == '\b')
      {
        /* Next character should be displayed instead of the current
           one */
        col --;
  
        /* Handle the case where we're at the beginning of a line */
        if (col < 0)
          {
            row --;
            col = COLUMNS-1;
  
            if (row < CONSOLE_ROW_START)
              {
                row = CONSOLE_ROW_START;
                col = 0;
              }
          }
  
        /* Replace the current character with a space */
        sos_x86_videomem_putchar
          (row, col, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, ' ');
      }
    else if (c != 0)
      {
        sos_x86_videomem_putchar
          (row, col, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, c);
        col++;
        if (col == COLUMNS)
          {
            col = 0;
            row++;
          }
      }
  
    /* Need to scroll ? */
    if (row == LINES)
      {
        int i;
  
        /* Copy each line in the previous line */
        for (i = CONSOLE_ROW_START; i < LINES; i++)
          memcpy ((char*) video + i * COLUMNS * 2,
                  (char*) video + ((i + 1) * COLUMNS * 2),
                  COLUMNS * 2);
  
        /* Reset the last line of the console */
        for (i = 0; i < COLUMNS; i++)
          sos_x86_videomem_putchar
            (LINES-1, i, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, ' ');
  
        row--;
      }
  
    sos_screen_set_cursor (row, col);
  
    return SOS_OK;
  }
  
  sos_ret_t sos_screen_init (void)
  {
    int i, j;
  
    row = CONSOLE_ROW_START;
    col = 0;
  
    /* Set the first scan line for the cursor, and the blinking
       mode. First scan line is 11, so that we have a visible
       cursor. */
    outb(VGA_SET_CURSOR_START, VGA_COMMAND_PORT);
    outb(((0x2 << 5) | 14), VGA_DATA_PORT);
  
    for (i = CONSOLE_ROW_START; i < LINES; i++)
      {
        for (j = 0; j < COLUMNS; j++)
          sos_x86_videomem_putchar
            (i, j, SOS_X86_VIDEO_FG_BLUE | SOS_X86_VIDEO_BG_LTGRAY, ' ');
      }
  
    sos_screen_set_cursor (row, col);
  
    return SOS_OK;
  }
  
 

/tmp/sos-code-article8/drivers/x86_videomem.h (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/x86_videomem.h (2005-12-28 11:44:56.000000000 +0100 )
Line 94 
Line 94 
                                   const char *format, /* args */...)                                   const char *format, /* args */...)
      __attribute__ ((format (printf, 4, 5)));      __attribute__ ((format (printf, 4, 5)));
  
  
  /**
   * Print a character on the console (support scrolling)
   */
  sos_ret_t sos_screen_putchar (char c);
  
  /**
   * Initialize the console that supports scrolling
   */
  sos_ret_t sos_screen_init (void);
  
 #endif /* _SOS_X86_VIDEOMEM_H_ */ #endif /* _SOS_X86_VIDEOMEM_H_ */
  
 

/tmp/sos-code-article8/drivers/zero.c (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/zero.c (2005-12-28 11:44:56.000000000 +0100 )
Line 23 
Line 23 
 #include <sos/kmem_slab.h> #include <sos/kmem_slab.h>
 #include <sos/list.h> #include <sos/list.h>
 #include <hwcore/paging.h> #include <hwcore/paging.h>
  #include <sos/uaccess.h>
  #include <sos/chardev.h>
  #include <drivers/devices.h>
  
 #include "zero.h" #include "zero.h"
  
Line 58 
Line 61 
 }; };
  
  
  /** Forward declaration: the FS operation for the /dev/zero character
      device */
  static struct sos_chardev_ops dev_zero_fs_ops;
  
  
 /** Helper function to insert the given physical page in the list of /** Helper function to insert the given physical page in the list of
     physical pages used for shared anonymous mappings */     physical pages used for shared anonymous mappings */
 static sos_ret_t insert_anonymous_physpage(struct zero_mapped_resource *mr, static sos_ret_t insert_anonymous_physpage(struct zero_mapped_resource *mr,
Line 73 
Line 81 
  
 sos_ret_t sos_dev_zero_subsystem_setup() sos_ret_t sos_dev_zero_subsystem_setup()
 { {
    sos_ret_t retval;
  
   cache_of_zero_mapped_pages =   cache_of_zero_mapped_pages =
     sos_kmem_cache_create("shared anonymous mappings",     sos_kmem_cache_create("shared anonymous mappings",
                           sizeof(struct zero_mapped_page),                           sizeof(struct zero_mapped_page),
Line 81 
Line 91 
   if (! cache_of_zero_mapped_pages)   if (! cache_of_zero_mapped_pages)
     return -SOS_ENOMEM;     return -SOS_ENOMEM;
  
    retval = sos_chardev_register_class(SOS_CHARDEV_ZERO_MAJOR,
                                        & dev_zero_fs_ops,
                                        NULL);
    if (SOS_OK != retval)
      {
        sos_kmem_cache_destroy(cache_of_zero_mapped_pages);
        return retval;
      }
  
   return SOS_OK;   return SOS_OK;
 } }
  
Line 207 
Line 226 
     {     {
       /* Map-in the zero page in READ ONLY whatever the access_rights       /* Map-in the zero page in READ ONLY whatever the access_rights
          or the type (shared/private) of the VR to activate COW */          or the type (shared/private) of the VR to activate COW */
       retval = sos_paging_map(sos_zero_page,       retval = sos_paging_map(sos_zero_physpage,
                               TRUE,                               TRUE,
                               SOS_VM_MAP_PROT_READ);                               SOS_VM_MAP_PROT_READ);
Line 305 
Line 324 
      
   return (sos_paddr_t)NULL;   return (sos_paddr_t)NULL;
 } }
  
  /*
   * /dev/zero character device FS operations
   */
  
  static sos_ret_t dev_zero_fs_open(struct sos_fs_node        * fsnode,
                                    struct sos_fs_opened_file * of,
                                    void * chardev_class_custom_data)
  {
    /* Make sure the device instance is known to the driver */
    if ( (SOS_CHARDEV_NULL_MINOR != fsnode->dev_id.device_instance)
         && (SOS_CHARDEV_ZERO_MINOR != fsnode->dev_id.device_instance) )
      return -SOS_ENODEV;
  
    return SOS_OK;
  }
  
  
  static sos_ret_t dev_zero_fs_seek(struct sos_fs_opened_file *this,
                                    sos_lsoffset_t offset,
                                    sos_seek_whence_t whence,
                                    /* out */ sos_lsoffset_t * result_position)
  {
    /* Artificiallly update the position in the "file" */
    sos_lsoffset_t ref_offs;
  
    *result_position = this->position;
    switch (whence)
      {
      case SOS_SEEK_SET:
        ref_offs = 0;
        break;
  
      case SOS_SEEK_CUR:
        ref_offs = this->position;
        break;
  
      case SOS_SEEK_END:
        return -SOS_ENOSUP;
        break;
  
      default:
        return -SOS_EINVAL;
      }
  
    if (offset < -ref_offs)
      return -SOS_EINVAL;
    
    this->position = ref_offs + offset;
    *result_position = this->position;
    return SOS_OK;
  }
  
  
  static sos_ret_t dev_zero_fs_read(struct sos_fs_opened_file *this,
                                    sos_uaddr_t dest_buf,
                                    sos_size_t * /* in/out */len)
  {
    struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry);
    sos_size_t offs, rdlen;
  
    /* Reading /dev/null returns immediately */
    if (SOS_CHARDEV_NULL_MINOR == fsnode->dev_id.device_instance)
      {
        *len = 0;
        return SOS_OK;
      }
  
    /* ZERO the destination buffer using the zero page (by page_size
       increments) */
    for (rdlen = offs = 0 ; offs < *len ; offs += SOS_PAGE_SIZE)
      {
        sos_size_t retval, memcpy_len = SOS_PAGE_SIZE;
        if (offs + memcpy_len > *len)
          memcpy_len = *len - offs;
        
        retval = sos_memcpy_to_user(dest_buf + offs, sos_zero_kernelpage,
                                    memcpy_len);
        if (retval < 0)
          break;
  
        rdlen += retval;
        if (retval != memcpy_len)
          break;
      }
  
    /* Artificiallly update the position in the "file" */
    *len = rdlen;
    this->position += rdlen;
    return SOS_OK;
  }
  
  
  static sos_ret_t dev_zero_fs_write(struct sos_fs_opened_file *this,
                                     sos_uaddr_t src_buf,
                                     sos_size_t * /* in/out */len)
  {
    /* Artificiallly update the position in the "file" */
    this->position += *len;
    return SOS_OK;
  }
  
  
  static sos_ret_t dev_zero_fs_mmap(struct sos_fs_opened_file *this,
                                    sos_uaddr_t *uaddr, sos_size_t size,
                                    sos_ui32_t access_rights,
                                    sos_ui32_t flags,
                                    sos_luoffset_t offset)
  {
    return sos_dev_zero_map(sos_process_get_address_space(this->owner),
                            uaddr, size, access_rights, flags);
  }
  
  
  static struct sos_chardev_ops dev_zero_fs_ops
    = (struct sos_chardev_ops) {
      .open  = dev_zero_fs_open,
      .close = NULL,
      .seek  = dev_zero_fs_seek,
      .read  = dev_zero_fs_read,
      .write = dev_zero_fs_write,
      .mmap  = dev_zero_fs_mmap,
      .fcntl = NULL,
      .ioctl = NULL
    };
  
 

/tmp/sos-code-article8/drivers/zero.h (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/drivers/zero.h (2005-12-28 11:44:56.000000000 +0100 )
Line 18 
Line 18 
 #ifndef _SOS_DEV_ZERO_H_ #ifndef _SOS_DEV_ZERO_H_
 #define _SOS_DEV_ZERO_H_ #define _SOS_DEV_ZERO_H_
  
  
  * "Driver" to map /dev/zero in user space  * "Driver" to map /dev/zero in user space
  */  */
Line 27 
Line 26 
 #include <sos/umem_vmm.h> #include <sos/umem_vmm.h>
  
  
  /**
   * Register the /dev/zero and /dev/null devices
   */
 sos_ret_t sos_dev_zero_subsystem_setup(); sos_ret_t sos_dev_zero_subsystem_setup();
  
  
 /** /**
  * Map /dev/zero into user space  * Map /dev/zero into user space
   * @note usage RESTRICTED to the kernel for start_init and the exec
   * syscall
  */  */
 sos_ret_t sos_dev_zero_map(struct sos_umem_vmm_as * dest_as, sos_ret_t sos_dev_zero_map(struct sos_umem_vmm_as * dest_as,
                            sos_uaddr_t *uaddr,                            sos_uaddr_t *uaddr,
  
 

/tmp/sos-code-article8/extra/bootsect.S (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/extra/bootsect.S (2005-12-28 11:44:56.000000000 +0100 )
Line 1 
Line 1 
  
 /* /*
  * @(#) $Id: bootsect.S,v 1.11 2005/04/28 21:55:35 d2 Exp $  * @(#) $Id: bootsect.S,v 1.12 2005/08/13 13:47:31 d2 Exp $
  * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty  * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty
  *           Jerome Petazzoni & Bernard Cassagne & coffeeman  *           Jerome Petazzoni & Bernard Cassagne & coffeeman
Line 88 
Line 88 
 #define LOAD_ADRESS 0x01000            /* 1er chargement du systeme */ #define LOAD_ADRESS 0x01000            /* 1er chargement du systeme */
 #define LOAD_SEG (LOAD_ADRESS>>4)      /* Segment du 1er chargement du */ #define LOAD_SEG (LOAD_ADRESS>>4)      /* Segment du 1er chargement du */
 #define MAX_KERN_LEN (COPY_ADRESS-LOAD_ADRESS) /* Taille noyau maxi */ #define MAX_KERN_LEN (COPY_ADRESS-LOAD_ADRESS) /* Taille noyau maxi */
 #define MAX_KERN_SECTS ((MAX_KERN_LEN + 511) / 512) /* Nbre de secteurs maxi */ #define MAX_KERN_SECTS ((MAX_KERN_LEN + 511) >> 9) /* Nbre de secteurs maxi */
 /* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente /* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente
                dans sos.lds ! */                dans sos.lds ! */
Line 153 
Line 153 
         int  $0x10         int  $0x10
  
         /* Verifie que le noyau n'est pas trop gros a charger */         /* Verifie que le noyau n'est pas trop gros a charger */
         cmpw $MAX_KERN_SECTS, (load_size)         cmpw $(MAX_KERN_SECTS), (load_size)
         movw $toobig, %si         movw $toobig, %si
         call message         call message
  
 

/tmp/sos-code-article8/extra/dot.mkvars (2005-07-01 16:39:48.000000000 +0200 )
../sos-code-article9/extra/dot.mkvars (2005-12-28 11:44:56.000000000 +0100 )
Line 3 
Line 3 
 # and customize the CC/LD/... variables. You still need the mtools # and customize the CC/LD/... variables. You still need the mtools
 # installed and running # installed and running
  
 CC := i586-gnu-gcc CC := i586-pc-elf-gcc
 LD := i586-gnu-ld LD := i586-pc-elf-ld
 OBJCOPY := i586-gnu-objcopy OBJCOPY := i586-pc-elf-objcopy
 STRIP := i586-gnu-strip STRIP := i586-pc-elf-strip
 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.
  
  
 

/tmp/sos-code-article8/extra/Makefile (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/extra/Makefile (2005-12-28 11:44:56.000000000 +0100 )
Line 2 
Line 2 
 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.
 EXTRA := $(shell [ -f ../userland/userprogs.kimg ] && echo ../userland/userprogs.kimg) EXTRA := $(shell [ -f ../userland/userprogs.kimg ] && echo ../userland/userprogs.kimg)
  
 all: sos_qemu.img all: sos_qemu.img termslave
 -include ../.mkvars -include ../.mkvars
  
Line 39 
Line 39 
 compile_kernel: compile_kernel:
         $(MAKE) -C ..         $(MAKE) -C ..
  
  termslave: termslave.c
          cc -Wall -o $@ $<
  
 clean: clean:
         $(RM) *.img *.elf *.bin *~ *.o *.out         $(RM) *.img *.elf *.bin *~ *.o *.out termslave
 

/tmp/sos-code-article8/extra/patch-qemu-port-e9.diff (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/extra/patch-qemu-port-e9.diff (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  
  Patch to enable the "port 0xe9" debugging facility in qemu (version
  0.7.2). This input/output port is used extensively in SOS to ease
  debugging (the sos_bochs_printf family of functions).
  
    -- Thomas Petazzoni and Christophe Lucas
  
  
  diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/hw/pc.c qemu-0.7.2-clucas/hw/pc.c
  --- qemu-0.7.2/hw/pc.c  2005-09-04 19:11:31.000000000 +0200
  +++ qemu-0.7.2-clucas/hw/pc.c   2005-09-14 11:24:51.000000000 +0200
  @@ -620,6 +620,12 @@ static void pc_init1(int ram_size, int v
   
       cmos_init(ram_size, boot_device, bs_table);
   
  +       for(i=0 ; i<MAX_PORT_E9_PORTS ; i++) {
  +               if (port_e9_hds[i]) {
  +                       port_e9_init(port_e9_hds[i]);
  +               }
  +       }
  +
       /* must be done after all PCI devices are instanciated */
       /* XXX: should be done in the Bochs BIOS */
       if (pci_enabled) {
  diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/Makefile.target qemu-0.7.2-clucas/Makefile.target
  --- qemu-0.7.2/Makefile.target  2005-09-04 19:11:31.000000000 +0200
  +++ qemu-0.7.2-clucas/Makefile.target   2005-09-14 11:24:50.000000000 +0200
  @@ -286,7 +286,7 @@ endif
   ifeq ($(TARGET_BASE_ARCH), i386)
   # Hardware support
   VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
  -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
  +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o port_e9.o
   VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
   endif
   ifeq ($(TARGET_BASE_ARCH), ppc)
  diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/port_e9.c qemu-0.7.2-clucas/port_e9.c
  --- qemu-0.7.2/port_e9.c        1970-01-01 01:00:00.000000000 +0100
  +++ qemu-0.7.2-clucas/port_e9.c 2005-09-14 11:24:51.000000000 +0200
  @@ -0,0 +1,51 @@
  +/*
  + * QEMU Port 0xe9 hack
  + *
  + * Copyright (c) 2000-2004 E. Marty, the bochs team, D.Decotigny
  + *
  + * Permission is hereby granted, free of charge, to any person obtaining a copy
  + * of this software and associated documentation files (the "Software"), to deal
  + * in the Software without restriction, including without limitation the rights
  + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  + * copies of the Software, and to permit persons to whom the Software is
  + * furnished to do so, subject to the following conditions:
  + *
  + * The above copyright notice and this permission notice shall be included in
  + * all copies or substantial portions of the Software.
  + *
  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  + * THE SOFTWARE.
  + */
  +
  +#include <stdio.h>
  +#include <unistd.h>
  +#include <inttypes.h>
  +
  +#include "vl.h"
  +
  +static void port_e9_write(void *opaque, uint32_t address, uint32_t data)
  +{
  +       CharDriverState *chr;
  +       chr = opaque;
  +
  +       qemu_chr_write(chr, & data, 1);
  +}
  +
  +static uint32_t port_e9_read(void *opaque, uint32_t address)
  +{
  +       return 0xE9;
  +}
  +
  +CharDriverState *port_e9_init (CharDriverState *chr)
  +{
  +       register_ioport_write(0xe9, 1, 1, port_e9_write, chr);
  +       register_ioport_read (0xe9, 1, 1, port_e9_read,  chr);
  +
  +       return chr;
  +}
  +
  diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/vl.c qemu-0.7.2-clucas/vl.c
  --- qemu-0.7.2/vl.c     2005-09-04 19:11:31.000000000 +0200
  +++ qemu-0.7.2-clucas/vl.c      2005-09-14 11:24:51.000000000 +0200
  @@ -146,6 +146,7 @@ int graphic_depth = 15;
   int full_screen = 0;
   TextConsole *vga_console;
   CharDriverState *serial_hds[MAX_SERIAL_PORTS];
  +CharDriverState *port_e9_hds[MAX_PORT_E9_PORTS];
   CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
   #ifdef TARGET_I386
   int win2k_install_hack = 0;
  @@ -2969,6 +2970,7 @@ enum {
       QEMU_OPTION_monitor,
       QEMU_OPTION_serial,
       QEMU_OPTION_parallel,
  +    QEMU_OPTION_port_e9,
       QEMU_OPTION_loadvm,
       QEMU_OPTION_full_screen,
       QEMU_OPTION_pidfile,
  @@ -3040,6 +3042,7 @@ const QEMUOption qemu_options[] = {
       { "monitor", 1, QEMU_OPTION_monitor },
       { "serial", 1, QEMU_OPTION_serial },
       { "parallel", 1, QEMU_OPTION_parallel },
  +    { "port-e9", 1, QEMU_OPTION_port_e9 },
       { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
       { "full-screen", 0, QEMU_OPTION_full_screen },
       { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
  @@ -3143,6 +3146,8 @@ int main(int argc, char **argv)
       char monitor_device[128];
       char serial_devices[MAX_SERIAL_PORTS][128];
       int serial_device_index;
  +    char port_e9_devices[MAX_PORT_E9_PORTS][128];
  +    int port_e9_device_index;
       char parallel_devices[MAX_PARALLEL_PORTS][128];
       int parallel_device_index;
       const char *loadvm = NULL;
  @@ -3184,12 +3189,17 @@ int main(int argc, char **argv)
       for(i = 1; i < MAX_SERIAL_PORTS; i++)
           serial_devices[i][0] = '\0';
       serial_device_index = 0;
  -    
  +
       pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc");
       for(i = 1; i < MAX_PARALLEL_PORTS; i++)
           parallel_devices[i][0] = '\0';
       parallel_device_index = 0;
  -    
  +
  +       pstrcpy(port_e9_devices[0], sizeof(port_e9_devices[0]), "vc");
  +       for(i = 1; i < MAX_PORT_E9_PORTS; i++)
  +               port_e9_devices[i][0] = '\0';
  +       port_e9_device_index = 0;
  +
       nb_tun_fds = 0;
       net_if_type = -1;
       nb_nics = 1;
  @@ -3526,6 +3536,15 @@ int main(int argc, char **argv)
                           sizeof(parallel_devices[0]), optarg);
                   parallel_device_index++;
                   break;
  +                       case QEMU_OPTION_port_e9:
  +                               if (port_e9_device_index >= MAX_PORT_E9_PORTS) {
  +                                       fprintf(stderr, "qemu: too many port e9 ports\n");
  +                                       exit(1);
  +                               }
  +                               pstrcpy(port_e9_devices[port_e9_device_index],
  +                                                       sizeof(port_e9_devices[0]), optarg);
  +                               port_e9_device_index++;
  +                               break;
              case QEMU_OPTION_loadvm:
                  loadvm = optarg;
                  break;
  @@ -3771,6 +3790,19 @@ int main(int argc, char **argv)
           }
       }
   
  +       for (i=0 ; i<MAX_PORT_E9_PORTS ; i++) {
  +               if (port_e9_devices[i][0] != '\0') {
  +                       port_e9_hds[i] = qemu_chr_open(port_e9_devices[i]);
  +                       if (!port_e9_hds[i]) {
  +                               fprintf(stderr, "qemu: could not open port e9 device '%s'\n", 
  +                                                                                               port_e9_devices[i]);
  +                               exit(1);
  +                       }
  +                       if (!strcmp(port_e9_devices[i], "vc"))
  +                               qemu_chr_printf(port_e9_hds[i], "port_e9_%d console\n", i);
  +               }
  +       }
  +
       /* setup cpu signal handlers for MMU / self modifying code handling */
   #if !defined(CONFIG_SOFTMMU)
       
  diff -urpNX /usr/kernel/dontdiff qemu-0.7.2/vl.h qemu-0.7.2-clucas/vl.h
  --- qemu-0.7.2/vl.h     2005-09-04 19:11:31.000000000 +0200
  +++ qemu-0.7.2-clucas/vl.h      2005-09-14 11:24:51.000000000 +0200
  @@ -242,6 +242,15 @@ extern CharDriverState *serial_hds[MAX_S
   
   extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
   
  +/* port E9 ports */
  +#define MAX_PORT_E9_PORTS 1
  +
  +#if (MAX_PORT_E9_PORTS != 1)
  + #error "No more than one port E9 is supported"
  +#endif
  +
  +extern CharDriverState *port_e9_hds[MAX_PORT_E9_PORTS];
  +
   /* network redirectors support */
   
   #define MAX_NICS 8
  @@ -688,6 +697,9 @@ SerialState *serial_init(int base, int i
   typedef struct ParallelState ParallelState;
   ParallelState *parallel_init(int base, int irq, CharDriverState *chr);
   
  +/* port-e9.c */
  +CharDriverState *port_e9_init(CharDriverState *chr);
  +
   /* i8259.c */
   
   typedef struct PicState2 PicState2;
  
 

/tmp/sos-code-article8/extra/patch-qemu-pty.diff (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/extra/patch-qemu-pty.diff (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  
  By default, with qemu version < 0.8.0 and with the command line
  qemu -monitor pty or -serial pty, local echo is
  enabled for the qemu side of the pty. This can result in infinite
  write/read loops and/or slowness of the simulation. Attached is a very
  small patch (against today's cvs) solving the problem. The 3 lines
  adjusting the tty fields could be replaced by "cfmakeraw(&tty)" if
  available on the host platform.
  
    -- David Decotigny (Dec 9 2005)
  
  
  Index: vl.c
  ===================================================================
  RCS file: /cvsroot/qemu/qemu/vl.c,v
  retrieving revision 1.152
  diff -u -r1.152 vl.c
  --- vl.c        5 Dec 2005 20:31:52 -0000        1.152
  +++ vl.c        9 Dec 2005 15:07:46 -0000
  @@ -1396,6 +1396,7 @@
   #if defined(__linux__)
   CharDriverState *qemu_chr_open_pty(void)
   {
  +    struct termios tty;
       char slave_name[1024];
       int master_fd, slave_fd;
       
  @@ -1403,6 +1404,14 @@
       if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
           return NULL;
       }
  +    
  +    /* Disabling local echo and line-buffered output */
  +    tcgetattr (master_fd, &tty);
  +    tty.c_lflag &= ~(ECHO|ICANON|ISIG);
  +    tty.c_cc[VMIN] = 1;
  +    tty.c_cc[VTIME] = 0;
  +    tcsetattr (master_fd, TCSAFLUSH, &tty);
  +
       fprintf(stderr, "char device redirected to %s\n", slave_name);
       return qemu_chr_open_fd(master_fd, master_fd);
   }
  
 

/tmp/sos-code-article8/extra/qemu-port-e9.diff (2005-07-01 16:39:48.000000000 +0200 )
../sos-code-article9/extra/qemu-port-e9.diff (1970-01-01 01:00:00.000000000 +0100 )
Line 1 
(File removed) 
 --- Makefile.target     17 Mar 2004 23:46:04 -0000        1.19 
 +++ Makefile.target     18 Mar 2004 14:20:29 -0000 
 @@ -217,7 +217,8 @@ 
  # must use static linking to avoid leaving stuff in virtual address space 
  VL_OBJS=vl.o osdep.o block.o monitor.o \ 
          ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ 
 -        fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o 
 +        fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o \ 
 +       port-e9.o 
  ifeq ($(TARGET_ARCH), ppc) 
  VL_OBJS+= hw.o 
  endif 
 --- hw/pc.c     14 Mar 2004 21:46:48 -0000        1.2 
 +++ hw/pc.c     18 Mar 2004 14:20:29 -0000 
 @@ -371,6 +371,7 @@ 
      SB16_init(); 
   
      fdctrl_init(6, 2, 0, 0x3f0, fd_table); 
 +    port_e9_init(); 
   
      cmos_init(ram_size, boot_device); 
  } 
 --- /dev/null   2003-01-30 11:24:37.000000000 +0100 
 +++ port-e9.c   2004-03-18 15:18:52.660493187 +0100 
 @@ -0,0 +1,38 @@ 
 +/* 
 + * QEMU Port 0xe9 hack 
 + *  
 + * Copyright (c) 2000-2004 E. Marty, the bochs team, D. Decotigny 
 + *  
 + * Permission is hereby granted, free of charge, to any person obtaining a copy 
 + * of this software and associated documentation files (the "Software"), to deal 
 + * in the Software without restriction, including without limitation the rights 
 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 + * copies of the Software, and to permit persons to whom the Software is 
 + * furnished to do so, subject to the following conditions: 
 + * 
 + * The above copyright notice and this permission notice shall be included in 
 + * all copies or substantial portions of the Software. 
 + * 
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 + * THE SOFTWARE. 
 + */ 
 +#include <stdio.h> 
 +#include <unistd.h> 
 +#include <inttypes.h> 
 + 
 +#include "vl.h" 
 + 
 +static void bochs_e9_write(void *opaque, uint32_t address, uint32_t data) 
 +{ 
 +  write(fileno(stdout), &data, 1); 
 +} 
 + 
 +void port_e9_init () 
 +{ 
 +   register_ioport_write(0xe9, 1, 1, bochs_e9_write, NULL); 
 +} 
 --- vl.h        17 Mar 2004 23:17:16 -0000        1.14 
 +++ vl.h        18 Mar 2004 14:29:06 -0000 
 @@ -268,4 +268,7 @@ 
  void term_flush(void); 
  void term_print_help(void); 
   
 +/* port-e9.c */ 
 +void port_e9_init(void); 
 + 
  #endif /* VL_H */ 
 

/tmp/sos-code-article8/extra/README (2005-07-01 16:39:48.000000000 +0200 )
../sos-code-article9/extra/README (2005-12-28 11:44:56.000000000 +0100 )
Line 19 
Line 19 
    of the kernel    of the kernel
  
 Misc: Misc:
  - qemu-port-e9.diff: patch over qemu to support the bochs "port 0xe9 hack"  - patch-qemu-port-e9.diff: patch over qemu to support the bochs "port
     0xe9 hack"
   - patch-qemu-pty.diff: patch over qemu to fix a bug related to the
     handling of the "-monitor pty" and "-serial pty" options
   - termslave.c: Linux program to dial with qemu's monitor (or serial
     line) from within a terminal. See comments in the beginning
  
 What you can do with these files What you can do with these files
  
 

/tmp/sos-code-article8/extra/termslave.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/extra/termslave.c (2005-12-28 11:44:56.000000000 +0100 )
(New file) 
Line 1 
  /* Unix pty slave program -- David Decotigny 2005
     License: GNU GPL version 2
     Most of it taken from the GNU C library doc examples */
  #include <utmp.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <termios.h>
  
  /**
   * @file termslave.c
   *
   * Linux pseudo-TTY slave program. To be used with "qemu -monitor pty"
   * to access qemu's monitor from any linux terminal. To use it, launch
   * a "qemu -monitor pty" in one terminal, take a look at the first
   * line stating "char device redirected to /dev/pts/4" for example,
   * and lauch the termslave program as "./termslave /dev/pts/4" in
   * another terminal.
   *
   * To make this correctly work, one has to apply the
   * patch-qemu-pty.diff patch to qemu < 0.8.0 (qemu 0.8.0 and beyond
   * already includes this patch).
   *
   * This program also works with the "-serial pty" flag of qemu. It can
   * be used to send commands to the SOS serial-line shell (article 9).
   */
  
  
  /* Use this variable to remember original terminal attributes. */
  struct termios saved_attributes;
  
  static void
  reset_input_mode (void)
  {
    tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
  }
  
  static void
  set_input_mode (void)
  {
    struct termios tattr;
    
    /* Make sure stdin is a terminal. */
    if (!isatty (STDIN_FILENO))
      {
        fprintf (stderr, "Not a terminal.\n");
        exit (EXIT_FAILURE);
      }
    
    /* Save the terminal attributes so we can restore them later. */
    tcgetattr (STDIN_FILENO, &saved_attributes);
    atexit (reset_input_mode);
    
    /* Set the funny terminal modes. */
    tcgetattr (STDIN_FILENO, &tattr);
    tattr.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                         |INLCR|IGNCR|ICRNL|IXON);
    tattr.c_lflag &= ~(ICANON|ECHO);
    tattr.c_cflag |= CLOCAL;
    tattr.c_cc[VMIN] = 1;
    tattr.c_cc[VTIME] = 0;
    tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr);
  }
  
  int main (int argc, char *argv[])
  {
    int term;
  
    if (argc < 2)
      {
        fprintf(stderr, "Usage: %s /dev/pts/number\n", argv[0]);
        return -1;
      }
  
    term = open(argv[1], O_RDWR);
    if (term < 0)
      {
        perror("open");
        return -1;
      }
    if (! isatty(term))
      {
        fprintf(stderr, "%s is not a valid terminal\n", argv[1]);
        return -1;
      }
  
    set_input_mode();
  
    while (1)
      {
        fd_set cur_set;
        FD_ZERO(& cur_set);
        FD_SET(STDIN_FILENO, & cur_set);
        FD_SET(term, & cur_set);
        if (select(FD_SETSIZE, & cur_set, NULL, NULL, NULL) < 1)
          continue;
  
        if (FD_ISSET(term, & cur_set))
          {
            char buf[1024];
            int len = read(term, buf, sizeof(buf));
  
            if (len >= 1)
              write(STDOUT_FILENO, buf, len);
            else
              {
                fprintf(stderr, "Master exitted\n");
                break;
              }
          }
  
        if (FD_ISSET(STDIN_FILENO, & cur_set))
          {
            char c;
            if (read(STDIN_FILENO, &c, 1) == 1)
              {
                if (c == 0x4) /* ctrl-D */
                  break;
                write(term, &c, 1);
              }
            else
              break;
          }
      }
    
    return 0;
  }
  
 

/tmp/sos-code-article8/hwcore/gdt.c (2005-07-01 16:39:48.000000000 +0200 )
../sos-code-article9/hwcore/gdt.c (2005-12-28 11:44:56.000000000 +0100 )
Line 48 
Line 48 
   sos_ui8_t  granularity:1;         /* 0=limit in bytes, 1=limit in pages */   sos_ui8_t  granularity:1;         /* 0=limit in bytes, 1=limit in pages */
      
   sos_ui8_t  base_paged_addr_31_24; /* Base address bits 31..24 */   sos_ui8_t  base_paged_addr_31_24; /* Base address bits 31..24 */
 } __attribute__ ((packed, aligned (8))); } __attribute__ ((packed, aligned(8)));
  
 /** /**
Line 59 
Line 59 
  * 3.5.1  * 3.5.1
  */  */
 struct x86_gdt_register { struct x86_gdt_register {
   /* The maximum GDT offset allowed to access an entry in the GDT */   /** Intel doc says that the real GDT register (ie the "limit" field)
   sos_ui16_t  limit;       should be odd-word aligned. That's why we add a padding here.
        Credits to Romain for having signalled this to us. */
    sos_ui16_t  padding;
   /* This is not exactly a "virtual" address, ie an adddress such as   /** The maximum GDT offset allowed to access an entry in the GDT */
      those of instructions and data; this is a "linear" address, ie an   sos_ui16_t  limit;
      address in the paged memory. However, in SOS we configure the   
      segmented memory as a "flat" space: the 0-4GB segment-based (ie   /**
      "virtual") addresses directly map to the 0-4GB paged memory (ie    * This is not exactly a "virtual" address, ie an adddress such as
      "linear"), so that the "linear" addresses are numerically equal    * those of instructions and data; this is a "linear" address, ie an
      to the "virtual" addresses: this base_addr will thus be the same    * address in the paged memory. However, in SOS we configure the
      as the address of the gdt array */    * segmented memory as a "flat" space: the 0-4GB segment-based (ie
   sos_ui32_t base_addr;    * "virtual") addresses directly map to the 0-4GB paged memory (ie
 } __attribute__((packed, aligned(8)));    * "linear"), so that the "linear" addresses are numerically equal
     * to the "virtual" addresses: this base_addr will thus be the same
     * as the address of the gdt array
     */
      sos_ui32_t base_addr;
  } __attribute__((packed, aligned(4)));
  
 /** /**
Line 104 
Line 111 
       .present=               1,                                \       .present=               1,                                \
       .limit_19_16=           0xf,                              \       .limit_19_16=           0xf,                              \
       .custom=                0,                                \       .custom=                0,                                \
        .zero=                  0,                                \
       .op_size=               1,  /* 32 bits instr/data */      \       .op_size=               1,  /* 32 bits instr/data */      \
       .granularity=           1   /* limit is in 4kB Pages */   \       .granularity=           1,  /* limit is in 4kB Pages */   \
        .base_paged_addr_31_24= 0                                 \
  
  
Line 120 
Line 129 
                                    register_kernel_tss */                                    register_kernel_tss */
 }; };
  
  
 sos_ret_t sos_gdt_subsystem_setup(void) sos_ret_t sos_gdt_subsystem_setup(void)
 { {
   struct x86_gdt_register gdtr;   struct x86_gdt_register gdtr;
  
    /* Put some garbage in the padding field of the GDTR */
    gdtr.padding   = ~0;
  
   /* Address of the GDT */   /* Address of the GDT */
   gdtr.base_addr = (sos_ui32_t) gdt;   gdtr.base_addr = (sos_ui32_t) gdt;
  
Line 145 
Line 158 
                  movw %%ax,  %%fs \n\                  movw %%ax,  %%fs \n\
                  movw %%ax,  %%gs"                  movw %%ax,  %%gs"
                 :                 :
                 :"m"(gdtr),                 :"m"(gdtr.limit) /* The real beginning of the GDT
                                      register is /after/ the "padding"
                                      field, ie at the "limit"
                                      field. */,
                  "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA))                  "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA))
                 :"memory","eax");                 :"memory","eax");
Line 170 
Line 186 
       .present=               1,       .present=               1,
       .limit_19_16=           0,    /* Size of a TSS is < 2^16 ! */       .limit_19_16=           0,    /* Size of a TSS is < 2^16 ! */
       .custom=                0,    /* Unused */       .custom=                0,    /* Unused */
        .zero=                  0,
       .op_size=               0,    /* See Intel x86 vol 3 figure 6-3 */       .op_size=               0,    /* See Intel x86 vol 3 figure 6-3 */
       .granularity=           1,    /* limit is in Bytes */       .granularity=           1,    /* limit is in Bytes */
       .base_paged_addr_31_24= (tss_vaddr >> 24) & 0xff       .base_paged_addr_31_24= (tss_vaddr >> 24) & 0xff
  
 

/tmp/sos-code-article8/hwcore/ioports.h (2005-07-01 16:39:48.000000000 +0200 )
../sos-code-article9/hwcore/ioports.h (2005-12-28 11:44:56.000000000 +0100 )
Line 62 
Line 62 
   _v;                                                           \   _v;                                                           \
 }) })
  
  // write value (word) on port
  #define outl(value, port)                                       \
    __asm__ volatile (                                                   \
          "outl %0,%w1"                                                \
          ::"a" (value),"Nd" (port)                                \
          )                                                        \
  
  // read one word from port
  #define inl(port)                                               \
  ({                                                              \
    unsigned int _v;                                              \
    __asm__ volatile (                                            \
          "inl %w1,%0"                                                \
          :"=a" (_v)                                                \
          :"Nd" (port)                                                \
          );                                                        \
    _v;                                                           \
  })
  
 #endif /* _SOS_IOPORTS_H_ */ #endif /* _SOS_IOPORTS_H_ */
  
 

/tmp/sos-code-article8/INSTALL (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/INSTALL (2005-12-28 11:44:58.000000000 +0100 )
Line 121 
Line 121 
  
 NOTE : recommended versions of the tools NOTE : recommended versions of the tools
 ---------------------------------------- ----------------------------------------
  - OS           : Linux 2.6.11.7-d2-1 i686 
  - gcc          : gcc (GCC) 3.3.6 (Debian 1:3.3.6-5) 
  - GNU binutils : GNU ld version 2.15 
  - GNU make     : GNU Make 3.80 
 Also tested with (on ppc/debian host): Release development platform:
  - OS           : Linux 2.6.10-powerpc ppc 
  - gcc          : gcc (GCC) 3.2.2  - OS           : Linux 2.6.14.3 x86_64
  - GNU binutils : GNU ld version 2.13.2  - gcc          : i586-pc-elf-gcc-4.0.2 (GCC) 4.0.2
   - GNU binutils : GNU ld version 2.16
  
  Usual development platforms known to work:
  
   + amd64 (x86_64)/debian sarge:
     - OS           : Linux 2.6.14.3 x86_64
     - gcc          : i586-pc-elf-gcc-4.0.2 (GCC) 4.0.2
     - GNU binutils : GNU ld version 2.16
  
   + x86/debian sarge:
     - OS           : Linux 2.6.11.7-d2-1 i686
     - gcc          : gcc (GCC) 3.3.6 (Debian 1:3.3.6-5)
     - GNU binutils : GNU ld version 2.15
  
   + ppc/debian sarge:
     - OS           : Linux 2.6.10-powerpc ppc
     - gcc          : gcc (GCC) 3.2.2
     - GNU binutils : GNU ld version 2.13.2
  
   + x86/windows with cygwin (http://sos.enix.org/SOSFaq#TOC_0_2_1):
     - OS           : MS Windows XP Pro SP2 / Cygwin
     - gcc          : gcc 3.4.4
     - GNU binutils : GNU ld version 2.16
     - GNU make     : GNU Make 3.80
  
 -- --
 David Decotigny David Decotigny
  
 

/tmp/sos-code-article8/Makefile (2005-07-01 16:39:47.000000000 +0200 )
../sos-code-article9/Makefile (2005-12-28 11:44:58.000000000 +0100 )
Line 19 
Line 19 
 LD=ld LD=ld
 CP=cp CP=cp
 STRIP=strip STRIP=strip
 CFLAGS  = -Wall -nostdinc -ffreestanding -DKERNEL_SOS -O CFLAGS  = -Wall -nostdinc -ffreestanding -DKERNEL_SOS -O -g
 LDFLAGS = --warn-common -nostdlib LDFLAGS = --warn-common -nostdlib
 OBJECTS = bootstrap/multiboot.o                                 \ OBJECTS = bootstrap/multiboot.o                                 \
Line 40 
Line 40 
           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/kbd.o drivers/kbdmapfr.o                        \
            drivers/tty.o drivers/serial.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                                        \           drivers/fs_virtfs.o sos/chardev.o                        \
  
 KERNEL_OBJ   = sos.elf KERNEL_OBJ   = sos.elf
 KERNEL_LOAD  = sos.gz KERNEL_LOAD  = sos.gz
 MULTIBOOT_IMAGE = fd.img MULTIBOOT_IMAGE = fd.img
 PWD := $(shell pwd) PWD := $(shell pwd | sed 's/"/\\\"/g;s/\$$/\\\$$/g')
 # Main target # Main target
 all: $(MULTIBOOT_IMAGE) all: $(MULTIBOOT_IMAGE)
Line 56 
Line 58 
         ./support/build_image.sh $@ $<         ./support/build_image.sh $@ $<
  
 $(KERNEL_LOAD): $(KERNEL_OBJ) $(KERNEL_LOAD): $(KERNEL_OBJ)
         $(CP) $< $<.strip && $(STRIP) -sx $<.strip         $(CP) $< $<.strip && $(STRIP) -sx -R .comment $<.strip
  
 $(KERNEL_OBJ): $(OBJECTS) ./support/sos.lds $(KERNEL_OBJ): $(OBJECTS) ./support/sos.lds
Line 72 
Line 74 
  
 # Create objects from C source code # Create objects from C source code
 %.o: %.c %.o: %.c
         $(CC) -I$(PWD) -c $< $(CFLAGS) -o $@         $(CC) "-I$(PWD)" -c "$<" $(CFLAGS) -o "$@"
 # Create objects from assembler (.S) source code # Create objects from assembler (.S) source code
 %.o: %.S %.o: %.S
         $(CC) -I$(PWD) -c $< $(CFLAGS) -DASM_SOURCE=1 -o $@         $(CC) "-I$(PWD)" -c "$<" $(CFLAGS) -DASM_SOURCE=1 -o "$@"
 FORCE: FORCE:
         @         @
Line 91 
Line 93 
         $(RM) sos/*.o sos/*~         $(RM) sos/*.o sos/*~
         $(RM) support/*~         $(RM) support/*~
         $(RM) extra/*~         $(RM) extra/*~
          $(MAKE) -C extra clean
         $(MAKE) -C userland clean         $(MAKE) -C userland clean
  
 

/tmp/sos-code-article8/README (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/README (2005-12-28 11:44:58.000000000 +0100 )
Line 42 
Line 42 
  - slab-type kernel memory allocation  - slab-type kernel memory allocation
  - no swap, no reverse mapping  - no swap, no reverse mapping
  - VERY simple drivers: keyboard, x86 video memory, IDE disks  - VERY simple drivers: keyboard, x86 video memory, IDE disks
  - logical devices: partitions, FAT filesystem, "hard-coded"  - logical devices: partitions, FAT/ext2 filesystem, Unix-style
    mountpoints only (~ MSDOS)    mountpoints, hard/soft links
  - no network stack  - basic network stack (ARP/IP/UDP)
    user threads (kernel-level scheduling only), mmap API, basic VFS    user threads (kernel-level scheduling only), mmap API, basic VFS
  
  
 

/tmp/sos-code-article8/sos/chardev.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/sos/chardev.c (2005-12-28 11:44:57.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005      David Decotigny, Thomas Petazzoni
  
     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/assert.h>
  #include <sos/types.h>
  #include <sos/fs.h>
  #include <sos/list.h>
  #include <sos/kmalloc.h>
  
  #include "chardev.h"
  
  struct sos_chardev_class
  {
    sos_ui32_t                device_class;
    struct sos_chardev_ops   *ops;
  
    /** This corresponds to the chardev_class_custom_data field passed
        to open/read/etc. and to sos_chardev_register_class() */
    void                     *custom_data;
  
    sos_count_t               ref_cnt; /**< increased each time a FS
                                            node is opened */
  
    struct sos_chardev_class *next, *prev;
  };
  
  
  struct sos_chardev_opened_file
  {
    /** "normal" VFS opened file structure is available in this
        structure */
    struct sos_fs_opened_file  super;
  
    /** Additional information for this opened file: the device's class
        structure */
    struct sos_chardev_class  *class;
  };
  
  
  /** The list of registered classes, ie the dictionary major number ->
      device class description */
  static struct sos_chardev_class *registered_chardev_classes;
  
  
  /* Forward declarations */
  static struct sos_fs_ops_opened_file chardev_ops_opened_file;
  static struct sos_fs_ops_opened_chardev chardev_ops_opened_chardev;
  
  static sos_ret_t
  chardev_helper_sync(struct sos_fs_node * this);
  static sos_ret_t
  chardev_helper_new_opened_file(struct sos_fs_node * this,
                                 const struct sos_process * owner,
                                 sos_ui32_t open_flags,
                                 struct sos_fs_opened_file ** result_of);
  static sos_ret_t
  chardev_helper_close_opened_file(struct sos_fs_node * this,
                                   struct sos_fs_opened_file * of);
  static sos_ret_t
  duplicate_opened_chardev(struct sos_fs_opened_file *this,
                           const struct sos_process  * for_owner,
                           struct sos_fs_opened_file **result);
  
  
  /**
   * Return the device descriptionn structure for the corresponding
   * device class, or NULL when none found.
   */
  static struct sos_chardev_class * lookup_chardev_class(sos_ui32_t device_class)
  {
    struct sos_chardev_class *chardev;
    int nb;
  
    list_foreach (registered_chardev_classes, chardev, nb)
      {
        if (chardev->device_class == device_class)
          return chardev;
      }
  
    return NULL;
  }
  
  
  sos_ret_t sos_chardev_register_class (sos_ui32_t device_class,
                                        struct sos_chardev_ops *ops,
                                        void * chardev_class_custom_data)
  {
    struct sos_chardev_class *chardev;
  
    /* Make sure this device class is not already registered */
    chardev = lookup_chardev_class(device_class);
    if (NULL != chardev)
      return -SOS_EBUSY;
  
    /* Allocate and initialize a new device description */
    chardev = (struct sos_chardev_class *)
      sos_kmalloc(sizeof(struct sos_chardev_class), 0);
    if (chardev == NULL)
      return -SOS_ENOMEM;
  
    chardev->device_class = device_class;
    chardev->custom_data  = chardev_class_custom_data;
    chardev->ops          = ops;
    chardev->ref_cnt      = 1;
  
    /* insert it into the list */
    list_add_tail (registered_chardev_classes, chardev);
  
    return SOS_OK;
  }
  
  
  sos_ret_t sos_chardev_unregister_class (sos_ui32_t device_class)
  {
    struct sos_chardev_class *chardev;
  
    /* Make sure this device class is already registered */
    chardev = lookup_chardev_class(device_class);
    if (NULL == chardev)
      return -SOS_ENODEV;
  
    /* Make sure no files are already opened for it */
    if (chardev->ref_cnt != 1)
      return -SOS_EBUSY;
  
    /* remove it from the list */
    list_delete (registered_chardev_classes, chardev);
    return sos_kfree((sos_vaddr_t)chardev);
  }
  
  
  
  sos_ret_t sos_chardev_helper_ref_new_fsnode(struct sos_fs_node * this)
  {
    this->sync              = chardev_helper_sync;
    this->new_opened_file   = chardev_helper_new_opened_file;
    this->close_opened_file = chardev_helper_close_opened_file;
  
    return SOS_OK;
  }
  
  
  sos_ret_t sos_chardev_helper_release_fsnode(struct sos_fs_node * this)
  {
    return SOS_OK;
  }
  
  
  /** No synchronization to anything needed for a character device */
  static sos_ret_t
  chardev_helper_sync(struct sos_fs_node * this)
  {
    return SOS_OK;
  }
  
  
  /** Callback called each time an FS-node is opened by a user process:
      create a new sos_chardev_opened_file object associated to the
      correct major number, and call the device driver's open method */
  static sos_ret_t
  chardev_helper_new_opened_file(struct sos_fs_node * this,
                                 const struct sos_process * owner,
                                 sos_ui32_t open_flags,
                                 struct sos_fs_opened_file ** result_of)
  {
    sos_ret_t retval;
    struct sos_chardev_opened_file *chardev_of;
  
    /* Lookup the character device description structure */
    struct sos_chardev_class * chardev
      = lookup_chardev_class(this->dev_id.device_class);
    if (NULL == chardev)
      return -SOS_ENODEV;
  
    /* Alloocate the new "open file" description structure */
    chardev_of = (struct sos_chardev_opened_file*)
      sos_kmalloc(sizeof(struct sos_chardev_opened_file), 0);
    if (NULL == chardev_of)
      return -SOS_ENOMEM;
  
    memset(chardev_of, 0x0, sizeof(struct sos_chardev_opened_file));
    chardev_of->class = chardev;
    *result_of = & chardev_of->super;
  
    /* Increase the reference coount for that node */
    SOS_ASSERT_FATAL(chardev->ref_cnt >= 1);
    chardev->ref_cnt ++;
  
    /* Initialize the read/write/seek callbacks */
    (*result_of)->owner       = owner;
    (*result_of)->open_flags  = open_flags;
    (*result_of)->ops_file    = & chardev_ops_opened_file;
    (*result_of)->ops_chardev = & chardev_ops_opened_chardev;
  
    /* Call the open callback */
    retval = chardev->ops->open(this, & chardev_of->super, chardev->custom_data);
    if (SOS_OK != retval)
      {
        sos_kfree((sos_vaddr_t) chardev_of);
        chardev->ref_cnt --;
        *result_of = NULL;
        return retval;
      }
  
    /* Specify the duplicate method */
    (*result_of)->duplicate = duplicate_opened_chardev;
  
    return retval;
  }
  
  
  /** Callback called each time an opened file is closed. Un-allocate
      the associated sos_chardev_opened_file object */
  static sos_ret_t
  chardev_helper_close_opened_file(struct sos_fs_node * this,
                                   struct sos_fs_opened_file * of)
  {
    sos_ret_t retval;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)of);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
  
    /* Free the new "open file" description structure */
    if (NULL != chardev->ops->close)
      retval = chardev->ops->close(& chardev_of->super, chardev->custom_data);
    else
      retval = SOS_OK;
    if (SOS_OK != retval)
      return retval;
  
    /* Decrease the reference coount for that node */
    SOS_ASSERT_FATAL(chardev->ref_cnt > 1);
    chardev->ref_cnt --;
    
    sos_kfree((sos_vaddr_t) chardev_of);
    return retval;
  }
  
  
  /**
   * Callback called each time a process is "forked": create a new
   * sos_chardev_opened_file for the new process.
   *
   * @note Almost identical to the open callback.
   */
  static sos_ret_t
  duplicate_opened_chardev(struct sos_fs_opened_file *this,
                           const struct sos_process  * for_owner,
                           struct sos_fs_opened_file **result)
  {
    sos_ret_t retval;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
    struct sos_chardev_opened_file *new_chardev_of;
    struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry);
  
    *result = NULL;
  
    /* Lookup the character device description structure */
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
  
    /* Allocate a new duplicate copy of the original opened file */
    new_chardev_of = (struct sos_chardev_opened_file*)
      sos_kmalloc(sizeof(struct sos_chardev_opened_file), 0);
    if (NULL == new_chardev_of)
      return -SOS_ENOMEM;
  
    memcpy(new_chardev_of, chardev_of, sizeof(*new_chardev_of));
    new_chardev_of->super.owner    = for_owner;
    new_chardev_of->super.direntry = NULL; /* Reset the direntry
                                              for the new opened file */
    SOS_ASSERT_FATAL(chardev->ref_cnt > 1);
    chardev->ref_cnt ++;
  
    retval = chardev->ops->open(fsnode,
                                & new_chardev_of->super, chardev->custom_data);
    if (SOS_OK != retval)
      {
        sos_kfree((sos_vaddr_t) new_chardev_of);
        chardev->ref_cnt --;
        return retval;
      }
  
    /* Make sure the required methods are overloaded */
    SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file);
    SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file->seek);
    SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file->read);
  
    *result = & new_chardev_of->super;
    return retval;
  }
  
  
  /*
   * FS generic character device wrapper functions
   */
  
  /**
   * Callback called to change the position in the opened file: call the
   * seek method of the device driver.
   */
  static sos_ret_t chardev_wrap_seek(struct sos_fs_opened_file *this,
                                     sos_lsoffset_t offset,
                                     sos_seek_whence_t whence,
                                     /* out */ sos_lsoffset_t * result_position)
  {
    sos_ret_t retval = -SOS_ENOSYS;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
    SOS_ASSERT_FATAL(NULL != chardev->ops);
  
    if (NULL != chardev->ops->seek)
      retval = chardev->ops->seek(this, offset, whence, result_position);
    
    return retval;
  }
  
  
  /**
   * Callback called to read the contents of the opened file: call the
   * read method of the device driver.
   */
  static sos_ret_t chardev_wrap_read(struct sos_fs_opened_file *this,
                                     sos_uaddr_t dest_buf,
                                     sos_size_t * /* in/out */len)
  {
    sos_ret_t retval = -SOS_ENOSYS;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
    SOS_ASSERT_FATAL(NULL != chardev->ops);
  
    if (NULL != chardev->ops->read)
      retval = chardev->ops->read(this, dest_buf, len);
    
    return retval;
  }
  
  
  /**
   * Callback called to write bytes to the opened file: call the write
   * method of the device driver.
   */
  static sos_ret_t chardev_wrap_write(struct sos_fs_opened_file *this,
                                      sos_uaddr_t src_buf,
                                      sos_size_t * /* in/out */len)
  {
    sos_ret_t retval = -SOS_ENOSYS;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
    SOS_ASSERT_FATAL(NULL != chardev->ops);
  
    if (NULL != chardev->ops->write)
      retval = chardev->ops->write(this, src_buf, len);
    
    return retval;
  }
  
  
  /**
   * Callback called to map the contents of the opened file: call the
   * map method of the device driver.
   */
  static sos_ret_t chardev_wrap_mmap(struct sos_fs_opened_file *this,
                                     sos_uaddr_t *uaddr, sos_size_t size,
                                     sos_ui32_t access_rights,
                                     sos_ui32_t flags,
                                     sos_luoffset_t offset)
  {
    sos_ret_t retval = -SOS_ENOSYS;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
    SOS_ASSERT_FATAL(NULL != chardev->ops);
  
    if (NULL != chardev->ops->mmap)
      retval = chardev->ops->mmap(this, uaddr, size,
                                  access_rights, flags, offset);
    
    return retval;
  }
  
  
  /**
   * Callback called to change the state of the opened file: call the
   * fcntl method of the device driver.
   */
  static sos_ret_t chardev_wrap_fcntl(struct sos_fs_opened_file *this,
                                      int req_id,
                                      sos_ui32_t req_arg)
  {
    sos_ret_t retval = -SOS_ENOSYS;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
    SOS_ASSERT_FATAL(NULL != chardev->ops);
  
    if (NULL != chardev->ops->fcntl)
      retval = chardev->ops->fcntl(this, req_id, req_arg);
    
    return retval;
  }
  
  
  /**
   * Callback called to control the underlying device: call the ioctl
   * method of the device driver.
   */
  static sos_ret_t chardev_wrap_ioctl(struct sos_fs_opened_file *this,
                                      int req_id,
                                      sos_ui32_t req_arg)
  {
    sos_ret_t retval = -SOS_ENOSYS;
    struct sos_chardev_opened_file *chardev_of
      = ((struct sos_chardev_opened_file*)this);
  
    struct sos_chardev_class * chardev = chardev_of->class;
    SOS_ASSERT_FATAL(NULL != chardev);
    SOS_ASSERT_FATAL(NULL != chardev->ops);
  
    if (NULL != chardev->ops->ioctl)
      retval = chardev->ops->ioctl(this, req_id, req_arg);
    
    return retval;
  }
  
  
  /**
   * Gather the callbacks for a "character device" opened file
   */
  static struct sos_fs_ops_opened_file chardev_ops_opened_file
    = (struct sos_fs_ops_opened_file) {
      .seek  = chardev_wrap_seek,
      .read  = chardev_wrap_read,
      .write = chardev_wrap_write,
      .mmap  = chardev_wrap_mmap,
      .fcntl = chardev_wrap_fcntl
    };
  
  
  static struct sos_fs_ops_opened_chardev chardev_ops_opened_chardev
    = (struct sos_fs_ops_opened_chardev) {
      .ioctl = chardev_wrap_ioctl
    };
  
 

/tmp/sos-code-article8/sos/chardev.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/sos/chardev.h (2005-12-28 11:44:57.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005      David Decotigny, Thomas Petazzoni
  
     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_CHARDEV_H_
  #define _SOS_CHARDEV_H_
  
  /**
   * @file chardev.h
   *
   * Interface between the VFS and the "character" devices. The
   * following functions provide the mechanisms to bind the "character
   * device" nodes (@see mknod) to their device driver.
   *
   * The VFS layer must be perceived as an uniform access library on top
   * of a set of specialized FS. The "chardev" layer is to be perceived
   * as a FS-agnostic layer on top of the FS that binds the special
   * "character device" nodes to a set of system-wide read/write/seek
   * functions.
   */
  
  #include "fs.h"
  
  /**
   * The fundamental callbacks for a character device: they are common
   * to all the character devices of the same class. One is free to do
   * whatever she likes with the "custom_data" of the opened file passed
   * as argument
   */
  struct sos_chardev_ops {
    /**
     * @note also called upon a "duplicate_opened_file", aka upon a
     * fork()
     * @note When this callback is called, of is NOT bound to any
     * nscache_node, so don't ever call any sos_fs_nscache_* function !
     * @note To get the fsnode associated to "of", don't call
     * sos_fs_nscache_get_fs_node(): it is already given by the "fsnode"
     * argument
     * @note MANDATORY !
     */
    sos_ret_t (*open)(struct sos_fs_node        * fsnode,
                      struct sos_fs_opened_file * of,
                      void * chardev_class_custom_data);
  
    /**
     * Called each time an opened "character device" is declared unused
     * by user space
     * @note Optional (might be NULL)
     */
    sos_ret_t (*close)(struct sos_fs_opened_file * of,
                       void * chardev_class_custom_data);
  
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     */
    sos_ret_t (*seek)(struct sos_fs_opened_file *this,
                      sos_lsoffset_t offset,
                      sos_seek_whence_t whence,
                      /* out */ sos_lsoffset_t * result_position);
  
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     */
    sos_ret_t (*read)(struct sos_fs_opened_file *this,
                      sos_uaddr_t dest_buf,
                      sos_size_t * /* in/out */len);
  
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     * @note Please call sos_fs_mark_dirty() if disk contents is changed
     */
    sos_ret_t (*write)(struct sos_fs_opened_file *this,
                       sos_uaddr_t src_buf,
                       sos_size_t * /* in/out */len);
  
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     * @note Please call sos_fs_mark_dirty() if disk contents is changed
     */
    sos_ret_t (*mmap)(struct sos_fs_opened_file *this,
                      sos_uaddr_t *uaddr, sos_size_t size,
                      sos_ui32_t access_rights,
                      sos_ui32_t flags,
                      sos_luoffset_t offset);
  
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     * @note Please call sos_fs_mark_dirty() if disk contents is changed
     */
    sos_ret_t (*fcntl)(struct sos_fs_opened_file *this,
                       int req_id,
                       sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
  
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     * @note Please call sos_fs_mark_dirty() if disk contents is changed
     */
    sos_ret_t (*ioctl)(struct sos_fs_opened_file *this,
                       int req_id,
                       sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
  };
  
  
  /**
   * Associate the given set of operations to the given major number.
   *
   * @note Character device drivers are registered for a complete class
   * of character devices (up to 4 billion devices per class)
   */
  sos_ret_t sos_chardev_register_class (sos_ui32_t device_class,
                                        struct sos_chardev_ops * ops,
                                        void * chardev_class_custom_data);
  
  
  /**
   * Unbind the given set of operations with the given major number
   *
   * @return SOS_EBUSY when the character device is still opened by any
   * process.
   */
  sos_ret_t sos_chardev_unregister_class (sos_ui32_t device_class);
  
  
  /*
   * Callbacks restricted to fs.c internals
   */
  
  /**
   * Update the FS node ops_blockdev callbacks after an FS
   * allocate_new_node or fetch_node_from_disk, in order to point to
   * the block layer API functions
   */
  sos_ret_t sos_chardev_helper_ref_new_fsnode(struct sos_fs_node * this);
  sos_ret_t sos_chardev_helper_release_fsnode(struct sos_fs_node * this);
  
  #endif
  
 

/tmp/sos-code-article8/sos/errno.h (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/errno.h (2005-12-28 11:44:57.000000000 +0100 )
Line 45 
Line 45 
 #define SOS_ENODEV       17   /* No such device */ #define SOS_ENODEV       17   /* No such device */
 #define SOS_EBADF        18   /* Bad file descriptor */ #define SOS_EBADF        18   /* Bad file descriptor */
 #define SOS_EMFILE       19   /* Reached maximal opened file for process */ #define SOS_EMFILE       19   /* Reached maximal opened file for process */
  #define SOS_ENOSYS       20   /* Operation not implemented */
  #define SOS_EIO          21   /* Input/output error */
 #define SOS_EFATAL      255 /* Internal fatal error */ #define SOS_EFATAL      255 /* Internal fatal error */
  
 /* A negative value means that an error occured.  For /* A negative value means that an error occured.  For
  
 

/tmp/sos-code-article8/sos/fs.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/fs.c (2005-12-28 11:44:57.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 "chardev.h"
  
 #include "fs.h" #include "fs.h"
  
Line 109 
Line 110 
  * Basic low-level memory & co related functions  * Basic low-level memory & co related functions
  */  */
  
 sos_ret_t sos_fs_subsystem_setup(const char * root_device, sos_ret_t
                                  const char * fsname, sos_fs_subsystem_setup(const char * root_device,
                                  const char * mount_args,                        const char * fsname,
                                  struct sos_fs_manager_instance ** result_rootfs)                        const char * mount_args,
                         struct sos_fs_manager_instance ** result_rootfs)
   sos_ret_t retval;   sos_ret_t retval;
   struct sos_fs_manager_type * fs_type;   struct sos_fs_manager_type * fs_type;
Line 179 
Line 181 
  
   if (node->inmem_ref_cnt == 0)   if (node->inmem_ref_cnt == 0)
     {     {
        if (SOS_FS_NODE_DEVICE_CHAR == node->type)
          sos_chardev_helper_release_fsnode(node);
       sos_hash_remove(node->fs->nodecache, node);       sos_hash_remove(node->fs->nodecache, node);
       node->destructor(node);       node->destructor(node);
     }     }
Line 244 
Line 248 
     return retval;     return retval;
  
   (*result_fsnode)->generation    = 0;   (*result_fsnode)->generation    = 0;
  
    /* Special case for device nodes */
    if (SOS_FS_NODE_DEVICE_CHAR == (*result_fsnode)->type)
      SOS_ASSERT_FATAL(SOS_OK
                       == sos_chardev_helper_ref_new_fsnode(*result_fsnode));
   sos_hash_insert(fs->nodecache, *result_fsnode);   sos_hash_insert(fs->nodecache, *result_fsnode);
   return SOS_OK;   return SOS_OK;
 } }
Line 277 
Line 286 
   /* Update some resrved fields */   /* Update some resrved fields */
   (*result_fsnode)->fs = fs;   (*result_fsnode)->fs = fs;
  
    /* Special case for device nodes */
    if (SOS_FS_NODE_DEVICE_CHAR == (*result_fsnode)->type)
      {
        SOS_ASSERT_FATAL(SOS_OK
                         == sos_chardev_helper_ref_new_fsnode(*result_fsnode));
      }
  
   /* insert it in the node cache */   /* insert it in the node cache */
   retval = sos_hash_insert(fs->nodecache, *result_fsnode);   retval = sos_hash_insert(fs->nodecache, *result_fsnode);
   if (SOS_OK != retval)   if (SOS_OK != retval)
Line 317 
Line 333 
         {         {
           /* Commit the FS changes to the device */           /* Commit the FS changes to the device */
           if (SOS_OK           if (SOS_OK
               == fsnode->fs->device->ops_file->sync(fsnode->fs->device))               == fsnode->fs->device->sync(fsnode->fs->device))
  
           /* We got a problem: FORCE re-add the node to the dirty list */           /* We got a problem: FORCE re-add the node to the dirty list */
Line 339 
Line 355 
   if (! fsnode->dirty)   if (! fsnode->dirty)
     return SOS_OK;     return SOS_OK;
  
   retval = fsnode->ops_file->sync(fsnode);   retval = fsnode->sync(fsnode);
     return retval;     return retval;
  
Line 366 
Line 382 
     }     }
      
   if (NULL != fs->device)   if (NULL != fs->device)
       return fs->device->ops_file->sync(fs->device);       return fs->device->sync(fs->device);
   return SOS_OK;   return SOS_OK;
 } }
Line 921 
Line 937 
  
   retval = fsnode->new_opened_file(fsnode, owner, open_flags, result_of);   retval = fsnode->new_opened_file(fsnode, owner, open_flags, result_of);
   if (SOS_OK != retval)   if (SOS_OK != retval)
     { 
       sos_fs_nscache_unref_node(nsnode); 
     } 
   (*result_of)->generation = 1;   (*result_of)->generation = 1;
  
Line 949 
Line 963 
   if (SOS_OK != retval)   if (SOS_OK != retval)
     return retval;     return retval;
  
    SOS_ASSERT_FATAL((*result_of)->owner == dst_proc);
   (*result_of)->ref_cnt    = 1;   (*result_of)->ref_cnt    = 1;
   (*result_of)->generation = 1;   (*result_of)->generation = 1;
   retval = sos_fs_nscache_register_opened_file(src_of->direntry, *result_of);   retval = sos_fs_nscache_register_opened_file(src_of->direntry, *result_of);
Line 976 
Line 991 
   struct sos_fs_pathname path;   struct sos_fs_pathname path;
  
   /* O_DIR | O_CREAT combination not supported */   /* O_DIR | O_CREAT combination not supported */
   if ((open_flags & SOS_FS_OPEN_DIRECTORY)   if ( (open_flags & SOS_FS_OPEN_DIRECTORY)
       && (open_flags & SOS_FS_OPEN_CREAT))        && ( (open_flags & (SOS_FS_OPEN_CREAT
                             | SOS_FS_OPEN_TRUNC)) ) )
  
   if (_pathlen <= 0)   if (_pathlen <= 0)
Line 1004 
Line 1020 
   if (path.length <= 0)   if (path.length <= 0)
     {     {
       /* Found the exact match ! */       /* Found the exact match ! */
  
        /* Handle O_EXCL flag */
       if (open_flags & SOS_FS_OPEN_EXCL)       if (open_flags & SOS_FS_OPEN_EXCL)
         {         {
           sos_fs_nscache_unref_node(nsnode);           sos_fs_nscache_unref_node(nsnode);
Line 1017 
Line 1035 
           sos_fs_nscache_unref_node(nsnode);           sos_fs_nscache_unref_node(nsnode);
           return -SOS_ENOTDIR;           return -SOS_ENOTDIR;
         }         }
  
        /* Handle O_TRUNC flag */
        if ((open_flags & SOS_FS_OPEN_TRUNC)
            && fsnode->ops_file->truncate)
          {
            retval = fsnode->ops_file->truncate(fsnode, 0);
            if (SOS_OK != retval)
              {
                sos_fs_nscache_unref_node(nsnode);
                return retval;
              }
          }
     }     }
   else   else
     {     {
Line 1093 
Line 1123 
     return -SOS_EPERM;     return -SOS_EPERM;
  
   if (! of->ops_file->read)   if (! of->ops_file->read)
     return -SOS_ENOSUP;     return -SOS_ENOSYS;
   return of->ops_file->read(of, dest_buf, len);   return of->ops_file->read(of, dest_buf, len);
 } }
Line 1103 
Line 1133 
                        sos_uaddr_t src_buf,                        sos_uaddr_t src_buf,
                        sos_size_t * /* in/out */len)                        sos_size_t * /* in/out */len)
 { {
   if (! (of->open_flags & SOS_FS_OPEN_WRITE))  if (! (of->open_flags & SOS_FS_OPEN_WRITE))
     return -SOS_EPERM;    return -SOS_EPERM;
   if (! of->ops_file->write)  if (! of->ops_file->write)
     return -SOS_ENOSUP;    return -SOS_ENOSYS;
   return of->ops_file->write(of, src_buf, len);   return of->ops_file->write(of, src_buf, len);
 } }
Line 1119 
Line 1149 
                       sos_lsoffset_t * result_position)                       sos_lsoffset_t * result_position)
 { {
   if (! of->ops_file->seek)   if (! of->ops_file->seek)
     return -SOS_ENOSUP;     return -SOS_ENOSYS;
   return of->ops_file->seek(of, offset, whence, result_position);   return of->ops_file->seek(of, offset, whence, result_position);
 } }
Line 1135 
Line 1165 
     return -SOS_EPERM;     return -SOS_EPERM;
  
   if (! fsnode->ops_file->truncate)   if (! fsnode->ops_file->truncate)
     return -SOS_ENOSUP;     return -SOS_ENOSYS;
   retval = fsnode->ops_file->truncate(fsnode, length);   retval = fsnode->ops_file->truncate(fsnode, length);
   if (SOS_OK == retval)   if (SOS_OK == retval)
Line 1155 
Line 1185 
   struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);   struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
  
   if (! of->ops_file->mmap)   if (! of->ops_file->mmap)
     return -SOS_ENOSUP;     return -SOS_ENOSYS;
   /* Translate VM requested rights into FS equivalent */   /* Translate VM requested rights into FS equivalent */
   if (access_rights & SOS_VM_MAP_PROT_READ)   if (access_rights & SOS_VM_MAP_PROT_READ)
Line 1182 
Line 1212 
                        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_ENOSUP;     return -SOS_ENOSYS;
   return of->ops_file->fcntl(of, req_id, req_arg);   return of->ops_file->fcntl(of, req_id, req_arg);
 } }
  
  
  sos_ret_t sos_fs_ioctl(struct sos_fs_opened_file *of,
                         int req_id,
                         sos_ui32_t req_arg /* Usually: sos_uaddr_t */)
  {
    struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
  
    if (fsnode->type == SOS_FS_NODE_DEVICE_CHAR)
      {
        if (! of->ops_chardev->ioctl)
          return -SOS_ENOSYS;
  
        return of->ops_chardev->ioctl(of, req_id, req_arg);
      }
    
    return -SOS_ENOSYS;
  }
  
  
 sos_ret_t sos_fs_readdir(struct sos_fs_opened_file * of, sos_ret_t sos_fs_readdir(struct sos_fs_opened_file * of,
                          struct sos_fs_dirent * result)                          struct sos_fs_dirent * result)
 { {
Line 1659 
Line 1707 
 } }
  
  
  sos_ret_t sos_fs_mknod(const struct sos_process * creator,
                         const char * _path,
                         sos_size_t _pathlen,
                         sos_fs_node_type_t type /* only block/char allowed */,
                         sos_ui32_t access_rights,
                         const struct sos_fs_dev_id_t * devid)
  {
    sos_ret_t retval;
    struct sos_fs_pathname path;
    struct sos_fs_nscache_node * nsnode;
    struct sos_fs_node * fsnode;
  
    if (type != SOS_FS_NODE_DEVICE_CHAR)
      return -SOS_EINVAL;
  
    path.contents = _path;
    path.length   = _pathlen;
  
    retval = fs_create_node(& path, creator, access_rights,
                            type, & nsnode);
    if (SOS_OK != retval)
      return retval;
  
    fsnode = sos_fs_nscache_get_fs_node(nsnode);
    fsnode->dev_id.device_class    = devid->device_class;
    fsnode->dev_id.device_instance = devid->device_instance;
  
    sos_fs_nscache_unref_node(nsnode);
    return SOS_OK;
  }
  
  
 sos_ret_t sos_fs_stat(const struct sos_process * actor, sos_ret_t sos_fs_stat(const struct sos_process * actor,
                       const char * _path,                       const char * _path,
                       sos_size_t _pathlen,                       sos_size_t _pathlen,
Line 1706 
Line 1786 
 sos_ret_t sos_fs_fsync(struct sos_fs_opened_file * of) sos_ret_t sos_fs_fsync(struct sos_fs_opened_file * of)
 { {
   struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);   struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(of->direntry);
   return fsnode->ops_file->sync(fsnode);   return fsnode->sync(fsnode);
  
  
Line 1794 
Line 1874 
   if (fsnode->fs->statfs)   if (fsnode->fs->statfs)
     retval = fsnode->fs->statfs(fsnode->fs, result);     retval = fsnode->fs->statfs(fsnode->fs, result);
   else   else
     retval = -SOS_ENOSUP;     retval = -SOS_ENOSYS;
   sos_fs_nscache_unref_node(nsnode);   sos_fs_nscache_unref_node(nsnode);
   return retval;     return retval;  
  
 

/tmp/sos-code-article8/sos/fs.h (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/fs.h (2005-12-28 11:44:57.000000000 +0100 )
Line 55 
Line 55 
  * =========  * =========
  * The VFS layer is based on 3 central concepts:  * The VFS layer is based on 3 central concepts:
  *  *
  *  - The meta-information for each file stored on disk (struct  *  - The meta-information for each file stored on disk: size,
  *    sos_fs_node for SOS, inode for Unix)  *    permissions, ... (struct sos_fs_node for SOS, inode for Unix)
  *    It is sufficient to know where this meta-information is located  *    It is sufficient to know where this meta-information is located
  *    on disk (a simple sector number most of the time) to build the  *    on disk (a simple sector number most of the time) to build the
Line 64 
Line 64 
  *    data of the file from the disk  *    data of the file from the disk
  *  *
  *    For example, consider that we know a sector that holds the meta  *    For example, consider that we know a sector that holds the meta
  *    information (ie size, permissions) is located at sector 64589 on  *    information is located at sector 64589 on disk. By retrieving
  *    disk. By retrieving this meta information directly from disk, we  *    this meta information directly from disk, we can build the
  *    can build the struct sos_fs_node, which would (for example) tell  *    struct sos_fs_node, which would (for example) tell that the
  *    that the corresponding file spans (for example) over sectors  *    corresponding file spans (for example) over sectors 4345, 5645,
  *    4345, 5645, 4539 and 6575, is 1.7kB long  *    4539 and 6575, is 1.7kB long
  *    Everything is stored this way on the disk, even the  *    Everything is stored this way on the disk, even the
  *    directories. From the disk contents' point of view, a directory  *    directories. From the disk contents' point of view, a directory
Line 171 
Line 171 
   SOS_FS_NODE_REGULAR_FILE = 0x42,   SOS_FS_NODE_REGULAR_FILE = 0x42,
   SOS_FS_NODE_DIRECTORY    = 0x24,   SOS_FS_NODE_DIRECTORY    = 0x24,
   SOS_FS_NODE_SYMLINK      = 0x84,   SOS_FS_NODE_SYMLINK      = 0x84,
    SOS_FS_NODE_DEVICE_CHAR  = 0x48,
 } sos_fs_node_type_t; } sos_fs_node_type_t;
  
  
Line 227 
Line 228 
  
  
 /** /**
  * Data related to a particular "mounting" of a file system. A so-called "superblock" under Linux  * Data related to a particular "mounting" of a file system. A
   * so-called "superblock" under Linux
  * This holds the FUNDAMENTAL functions responsible for loading struct  * This holds the FUNDAMENTAL functions responsible for loading struct
  * sos_fs_node from disk, or for allocating thom on disk. It also  * sos_fs_node from disk, or for allocating thom on disk. It also
Line 423 
Line 425 
    */    */
   sos_lcount_t generation;   sos_lcount_t generation;
  
    /**
     * @note Available only for device files (char/block)
     * @note Publicly readable. Written only by
     * sos_fs_manager_instance::fetch_node_from_disk() and mknod()
     */
    struct sos_fs_dev_id_t
    {
      sos_ui32_t device_class;    /**< aka "major" */
      sos_ui32_t device_instance; /**< aka "minor" */
    } dev_id;
  
   /** Operations common to all node types */   /** Operations common to all node types */
   struct sos_fs_node_ops_file  *ops_file;   struct sos_fs_node_ops_file  *ops_file;
  
Line 438 
Line 451 
  
  
   /**   /**
     * Flush any change to disk
     *
     * @note Mandatory, may block. Appropriate locking MUST be implemented
     */
    sos_ret_t (*sync)(struct sos_fs_node *this);
  
  
    /**
    * Simply free this FS node from the kernel memory: it does NOT    * Simply free this FS node from the kernel memory: it does NOT
    * mean that the corresponding on-disk node is free ! Actually, the    * mean that the corresponding on-disk node is free ! Actually, the
    * corresponding ON-DISK node is free iff ondisk_lnk_cnt == 0. No    * corresponding ON-DISK node is free iff ondisk_lnk_cnt == 0. No
Line 452 
Line 473 
    * Called when a process opens the node    * Called when a process opens the node
    *    *
    * @note Mandatory, may block. Appropriate locking MUST be implemented    * @note Mandatory, may block. Appropriate locking MUST be implemented
     * @note FS-specific EXCPET for device special files (char &
     * block) because they are handled in an uniform way by the
     * chardev/blockdev subsystems
     * @note As a consequence, FS code can safely assume that "this" is
     * never a character or block device
    */    */
   sos_ret_t (*new_opened_file)(struct sos_fs_node * this,   sos_ret_t (*new_opened_file)(struct sos_fs_node * this,
                                const struct sos_process * owner,                                const struct sos_process * owner,
Line 462 
Line 488 
    * Called when a process opens the node    * Called when a process opens the node
    *    *
    * @note Mandatory, may block. Appropriate locking MUST be implemented    * @note Mandatory, may block. Appropriate locking MUST be implemented
     * @note FS-specific EXCEPT for device special files (char &
     * block) because they are handled in an uniform way by the
     * chardev/blockdev subsystems
     * @note As a consequence, FS code can safely assume that "this" is
     * never a character or block device
    */    */
   sos_ret_t (*close_opened_file)(struct sos_fs_node * this,   sos_ret_t (*close_opened_file)(struct sos_fs_node * this,
                                  struct sos_fs_opened_file * of);                                  struct sos_fs_opened_file * of);
Line 507 
Line 538 
                     struct sos_fs_stat * result);                     struct sos_fs_stat * result);
  
   /**   /**
    * Flush any change to disk 
    * 
    * @note Mandatory, may block. Appropriate locking MUST be implemented 
    */ 
   sos_ret_t (*sync)(struct sos_fs_node *this); 
  
   /** 
    *    *
    * @note Mandatory, may block. Appropriate locking MUST be implemented    * @note Mandatory, may block. Appropriate locking MUST be implemented
Line 647 
Line 671 
   {   {
     /** when direntry->fs_node->type == SOS_FS_NODE_DIRECTORY */     /** when direntry->fs_node->type == SOS_FS_NODE_DIRECTORY */
     struct sos_fs_ops_opened_dir      * ops_dir;     struct sos_fs_ops_opened_dir      * ops_dir;
  
      /** when direntry->fs_node->type == SOS_FS_NODE_DEVICE_CHAR */
      struct sos_fs_ops_opened_chardev  * ops_chardev;
   }; /* Anonymous union (gcc extension) */   }; /* Anonymous union (gcc extension) */
  
   /**   /**
    * Called upon fork() to duplicate all the opened files    * Called upon fork() to duplicate all the opened files
     *
     * @note FS-specific EXCEPT for device special files (char &
     * block) because they are handled in an uniform way by the
     * chardev/blockdev subsystems
     * @note As a consequence, FS code can safely assume that "this" is
     * never a character or block device
    */    */
   sos_ret_t (*duplicate)(struct sos_fs_opened_file *this,   sos_ret_t (*duplicate)(struct sos_fs_opened_file *this,
                          const struct sos_process  * for_owner,                          const struct sos_process  * for_owner,
Line 725 
Line 758 
 }; };
  
  
  /**
   * The list of methods implementing the basic VFS opened character device
   * operations
   *
   * @see sos_fs_opened_file::ops_file
   */
  struct sos_fs_ops_opened_chardev
  {
    /**
     * @note Optional (might be NULL), may block. Appropriate locking
     * MUST be implemented
     * @note Please call sos_fs_mark_dirty() if disk contents is changed
     */
    sos_ret_t (*ioctl)(struct sos_fs_opened_file *this,
                       int req_id,
                       sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
  };
  
  
 /** Data structure that is to be filled by readdir */ /** Data structure that is to be filled by readdir */
 struct sos_fs_dirent struct sos_fs_dirent
 { {
Line 766 
Line 818 
  */  */
 struct sos_fs_stat struct sos_fs_stat
 { {
    struct sos_fs_dev_id_t st_rdev;
   sos_fs_node_type_t     st_type;   sos_fs_node_type_t     st_type;
   sos_ui64_t             st_storage_location;   sos_ui64_t             st_storage_location;
   sos_ui32_t             st_access_rights;   sos_ui32_t             st_access_rights;
Line 781 
Line 834 
  */  */
 struct sos_fs_statfs struct sos_fs_statfs
 { {
    struct sos_fs_dev_id_t f_rdev;
   sos_size_t             f_sz_total;  /**< Total size */   sos_size_t             f_sz_total;  /**< Total size */
   sos_size_t             f_sz_free;   /**< Size left on device */   sos_size_t             f_sz_free;   /**< Size left on device */
   sos_count_t            f_node_total;/**< Total allocatable FS nodes */   sos_count_t            f_node_total;/**< Total allocatable FS nodes */
Line 838 
Line 892 
 sos_ret_t sos_fs_sync_all_fs(); sos_ret_t sos_fs_sync_all_fs();
  
 /** /**
  * Retrieve filesystem status, or return -SOS_ENOSUP if filesystem  * Retrieve filesystem status, or return -SOS_ENOSYS if filesystem
  */  */
 sos_ret_t sos_fs_vfstat(const struct sos_process * actor, sos_ret_t sos_fs_vfstat(const struct sos_process * actor,
Line 851 
Line 905 
  */  */
 #define SOS_FS_OPEN_EXCL        (1 << 0) #define SOS_FS_OPEN_EXCL        (1 << 0)
 #define SOS_FS_OPEN_CREAT       (1 << 1) #define SOS_FS_OPEN_CREAT       (1 << 1)
 #define SOS_FS_OPEN_NOFOLLOW    (1 << 2) #define SOS_FS_OPEN_TRUNC       (1 << 2)
 #define SOS_FS_OPEN_DIRECTORY   (1 << 3) /* Incompatible with CREAT */ #define SOS_FS_OPEN_NOFOLLOW    (1 << 3)
 #define SOS_FS_OPEN_SYNC        (1 << 4) #define SOS_FS_OPEN_DIRECTORY   (1 << 4) /* Incompatible with CREAT/TRUNC */
 #define SOS_FS_OPEN_KEEPONEXEC  (1 << 5) /* By default, files are closed #define SOS_FS_OPEN_SYNC        (1 << 5)
                                             upon an exec() */ #define SOS_FS_OPEN_CLOSEONEXEC (1 << 6) /* By default, files are kept
                                              open upon an exec() */
 #define SOS_FS_OPEN_READ        (1 << 16) #define SOS_FS_OPEN_READ        (1 << 16)
 #define SOS_FS_OPEN_WRITE       (1 << 17) #define SOS_FS_OPEN_WRITE       (1 << 17)
Line 910 
Line 965 
                        int req_id,                        int req_id,
                        sos_ui32_t req_arg /* Usually: sos_uaddr_t */);                        sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
  
  sos_ret_t sos_fs_ioctl(struct sos_fs_opened_file *of,
                         int req_id,
                         sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
  
 sos_ret_t sos_fs_creat(const struct sos_process * creator, sos_ret_t sos_fs_creat(const struct sos_process * creator,
                        const char * _path,                        const char * _path,
                        sos_size_t _pathlen,                        sos_size_t _pathlen,
Line 937 
Line 996 
                          sos_uaddr_t symlink_target,                          sos_uaddr_t symlink_target,
                          sos_size_t symlink_target_len);                          sos_size_t symlink_target_len);
  
  sos_ret_t sos_fs_mknod(const struct sos_process * creator,
                         const char * _path,
                         sos_size_t _pathlen,
                         sos_fs_node_type_t type /* only block/char allowed */,
                         sos_ui32_t access_rights,
                         const struct sos_fs_dev_id_t * devid);
  
 sos_ret_t sos_fs_mkdir(const struct sos_process * creator, sos_ret_t sos_fs_mkdir(const struct sos_process * creator,
                        const char * _path,                        const char * _path,
                        sos_size_t _pathlen,                        sos_size_t _pathlen,
  
 

/tmp/sos-code-article8/sos/kmalloc.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/kmalloc.c (2005-12-28 11:44:57.000000000 +0100 )
Line 73 
Line 73 
 { {
   /* Look for a suitable pre-allocated kmalloc cache */   /* Look for a suitable pre-allocated kmalloc cache */
   int i;   int i;
    SOS_ASSERT_FATAL(size > 0);
   for (i = 0 ; kmalloc_cache[i].object_size != 0 ; i ++)   for (i = 0 ; kmalloc_cache[i].object_size != 0 ; i ++)
     {     {
       if (kmalloc_cache[i].object_size >= size)       if (kmalloc_cache[i].object_size >= size)
  
 

/tmp/sos-code-article8/sos/main.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/main.c (2005-12-28 11:44:57.000000000 +0100 )
Line 46 
Line 46 
 #include <drivers/zero.h> #include <drivers/zero.h>
 #include <sos/fs.h> #include <sos/fs.h>
 #include <drivers/fs_virtfs.h> #include <drivers/fs_virtfs.h>
  #include <drivers/devices.h>
  #include <drivers/mem.h>
  #include <drivers/tty.h>
  #include <drivers/console.h>
  #include <drivers/serial.h>
  
 /* Helper function to display each bits of a 32bits integer on the /* Helper function to display each bits of a 32bits integer on the
    screen as dark or light carrets */    screen as dark or light carrets */
Line 211 
Line 216 
 /* ====================================================================== /* ======================================================================
  * Kernel thread showing some CPU usage statistics on the console every 1s  * Kernel thread showing some CPU usage statistics on the console every 1s
  */  */
  #define LOAD_DISPLAY_BASELINE  4
  #define LOAD_DISPLAY_STARTROW 34
 static void stat_thread() static void stat_thread()
 { {
   while (1)   while (1)
Line 231 
Line 238 
       sos_load_to_string(str1, load1);       sos_load_to_string(str1, load1);
       sos_load_to_string(str5, load5);       sos_load_to_string(str5, load5);
       sos_load_to_string(str15, load15);       sos_load_to_string(str15, load15);
       sos_x86_videomem_printf(16, 34,       sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+0, LOAD_DISPLAY_STARTROW,
                               "Kernel (- Idle): %s %s %s    ",                               "Kernel (- Idle): %s %s %s    ",
                               str1, str5, str15);                               str1, str5, str15);
Line 240 
Line 247 
       sos_load_to_string(str1, load1);       sos_load_to_string(str1, load1);
       sos_load_to_string(str5, load5);       sos_load_to_string(str5, load5);
       sos_load_to_string(str15, load15);       sos_load_to_string(str15, load15);
       sos_x86_videomem_printf(17, 34,       sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+1, LOAD_DISPLAY_STARTROW,
                               "User: %s %s %s        ",                               "User: %s %s %s        ",
                               str1, str5, str15);                               str1, str5, str15);
Line 249 
Line 256 
       sos_load_to_string(str1, load1);       sos_load_to_string(str1, load1);
       sos_load_to_string(str5, load5);       sos_load_to_string(str5, load5);
       sos_load_to_string(str15, load15);       sos_load_to_string(str15, load15);
       sos_x86_videomem_printf(18, 34,       sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+2, LOAD_DISPLAY_STARTROW,
                               "User CPU %%: %s %s %s        ",                               "User CPU %%: %s %s %s        ",
                               str1, str5, str15);                               str1, str5, str15);
Line 259 
Line 266 
       sos_load_to_string(str1, load1);       sos_load_to_string(str1, load1);
       sos_load_to_string(str5, load5);       sos_load_to_string(str5, load5);
       sos_load_to_string(str15, load15);       sos_load_to_string(str15, load15);
       sos_x86_videomem_printf(19, 34,       sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+3, LOAD_DISPLAY_STARTROW,
                               "Kernel CPU %% (+ Idle): %s %s %s    ",                               "Kernel CPU %% (+ Idle): %s %s %s    ",
                               str1, str5, str15);                               str1, str5, str15);
Line 325 
Line 332 
       return -SOS_ENOENT;       return -SOS_ENOENT;
     }     }
  
  
  
   /* Map the 'init' program in user space */   /* Map the 'init' program in user space */
   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 376 
Line 385 
   unsigned long int upper_mem = 0;   unsigned long int upper_mem = 0;
  
   /* Setup bochs and console, and clear the console */   /* Setup bochs and console, and clear the console */
   sos_bochs_setup();   sos_bochs_subsystem_setup();
   sos_x86_videomem_setup();   sos_x86_videomem_setup();
   sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);   sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);
Line 397 
Line 406 
       sos_x86_videomem_printf(1, 0,       sos_x86_videomem_printf(1, 0,
                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
                               "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",                               "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",
                               "SOS article 8", ',',                               "SOS article 9", ',',
                               (unsigned)upper_mem);                               (unsigned)upper_mem);
     }     }
Line 408 
Line 417 
       sos_x86_videomem_printf(1, 0,       sos_x86_videomem_printf(1, 0,
                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
                               "Welcome to %s%c RAM is %dMB (upper mem = 0x%x kB)",                               "Welcome to %s%c RAM is %dMB (upper mem = 0x%x kB)",
                               "SOS article 8", ',',                               "SOS article 9", ',',
                               (unsigned)upper_mem);                               (unsigned)upper_mem);
     }     }
Line 416 
Line 425 
     /* Not loaded with grub, not from an enhanced bootsect */     /* Not loaded with grub, not from an enhanced bootsect */
     sos_x86_videomem_printf(1, 0,     sos_x86_videomem_printf(1, 0,
                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
                             "Welcome to SOS article 8");                             "Welcome to SOS article 9");
   sos_bochs_putstring("Message in a bochs: This is SOS article 8.\n");   sos_bochs_putstring("Message in a bochs: This is SOS article 9.\n");
   /* Setup CPU segmentation and IRQ subsystem */   /* Setup CPU segmentation and IRQ subsystem */
   sos_gdt_subsystem_setup();   sos_gdt_subsystem_setup();
Line 539 
Line 548 
    */    */
   sos_umem_vmm_subsystem_setup();   sos_umem_vmm_subsystem_setup();
   sos_dev_zero_subsystem_setup();   sos_dev_zero_subsystem_setup();
    sos_dev_mem_chardev_setup();
  
   /*   /*
    * Initialize process stuff    * Initialize process stuff
Line 558 
Line 568 
                                                     & rootfs));                                                     & rootfs));
  
  
    tty_subsystem_setup();
    sos_ttyS0_subsystem_setup();
    sos_console_subsystem_setup();
  
  
  
  
   /* Start the 'init' process, which in turns launches the other   /* Start the 'init' process, which in turns launches the other
      programs */      programs */
   start_init(rootfs);   start_init(rootfs);
  
 

/tmp/sos-code-article8/sos/physmem.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/physmem.c (2005-12-28 11:44:57.000000000 +0100 )
Line 384 
Line 384 
     *nonfree_ppages = physmem_nonfree_pages;     *nonfree_ppages = physmem_nonfree_pages;
   return SOS_OK;   return SOS_OK;
 } }
  
  
 

/tmp/sos-code-article8/sos/physmem.h (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/physmem.h (2005-12-28 11:44:57.000000000 +0100 )
Line 77 
Line 77 
                                       /* out */sos_paddr_t *kernel_core_base,                                       /* out */sos_paddr_t *kernel_core_base,
                                       /* out */sos_paddr_t *kernel_core_top);                                       /* out */sos_paddr_t *kernel_core_top);
  
  
 /** /**
  * Retrieve the total number of pages, and the number of free pages  * Retrieve the total number of pages, and the number of free pages
   *
   * @note both parameters may be NULL
  */  */
 sos_ret_t sos_physmem_get_state(/* out */sos_count_t *total_ppages, sos_ret_t sos_physmem_get_state(/* out */sos_count_t *total_ppages,
                                 /* out */sos_count_t *nonfree_ppages);                                 /* out */sos_count_t *nonfree_ppages);
  
 

/tmp/sos-code-article8/sos/process.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/process.c (2005-12-28 11:44:57.000000000 +0100 )
Line 132 
Line 132 
   sos_ui32_t flags;   sos_ui32_t flags;
   struct sos_process *proc;   struct sos_process *proc;
  
  
   proc = (struct sos_process*) sos_kmem_cache_alloc(cache_struct_process, 0);   proc = (struct sos_process*) sos_kmem_cache_alloc(cache_struct_process, 0);
   if (! proc)   if (! proc)
     return NULL;     return NULL;
Line 207 
Line 208 
       /* Close the file descriptors */       /* Close the file descriptors */
       for (fd = 0 ; fd < SOS_PROCESS_MAX_OPENED_FILES ; fd++)       for (fd = 0 ; fd < SOS_PROCESS_MAX_OPENED_FILES ; fd++)
         if (NULL != proc->fds[fd])         if (NULL != proc->fds[fd])
           sos_fs_close(proc->fds[fd]);           {
              sos_fs_close(proc->fds[fd]);
              proc->fds[fd] = NULL;
            }
       if (proc->root)       if (proc->root)
         sos_fs_close(proc->root);         sos_fs_close(proc->root);
       if (proc->cwd)       if (proc->cwd)
         sos_fs_close(proc->cwd);         sos_fs_close(proc->cwd);
        proc->root = proc->cwd = NULL;
  
       sos_kmem_cache_free((sos_vaddr_t) proc);       sos_kmem_cache_free((sos_vaddr_t) proc);
       proc = NULL;       proc = NULL;
Line 266 
Line 271 
   /* Close the FD that are not allowed to be duplicated */   /* Close the FD that are not allowed to be duplicated */
   for (fd = 0 ; fd < SOS_PROCESS_MAX_OPENED_FILES ; fd++)   for (fd = 0 ; fd < SOS_PROCESS_MAX_OPENED_FILES ; fd++)
     if ( (NULL != proc->fds[fd])     if ( (NULL != proc->fds[fd])
          && (! (proc->fds[fd]->open_flags & SOS_FS_OPEN_KEEPONEXEC)) )          && (proc->fds[fd]->open_flags & SOS_FS_OPEN_CLOSEONEXEC) )
       sos_fs_close(proc->fds[fd]);       {
          sos_fs_close(proc->fds[fd]);
          proc->fds[fd] = NULL;
        }
   if (proc->address_space)   if (proc->address_space)
     {     {
Line 415 
Line 423 
   /* Close the file descriptors */   /* Close the file descriptors */
   for (fd = 0 ; fd < SOS_PROCESS_MAX_OPENED_FILES ; fd++)   for (fd = 0 ; fd < SOS_PROCESS_MAX_OPENED_FILES ; fd++)
     if (NULL != proc->fds[fd])     if (NULL != proc->fds[fd])
       sos_fs_close(proc->fds[fd]);       {
          sos_fs_close(proc->fds[fd]);
          proc->fds[fd] = NULL;
        }
   sos_fs_close(proc->root);   sos_fs_close(proc->root);
   sos_fs_close(proc->cwd);   sos_fs_close(proc->cwd);
    proc->root = proc->cwd = NULL;
  
   /* First: free the user address space */   /* First: free the user address space */
   retval = sos_umem_vmm_delete_as(proc->address_space);   retval = sos_umem_vmm_delete_as(proc->address_space);
  
 

/tmp/sos-code-article8/sos/syscall.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/syscall.c (2005-12-28 11:44:57.000000000 +0100 )
Line 30 
Line 30 
 #include <sos/uaccess.h> #include <sos/uaccess.h>
 #include "syscall.h" #include "syscall.h"
  
  
  * THE syscall entry point  * THE syscall entry point
  */  */
Line 191 
Line 190 
       }       }
       break;       break;
  
     case SOS_SYSCALL_ID_FAKEMMAP: 
       { 
         sos_uaddr_t ptr_hint_uaddr; 
         sos_uaddr_t hint_uaddr; 
         sos_size_t  length; 
         sos_ui32_t  prot; 
         sos_ui32_t  flags; 
         sos_uaddr_t name_user; 
         sos_ui32_t  offs64_hi; 
         sos_ui32_t  offs64_lo; 
         sos_luoffset_t offset_in_resource; 
         char        name[256]; 
         struct sos_umem_vmm_as * my_as; 
          
         retval = sos_syscall_get7args(user_ctxt, 
                                       (unsigned int*)& ptr_hint_uaddr, 
                                       (unsigned int*)& length, 
                                       (unsigned int*)& prot, 
                                       (unsigned int*)& flags, 
                                       (unsigned int*)& name_user, 
                                       (unsigned int*)& offs64_hi, 
                                       (unsigned int*)& offs64_lo); 
         if (SOS_OK != retval) 
           break; 
  
         /* Compute 64 bits offset value */ 
         offset_in_resource   = offs64_hi; 
         offset_in_resource <<= 32; 
         offset_in_resource  |= offs64_lo; 
  
         retval = sos_memcpy_from_user((sos_vaddr_t)& hint_uaddr, 
                                       ptr_hint_uaddr, 
                                       sizeof(hint_uaddr)); 
         if (sizeof(hint_uaddr) != retval) 
           { 
             retval = -SOS_EFAULT; 
             break; 
           } 
  
         retval = sos_strzcpy_from_user(name, name_user, sizeof(name)); 
         if (SOS_OK != retval) 
           break; 
  
         my_as 
           = sos_process_get_address_space(sos_thread_get_current()->process); 
         if ( (0 == strncmp(name, "/dev/zero", sizeof(name))) 
              || (0 == strncmp(name, "/dev/null", sizeof(name))) ) 
           retval = sos_dev_zero_map(my_as, & hint_uaddr, length, prot, flags); 
         else if (0 == strncmp(name, "/dev/mem", sizeof(name))) 
           retval = sos_dev_physmem_map(my_as, & hint_uaddr, length, 
                                        offset_in_resource, prot, flags); 
         else if (0 == strncmp(name, "/dev/kmem", sizeof(name))) 
           retval = sos_dev_kmem_map(my_as, & hint_uaddr, length, 
                                     offset_in_resource, prot, flags); 
         else 
           retval = -SOS_ENOENT; 
  
         if (SOS_OK == retval) 
           { 
             if (sizeof(hint_uaddr) 
                 != sos_memcpy_to_user(ptr_hint_uaddr, 
                                       (sos_vaddr_t)& hint_uaddr, 
                                       sizeof(hint_uaddr))) 
               { 
                 sos_umem_vmm_unmap(my_as, hint_uaddr, length); 
                 retval = -SOS_EFAULT; 
               } 
           } 
  
       } 
       break; 
  
       {       {
         sos_uaddr_t start_uaddr;         sos_uaddr_t start_uaddr;
Line 461 
Line 388 
       {       {
         sos_uaddr_t user_src;         sos_uaddr_t user_src;
         sos_size_t srclen;         sos_size_t srclen;
         const char * kernel_src = NULL;         char * kernel_src = NULL;
         sos_size_t dstlen;         sos_size_t dstlen;
         const char * kernel_dst;         char * kernel_dst;
         sos_uaddr_t user_fstype;         sos_uaddr_t user_fstype;
         char * kernel_fstype;         char * kernel_fstype;
Line 486 
Line 413 
  
         if (user_src != (sos_uaddr_t)NULL)         if (user_src != (sos_uaddr_t)NULL)
           {           {
             retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_src, user_src, srclen, 0);             retval = sos_strndup_from_user(&kernel_src, user_src, srclen, 0);
               break;               break;
           }           }
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_dst, user_dst, dstlen, 0);         retval = sos_strndup_from_user(&kernel_dst, user_dst, dstlen, 0);
           {           {
             if (kernel_src)             if (kernel_src)
Line 550 
Line 477 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
                  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
                  
Line 584 
Line 511 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 620 
Line 547 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 978 
Line 905 
       }       }
       break;       break;
  
      case SOS_SYSCALL_ID_IOCTL:
        {
          struct sos_fs_opened_file * of;
          struct sos_process * proc;
          sos_ui32_t cmd, arg;
          int fd;
  
          proc = sos_thread_get_current()->process;
          retval = sos_syscall_get3args(user_ctxt,
                                        (unsigned int*)& fd,
                                        (unsigned int*)& cmd,
                                        (unsigned int*)& arg);
          if (SOS_OK != retval)
            break;
  
          of = sos_process_get_opened_file(proc, fd);
          if (NULL == of)
            {
              retval = -SOS_EBADF;
              break;
            }
  
          /* Do the actual ioctl */
          retval = sos_fs_ioctl(of, cmd, arg);
        }
        break;
  
     case SOS_SYSCALL_ID_CREAT:     case SOS_SYSCALL_ID_CREAT:
       {       {
         sos_uaddr_t user_str;         sos_uaddr_t user_str;
Line 994 
Line 948 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1022 
Line 976 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_oldpath,         retval = sos_strndup_from_user(&kernel_oldpath,
                                       user_oldpath,                                        user_oldpath,
                                       oldpathlen, 0);                                        oldpathlen, 0);
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_newpath,         retval = sos_strndup_from_user(&kernel_newpath,
                                       user_newpath,                                        user_newpath,
                                       newpathlen, 0);                                        newpathlen, 0);
           {           {
             sos_kfree((sos_vaddr_t) kernel_oldpath);             sos_kfree((sos_vaddr_t) kernel_oldpath);
Line 1064 
Line 1018 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1090 
Line 1044 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &kernel_path,         retval = sos_strndup_from_user(&kernel_path,
                                       user_path,                                        user_path,
                                       pathlen, 0);                                        pathlen, 0);
           break;           break;
  
Line 1103 
Line 1057 
       }       }
       break;       break;
  
      case SOS_SYSCALL_ID_MKNOD:
        {
          sos_uaddr_t user_str;
          sos_size_t  len;
          sos_ui32_t  access_rights;
          int type;
          char * path;
          struct sos_fs_dev_id_t dev_id;
          struct sos_process * proc;
  
          proc = sos_thread_get_current()->process;
          retval = sos_syscall_get6args(user_ctxt,
                                        (unsigned int*)& user_str,
                                        (unsigned int*)& len,
                                        (unsigned int*)& type,
                                        (unsigned int*)& access_rights,
                                        (unsigned int*)& dev_id.device_class,
                                        (unsigned int*)& dev_id.device_instance);
          if (SOS_OK != retval)
            break;
  
          retval = sos_strndup_from_user(&path, user_str, len, 0);
          if (SOS_OK != retval)
            break;
  
          switch (type)
            {
            case SOS_FS_NODE_REGULAR_FILE:
              retval = sos_fs_creat(proc, path, len, access_rights);
              break;
  
            case SOS_FS_NODE_DIRECTORY:
              retval = sos_fs_mkdir(proc, path, len, access_rights);
              break;
  
            case SOS_FS_NODE_SYMLINK:
              retval = -SOS_ENOSUP;
              break;
  
            case SOS_FS_NODE_DEVICE_CHAR:
              retval = sos_fs_mknod(proc,
                                    path, len, type, access_rights, &dev_id);
              break;
  
            default:
              retval = -SOS_EINVAL;
              break;
            }
  
          sos_kfree((sos_vaddr_t)path);
        }
        break;
  
     case SOS_SYSCALL_ID_MKDIR:     case SOS_SYSCALL_ID_MKDIR:
       {       {
         sos_uaddr_t user_str;         sos_uaddr_t user_str;
Line 1119 
Line 1126 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1143 
Line 1150 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1168 
Line 1175 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1196 
Line 1203 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1229 
Line 1236 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         retval = sos_memdup_from_user((sos_vaddr_t*) &path, user_str, len, 0);         retval = sos_strndup_from_user(&path, user_str, len, 0);
           break;           break;
  
Line 1334 
Line 1341 
         if (SOS_OK != retval)         if (SOS_OK != retval)
           break;           break;
  
         str = (char*)sos_kmalloc(len, 0);         str = (unsigned char*)sos_kmalloc(len, 0);
           {           {
             int i;             int i;
  
 

/tmp/sos-code-article8/sos/syscall.h (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/syscall.h (2005-12-28 11:44:57.000000000 +0100 )
Line 44 
Line 44 
  */  */
 #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, retval=errno */
 #define SOS_SYSCALL_ID_FAKEMMAP    259 /**< Args: &hint len prot flags fd uoffs64_hi uoffs64_lo, 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 73 
Line 72 
 #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 */
  #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 */
 #define SOS_SYSCALL_ID_LINK        571 /**< Args: uaddr_oldpath oldpathlen uaddr_newpath newpathlen, retval=errno */ #define SOS_SYSCALL_ID_LINK        571 /**< Args: uaddr_oldpath oldpathlen uaddr_newpath newpathlen, retval=errno */
 #define SOS_SYSCALL_ID_RENAME      572 /**< Args: uaddr_oldpath oldpathlen uaddr_newpath newpathlen, retval=errno */ #define SOS_SYSCALL_ID_RENAME      572 /**< Args: uaddr_oldpath oldpathlen uaddr_newpath newpathlen, retval=errno */
 #define SOS_SYSCALL_ID_UNLINK      573 /**< Args: uaddr_path pathlen, retval=errno */ #define SOS_SYSCALL_ID_UNLINK      573 /**< Args: uaddr_path pathlen, retval=errno */
 #define SOS_SYSCALL_ID_SYMLINK     574 /**< Args: uaddr_path pathlen uaddr_target targetlen, retval=errno */ #define SOS_SYSCALL_ID_SYMLINK     574 /**< Args: uaddr_path pathlen uaddr_target targetlen, retval=errno */
  #define SOS_SYSCALL_ID_MKNOD       575 /**< Args: uaddr_path pathlen type access_rights major minor, retval=errno */
  
 #define SOS_SYSCALL_ID_MKDIR       576 /**< Args: uaddr_path pathlen access_rights, retval=errno */ #define SOS_SYSCALL_ID_MKDIR       576 /**< Args: uaddr_path pathlen access_rights, retval=errno */
 #define SOS_SYSCALL_ID_RMDIR       577 /**< Args: uaddr_path pathlen, retval=errno */ #define SOS_SYSCALL_ID_RMDIR       577 /**< Args: uaddr_path pathlen, retval=errno */
  
 

/tmp/sos-code-article8/sos/thread.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/thread.c (2005-12-28 11:44:57.000000000 +0100 )
Line 722 
Line 722 
   sos_vaddr_t stack_bottom = current_thread->kernel_stack_base_addr;   sos_vaddr_t stack_bottom = current_thread->kernel_stack_base_addr;
   sos_size_t stack_size    = current_thread->kernel_stack_size;   sos_size_t stack_size    = current_thread->kernel_stack_size;
  
   static void backtracer(sos_vaddr_t PC,   void backtracer(sos_vaddr_t PC,
                          sos_vaddr_t params,                   sos_vaddr_t params,
                          sos_ui32_t depth,                   sos_ui32_t depth,
                          void *custom_arg)                   void *custom_arg)
       sos_ui32_t invalid = 0xffffffff, *arg1, *arg2, *arg3, *arg4;       sos_ui32_t invalid = 0xffffffff, *arg1, *arg2, *arg3, *arg4;
  
  
 

/tmp/sos-code-article8/sos/types.h (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/types.h (2005-12-28 11:44:57.000000000 +0100 )
Line 33 
Line 33 
 /** User virtual address */ /** User virtual address */
 typedef unsigned int           sos_uaddr_t; typedef unsigned int           sos_uaddr_t;
  
  /** Generic (Kernel or User) virtual address */
  typedef unsigned int           sos_genaddr_t;
  
 /** Memory size of an object (positive) */ /** Memory size of an object (positive) */
 typedef unsigned int           sos_size_t; typedef unsigned int           sos_size_t;
 /** Generic positive offset into objects */ /** Generic positive offset into objects */
  
 

/tmp/sos-code-article8/sos/uaccess.c (2005-07-01 16:39:49.000000000 +0200 )
../sos-code-article9/sos/uaccess.c (2005-12-28 11:44:57.000000000 +0100 )
Line 120 
Line 120 
   sos_ret_t retval;   sos_ret_t retval;
  
   if (length <= 0)   if (length <= 0)
     return 0;     return -SOS_EINVAL;
   *kernel_to = sos_kmalloc(length, kmalloc_flags);   *kernel_to = sos_kmalloc(length, kmalloc_flags);
   if (NULL == (void*) *kernel_to)   if (NULL == (void*) *kernel_to)
  
 

/tmp/sos-code-article8/sos/umem_vmm.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/sos/umem_vmm.c (2005-12-28 11:44:58.000000000 +0100 )
Line 139 
Line 139 
  * Physical address of THE page (full of 0s) used for anonymous  * Physical address of THE page (full of 0s) used for anonymous
  * mappings  * mappings
  */  */
 sos_paddr_t sos_zero_page = 0 /* Initial value prior to allocation */; sos_paddr_t sos_zero_physpage = 0 /* Initial value prior to allocation */;
  sos_vaddr_t sos_zero_kernelpage = 0 /* Initial value prior to allocation */;
  
 /* /*
Line 187 
Line 188 
  
 sos_ret_t sos_umem_vmm_subsystem_setup() sos_ret_t sos_umem_vmm_subsystem_setup()
 { {
   sos_vaddr_t vaddr_zero_page; 
  
      reset it with 0s */      reset it with 0s */
   vaddr_zero_page = sos_kmem_vmm_alloc(1, SOS_KMEM_VMM_MAP);   sos_zero_kernelpage = sos_kmem_vmm_alloc(1, SOS_KMEM_VMM_MAP);
   if (vaddr_zero_page == (sos_vaddr_t)NULL)   if (sos_zero_kernelpage == (sos_vaddr_t)NULL)
   memset((void*)vaddr_zero_page, 0x0, SOS_PAGE_SIZE);   memset((void*)sos_zero_kernelpage, 0x0, SOS_PAGE_SIZE);
   /* Keep a reference to the underlying pphysical page... */   /* Keep a reference to the underlying pphysical page... */
   sos_zero_page = sos_paging_get_paddr(vaddr_zero_page);   sos_zero_physpage = sos_paging_get_paddr(sos_zero_kernelpage);
   SOS_ASSERT_FATAL(NULL != (void*)sos_zero_page);   SOS_ASSERT_FATAL(NULL != (void*)sos_zero_physpage);
   sos_physmem_ref_physpage_at(sos_zero_page);   sos_physmem_ref_physpage_at(sos_zero_physpage);
  
   /* ... but it is not needed in kernel space anymore, so we can 
      safely unmap it from kernel space */ 
   sos_paging_unmap(vaddr_zero_page); 
   /* Allocate the VR/AS caches */   /* Allocate the VR/AS caches */
   cache_of_as   cache_of_as
Line 214 
Line 209 
                             | SOS_KSLAB_CREATE_ZERO);                             | SOS_KSLAB_CREATE_ZERO);
   if (! cache_of_as)   if (! cache_of_as)
     {     {
       sos_physmem_unref_physpage(sos_zero_page);       sos_physmem_unref_physpage(sos_zero_physpage);
     }     }
  
Line 226 
Line 221 
                             | SOS_KSLAB_CREATE_ZERO);                             | SOS_KSLAB_CREATE_ZERO);
   if (! cache_of_vr)   if (! cache_of_vr)
     {     {
       sos_physmem_unref_physpage(sos_zero_page);       sos_physmem_unref_physpage(sos_zero_physpage);
       return -SOS_ENOMEM;       return -SOS_ENOMEM;
     }     }
  
 

/tmp/sos-code-article8/sos/umem_vmm.h (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/sos/umem_vmm.h (2005-12-28 11:44:58.000000000 +0100 )
Line 254 
Line 254 
  * mappings. Anybody can map it provided it is ALWAYS in read-only  * mappings. Anybody can map it provided it is ALWAYS in read-only
  * mode  * mode
  */  */
 extern sos_paddr_t sos_zero_page; extern sos_paddr_t sos_zero_physpage;
  
  /**
   * "ZERO" page address mapped in kernel space
   */
  extern sos_vaddr_t sos_zero_kernelpage;
  
 /** /**
  
 

/tmp/sos-code-article8/support/sos.lds (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/support/sos.lds (2005-12-28 11:44:58.000000000 +0100 )
Line 110 
Line 110 
     /* We take note of the end of the kernel: this is where the GPFM     /* We take note of the end of the kernel: this is where the GPFM
        will begin */        will begin */
     __e_kernel = .;     __e_kernel = .;
  
     /* We don't care of the note, indent, comment, etc.. sections 
        generated by gcc */ 
         /DISCARD/ :{ 
                 *(.note*) 
                 *(.indent) 
                 *(.comment) 
                 *(.stab) 
                 *(.stabstr) 
         } 
  
  
 

/tmp/sos-code-article8/userland/banner.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/banner.c (2005-12-28 11:44:58.000000000 +0100 )
Line 120 
Line 120 
 static struct thread_param p1, p2; static struct thread_param p1, p2;
 int main() int main()
 { {
    int fd;
  
   /* Map the x86 text-mode framebuffer in user space */   /* Map the x86 text-mode framebuffer in user space */
   video = fakemmap(0, 4096,   fd = open("/dev/mem", O_RDWR);
                    PROT_READ | PROT_WRITE,   video = mmap(0, 4096,
                    MAP_SHARED,                PROT_READ | PROT_WRITE,
                    "/dev/mem", 0xb8000);                MAP_SHARED,
                 fd, 0xb8000);
    close(fd);
   p1.top_line  = 3;   p1.top_line  = 3;
   p1.str       = str1;   p1.str       = str1;
  
 

/tmp/sos-code-article8/userland/crt.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/crt.c (2005-12-28 11:44:58.000000000 +0100 )
Line 63 
Line 63 
                   unsigned int arg3)                   unsigned int arg3)
 { {
   int ret;   int ret;
    
                "movl %2,%%ebx \n"                "movl %2,%%ebx \n"
                "movl %3,%%ecx \n"                "movl %3,%%ecx \n"
Line 73 
Line 73 
                :"=g"(ret)                :"=g"(ret)
                :"g"(id),"g"(arg1),"g"(arg2),"g"(arg3)                :"g"(id),"g"(arg1),"g"(arg2),"g"(arg3)
                 ,"i"(SOS_SWINTR_SOS_SYSCALL)                 ,"i"(SOS_SWINTR_SOS_SYSCALL)
                :"eax","ebx","ecx","edx");                :"eax","ebx","ecx","edx","memory");
   return ret;   return ret;
 } }
Line 196 
Line 196 
 } }
  
  
 int _sos_fakemmap(void ** ptr_hint_addr, size_t len, int prot, int flags, 
                   const char *resource_path, loff_t offset) 
 { 
   return _sos_syscall7(SOS_SYSCALL_ID_FAKEMMAP, 
                        (unsigned int)ptr_hint_addr, len, prot, flags, 
                        (unsigned int)resource_path, 
                        /* offs64_hi */(offset >> 32), 
                        /* offs64_lo */(offset & 0xffffffff)); 
 } 
  
  
 { {
   return _sos_syscall2(SOS_SYSCALL_ID_MUNMAP,   return _sos_syscall2(SOS_SYSCALL_ID_MUNMAP,
Line 333 
Line 322 
 { {
   if (! pathname)   if (! pathname)
     return -1;     return -1;
      
                        (unsigned)pathname,                        (unsigned)pathname,
                        strlen(pathname),                        strlen(pathname),
Line 398 
Line 387 
 } }
  
  
  int _sos_ioctl(int fd, int cmd, int arg)
  {
    return _sos_syscall3(SOS_SYSCALL_ID_IOCTL, fd,
                         (unsigned int)cmd,
                         (unsigned int)arg);
  }
  
  
 int _sos_creat(const char *pathname, int mode) int _sos_creat(const char *pathname, int mode)
 { {
   if (! pathname)   if (! pathname)
Line 460 
Line 457 
 } }
  
  
  int _sos_mknod(const char *pathname, mode_t mode,
                 int type,
                 unsigned int major, unsigned minor)
  {
    if (!pathname)
      return -1;
  
    return _sos_syscall6(SOS_SYSCALL_ID_MKNOD,
                         (unsigned int)pathname,
                         strlen(pathname),
                         type, mode, major, minor);
  }
  
  
 struct dirent; /* Forward declaration */ struct dirent; /* Forward declaration */
 int _sos_readdir(int fd, struct dirent * dirent) int _sos_readdir(int fd, struct dirent * dirent)
 { {
  
 

/tmp/sos-code-article8/userland/crt.h (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/crt.h (2005-12-28 11:44:58.000000000 +0100 )
Line 119 
Line 119 
  
  
 /** /**
  * Syscall to map the given resource. Preliminary version without file 
  * system support 
  */ 
 int _sos_fakemmap(void ** ptr_hint_addr, size_t len, int prot, int flags, 
                   const char *resource_path, loff_t offset); 
  
  
 /** 
  */  */
 int _sos_munmap(void * start, size_t length); int _sos_munmap(void * start, size_t length);
Line 191 
Line 183 
 int _sos_fmmap(void ** ptr_hint_addr, size_t len, int prot, int flags, int _sos_fmmap(void ** ptr_hint_addr, size_t len, int prot, int flags,
                int fd, loff_t offset);                int fd, loff_t offset);
 int _sos_fcntl(int fd, int cmd, int arg); int _sos_fcntl(int fd, int cmd, int arg);
  int _sos_ioctl(int fd, int cmd, int arg);
  
 struct dirent; /* Forward declaration */ struct dirent; /* Forward declaration */
 int _sos_readdir(int fd, struct dirent * dirent); int _sos_readdir(int fd, struct dirent * dirent);
Line 200 
Line 193 
 int _sos_unlink(const char *pathname); int _sos_unlink(const char *pathname);
 int _sos_rename (const char *oldpath, const char *newpath); int _sos_rename (const char *oldpath, const char *newpath);
 int _sos_symlink(const char *target, const char *path); int _sos_symlink(const char *target, const char *path);
  int _sos_mknod(const char *pathname, mode_t mode,
                 int type,
                 unsigned int major, unsigned minor);
  
 int _sos_mkdir(const char *pathname, mode_t mode); int _sos_mkdir(const char *pathname, mode_t mode);
 int _sos_rmdir(const char *pathname); int _sos_rmdir(const char *pathname);
Line 210 
Line 206 
 int _sos_stat(const char *pathname, int nofollow, struct stat * st); int _sos_stat(const char *pathname, int nofollow, struct stat * st);
  
 int _sos_chroot(const char *dirname); int _sos_chroot(const char *dirname);
  int _sos_chdir(const char *dirname);
 int _sos_fchdir(int fd); int _sos_fchdir(int fd);
  
 #endif /* _SOS_USER_CRT_H_ */ #endif /* _SOS_USER_CRT_H_ */
  
 

/tmp/sos-code-article8/userland/devtest.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/userland/devtest.c (2005-12-28 11:44:58.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005 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 <crt.h>
  #include <libc.h>
  #include <stdarg.h>
  #include <string.h>
  #include <debug.h>
  
  #include "fstest_utils.h"
  
  /**
   * @file devtest.c
   *
   * Block/character devices tests
   */
  
  int main()
  {
    int fd, len;
    unsigned int sum, mem_size;
    char buff[256];
    char *uaddr;
  
    bochs_printf("Hi from devtest\n");
  
    /* Make things more complicated */
    fork();
    fork();
  
    /*
     * /dev/zero
     */
  
    TEST_EXPECT_CONDITION(fd = open("/dev/zero", O_RDWR), RETVAL == 3);
  
    /* Make things more complicated: spawn and stay in child */
    if (fork() > 0)
      return 0;
  
    strzcpy(buff, "Garbage", sizeof(buff));
    TEST_EXPECT_CONDITION(len = read(fd, buff, sizeof(buff)),
                          RETVAL == sizeof(buff));
  
    /* Make sure it is full with 0 */
    for (len = 0 ; len < sizeof(buff) ; len ++)
      if (buff[len])
        break;
    TEST_EXPECT_CONDITION(len, RETVAL == sizeof(buff));
  
    TEST_EXPECT_CONDITION(len = write(fd, 0, 123456789), RETVAL == 123456789);
    TEST_EXPECT_CONDITION(len = lseek(fd, 1234, SEEK_SET), RETVAL == 1234);
  
    /* Map it once */
    TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192,
                                       PROT_READ | PROT_WRITE, 0,
                                       fd, 4096), RETVAL != (int)NULL);
  
    /* Make sure it is full with 0 */
    for (len = 0 ; len < 8192 ; len ++)
      if (uaddr[len])
        break;
    TEST_EXPECT_CONDITION(len, RETVAL == 8192);
  
    strzcpy(uaddr, "Hello /dev/zero", 8192);
    TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/zero"), RETVAL == 0);
  
    /* Map it again */
    TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192,
                                       PROT_READ | PROT_WRITE, 0,
                                       fd, 4096), RETVAL != (int)NULL);
    /* Make sure it is full with 0 */
    for (len = 0 ; len < 8192 ; len ++)
      if (uaddr[len])
        break;
    TEST_EXPECT_CONDITION(len, RETVAL == 8192);
  
    strzcpy(uaddr, "Hello /dev/zero", 8192);
    TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/zero"), RETVAL == 0);
  
    TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);
  
  
    /*
     * /dev/null
     */
  
    TEST_EXPECT_CONDITION(fd = open("/dev/null", O_RDWR), RETVAL == 3);
  
    /* Make things more complicated: spawn and stay in child */
    if (fork() > 0)
      return 0;
  
    strzcpy(buff, "Garbage", sizeof(buff));
    TEST_EXPECT_CONDITION(len = read(fd, buff, sizeof(buff)),
                          RETVAL == 0);
  
    /* Make sure buffer did not change */
    TEST_EXPECT_CONDITION(strcmp("Garbage", buff), RETVAL == 0);
  
    TEST_EXPECT_CONDITION(len = write(fd, 0, 123456789), RETVAL == 123456789);
    TEST_EXPECT_CONDITION(len = lseek(fd, 1234, SEEK_SET), RETVAL == 1234);
  
    /* Map it once */
    TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192,
                                       PROT_READ | PROT_WRITE, 0,
                                       fd, 4096), RETVAL != (int)NULL);
    /* Make sure it is full with 0 */
    for (len = 0 ; len < 8192 ; len ++)
      if (uaddr[len])
        break;
    TEST_EXPECT_CONDITION(len, RETVAL == 8192);
  
    strzcpy(uaddr, "Hello /dev/null", 8192);
    TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/null"), RETVAL == 0);
  
    /* Map it again */
    TEST_EXPECT_CONDITION(uaddr = mmap(NULL, 8192,
                                       PROT_READ | PROT_WRITE, 0,
                                       fd, 4096), RETVAL != (int)NULL);
    /* Make sure it is full with 0 */
    for (len = 0 ; len < 8192 ; len ++)
      if (uaddr[len])
        break;
    TEST_EXPECT_CONDITION(len, RETVAL == 8192);
  
    strzcpy(uaddr, "Hello /dev/null", 8192);
    TEST_EXPECT_CONDITION(strcmp(uaddr, "Hello /dev/null"), RETVAL == 0);
  
    TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);
  
    /*
     * Invalid device instance of zero.c
     */
    TEST_EXPECT_CONDITION(mknod("/dev/invalid_zero", S_IRUSR | S_IWUSR,
                                S_IFCHR, 1, 42), RETVAL == 0);
    ls("/", 1, 1);
    TEST_EXPECT_CONDITION(fd = open("/dev/invalid_zero", O_RDWR), RETVAL < 0);
    TEST_EXPECT_CONDITION(unlink("/dev/invalid_zero"), RETVAL == 0);
  
  
    /*
     * Invalid device class / device instance
     */
    TEST_EXPECT_CONDITION(mknod("/dev/invalid_devclass", S_IRUSR | S_IWUSR,
                                S_IFCHR, 54654, 476576), RETVAL == 0);
    ls("/", 1, 1);
    TEST_EXPECT_CONDITION(fd = open("/dev/invalid_devclass",
                                    O_RDWR), RETVAL < 0);
    TEST_EXPECT_CONDITION(unlink("/dev/invalid_devclass"), RETVAL == 0);
  
  
    /*
     * Test Block devices
     */
    TEST_EXPECT_CONDITION(fd = open("/dev/hda", O_RDONLY), RETVAL < 0);
    ls("/", 1, 1);
    TEST_EXPECT_CONDITION(close(fd), RETVAL < 0);
  
    /*
     * Make a checksum of all physical memory (/dev/mem)
     */
    TEST_EXPECT_CONDITION(fd = open("/dev/mem", O_RDONLY), RETVAL == 3);
  
    /* Make things more complicated: spawn and stay in child */
    if (fork() > 0)
      return 0;
  
    for (mem_size = 0, sum = 0 ;
         len = read(fd, buff, sizeof(buff)), len > 0 ;
         mem_size += len)
      {
        char *c;
        if (((mem_size / sizeof(buff)) % 4000) == 0)
          printf("Read %d MB of physical memory\n", mem_size >> 20);
  
        for (c = buff ; c - buff < len ; c++)
          sum += *c;
      }
    TEST_EXPECT_CONDITION(mem_size, RETVAL > 0);
    printf("Checkum of RAM (%d MB) is %x\n", mem_size >> 20, sum);
    TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_SET), len == 0);
    TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_END), len == mem_size);
    TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);
  
    /*
     * Make a checksum of main kernel memory (/dev/kmem)
     */
    TEST_EXPECT_CONDITION(fd = open("/dev/kmem", O_RDONLY), RETVAL == 3);
  
    /* Make things more complicated: spawn and stay in child */
    if (fork() > 0)
      return 0;
  
    /* Seek to beginning of main .text section */
    TEST_EXPECT_CONDITION(lseek(fd, 0x201000, SEEK_SET), RETVAL == 0x201000);
    for (mem_size = 0, sum = 0 ;
         len = read(fd, buff, sizeof(buff)), len > 0 ;
         mem_size += len)
      {
        char *c;
        if (((mem_size / sizeof(buff)) % 400) == 0)
          printf("Read %d kB of kernel memory\n", mem_size >> 10);
  
        for (c = buff ; c - buff < len ; c++)
          sum += *c;
      }
    TEST_EXPECT_CONDITION(mem_size, RETVAL > 0);
    printf("Checkum of main kernel area (%d kB) is %x\n",
           mem_size >> 10, sum);
    TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_SET), len == 0);
    TEST_EXPECT_CONDITION(len = lseek(fd, 0, SEEK_END), len == 0x40000000);
    TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);
  
    printf("Bye from devtest\n");
    ls("/", 1, 1);
  
    /* Crash the whole kernel */
    bochs_printf("NOW Crashing the whole thing !...\n");
  
    {
      int i;
      for (i = 5 ; i >= 0 ; i --)
        {
          printf("Crashing the whole thing in %ds !...     \r", i);
          sleep(1);
        }
    }
    printf("\nGO !\n");
    TEST_EXPECT_CONDITION(fd = open("/dev/mem", O_WRONLY), RETVAL == 3);
    memset(buff, 0xcc, sizeof(buff));
    while (write(fd, buff, sizeof(buff)))
      continue;  
  
    return 0;
  }
  
 

/tmp/sos-code-article8/userland/fstest.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/fstest.c (2005-12-28 11:44:58.000000000 +0100 )
Line 24 
Line 24 
  
 #include "fstest_utils.h" #include "fstest_utils.h"
  
  #define OPEN_BASE_FD 3
  
 /** /**
  * @file fstest.c  * @file fstest.c
  *  *
Line 36 
Line 38 
   char buff[256];   char buff[256];
  
   bochs_printf("Hi from fstest\n");   bochs_printf("Hi from fstest\n");
    
   ls(".", 1, 1);   ls(".", 1, 1);
   ls("", 1, 1);   ls("", 1, 1);
Line 49 
Line 51 
                         RETVAL < 0);                         RETVAL < 0);
  
   TEST_EXPECT_CONDITION(fd = open("/", O_RDWR),   TEST_EXPECT_CONDITION(fd = open("/", O_RDWR),
                         RETVAL == 0);                         RETVAL == OPEN_BASE_FD + 0);
   TEST_EXPECT_CONDITION(fd = open("/", O_RDONLY),   TEST_EXPECT_CONDITION(fd = open("/", O_RDONLY),
                         RETVAL == 1);                         RETVAL == OPEN_BASE_FD + 1);
   TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY),   TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY),
                         RETVAL == 2);                         RETVAL == OPEN_BASE_FD + 2);
   TEST_EXPECT_CONDITION(close(1),   TEST_EXPECT_CONDITION(close(OPEN_BASE_FD + 1),
      
   TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY),   TEST_EXPECT_CONDITION(fd = open("/", O_WRONLY),
                         RETVAL == 1);                         RETVAL == OPEN_BASE_FD + 1);
   TEST_EXPECT_CONDITION(fd = open("//", O_WRONLY),   TEST_EXPECT_CONDITION(fd = open("//", O_WRONLY),
                         RETVAL == 3);                         RETVAL == OPEN_BASE_FD + 3);
   TEST_EXPECT_CONDITION(fd = open("////////", O_WRONLY),   TEST_EXPECT_CONDITION(fd = open("////////", O_WRONLY),
                         RETVAL == 4);                         RETVAL == OPEN_BASE_FD + 4);
   TEST_EXPECT_CONDITION(fd = open("/does not exist", O_WRONLY),   TEST_EXPECT_CONDITION(fd = open("/does not exist", O_WRONLY),
                         RETVAL < 0);                         RETVAL < 0);
Line 118 
Line 120 
                         RETVAL < 0);                         RETVAL < 0);
  
   TEST_EXPECT_CONDITION(fd = open("/", O_RDWR),   TEST_EXPECT_CONDITION(fd = open("/", O_RDWR),
                         RETVAL == 5);                         RETVAL == OPEN_BASE_FD + 5);
   TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR),   TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR),
                         RETVAL < 0);                         RETVAL < 0);
Line 127 
Line 129 
  
   TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("/tutu.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 6);                         RETVAL == OPEN_BASE_FD + 6);
   ls("/", 1, 1);   ls("/", 1, 1);
  
   TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT),   TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT),
                         RETVAL == 7);                         RETVAL == OPEN_BASE_FD + 7);
   /* O_EXCL with an already-existing file */   /* O_EXCL with an already-existing file */
   TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT | O_EXCL),   TEST_EXPECT_CONDITION(fd = open("tutu.txt", O_RDWR | O_CREAT | O_EXCL),
Line 140 
Line 142 
  
   TEST_EXPECT_CONDITION(fd = open("/toto.txt", O_RDWR | O_CREAT | O_EXCL,   TEST_EXPECT_CONDITION(fd = open("/toto.txt", O_RDWR | O_CREAT | O_EXCL,
                                   S_IRWXALL),                                   S_IRWXALL),
                         RETVAL == 8);                         RETVAL == OPEN_BASE_FD + 8);
   /* O_EXCL with an already-existing file */   /* O_EXCL with an already-existing file */
   TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT | O_EXCL),   TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT | O_EXCL),
Line 148 
Line 150 
  
   TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("toto.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 9);                         RETVAL == OPEN_BASE_FD + 9);
   /* Trailing slash on non-dir entries */   /* Trailing slash on non-dir entries */
   TEST_EXPECT_CONDITION(fd = open("toto.txt/", O_RDWR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("toto.txt/", O_RDWR), RETVAL < 0);
Line 160 
Line 162 
   TEST_EXPECT_CONDITION(fd = open("toto1.txt", O_RDWR),   TEST_EXPECT_CONDITION(fd = open("toto1.txt", O_RDWR),
                         RETVAL < 0);                         RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("toto1.tx", O_RDWR | O_CREAT, S_IWUSR),   TEST_EXPECT_CONDITION(fd = open("toto1.tx", O_RDWR | O_CREAT, S_IWUSR),
                         RETVAL == 10);                         RETVAL == OPEN_BASE_FD + 10);
   /* Substring match */   /* Substring match */
   TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR),   TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR),
                         RETVAL < 0);                         RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("toto.tx", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 11);                         RETVAL == OPEN_BASE_FD + 11);
   /*   /*
    * read/write/seek    * read/write/seek
Line 229 
Line 231 
   /* Open r/w, create read-only */   /* Open r/w, create read-only */
  
   TEST_EXPECT_CONDITION(fd = open("toto2.txt", O_RDWR | O_CREAT, S_IRUSR),   TEST_EXPECT_CONDITION(fd = open("toto2.txt", O_RDWR | O_CREAT, S_IRUSR),
                         RETVAL == 12);                         RETVAL == OPEN_BASE_FD + 12);
   strzcpy(buff, "Garbage garbage garbage", 256);   strzcpy(buff, "Garbage garbage garbage", 256);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256),   TEST_EXPECT_CONDITION(len = read(fd, buff, 256),
Line 250 
Line 252 
  
   TEST_EXPECT_CONDITION(fd = open("toto3.txt", O_RDONLY | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("toto3.txt", O_RDONLY | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 13);                         RETVAL == OPEN_BASE_FD + 13);
   strzcpy(buff, "Garbage garbage garbage", 256);   strzcpy(buff, "Garbage garbage garbage", 256);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0);
Line 271 
Line 273 
     {     {
       bochs_printf("Hello from child\n");       bochs_printf("Hello from child\n");
       TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDWR | O_CREAT, S_IRWXALL),       TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDWR | O_CREAT, S_IRWXALL),
                             RETVAL == 14);                             RETVAL == OPEN_BASE_FD + 14);
       TEST_EXPECT_CONDITION(len = write(fd, buff, 19),       TEST_EXPECT_CONDITION(len = write(fd, buff, 19),
                             RETVAL == 19);                             RETVAL == 19);
Line 284 
Line 286 
   nanosleep(1, 0);   nanosleep(1, 0);
   ls("/", 1, 1);   ls("/", 1, 1);
   TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDONLY),   TEST_EXPECT_CONDITION(fd = open("shrd.txt", O_RDONLY),
                         RETVAL == 14);                         RETVAL == OPEN_BASE_FD + 14);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256),   TEST_EXPECT_CONDITION(len = read(fd, buff, 256),
                         RETVAL == 19);                         RETVAL == 19);
Line 301 
Line 303 
  
   TEST_EXPECT_CONDITION(fcntl(fd, 2, 3), RETVAL < 0); /* Not supported   TEST_EXPECT_CONDITION(fcntl(fd, 2, 3), RETVAL < 0); /* Not supported
                                                          by virtfs */                                                          by virtfs */
    TEST_EXPECT_CONDITION(ioctl(fd, 2, 3), RETVAL < 0); /* Not supported
                                                           by virtfs */
  
   ls("/", 1, 1);   ls("/", 1, 1);
  
Line 316 
Line 320 
   TEST_EXPECT_CONDITION(chmod("toto5.txt", S_IRUSR | S_IWUSR), RETVAL == 0);   TEST_EXPECT_CONDITION(chmod("toto5.txt", S_IRUSR | S_IWUSR), RETVAL == 0);
   ls("/", 1, 1);   ls("/", 1, 1);
  
   TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR), RETVAL == 14);   TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR),
                          RETVAL == OPEN_BASE_FD + 14);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0);
  
Line 331 
Line 336 
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);
   bochs_printf("read s='%s'\n", buff);   bochs_printf("read s='%s'\n", buff);
  
   TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR), RETVAL == 15);   TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR),
                          RETVAL == OPEN_BASE_FD + 15);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);
   bochs_printf("read s='%s'\n", buff);   bochs_printf("read s='%s'\n", buff);
Line 359 
Line 365 
  
   ls("/", 1, 1);   ls("/", 1, 1);
  
   TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR), RETVAL == 16);   TEST_EXPECT_CONDITION(fd = open("toto5.txt", O_RDWR),
                          RETVAL == OPEN_BASE_FD + 16);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 0);
  
Line 375 
Line 382 
   bochs_printf("read s='%s'\n", buff);   bochs_printf("read s='%s'\n", buff);
   TEST_EXPECT_CONDITION(strcmp(buff, "Hello world from toto5"), RETVAL == 0);   TEST_EXPECT_CONDITION(strcmp(buff, "Hello world from toto5"), RETVAL == 0);
  
   TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR), RETVAL == 17);   TEST_EXPECT_CONDITION(fd = open("toto4.txt", O_RDWR),
                          RETVAL == OPEN_BASE_FD + 17);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);
   bochs_printf("read s='%s'\n", buff);   bochs_printf("read s='%s'\n", buff);
Line 386 
Line 394 
   TEST_EXPECT_CONDITION(symlink("dangling", "toto6.txt"), RETVAL < 0); /*EEXIST*/   TEST_EXPECT_CONDITION(symlink("dangling", "toto6.txt"), RETVAL < 0); /*EEXIST*/
  
   TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR | O_NOFOLLOW), RETVAL == 18);   TEST_EXPECT_CONDITION(fd = open("toto6.txt", O_RDWR | O_NOFOLLOW),
                          RETVAL == OPEN_BASE_FD + 18);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 8);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 8);
   bochs_printf("read s='%s'\n", buff);   bochs_printf("read s='%s'\n", buff);
Line 411 
Line 420 
  
   TEST_EXPECT_CONDITION(mkdir("yoplait1", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yoplait1", S_IRWXALL), RETVAL == 0);
   TEST_EXPECT_CONDITION(rename("yoplait1", "mouf1"), RETVAL == 0);   TEST_EXPECT_CONDITION(rename("yoplait1", "mouf1"), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("mouf1/a", O_RDWR | O_CREAT, S_IRWXALL), RETVAL == 19);   TEST_EXPECT_CONDITION(fd = open("mouf1/a", O_RDWR | O_CREAT, S_IRWXALL),
                          RETVAL == OPEN_BASE_FD + 19);
   TEST_EXPECT_CONDITION(rmdir("mouf1"), RETVAL == 0);   TEST_EXPECT_CONDITION(rmdir("mouf1"), RETVAL == 0);
  
   TEST_EXPECT_CONDITION(mkdir("yoplait2", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yoplait2", S_IRWXALL), RETVAL == 0);
   TEST_EXPECT_CONDITION(rename("yoplait2", "mouf2"), RETVAL == 0);   TEST_EXPECT_CONDITION(rename("yoplait2", "mouf2"), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("mouf2/a", O_RDWR | O_CREAT, S_IRWXALL), RETVAL == 20);   TEST_EXPECT_CONDITION(fd = open("mouf2/a", O_RDWR | O_CREAT, S_IRWXALL),
                          RETVAL == OPEN_BASE_FD + 20);
  
   TEST_EXPECT_CONDITION(mkdir("yoplait3", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yoplait3", S_IRWXALL), RETVAL == 0);
Line 433 
Line 444 
  
   ls("/", 1, 1);   ls("/", 1, 1);
  
    /* Not supported by virtfs */
    TEST_EXPECT_CONDITION(mknod("dev1", S_IRWXALL, S_IFCHR, 420, 268),
                          RETVAL == 0);
    /* Make sure the device cannot be opened (no device should be
       associated to it */
    TEST_EXPECT_CONDITION(open("dev1", O_RDONLY), RETVAL < 0);
    TEST_EXPECT_CONDITION(unlink("dev1"), RETVAL == 0);
  
   ls("/", 1, 1);   ls("/", 1, 1);
   ls("..", 1, 1);   ls("..", 1, 1);
   ls("../", 1, 1);   ls("../", 1, 1);
Line 440 
Line 459 
  
   /* subdirs */   /* subdirs */
   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT,
                                    S_IRUSR), RETVAL < 0);
   ls("/", 1, 1);   ls("/", 1, 1);
   ls("/yo1", 1, 1);   ls("/yo1", 1, 1);
  
   TEST_EXPECT_CONDITION(mkdir("yo1", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yo1", S_IRWXALL), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL == 21);   TEST_EXPECT_CONDITION(fd = open("yo1/titi1.txt", O_RDONLY | O_CREAT,
                                    S_IRUSR), RETVAL == OPEN_BASE_FD + 21);
   ls("/", 1, 1);   ls("/", 1, 1);
   ls("/yo1", 1, 1);   ls("/yo1", 1, 1);
  
   TEST_EXPECT_CONDITION(mkdir("yo2", S_IRUSR | S_IXUSR), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yo2", S_IRUSR | S_IXUSR), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo2/titi1.txt", O_RDONLY | O_CREAT,
                                    S_IRUSR), RETVAL < 0);
   ls("/", 1, 1);   ls("/", 1, 1);
  
   TEST_EXPECT_CONDITION(mkdir("yo3", S_IWUSR | S_IXUSR), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yo3", S_IWUSR | S_IXUSR), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL == 22);   TEST_EXPECT_CONDITION(fd = open("yo3/titi1.txt", O_RDONLY | O_CREAT,
                                    S_IRUSR), RETVAL == OPEN_BASE_FD + 22);
   ls("/", 1, 1);   ls("/", 1, 1);
  
   TEST_EXPECT_CONDITION(mkdir("yo4", S_IWUSR), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("yo4", S_IWUSR), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY | O_CREAT, S_IRUSR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("yo4/titi1.txt", O_RDONLY | O_CREAT,
                                    S_IRUSR), RETVAL < 0);
   ls("/", 1, 1);   ls("/", 1, 1);
  
Line 503 
Line 527 
   ls("/", 1, 1);   ls("/", 1, 1);
  
   /* Make sure we cannot umount if the FS is in use */   /* Make sure we cannot umount if the FS is in use */
   TEST_EXPECT_CONDITION(fd = open("mnt/subdir_mounted", O_DIRECTORY), RETVAL == 23);   TEST_EXPECT_CONDITION(fd = open("mnt/subdir_mounted", O_DIRECTORY),
                          RETVAL == OPEN_BASE_FD + 23);
   TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);   TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);
  
Line 518 
Line 543 
     {     {
       bochs_printf("Hello from child\n");       bochs_printf("Hello from child\n");
       TEST_EXPECT_CONDITION(chdir("mnt"), RETVAL == 0);       TEST_EXPECT_CONDITION(chdir("mnt"), RETVAL == 0);
       TEST_EXPECT_CONDITION(fd = open("subdir_mounted", O_DIRECTORY), RETVAL == 23);       TEST_EXPECT_CONDITION(fd = open("subdir_mounted", O_DIRECTORY),
                              RETVAL == OPEN_BASE_FD + 23);
       nanosleep(2, 0);       nanosleep(2, 0);
       bochs_printf("Bye from child\n");       bochs_printf("Bye from child\n");
Line 563 
Line 589 
  
   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 23);                         RETVAL == OPEN_BASE_FD + 23);
   TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0);   TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0);
   ls("/", 1, 1);   ls("/", 1, 1);
Line 601 
Line 627 
  
   TEST_EXPECT_CONDITION(mkdir("plotch", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("plotch", S_IRWXALL), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("plotch/a", O_RDWR | O_CREAT, S_IRWXALL),   TEST_EXPECT_CONDITION(fd = open("plotch/a", O_RDWR | O_CREAT, S_IRWXALL),
                         RETVAL == 24);                         RETVAL == OPEN_BASE_FD + 24);
   TEST_EXPECT_CONDITION(unlink("plotch/a"), RETVAL == 0);   TEST_EXPECT_CONDITION(unlink("plotch/a"), RETVAL == 0);
   TEST_EXPECT_CONDITION(rmdir("plotch"), RETVAL == 0);   TEST_EXPECT_CONDITION(rmdir("plotch"), RETVAL == 0);
Line 614 
Line 640 
   TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination ", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination ", S_IRWXALL), RETVAL == 0);
   TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination / directory", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(mkdir("this is / a long path/tothe/destination / directory", S_IRWXALL), RETVAL == 0);
   TEST_EXPECT_CONDITION(fd = open("this is / a long path/tothe/destination / directory/a", O_RDWR | O_CREAT, S_IRWXALL),   TEST_EXPECT_CONDITION(fd = open("this is / a long path/tothe/destination / directory/a", O_RDWR | O_CREAT, S_IRWXALL),
                         RETVAL == 24);                         RETVAL == OPEN_BASE_FD + 24);
   TEST_EXPECT_CONDITION(unlink("this is / a long path/tothe/destination / directory/a"), RETVAL == 0);   TEST_EXPECT_CONDITION(unlink("this is / a long path/tothe/destination / directory/a"), RETVAL == 0);
   TEST_EXPECT_CONDITION(rmdir("this is / a long path/tothe/destination / directory"), RETVAL == 0);   TEST_EXPECT_CONDITION(rmdir("this is / a long path/tothe/destination / directory"), RETVAL == 0);
Line 632 
Line 658 
  
   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 24);                         RETVAL == OPEN_BASE_FD + 24);
   TEST_EXPECT_CONDITION(link("toto8.txt", "toto9.txt"), RETVAL == 0);   TEST_EXPECT_CONDITION(link("toto8.txt", "toto9.txt"), RETVAL == 0);
   TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0);   TEST_EXPECT_CONDITION(unlink("toto8.txt"), RETVAL == 0);
Line 653 
Line 679 
   bochs_printf("read s='%s'\n", buff);   bochs_printf("read s='%s'\n", buff);
  
   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR), RETVAL == 25);   TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR),
                          RETVAL == OPEN_BASE_FD + 25);
   strzcpy(buff, "Garbage garbage garbage", 256);   strzcpy(buff, "Garbage garbage garbage", 256);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);
Line 667 
Line 694 
  
   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 26);                         RETVAL == OPEN_BASE_FD + 26);
   TEST_EXPECT_CONDITION(rename("toto8.txt", "toto9.txt"), RETVAL == 0);   TEST_EXPECT_CONDITION(rename("toto8.txt", "toto9.txt"), RETVAL == 0);
   ls("/", 1, 1);   ls("/", 1, 1);
Line 688 
Line 715 
   TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);   TEST_EXPECT_CONDITION(close(fd), RETVAL == 0);
  
   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0);   TEST_EXPECT_CONDITION(fd = open("toto8.txt", O_RDWR), RETVAL < 0);
   TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR), RETVAL == 26);   TEST_EXPECT_CONDITION(fd = open("toto9.txt", O_RDWR),
                          RETVAL == OPEN_BASE_FD + 26);
   strzcpy(buff, "Garbage garbage garbage", 256);   strzcpy(buff, "Garbage garbage garbage", 256);
   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);   TEST_EXPECT_CONDITION(len = read(fd, buff, 256), RETVAL == 24);
Line 721 
Line 749 
   /* Common use: shared file suppressed as soon as possible */   /* Common use: shared file suppressed as soon as possible */
   TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 26);                         RETVAL == OPEN_BASE_FD + 26);
     {     {
       char *shrd;       char *shrd;
Line 753 
Line 781 
   /* Common use: shared file suppressed as soon as possible */   /* Common use: shared file suppressed as soon as possible */
   TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,   TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,
                                   S_IRUSR | S_IWUSR),                                   S_IRUSR | S_IWUSR),
                         RETVAL == 27);                         RETVAL == OPEN_BASE_FD + 27);
   if (fork() == 0)   if (fork() == 0)
     {     {
Line 781 
Line 809 
   ls("/", 1, 1);   ls("/", 1, 1);
  
   /* Basic use */   /* Basic use */
   TEST_EXPECT_CONDITION(creat("mmap.txt", S_IRWXALL), RETVAL == 0);   TEST_EXPECT_CONDITION(creat("mmap.txt", S_IRUSR | S_IWUSR), RETVAL == 0);
     {     {
       char *shrd;       char *shrd;
       TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,       TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,
                                       S_IRUSR | S_IWUSR),                                       S_IRUSR | S_IWUSR),
                             RETVAL == 28);                             RETVAL == OPEN_BASE_FD + 28);
                                         MAP_SHARED, fd, 4096),                                         MAP_SHARED, fd, 4096),
                             shrd != NULL);                             shrd != NULL);
Line 800 
Line 828 
       char *shrd;       char *shrd;
       TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,       TEST_EXPECT_CONDITION(fd = open("mmap.txt", O_RDWR | O_CREAT,
                                       S_IRUSR | S_IWUSR),                                       S_IRUSR | S_IWUSR),
                             RETVAL == 28);                             RETVAL == OPEN_BASE_FD + 28);
                                         MAP_SHARED, fd, 4096),                                         MAP_SHARED, fd, 4096),
                             shrd != NULL);                             shrd != NULL);
  
 

/tmp/sos-code-article8/userland/fstest_utils.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/fstest_utils.c (2005-12-28 11:44:58.000000000 +0100 )
Line 17 
Line 17 
 */ */
  
 #include <libc.h> #include <libc.h>
  #include <stdarg.h>
 #include <debug.h> #include <debug.h>
  
 #include "fstest_utils.h" #include "fstest_utils.h"
Line 58 
Line 59 
         case S_IFREG: entrychar='-'; entrysuffix=""; break;         case S_IFREG: entrychar='-'; entrysuffix=""; break;
         case S_IFDIR: entrychar='d'; entrysuffix="/"; break;         case S_IFDIR: entrychar='d'; entrysuffix="/"; break;
         case S_IFLNK: entrychar='l'; entrysuffix="@"; break;         case S_IFLNK: entrychar='l'; entrysuffix="@"; break;
          case S_IFCHR: entrychar='c'; entrysuffix=NULL; break;
         default: entrychar='?'; entrysuffix="?!?"; break;         default: entrychar='?'; entrysuffix="?!?"; break;
         }         }
  
Line 65 
Line 67 
         {         {
           struct stat stat;           struct stat stat;
           char target_name[SOS_FS_DIRENT_NAME_MAXLEN];           char target_name[SOS_FS_DIRENT_NAME_MAXLEN];
                      char majorminor[24];
  
             continue;             continue;
  
           *target_name = '\0';           *target_name = '\0';
           if (stat.st_type==S_IFLNK)           if (stat.st_type == S_IFLNK)
               int fd = open(dirent->name, O_RDONLY | O_NOFOLLOW);               int fd = open(dirent->name, O_RDONLY | O_NOFOLLOW);
               if (fd >= 0)               if (fd >= 0)
Line 83 
Line 86 
                   close(fd);                   close(fd);
                 }                 }
             }             }
            else if (stat.st_type == S_IFCHR)
              {
                snprintf(majorminor, sizeof(majorminor), " %d,%d",
                         stat.st_rdev_major, stat.st_rdev_minor);
                entrysuffix = majorminor;
              }
  
           bochs_printf("%s%c%c%c%c %lld %s%s%s%s (location=0x%llx)\n",           bochs_printf("%s%c%c%c%c %lld %s%s%s%s (location=0x%llx)\n",
                        tab, entrychar,                        tab, entrychar,
  
 

/tmp/sos-code-article8/userland/init.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/init.c (2005-12-28 11:44:58.000000000 +0100 )
Line 18 
Line 18 
  
 #include <libc.h> #include <libc.h>
 #include <debug.h> #include <debug.h>
  #include <drivers/devices.h>
  #include "fstest_utils.h"
 /** /**
  * @file init.c  * @file init.c
  * Test brk (and, hence: mremap) and exec()  * Test fork and exec()
  
 int main() int main()
 { {
   bochs_printf("init: Welcome in userland !\n");   bochs_printf("init: Welcome in userland !\n");
  
   /* launch the tests */ 
    /* Creating initial device nodes */
    TEST_EXPECT_CONDITION(mkdir("/dev", S_IRWXALL), RETVAL == 0);
    TEST_EXPECT_CONDITION(mknod("/dev/zero", S_IRUSR | S_IWUSR,
                                S_IFCHR, SOS_CHARDEV_ZERO_MAJOR, SOS_CHARDEV_ZERO_MINOR), RETVAL == 0);
    TEST_EXPECT_CONDITION(mknod("/dev/null", S_IRUSR | S_IWUSR,
                                S_IFCHR, SOS_CHARDEV_ZERO_MAJOR, SOS_CHARDEV_NULL_MINOR), RETVAL == 0);
    TEST_EXPECT_CONDITION(mknod("/dev/kmem", S_IRUSR | S_IWUSR,
                                S_IFCHR, SOS_CHARDEV_MEM_MAJOR, SOS_CHARDEV_KMEM_MINOR), RETVAL == 0);
    TEST_EXPECT_CONDITION(mknod("/dev/mem", S_IRUSR | S_IWUSR,
                                S_IFCHR, SOS_CHARDEV_MEM_MAJOR, SOS_CHARDEV_PHYSMEM_MINOR), RETVAL == 0);
    TEST_EXPECT_CONDITION(mknod("/dev/tty", S_IRUSR | S_IWUSR,
                                S_IFCHR, SOS_CHARDEV_TTY_MAJOR, SOS_CHARDEV_CONSOLE_MINOR), RETVAL == 0);
    TEST_EXPECT_CONDITION(mknod("/dev/ttyS", S_IRUSR | S_IWUSR,
                                S_IFCHR, SOS_CHARDEV_TTY_MAJOR, SOS_CHARDEV_SERIAL_MINOR), RETVAL == 0);
  
    ls("/", 1, 1);
  
    /* Set up the shell on the console */
    TEST_EXPECT_CONDITION(open("/dev/tty", O_RDWR), RETVAL == 0);
    TEST_EXPECT_CONDITION(open("/dev/tty", O_RDWR), RETVAL == 1);
    TEST_EXPECT_CONDITION(open("/dev/tty", O_RDWR), RETVAL == 2);
  
     exec("fstest");     exec ("shell");
  
    close (2);
    close (1);
    close (0);
  
    /* Set up the shell on the serial port */
    TEST_EXPECT_CONDITION(open("/dev/ttyS", O_RDWR), RETVAL == 0);
    TEST_EXPECT_CONDITION(open("/dev/ttyS", O_RDWR), RETVAL == 1);
    TEST_EXPECT_CONDITION(open("/dev/ttyS", O_RDWR), RETVAL == 2);
   if (fork() == 0)   if (fork() == 0)
     exec("banner");     exec ("shell");
  
    close (2);
    close (1);
    close (0);
  
   bochs_printf("init: The end\n");   bochs_printf("init: The end\n");
   return 0;   return 0;
  
 

/tmp/sos-code-article8/userland/libc.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/libc.c (2005-12-28 11:44:58.000000000 +0100 )
Line 17 
Line 17 
 */ */
  
 #include "crt.h" #include "crt.h"
 #include "libc.h" #include "string.h"
  
  #include "libc.h"
  
 void * fakemmap(void *start, size_t length, int prot , int flags, void exit (int status)
                 const char *path, loff_t offset) 
   /* At kernel side, offset is considered positive */   _sos_exit(status);
   if (offset < 0) }
     return NULL; 
   if (0 != _sos_fakemmap(& start, length, prot, flags, path, offset)) 
     return NULL; 
   return start; pid_t fork(void)
  {
    return _sos_fork();
  }
  
  
  int exec(const char *progname)
  {
    return _sos_exec(progname);
  }
  
  
  int sleep(unsigned int seconds)
  {
    return nanosleep(seconds, 0);
  }
  
  
  int nanosleep(unsigned long int sec,
                unsigned long int nanosec)
  {
    return _sos_nanosleep(sec, nanosec);
  }
  
  
  
  int munmap(void * start, size_t length)
  {
    return _sos_munmap(start, length);
  
  
Line 47 
Line 72 
 } }
  
  
  int mprotect(const void *addr, size_t len, int prot)
  {
    return _sos_mprotect(addr, len, prot);
  }
  
  
 /** /**
  * The presence of this global variable without any protected access  * The presence of this global variable without any protected access
  * to it explains why the "brk/sbrk" functions below are MT-unsafe !  * to it explains why the "brk/sbrk" functions below are MT-unsafe !
Line 114 
Line 145 
 } }
  
  
  
  int mount(const char *source, const char *target,
            const char *filesystemtype, unsigned long mountflags,
            const char *data)
  {
    return _sos_mount(source, target, filesystemtype, mountflags, data);
  }
  
  
  int umount(const char *target)
  {
    return _sos_umount(target);
  }
  
  
  void sync(void)
  {
    return _sos_sync();
  }
  
  
  int statvfs(const char *path, struct statvfs *buf)
  {
    return _sos_statvfs(path, buf);
  }
  
  
 int open(const char *pathname, int flags, /* mode_t mode */...) int open(const char *pathname, int flags, /* mode_t mode */...)
 { {
   va_list ap;   va_list ap;
Line 128 
Line 186 
 } }
  
  
  int close(int fd)
  {
    return _sos_close(fd);
  }
  
  
 int read(int fd, char * buf, size_t len) int read(int fd, char * buf, size_t len)
 { {
   int retval = _sos_read(fd, buf, & len);   int retval = _sos_read(fd, buf, & len);
Line 186 
Line 250 
 } }
  
  
  int ftruncate64(int fd, loff_t length)
  {
    return _sos_ftruncate64(fd, length);
  }
  
  
  int fcntl(int fd, int cmd, int arg)
  {
    return _sos_fcntl(fd, cmd, arg);
  }
  
  
  int ioctl(int fd, int cmd, int arg)
  {
    return _sos_ioctl(fd, cmd, arg);
  }
  
  
  int creat(const char *pathname, mode_t mode)
  {
    return _sos_creat(pathname, mode);
  }
  
  int link (const char *oldpath, const char *newpath)
  {
    return _sos_link(oldpath, newpath);
  }
  
  
  int unlink(const char *pathname)
  {
    return _sos_unlink(pathname);
  }
  
  
  int rename(const char *oldpath, const char *newpath)
  {
    return _sos_rename(oldpath, newpath);
  }
  
  
  int symlink(const char *target, const char *path)
  {
    return _sos_symlink(target, path);
  }
  
  
  int mknod(const char *pathname, mode_t mode,
            int type,
            unsigned int major, unsigned minor)
  {
    if (type == S_IFREG)
      return creat(pathname, mode);
    
    return _sos_mknod(pathname, mode, type,
                      major, minor);
  }
  
  
  int mkdir(const char *pathname, mode_t mode)
  {
    return _sos_mkdir(pathname, mode);
  }
  
  
  int rmdir(const char *pathname)
  {
    return _sos_rmdir(pathname);
  }
  
  
  int chmod(const char *path, mode_t mode)
  {
    return _sos_chmod(path, mode);
  }
  
  
 struct sos_DIR_struct struct sos_DIR_struct
 { {
   int fd;   int fd;
Line 239 
Line 380 
 { {
   return _sos_stat(file_name, FALSE, buf);   return _sos_stat(file_name, FALSE, buf);
 } }
  
  
  int chroot(const char *path)
  {
    return _sos_chroot(path);
  }
  
  
  int chdir(const char *path)
  {
    return _sos_chdir(path);
  }
  
  int fchdir(int fd)
  {
    return _sos_fchdir(fd);
  }
  
  
  
  int printf (const char *format, ...)
  {
    char buff[4096];
    va_list ap;
  
    va_start(ap, format);
    vsnprintf(buff, sizeof(buff), format, ap);
    va_end(ap);
  
    return write (1, buff, strlen(buff));
  }
  
  
  
 

/tmp/sos-code-article8/userland/libc.h (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/libc.h (2005-12-28 11:44:58.000000000 +0100 )
Line 30 
Line 30 
 /** /**
  * The most important function of a C program ! ;)  * The most important function of a C program ! ;)
  */  */
 void exit (int status) void exit (int status);
      __attribute__((noreturn, alias("_sos_exit"))); 
  
 /** /**
  * Function to duplicate the current running process  * Function to duplicate the current running process
  */  */
 pid_t fork(void) pid_t fork(void);
      __attribute__ ((alias("_sos_fork"))); 
  
 /** /**
  * 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 exec(const char *progname);
      __attribute__ ((alias("_sos_exec"))); 
  
 int nanosleep(unsigned long int sec, int nanosleep(unsigned long int sec,
               unsigned long int nanosec)               unsigned long int nanosec);
      __attribute__ ((alias("_sos_nanosleep"))); 
  
  int sleep(unsigned int seconds);
  
 /** /**
  * These flags (for mmap API) MUST be consistent with those defined in  * These flags (for mmap API) MUST be consistent with those defined in
Line 65 
Line 65 
 #define MAP_SHARED (1 << 0) #define MAP_SHARED (1 << 0)
 #define MAP_FIXED  (1 << 31) #define MAP_FIXED  (1 << 31)
  
 /** 
  * Non standard version of mmap. Differences with standard version: 
  *  - the resource to map is given by its "path", not by a file descriptor 
  *  - the offset is a signed 64bits, and MUST be >= 0 (error otherwise) 
  *  - no errno support 
  */ 
 void * fakemmap(void *start, size_t length, int prot , int flags, 
                 const char *path, loff_t offset); 
  
 /** /**
  * Unmap the given user address interval  * Unmap the given user address interval
  */  */
 int munmap(void * start, size_t length) int munmap(void * start, size_t length);
      __attribute__ ((alias("_sos_munmap"))); 
  
 /** /**
  * Change the access permissions of the given user address interval  * Change the access permissions of the given user address interval
  */  */
 int mprotect(const void *addr, size_t len, int prot) int mprotect(const void *addr, size_t len, int prot);
      __attribute__ ((alias("_sos_mprotect"))); 
  
  
 /** /**
Line 129 
Line 117 
  
 int mount(const char *source, const char *target, int mount(const char *source, const char *target,
           const char *filesystemtype, unsigned long mountflags,           const char *filesystemtype, unsigned long mountflags,
           const char *data)           const char *data);
      __attribute__ ((alias("_sos_mount"))); 
 int umount(const char *target) 
      __attribute__ ((alias("_sos_umount"))); int umount(const char *target);
 void sync(void) 
      __attribute__ ((alias("_sos_sync"))); 
  void sync(void);
  
 struct statvfs struct statvfs
 { {
    unsigned int  f_rdev_major;
    unsigned int  f_rdev_minor;
   size_t        f_sz_total;  /**< Total size */   size_t        f_sz_total;  /**< Total size */
   size_t        f_sz_free;   /**< Size left on device */   size_t        f_sz_free;   /**< Size left on device */
   unsigned int  f_node_total;/**< Total allocatable FS nodes */   unsigned int  f_node_total;/**< Total allocatable FS nodes */
Line 145 
Line 137 
   unsigned int  f_flags;   unsigned int  f_flags;
 }; };
  
 int statvfs(const char *path, struct statvfs *buf) int statvfs(const char *path, struct statvfs *buf);
      __attribute__ ((alias("_sos_statvfs"))); 
 #define O_EXCL      (1 << 0) #define O_EXCL      (1 << 0)
 #define O_CREAT     (1 << 1) #define O_CREAT     (1 << 1)
 #define O_NOFOLLOW  (1 << 2) #define O_TRUNC     (1 << 2)
 #define O_DIRECTORY (1 << 3) /* Incompatible with CREAT */ #define O_NOFOLLOW  (1 << 3)
 #define O_SYNC      (1 << 4) #define O_DIRECTORY (1 << 4) /* Incompatible with CREAT/TRUNC */
  #define O_SYNC      (1 << 5)
 #define O_RDONLY    (1 << 16) #define O_RDONLY    (1 << 16)
 #define O_WRONLY    (1 << 17) #define O_WRONLY    (1 << 17)
Line 168 
Line 161 
  
 int open(const char *pathname, int flags, /* mode_t mode */...); int open(const char *pathname, int flags, /* mode_t mode */...);
  
 int close(int fd) int close(int fd);
      __attribute__ ((alias("_sos_close"))); 
 int read(int fd, char * buf, size_t len); int read(int fd, char * buf, size_t len);
 int write(int fd, const char * buf, size_t len); int write(int fd, const char * buf, size_t len);
Line 183 
Line 176 
 void * mmap(void *start, size_t length, int prot , int flags, void * mmap(void *start, size_t length, int prot , int flags,
             int fd, loff_t offset);             int fd, loff_t offset);
 int ftruncate(int fd, off_t length); int ftruncate(int fd, off_t length);
 int ftruncate64(int fd, loff_t length) int ftruncate64(int fd, loff_t length);
      __attribute__ ((alias("_sos_ftruncate64"))); int fcntl(int fd, int cmd, int arg);
 int fcntl(int fd, int cmd, int arg) int ioctl(int fd, int cmd, int arg);
      __attribute__ ((alias("_sos_fcntl"))); 
  int creat(const char *pathname, mode_t mode);
 int creat(const char *pathname, mode_t mode) int link (const char *oldpath, const char *newpath);
      __attribute__ ((alias("_sos_creat"))); int unlink(const char *pathname);
 int link (const char *oldpath, const char *newpath) int rename(const char *oldpath, const char *newpath);
      __attribute__ ((alias("_sos_link"))); int symlink(const char *target, const char *path);
 int unlink(const char *pathname) 
      __attribute__ ((alias("_sos_unlink"))); /* Same as sos_fs_node_type_t in kernel fs.h */
 int rename(const char *oldpath, const char *newpath) #define S_IFREG 0x42
      __attribute__ ((alias("_sos_rename"))); #define S_IFDIR 0x24
 int symlink(const char *target, const char *path) #define S_IFLNK 0x84
      __attribute__ ((alias("_sos_symlink"))); #define S_IFCHR 0x48
  int mknod(const char *pathname, mode_t mode,
 int mkdir(const char *pathname, mode_t mode)           int type,
      __attribute__ ((alias("_sos_mkdir")));           unsigned int major, unsigned minor);
 int rmdir(const char *pathname) 
      __attribute__ ((alias("_sos_rmdir"))); 
  int mkdir(const char *pathname, mode_t mode);
  
  
  int rmdir(const char *pathname);
  
  
  int chmod(const char *path, mode_t mode);
 int chmod(const char *path, mode_t mode) 
      __attribute__ ((alias("_sos_chmod"))); 
 struct dirent struct dirent
 { {
   unsigned long long int storage_location;   unsigned long long int storage_location;
   unsigned long long int offset_in_dirfile;   unsigned long long int offset_in_dirfile;
  
 /* Same as sos_fs_node_type_t in kernel fs.h */ 
 #define S_IFREG 0x42 
 #define S_IFDIR 0x24 
 #define S_IFLNK 0x84 
   unsigned short namelen;   unsigned short namelen;
  
Line 234 
Line 227 
  
 struct stat struct stat
 { {
    unsigned int           st_rdev_major;
    unsigned int           st_rdev_minor;
   int                    st_type;   int                    st_type;
   unsigned long long int st_storage_location;   unsigned long long int st_storage_location;
   int                    st_access_rights;   int                    st_access_rights;
Line 243 
Line 238 
  
 int stat(const char *file_name, struct stat *buf); int stat(const char *file_name, struct stat *buf);
 int lstat(const char *file_name, struct stat *buf); int lstat(const char *file_name, struct stat *buf);
  int chroot(const char *path);
  int chdir(const char *path);
  int fchdir(int fd);
  
 int chroot(const char *path) int printf(const char *, ...);
      __attribute__ ((alias("_sos_chroot"))); 
 int chdir(const char *path) 
      __attribute__ ((alias("_sos_chdir"))); 
 int fchdir(int fd) 
      __attribute__ ((alias("_sos_fchdir"))); 
  
  
 #endif /* _SOS_USER_LIBC_H_ */ #endif /* _SOS_USER_LIBC_H_ */
  
 

/tmp/sos-code-article8/userland/Makefile (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/Makefile (2005-12-28 11:44:58.000000000 +0100 )
Line 31 
Line 31 
  
 PROGS := init myprog1 myprog2 myprog3 myprog4 myprog5 myprog6 \ PROGS := init myprog1 myprog2 myprog3 myprog4 myprog5 myprog6 \
          myprog7 myprog8 myprog9 myprog10 myprog11 myprog12   \          myprog7 myprog8 myprog9 myprog10 myprog11 myprog12   \
          myprog13 myprog14 banner fstest          myprog13 myprog14 banner fstest devtest shell
 # Build dependencies of the programs # Build dependencies of the programs
  init: fstest_utils.o
 fstest: fstest_utils.o fstest: fstest_utils.o
  devtest: fstest_utils.o
  shell: fstest_utils.o
 $(PROGS) : % : %.o crt.o libc.a $(PROGS) : % : %.o crt.o libc.a
  
 PWD := $(shell pwd) PWD := $(shell pwd | sed 's/"/\\\"/g;s/\$$/\\\$$/g')
 # Programs generation # Programs generation
 $(PROGS): $(PROGS):
Line 83 
Line 86 
  
 # Create objects from C source code # Create objects from C source code
 %.o: %.c %.o: %.c
         $(CC) -I$(PWD) -c $< $(CFLAGS) -o $@         $(CC) "-I$(PWD)" -c "$<" $(CFLAGS) -o "$@"
 # Create objects from assembler (.S) source code # Create objects from assembler (.S) source code
 %.o: %.S %.o: %.S
         $(CC) -I$(PWD) -c $< $(CFLAGS) -DASM_SOURCE=1 -o $@         $(CC) "-I$(PWD)" -c "$<" $(CFLAGS) -DASM_SOURCE=1 -o "$@"
 # Clean directory # Clean directory
 clean: clean:
  
 

/tmp/sos-code-article8/userland/myprog10.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/myprog10.c (2005-12-28 11:44:58.000000000 +0100 )
Line 33 
Line 33 
 int main() int main()
 { {
   char * zoup;   char * zoup;
    int fd;
  
    fd = open("/dev/zero", O_RDWR);
    zoup = mmap((void*)4096, 8*1024*1024,
                PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, 34);
    close(fd);
  
   zoup = fakemmap((void*)4096, 8*1024*1024, 
                   PROT_READ | PROT_WRITE, 
                   MAP_SHARED, 
                   "/dev/zero", 34); 
  
   /* Do some forks to complicate things */   /* Do some forks to complicate things */
  
 

/tmp/sos-code-article8/userland/myprog11.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/myprog11.c (2005-12-28 11:44:58.000000000 +0100 )
Line 36 
Line 36 
 { {
   void * moved;   void * moved;
   char * zoup;   char * zoup;
    int fd;
  
    fd = open("/dev/zero", O_RDWR);
    zoup = mmap((void*)4096, 8*1024*1024,
                PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, 34);
    close(fd);
  
   zoup = fakemmap((void*)4096, 8*1024*1024, 
                   PROT_READ | PROT_WRITE, 
                   MAP_SHARED, 
                   "/dev/zero", 34); 
  
   /* Do some forks to complicate things */   /* Do some forks to complicate things */
  
 

/tmp/sos-code-article8/userland/myprog12.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/myprog12.c (2005-12-28 11:44:58.000000000 +0100 )
Line 38 
Line 38 
  
   /* Map the x86 text framebuffer into this process address space in   /* Map the x86 text framebuffer into this process address space in
      shared mode */      shared mode */
   zoup = fakemmap(0, 4096, PROT_READ | PROT_WRITE,   int fd;
                   MAP_SHARED, 
                   "/dev/mem", 0xb8000);   fd = open("/dev/mem", O_RDWR);
    zoup = mmap(0, 4096, PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, 0xb8000);
    close(fd);
  
   _sos_syscall1(4004, (unsigned)"Apres mmap video");   _sos_syscall1(4004, (unsigned)"Apres mmap video");
  
Line 55 
Line 60 
  
   /* Map the x86 text framebuffer into this process address space in   /* Map the x86 text framebuffer into this process address space in
      PRIVATE mode */      PRIVATE mode */
   zoup = fakemmap(0, 4096, PROT_READ | PROT_WRITE,   fd = open("/dev/mem", O_RDWR);
                   0 /* Private */,   zoup = mmap(0, 4096, PROT_READ | PROT_WRITE,
                   "/dev/mem", 0xb8000);               0 /* Private */,
                fd, 0xb8000);
    close(fd);
   _sos_syscall1(4004, (unsigned)"Apres mmap video");   _sos_syscall1(4004, (unsigned)"Apres mmap video");
  
Line 77 
Line 84 
      "private" mode here, this way we can do whatever we like in this      "private" mode here, this way we can do whatever we like in this
      area. If we'd mapped it read/write, this would overwrite kernel      area. If we'd mapped it read/write, this would overwrite kernel
      data/code, causing a crash sooner or later. */      data/code, causing a crash sooner or later. */
   zoup = fakemmap(0, 100*4096, PROT_READ | PROT_WRITE,   fd = open("/dev/kmem", O_RDWR);
                   0 /* private */,   zoup = mmap(0, 100*4096, PROT_READ | PROT_WRITE,
                   "/dev/kmem", 0x00201000);               0 /* private */,
                fd, 0x00201000);
    close(fd);
   _sos_syscall1(4004, (unsigned)"Apres mmap kernel");   _sos_syscall1(4004, (unsigned)"Apres mmap kernel");
  
  
 

/tmp/sos-code-article8/userland/myprog14.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/myprog14.c (2005-12-28 11:44:58.000000000 +0100 )
Line 38 
Line 38 
 int main() int main()
 { {
   char * zoup;   char * zoup;
    int fd;
  
    fd = open("/dev/zero", O_RDWR);
    zoup = mmap(0, 8192,
                PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, 34);
    close(fd);
  
   zoup = fakemmap(0, 8192, 
                   PROT_READ | PROT_WRITE, 
                   MAP_SHARED, 
                   "/dev/zero", 34); 
  
   /* Do some forks to complicate things */   /* Do some forks to complicate things */
  
 

/tmp/sos-code-article8/userland/myprog8.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/myprog8.c (2005-12-28 11:44:58.000000000 +0100 )
Line 31 
Line 31 
 { {
   int i;   int i;
   char *zoup;   char *zoup;
    int fd;
  
    fd = open("/dev/zero", O_RDWR);
    zoup = mmap((void*)4096, 8*1024*1024,
                PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, 0x123456789012345ULL);
    close(fd);
  
   zoup = fakemmap((void*)4096, 8*1024*1024, 
                   PROT_READ | PROT_WRITE, 
                   MAP_SHARED, 
                   "/dev/zero", 0x123456789012345ULL); 
  
   switch (fork())   switch (fork())
  
 

/tmp/sos-code-article8/userland/myprog9.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/myprog9.c (2005-12-28 11:44:58.000000000 +0100 )
Line 33 
Line 33 
 int main() int main()
 { {
   char *zoup;   char *zoup;
    int fd;
  
    fd = open("/dev/zero", O_RDWR);
    zoup = mmap((void*)4096, 8*1024*1024,
                PROT_READ | PROT_WRITE,
                MAP_SHARED,
                fd, 34);
    close(fd);
  
   zoup = fakemmap((void*)4096, 8*1024*1024, 
                   PROT_READ | PROT_WRITE, 
                   MAP_SHARED, 
                   "/dev/zero", 34); 
  
   /* Do a fork() here to complicate things */   /* Do a fork() here to complicate things */
  
 

/tmp/sos-code-article8/userland/shell.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article9/userland/shell.c (2005-12-28 11:44:58.000000000 +0100 )
(New file) 
Line 1 
  /* Copyright (C) 2005 David Decotigny, Thomas Petazzoni
  
     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 <crt.h>
  #include <libc.h>
  #include <stdarg.h>
  #include <string.h>
  #include <debug.h>
  #include <drivers/devices.h>
  
  #include "fstest_utils.h"
  
  /**
   * @file shell.c
   *
   * Small shell.
   */
  
  static int shell_uname (int argc, char *argv[])
  {
    printf ("SOS article 9\n");
    return 0;
  }
  
  static void shell_ls_internal(int detailed, int recursive, int reclevel)
  {
    char tab[256], *c;
    int i;
    struct dirent * dirent;
    DIR * here;
  
    here = opendir(".");
    if (! here)
      return;
  
    /* Build initial tabulation */
    if (recursive)
      {
        for (c = tab, i = 0 ; (i < reclevel) && (i < sizeof(tab)/2) ; i++)
          {
            *c++ = ' ';
            *c++ = ' ';
          }
        *c++ = '\0';
      }
    else
      *tab = '\0';
  
    while ((dirent = readdir(here)) != NULL)
      {
        char entrychar;
        char * entrysuffix;
  
        switch(dirent->type)
          {
          case S_IFREG: entrychar='-'; entrysuffix=""; break;
          case S_IFDIR: entrychar='d'; entrysuffix="/"; break;
          case S_IFLNK: entrychar='l'; entrysuffix="@"; break;
          case S_IFCHR: entrychar='c'; entrysuffix=NULL; break;
          default: entrychar='?'; entrysuffix="?!?"; break;
          }
  
        if (detailed)
          {
            struct stat stat;
            char target_name[SOS_FS_DIRENT_NAME_MAXLEN];
            char majorminor[24];
  
            if (lstat(dirent->name, & stat))
              continue;
  
            *target_name = '\0';
            if (stat.st_type == S_IFLNK)
              {
                int fd = open(dirent->name, O_RDONLY | O_NOFOLLOW);
                if (fd >= 0)
                  {
                    int len = read(fd, target_name, sizeof(target_name) - 1);
                    if (len < 0)
                      *target_name='\0';
                    else
                      target_name[len] = '\0';
                    close(fd);
                  }
              }
            else if (stat.st_type == S_IFCHR)
              {
                snprintf(majorminor, sizeof(majorminor), " %d,%d",
                         stat.st_rdev_major, stat.st_rdev_minor);
                entrysuffix = majorminor;
              }
  
            printf("%s%c%c%c%c %lld %s%s%s%s (location=0x%llx)\n",
                   tab, entrychar,
                   (stat.st_access_rights&S_IRUSR)?'r':'-',
                   (stat.st_access_rights&S_IWUSR)?'w':'-',
                   (stat.st_access_rights&S_IXUSR)?'x':'-',
                   stat.st_size,
                   dirent->name,
                   entrysuffix,
                   (stat.st_type==S_IFLNK)?" -> ":"",
                   target_name,
                   stat.st_storage_location);
          }
        else
            printf("%s%s%s\n",
                   tab, dirent->name, entrysuffix);
  
        /* Next iteration */
        if (recursive)
          {
            int fd_here = dirfd(here);
            if (chdir(dirent->name))
              continue;
            shell_ls_internal(detailed, recursive, reclevel+1);
            if(fchdir(fd_here))
              {
                  closedir(here);
                  return;
              }
          }
      }
    closedir(here);
  }
  
  static void shell_ls(const char * path, int detailed, int recursive)
  {
    int fd_here = open(".", O_RDONLY | O_DIRECTORY);
    if (fd_here < 0)
      return;
  
    if (chdir(path))
      {
        close(fd_here);
        return;
      }
  
    shell_ls_internal(detailed, recursive, 1);
  
    fchdir(fd_here);
    close(fd_here);
  }
  
  static int shell_touch (int argc, char *argv[])
  {
    return creat (argv[1], S_IRUSR | S_IWUSR);
  }
  
  static int shell_mkdir (int argc, char *argv[])
  {
    return mkdir (argv[1], S_IRUSR | S_IWUSR | S_IXUSR);
  }
  
  static int shell_cat (int argc, char *argv[])
  {
    int fd;
    char buf[4096];
    int len;
  
    fd = open (argv[1], O_RDONLY);
    if (fd < 0) {
      printf ("Cannot open '%s'\n", argv[1]);
      return -1;
    }
  
    while (1)
      {
        len = read (fd, buf, sizeof(buf)-1);
        if (len <= 0)
          break;
        buf[len] = '\0';
  
        printf ("%s", buf);
      }
  
    close (fd);
    return 0;
  }
  
  static int shell_edit (int argc, char *argv[])
  {
    int fd;
    char buf[16];
    int len;
  
    fd = open (argv[1], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd < 0) {
      printf ("Cannot create '%s': %d\n", argv[1], fd);
      return -1;
    }
  
    /* Activate echo and activate again canonical mode */
    ioctl (0, SOS_IOCTL_TTY_SETPARAM, SOS_IOCTLPARAM_TTY_ECHO);
    ioctl (0, SOS_IOCTL_TTY_SETPARAM, SOS_IOCTLPARAM_TTY_CANON);
  
    while (1)
      {
        len = read (0, buf, sizeof(buf));
        if (len <= 1)
          break;
  
        bochs_printf ("Writing %d bytes\n", len);
        len = write (fd, buf, len);
        if (len <= 0) {
          printf ("Cannot write to '%s': %d\n", argv[1], len);
          break;
        }
      }
  
    /* Desactivate echo and remove canonical mode */
    ioctl (0, SOS_IOCTL_TTY_RESETPARAM, SOS_IOCTLPARAM_TTY_ECHO);
    ioctl (0, SOS_IOCTL_TTY_RESETPARAM, SOS_IOCTLPARAM_TTY_CANON);
  
    close (fd);
    return 0;
  }
  
  static int shell_hexdump (int argc, char *argv[])
  {
    int fd;
    char buf[16];
    int count = 0;
    int len;
  
    fd = open (argv[1], O_RDONLY);
    if (fd < 0) {
      printf ("Cannot open '%s': %d\n", argv[1], fd);
      return -1;
    }
  
    while (1)
      {
        int i;
  
        len = read (fd, buf, sizeof(buf));
        if (len <= 0)
          break;
  
        if (count < 0x10)
          printf ("00%x ", count);
        else if (count < 0x100)
          printf ("0%x ", count);
        else if (count < 0x1000)
          printf ("%x ", count);
  
        for (i = 0; i < len; i++)
          {
            if (buf[i] < 0x10)
              printf ("0%x ", buf[i]);
            else
              printf ("%x ", buf[i]);
          }
  
        printf ("\n");
  
        count += len;
      }
  
    close (fd);
    return 0;
  }
  
  static int shell_test (int argc, char *argv[])
  {
    int i;
    for (i = 0; i < argc; i++)
      {
        printf ("argv[%d] = %s\n", i, argv[i]);
      }
    return 0;
  }
  
  
  static int shell_devtest (int argc, char *argv[])
  {
    bochs_printf("WARNING: This test will eventually write 0 on kernel code !\n");
    bochs_printf("This WILL crash the kernel (as expected...) !\n");
    printf("WARNING: This test will eventually write 0 on kernel code !\n");
    printf("This WILL crash the kernel (as expected...) !\n");
    if (fork() == 0)
      exec("devtest");
    return 0;
  }
  
  
  static int shell_fstest (int argc, char *argv[])
  {
    if (fork() == 0)
      exec("fstest");
    return 0;
  }
  
  void command_exec (char * cmd)
  {
    char *c;
    int argc = 1, i;
    char **argv;
  
    for (c = cmd; *c != '\0'; c++)
      if (*c == ' ')
        argc++;
  
    argv = malloc (argc * sizeof(char*));
    if (argv == NULL)
      return;
  
    for (i = 0, c = cmd; i < argc; i++)
      {
        argv[i] = c;
        while (*c != ' ' && *c != '\0')
          c++;
        *c = '\0';
        c++;
      }
  
    if (! strcmp (argv[0], "uname"))
      shell_uname(argc, argv);
  
    else if (! strcmp (argv[0], "ls"))
      {
        if (argv[1])
          shell_ls (argv[1], 1, 0);
        else
          shell_ls (".", 1, 0);
      }
  
    else if (! strcmp (argv[0], "touch"))
      {
        shell_touch (argc, argv);
      }
  
    else if (! strcmp (argv[0], "mkdir"))
      {
        shell_mkdir (argc, argv);
      }
  
    else if (! strcmp (argv[0], "cat"))
      {
        shell_cat (argc, argv);
      }
  
    else if (! strcmp (argv[0], "edit"))
      {
        shell_edit (argc, argv);
      }
  
    else if (! strcmp (argv[0], "hexdump"))
      {
        shell_hexdump (argc, argv);
      }
    else if (! strcmp (argv[0], "test"))
      {
        shell_test (argc, argv);
      }
    else if (! strcmp (argv[0], "devtest"))
      {
        shell_devtest (argc, argv);
      }
    else if (! strcmp (argv[0], "fstest"))
      {
        shell_fstest (argc, argv);
      }
  
  
    else
      printf ("Command not found\n");
  
    free (argv);
  }
  
  int main()
  {
    char buffer[256];
    int i;
    char chr;
  
    ioctl (0, SOS_IOCTL_TTY_RESETPARAM, SOS_IOCTLPARAM_TTY_CANON);
  
    while (1)
      {
        memset (buffer, 0, sizeof(buffer));
        i = 0;
        printf ("$ ");
  
        while (1)
          {
            read (0, & chr, 1);
            if (chr == '\n')
              {
                buffer[i] = '\0';
                printf ("\n");
                if (i != 0)
                  command_exec (buffer);
                break;
              }
            else if (chr == '\b')
              {
                if (i > 0)
                  {
                    i--;
                    printf ("\b");
                  }
              }
  
            else if (i < 256)
              {
                buffer[i++] = chr;
                printf ("%c", chr);
              }
            else
              printf ("%c", chr);
          }
      }
  
    return 0;
  }
  
 

/tmp/sos-code-article8/userland/string.c (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/string.c (2005-12-28 11:44:58.000000000 +0100 )
Line 140 
Line 140 
      
   return c1 - c2;   return c1 - c2;
 } }
  
  
  
 

/tmp/sos-code-article8/userland/string.h (2005-07-01 16:39:50.000000000 +0200 )
../sos-code-article9/userland/string.h (2005-12-28 11:44:58.000000000 +0100 )
Line 58 
Line 58 
 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 );
  
  
 #endif /* _SOS_LIBC_STRING_H_ */ #endif /* _SOS_LIBC_STRING_H_ */
  
 

/tmp/sos-code-article8/VERSION (2005-07-01 16:39:48.000000000 +0200 )
../sos-code-article9/VERSION (2005-12-28 11:44:58.000000000 +0100 )
Line 1 
Line 1 
 SOS -- Simple OS SOS -- Simple OS
 Copyright (C) 2003,2004,2005 The SOS Team (David Decotigny & Thomas Petazzoni) Copyright (C) 2003,2004,2005 The SOS Team (David Decotigny & Thomas Petazzoni)
  
 Version "Article 8" -- Basic VFS support (read/write/mount/symlink/unlink/mmap) Version "Article 9 (1st part)" -- User interactions with the devices drivers
                                    through the VFS: character devices, ttys,
                                    console and serial drivers, /dev/mem and
                                    /dev/zero devices
    This program is free software; you can redistribute it and/or    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License    modify it under the terms of the GNU General Public License


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

File list:
    
../sos-code-article9/drivers/bochs.c
    ../sos-code-article9/drivers/bochs.h
    ../sos-code-article9/drivers/console.c
    ../sos-code-article9/drivers/console.h
    ../sos-code-article9/drivers/devices.h
    ../sos-code-article9/drivers/fs_virtfs.c
    ../sos-code-article9/drivers/kbd.c
    ../sos-code-article9/drivers/kbd.h
    ../sos-code-article9/drivers/kbdmapfr.c
    ../sos-code-article9/drivers/mem.c
    ../sos-code-article9/drivers/mem.h
    ../sos-code-article9/drivers/serial.c
    ../sos-code-article9/drivers/serial.h
    ../sos-code-article9/drivers/tty.c
    ../sos-code-article9/drivers/tty.h
    ../sos-code-article9/drivers/x86_videomem.c
    ../sos-code-article9/drivers/x86_videomem.h
    ../sos-code-article9/drivers/zero.c
    ../sos-code-article9/drivers/zero.h
    ../sos-code-article9/extra/bootsect.S
    ../sos-code-article9/extra/dot.mkvars
    ../sos-code-article9/extra/Makefile
    ../sos-code-article9/extra/patch-qemu-port-e9.diff
    ../sos-code-article9/extra/patch-qemu-pty.diff
    ../sos-code-article9/extra/qemu-port-e9.diff
    ../sos-code-article9/extra/README
    ../sos-code-article9/extra/termslave.c
    ../sos-code-article9/hwcore/gdt.c
    ../sos-code-article9/hwcore/ioports.h
    ../sos-code-article9/INSTALL
    ../sos-code-article9/Makefile
    ../sos-code-article9/README
    ../sos-code-article9/sos/chardev.c
    ../sos-code-article9/sos/chardev.h
    ../sos-code-article9/sos/errno.h
    ../sos-code-article9/sos/fs.c
    ../sos-code-article9/sos/fs.h
    ../sos-code-article9/sos/kmalloc.c
    ../sos-code-article9/sos/main.c
    ../sos-code-article9/sos/physmem.c
    ../sos-code-article9/sos/physmem.h
    ../sos-code-article9/sos/process.c
    ../sos-code-article9/sos/syscall.c
    ../sos-code-article9/sos/syscall.h
    ../sos-code-article9/sos/thread.c
    ../sos-code-article9/sos/types.h
    ../sos-code-article9/sos/uaccess.c
    ../sos-code-article9/sos/umem_vmm.c
    ../sos-code-article9/sos/umem_vmm.h
    ../sos-code-article9/support/sos.lds
    ../sos-code-article9/userland/banner.c
    ../sos-code-article9/userland/crt.c
    ../sos-code-article9/userland/crt.h
    ../sos-code-article9/userland/devtest.c
    ../sos-code-article9/userland/fstest.c
    ../sos-code-article9/userland/fstest_utils.c
    ../sos-code-article9/userland/init.c
    ../sos-code-article9/userland/libc.c
    ../sos-code-article9/userland/libc.h
    ../sos-code-article9/userland/Makefile
    ../sos-code-article9/userland/myprog10.c
    ../sos-code-article9/userland/myprog11.c
    ../sos-code-article9/userland/myprog12.c
    ../sos-code-article9/userland/myprog14.c
    ../sos-code-article9/userland/myprog8.c
    ../sos-code-article9/userland/myprog9.c
    ../sos-code-article9/userland/shell.c
    ../sos-code-article9/userland/string.c
    ../sos-code-article9/userland/string.h
    ../sos-code-article9/VERSION