/tmp/sos-code-article2/Makefile (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/Makefile (2004-08-31 14:49:20.000000000 +0200 )
Line 1 
Line 1 
 CC=gcc CC=gcc
 CFLAGS  = -Wall -nostdlib -nostdinc -ffreestanding CFLAGS  = -Wall -nostdlib -nostdinc -ffreestanding -DKERNEL_SOS
 OBJECTS = bootstrap/multiboot.o \ OBJECTS = bootstrap/multiboot.o                                 \
           hwcore/idt.o hwcore/gdt.o \           hwcore/idt.o hwcore/gdt.o                             \
           hwcore/exception.o hwcore/exception_wrappers.o \           hwcore/exception.o hwcore/exception_wrappers.o        \
           hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o \           hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o        \
           hwcore/i8254.o drivers/x86_videomem.o drivers/bochs.o \           hwcore/i8254.o drivers/x86_videomem.o drivers/bochs.o        \
           sos/klibc.o sos/main.o           sos/physmem.o sos/klibc.o sos/main.o
 KERNEL_OBJ   = sos.elf KERNEL_OBJ   = sos.elf
 MULTIBOOT_IMAGE = fd.img MULTIBOOT_IMAGE = fd.img
Line 18 
Line 18 
 $(MULTIBOOT_IMAGE): $(KERNEL_OBJ) $(MULTIBOOT_IMAGE): $(KERNEL_OBJ)
         ./support/build_image.sh $@ $<         ./support/build_image.sh $@ $<
  
 $(KERNEL_OBJ): $(OBJECTS) $(KERNEL_OBJ): $(OBJECTS) ./support/sos.lds
         $(LD) $(LDFLAGS) -T ./support/sos.lds -o $@ $^         $(LD) $(LDFLAGS) -T ./support/sos.lds -o $@ $(OBJECTS)
  
 -include .mkvars -include .mkvars
  
 

/tmp/sos-code-article2/README (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/README (2004-08-31 14:49:20.000000000 +0200 )
Line 2 
Line 2 
                     SOS: A Simple Operating System                     SOS: A Simple Operating System
  
  
 This   is   SOS,   a   Simple   Operating   System   for   i486-family This   is   SOS,   a   Simple   Operating   System   for   i386-family
 basic Operating System on real  common hardware (PC).  The code should basic Operating System on real  common hardware (PC).  The code should
 be easily readable and understandable thanks to frequent comments, and be easily readable and understandable thanks to frequent comments, and
Line 28 
Line 28 
  
 The initial technical features and lack-of-features of the OS are: The initial technical features and lack-of-features of the OS are:
  - monolithic kernel, fully interruptible, non-preemptible (big kernel  - monolithic kernel, fully interruptible, non-preemptible (big kernel
    lock)    lock), target machines = i386 PC or better
    i586-gnu) is available. Can be tested on real i486/pentium    i586-gnu) is available. Can be tested on real i486/pentium
    hardware, or on any host that can run an i486/pentium PC emulator    hardware, or on any host that can run an i486/pentium PC emulator
  
 

/tmp/sos-code-article2/VERSION (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/VERSION (2004-08-31 14:49:20.000000000 +0200 )
Line 1 
Line 1 
 SOS -- Simple OS SOS -- Simple OS
 Copyright (C) 2003,2004 The SOS Team (David Decotigny & Thomas Petazzoni) Copyright (C) 2003,2004 The SOS Team (David Decotigny & Thomas Petazzoni)
  
 Version "Article 2" -- Basic interrupt & processor exception management Version "Article 3" -- Physical memory management & physical page allocator
    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
  
 

/tmp/sos-code-article2/bootstrap/multiboot.S (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/bootstrap/multiboot.S (2004-08-31 14:49:20.000000000 +0200 )
Line 54 
Line 54 
  
         /* Set EFLAGS to 0 */         /* Set EFLAGS to 0 */
         pushl $0         pushl $0
          /* pop stack into the EFLAGS register */
         popf         popf
  
         /* Push the magic and the address on the stack, so that they         /* Push the magic and the address on the stack, so that they
  
 

/tmp/sos-code-article2/drivers/x86_videomem.c (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/drivers/x86_videomem.c (2004-08-31 14:49:20.000000000 +0200 )
Line 40 
Line 40 
 } __attribute__ ((packed)) x86_video_mem[LINES*COLUMNS]; } __attribute__ ((packed)) x86_video_mem[LINES*COLUMNS];
  
  
  
 /** The base pointer for the video memory */ /** The base pointer for the video memory */
 static volatile x86_video_mem *video = (volatile x86_video_mem*)VIDEO; static volatile x86_video_mem *video = (volatile x86_video_mem*)VIDEO;
  
  
 { {
   /*   /*
Line 101 
Line 101 
                                    unsigned char attribute,                                    unsigned char attribute,
                                    unsigned char c)                                    unsigned char c)
 { {
     unsigned video_offs = row*COLUMNS + col;   unsigned video_offs = row*COLUMNS + col;
   if (video_offs >= LINES*COLUMNS)   if (video_offs >= LINES*COLUMNS)
     return -SOS_EINVAL;     return -SOS_EINVAL;
  
 

/tmp/sos-code-article2/extra/bootsect.S (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/extra/bootsect.S (2004-08-31 14:49:20.000000000 +0200 )
Line 1 
Line 1 
  
 /* /*
  * @(#) $Id: bootsect.S,v 1.5 2004/03/25 09:53:58 d2 Exp $  * @(#) $Id: bootsect.S,v 1.6 2004/06/18 07:43:51 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 91 
Line 91 
 #define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */ #define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */
  
 /* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente /* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente
                dans kos.lds ! */                dans sos.lds ! */
                                           ou est charge le noyau */                                           ou est charge le noyau */
  
  
 

/tmp/sos-code-article2/hwcore/exception.c (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/hwcore/exception.c (2004-08-31 14:49:20.000000000 +0200 )
Line 30 
Line 30 
  
 sos_ret_t sos_exceptions_setup(void) sos_ret_t sos_exceptions_setup(void)
 { {
   return SOS_OK;   /* We inidicate that the double fault exception handler is defined,
       and give its address. this handler is a do-nothing handler (see
       exception_wrappers.S), and it can NOT be overriden by the
       functions below */
    return sos_idt_set_handler(SOS_EXCEPT_BASE + SOS_EXCEPT_DOUBLE_FAULT,
                              (sos_vaddr_t) sos_exception_wrapper_array[SOS_EXCEPT_DOUBLE_FAULT],
                              0 /* CPL0 routine */);
  
  
  
 

/tmp/sos-code-article2/sos/errno.h (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/sos/errno.h (2004-08-31 14:49:21.000000000 +0200 )
Line 29 
Line 29 
 #define SOS_OK     0   /* No error */ #define SOS_OK     0   /* No error */
 #define SOS_EINVAL 1   /* Invalid argument */ #define SOS_EINVAL 1   /* Invalid argument */
 #define SOS_ENOSUP 2   /* Operation not supported */ #define SOS_ENOSUP 2   /* Operation not supported */
  #define SOS_ENOMEM 3   /* No available memory */
 #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-article2/sos/klibc.c (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/sos/klibc.c (2004-08-31 14:49:21.000000000 +0200 )
Line 73 
Line 73 
   const char *sc;   const char *sc;
      
   for (sc = s; count-- && *sc != '\0'; ++sc)   for (sc = s; count-- && *sc != '\0'; ++sc)
     /* nothing */;     /* nothing */continue;
  
 } }
  
Line 81 
Line 82 
 char *strzcpy(register char *dst, register const char *src, register int len) char *strzcpy(register char *dst, register const char *src, register int len)
 { {
   int i;   int i;
  
    if (len <= 0)
      return dst;
      
   for (i = 0; i < len; i++)   for (i = 0; i < len; i++)
     {     {
Line 93 
Line 97 
   return dst;   return dst;
 } }
  
  
 char *strzcat (char *dest, const char *src, sos_size_t n) char *strzcat (char *dest, const char *src, sos_size_t n)
 { {
   char *res = dest;   char *res = dest;
  
 

/tmp/sos-code-article2/sos/list.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article3/sos/list.h (2004-08-31 14:49:21.000000000 +0200 )
(New file) 
Line 1 
  /* Copyright (C) 2001  David Decotigny
   
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
     as published by the Free Software Foundation; either version 2
     of the License, or (at your option) any later version.
      
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
      
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
     USA.
  */
  #ifndef _SOS_LIST_H_
  #define _SOS_LIST_H_
  
  /**
   * @file list.h
   *
   * Circular doubly-linked lists implementation entirely based on C
   * macros
   */
  
  
  /* *_named are used when next and prev links are not exactly next
     and prev. For instance when we have next_in_team, prev_in_team,
     prev_global and next_global */
  
  #define list_init_named(list,prev,next) \
    ((list) = NULL)
  
  #define list_singleton_named(list,item,prev,next) ({ \
    (item)->next = (item)->prev = (item); \
    (list) = (item); \
  })
  
  #define list_is_empty_named(list,prev,next) \
    ((list) == NULL)
  
  #define list_get_head_named(list,prev,next) \
    (list)
  
  #define list_get_tail_named(list,prev,next) \
    ((list)?((list)->prev):NULL)
  
  /* Internal macro : insert before the head == insert at tail */
  #define __list_insert_atleft_named(before_this,item,prev,next) ({ \
     (before_this)->prev->next = (item); \
     (item)->prev = (before_this)->prev; \
     (before_this)->prev = (item); \
     (item)->next = (before_this); \
  })
  
  /* @note Before_this and item are expected to be valid ! */
  #define list_insert_before_named(list,before_this,item,prev,next) ({ \
     __list_insert_atleft_named(before_this,item,prev,next); \
     if ((list) == (before_this)) (list) = (item); \
  })    
  
  /** @note After_this and item are expected to be valid ! */
  #define list_insert_after_named(list,after_this,item,prev,next) ({ \
     (after_this)->next->prev = (item); \
     (item)->next = (after_this)->next; \
     (after_this)->next = (item); \
     (item)->prev = (after_this); \
  })
  
  #define list_add_head_named(list,item,prev,next) ({ \
    if (list) \
      list_insert_before_named(list,list,item,prev,next); \
    else \
      list_singleton_named(list,item,prev,next); \
    (list) = (item); \
  })
  
  #define list_add_tail_named(list,item,prev,next) ({ \
    if (list) \
      __list_insert_atleft_named(list,item,prev,next); \
    else \
      list_singleton_named(list,item,prev,next); \
  })
  
  /** @note NO check whether item really is in list ! */
  #define list_delete_named(list,item,prev,next) ({ \
    if ( ((item)->next == (item)) && ((item)->prev == (item)) ) \
      (item)->next = (item)->prev = (list) = NULL; \
    else { \
      (item)->prev->next = (item)->next; \
      (item)->next->prev = (item)->prev; \
      if ((item) == (list)) (list) = (item)->next; \
      (item)->prev = (item)->next = NULL; \
    } \
  })
  
  #define list_pop_head_named(list,prev,next) ({ \
    typeof(list) __ret_elt = (list); \
    list_delete_named(list,__ret_elt,prev,next); \
    __ret_elt; })
  
  /** Loop statement that iterates through all of its elements, from
      head to tail */
  #define list_foreach_forward_named(list,iterator,nb_elements,prev,next) \
          for (nb_elements=0, (iterator) = (list) ; \
               (iterator) && (!nb_elements || ((iterator) != (list))) ; \
               nb_elements++, (iterator) = (iterator)->next )
  
  /** Loop statement that iterates through all of its elements, from
      tail back to head */
  #define list_foreach_backward_named(list,iterator,nb_elements,prev,next) \
          for (nb_elements=0, (iterator) = list_get_tail_named(list,prev,next) ; \
               (iterator) && (!nb_elements || \
                 ((iterator) != list_get_tail_named(list,prev,next))) ; \
               nb_elements++, (iterator) = (iterator)->prev )
  
  #define list_foreach_named list_foreach_forward_named
  
  /** True when we exitted early from the foreach loop (ie break) */
  #define list_foreach_early_break(list,iterator,nb_elements) \
    ((list) && ( \
      ((list) != (iterator)) || \
      ( ((list) == (iterator)) && (nb_elements == 0)) ))
  
  /** Loop statement that also removes the item at each iteration */
  #define list_collapse_named(list,iterator,prev,next) \
          for ( ; ({ ((iterator) = (list)) ; \
                     if (list) list_delete_named(list,iterator,prev,next) ; \
                     (iterator); }) ; )
  
  
  /*
   * the same macros : assume that the prev and next fields are really
   * named "prev" and "next"
   */
  
  #define list_init(list) \
    list_init_named(list,prev,next)
  
  #define list_singleton(list,item) \
    list_singleton_named(list,item,prev,next)
  
  #define list_is_empty(list) \
    list_is_empty_named(list,prev,next)
  
  #define list_get_head(list) \
    list_get_head_named(list,prev,next) \
  
  #define list_get_tail(list) \
    list_get_tail_named(list,prev,next) \
  
  /* @note Before_this and item are expected to be valid ! */
  #define list_insert_after(list,after_this,item) \
    list_insert_after_named(list,after_this,item,prev,next)
  
  /* @note After_this and item are expected to be valid ! */
  #define list_insert_before(list,before_this,item) \
    list_insert_before_named(list,before_this,item,prev,next)
  
  #define list_add_head(list,item) \
    list_add_head_named(list,item,prev,next)
  
  #define list_add_tail(list,item) \
    list_add_tail_named(list,item,prev,next)
  
  /* @note NO check whether item really is in list ! */
  #define list_delete(list,item) \
    list_delete_named(list,item,prev,next)
  
  #define list_pop_head(list) \
    list_pop_head_named(list,prev,next)
  
  #define list_foreach_forward(list,iterator,nb_elements) \
    list_foreach_forward_named(list,iterator,nb_elements,prev,next)
  
  #define list_foreach_backward(list,iterator,nb_elements) \
    list_foreach_backward_named(list,iterator,nb_elements,prev,next)
  
  #define list_foreach list_foreach_forward
  
  #define list_collapse(list,iterator) \
    list_collapse_named(list,iterator,prev,next)
  
  #endif /* _SOS_LIST_H_ */
  
 

/tmp/sos-code-article2/sos/macros.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article3/sos/macros.h (2004-08-31 14:49:21.000000000 +0200 )
(New file) 
Line 1 
  /* Copyright (C) 2004  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_MACROS_H_
  #define _SOS_MACROS_H_
  
  /** Align on a boundary (MUST be a power of 2), so that return value <= val */
  #define SOS_ALIGN_INF(val,boundary) \
    (((unsigned)(val)) & (~((boundary)-1)))
   
  /** Align on a boundary (MUST be a power of 2), so that return value >= val */
  #define SOS_ALIGN_SUP(val,boundary) \
    ({ unsigned int __bnd=(boundary); \
       (((((unsigned)(val))-1) & (~(__bnd - 1))) + __bnd); })
  
  /**
   * @return TRUE if val is a power of 2.
   * @note val is evaluated multiple times
   */
  #define SOS_IS_POWER_OF_2(val) \
    ((((val) - 1) & (val)) == 0)
  
  #endif /* _SOS_MACROS_H_ */
  
 

/tmp/sos-code-article2/sos/main.c (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/sos/main.c (2004-08-31 14:49:21.000000000 +0200 )
Line 24 
Line 24 
 #include <hwcore/irq.h> #include <hwcore/irq.h>
 #include <hwcore/exception.h> #include <hwcore/exception.h>
 #include <hwcore/i8254.h> #include <hwcore/i8254.h>
  #include <sos/list.h>
  #include <sos/physmem.h>
 #include <sos/klibc.h> #include <sos/klibc.h>
 #include <sos/assert.h> #include <sos/assert.h>
 #include <drivers/x86_videomem.h> #include <drivers/x86_videomem.h>
Line 63 
Line 65 
  
 } }
  
 /* Division by zero exception handler */ #define MY_PPAGE_NUM_INT 511
 static void divide_ex(int exid) struct my_ppage
   static sos_ui32_t div_count = 0;   sos_ui32_t before[MY_PPAGE_NUM_INT];
   display_bits(0, 0,   struct my_ppage *prev, *next;
                SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE,   sos_ui32_t after[MY_PPAGE_NUM_INT];
                div_count); }; /* sizeof() Must be <= 4kB */
   div_count++; 
  static void test_physmem()
  {
    /* We place the pages we did allocate here */
    struct my_ppage *ppage_list, *my_ppage;
    sos_count_t num_alloc_ppages = 0, num_free_ppages = 0;
  
    ppage_list = NULL;
    while ((my_ppage = (struct my_ppage*)sos_physmem_ref_physpage_new(FALSE))
           != NULL)
      {
        int i;
        num_alloc_ppages++;
        
        /* Print the allocation status */
        sos_x86_videomem_printf(2, 0,
                                SOS_X86_VIDEO_FG_YELLOW
                                | SOS_X86_VIDEO_BG_BLUE,
                                "Could allocate %d pages      ",
                                num_alloc_ppages);
  
        /* We fill this page with its address */
        for (i = 0 ; i < MY_PPAGE_NUM_INT ; i++)
          my_ppage->before[i] = my_ppage->after[i] = (sos_ui32_t)my_ppage;
  
        /* We add this page at the tail of our list of ppages */
        list_add_tail(ppage_list, my_ppage);
      }
  
    /* Now we release these pages in FIFO order */
    while ((my_ppage = list_pop_head(ppage_list)) != NULL)
      {
        /* We make sure this page was not overwritten by any unexpected
           value */
        int i;
        for (i = 0 ; i < MY_PPAGE_NUM_INT ; i++)
          {
            /* We don't get what we expect ! */
            if ((my_ppage->before[i] !=  (sos_ui32_t)my_ppage)
                || (my_ppage->after[i] !=  (sos_ui32_t)my_ppage))
              {
                /* STOP ! */
                sos_x86_videomem_putstring(20, 0,
                                           SOS_X86_VIDEO_FG_LTRED
                                             | SOS_X86_VIDEO_BG_BLUE,
                                           "Page overwritten");
                return;
              }
          }
  
        /* Release the descriptor */
        if (sos_physmem_unref_physpage((sos_paddr_t)my_ppage) < 0)
          {
            /* STOP ! */
            sos_x86_videomem_putstring(20, 0,
                                       SOS_X86_VIDEO_FG_LTRED
                                         | SOS_X86_VIDEO_BG_BLUE,
                                       "Cannot release page");
            return;
          }
  
        /* Print the deallocation status */
        num_free_ppages ++;
        sos_x86_videomem_printf(2, 0,
                                SOS_X86_VIDEO_FG_YELLOW
                                | SOS_X86_VIDEO_BG_BLUE,
                                "Could free %d pages      ",
                                num_free_ppages);
      }
  
    /* Print the overall stats */
    sos_x86_videomem_printf(2, 0,
                            SOS_X86_VIDEO_FG_LTGREEN
                            | SOS_X86_VIDEO_BG_BLUE,
                            "Could allocate %d bytes, could free %d bytes     ",
                            num_alloc_ppages << SOS_PAGE_SHIFT,
                            num_free_ppages << SOS_PAGE_SHIFT);
  
    SOS_ASSERT_FATAL(num_alloc_ppages == num_free_ppages);
  
  
 /* The C entry point of our operating system */ /* The C entry point of our operating system */
 void sos_main(unsigned long magic, unsigned long addr) void sos_main(unsigned long magic, unsigned long addr)
 { {
   unsigned i;   unsigned i;
    sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr;
  
   /* Grub sends us a structure, called multiboot_info_t with a lot of   /* Grub sends us a structure, called multiboot_info_t with a lot of
      precious informations about the system, see the multiboot      precious informations about the system, see the multiboot
Line 118 
Line 200 
   /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */   /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */
   sos_i8254_set_frequency(100);   sos_i8254_set_frequency(100);
  
  
    /* We need a multiboot-compliant boot loader to get the size of the RAM */
    if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
      {
        sos_x86_videomem_putstring(20, 0,
                                   SOS_X86_VIDEO_FG_LTRED
                                     | SOS_X86_VIDEO_BG_BLUE
                                     | SOS_X86_VIDEO_FG_BLINKING,
                                   "I'm not loaded with Grub !");
        /* STOP ! */
        for (;;)
          continue;
      }
  
   /* Binding some HW interrupts and exceptions to software routines */   /* Binding some HW interrupts and exceptions to software routines */
   sos_irq_set_routine(SOS_IRQ_TIMER,   sos_irq_set_routine(SOS_IRQ_TIMER,
                             clk_it);                             clk_it);
   sos_exception_set_routine(SOS_EXCEPT_DIVIDE_ERROR, 
                             divide_ex); 
      interrupt call our clk_it handler */      interrupt call our clk_it handler */
   asm volatile ("sti\n");   asm volatile ("sti\n");
    /* Multiboot says: "The value returned for upper memory is maximally
   /* Raise a rafale of 'division by 0' exceptions. All this code is      the address of the first upper memory hole minus 1 megabyte.". It
      not really needed (equivalent to a bare "i=1/0;"), except when      also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */
      compiling with -O3: "i=1/0;" is considered dead code with gcc   sos_physmem_setup((mbi->mem_upper<<10) + (1<<20),
      -O3. */                     & sos_kernel_core_base_paddr,
   i = 10;                     & sos_kernel_core_top_paddr);
   while (1)   test_physmem();
     { 
       /* Stupid function call to fool gcc optimizations */   /* An operatig system never ends */
       sos_bochs_printf("i = 1 / %d...\n", i);   for (;;)
       i = 1 / i;     continue;
     } 
  
   /* Will never print this since the "divide by zero" exception always 
      returns to the faulting instruction (see Intel x86 doc vol 3, 
      section 5.12), thus re-evaluating the "divide-by-zero" exprssion 
      and raising the "divide by zero" exception again and again... */ 
   sos_x86_videomem_putstring(2, 0, 
                              SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, 
                              "Invisible"); 
   return;   return;
 } }
  
 

/tmp/sos-code-article2/sos/physmem.c (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article3/sos/physmem.c (2004-08-31 14:49:21.000000000 +0200 )
(New file) 
Line 1 
  /* Copyright (C) 2004  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/list.h>
  #include <sos/macros.h>
  #include <sos/assert.h>
  #include <sos/klibc.h>
  
  #include "physmem.h"
  
  /** A descriptor for a physical page in SOS */
  struct physical_page_descr
  {
    /** The physical base address for the page */
    sos_paddr_t paddr;
  
    /** The reference count for this physical page. > 0 means that the
       page is in the used list. */
    sos_count_t ref_cnt;
  
    /** The other pages on the list (used, free) */
    struct physical_page_descr *prev, *next;
  };
  
  /** These are some markers present in the executable file (see sos.lds) */
  extern char __b_kernel, __e_kernel;
  
  /** The array of ppage descriptors will be located at this address */
  #define PAGE_DESCR_ARRAY_ADDR \
    SOS_PAGE_ALIGN_SUP((sos_paddr_t) (& __e_kernel))
  static struct physical_page_descr * physical_page_descr_array;
  
  /** The list of physical pages currently available */
  static struct physical_page_descr *free_ppage;
  
  /** The list of physical pages currently in use */
  static struct physical_page_descr *used_ppage;
  
  /** We will store here the interval of valid physical addresses */
  static sos_paddr_t physmem_base, physmem_top;
  
  /** We store the number of pages used/free */
  static sos_count_t physmem_total_pages, physmem_used_pages;
  
  sos_ret_t sos_physmem_setup(sos_size_t ram_size,
                              /* out */sos_paddr_t *kernel_core_base,
                              /* out */sos_paddr_t *kernel_core_top)
  {
    /* The iterator over the page descriptors */
    struct physical_page_descr *ppage_descr;
  
    /* The iterator over the physical addresses */
    sos_paddr_t ppage_addr;
  
    /* Make sure ram size is aligned on a page boundary */
    ram_size = SOS_PAGE_ALIGN_INF(ram_size);/* Yes, we may lose at most a page */
  
    /* Reset the used/free page lists before building them */
    free_ppage = used_ppage = NULL;
    physmem_total_pages = physmem_used_pages = 0;
  
    /* Make sure that there is enough memory to store the array of page
       descriptors */
    *kernel_core_base = SOS_PAGE_ALIGN_INF((sos_paddr_t)(& __b_kernel));
    *kernel_core_top
      = PAGE_DESCR_ARRAY_ADDR
        + SOS_PAGE_ALIGN_SUP( (ram_size >> SOS_PAGE_SHIFT)
                              * sizeof(struct physical_page_descr));
    if (*kernel_core_top > ram_size)
      return -SOS_ENOMEM;
  
    /* Page 0-4kB is not available in order to return address 0 as a
       means to signal "no page available" */
    physmem_base = SOS_PAGE_SIZE;
    physmem_top  = ram_size;
  
    /* Setup the page descriptor arrray */
    physical_page_descr_array
      = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR;
  
    /* Scan the list of physical pages */
    for (ppage_addr = 0,
           ppage_descr = physical_page_descr_array ;
         ppage_addr < physmem_top ;
         ppage_addr += SOS_PAGE_SIZE,
           ppage_descr ++)
      {
        enum { PPAGE_MARK_RESERVED, PPAGE_MARK_FREE,
               PPAGE_MARK_KERNEL, PPAGE_MARK_HWMAP } todo;
  
        memset(ppage_descr, 0x0, sizeof(struct physical_page_descr));
  
        /* Init the page descriptor for this page */
        ppage_descr->paddr = ppage_addr;
  
        /* Reserved : 0 ... base */
        if (ppage_addr < physmem_base)
          todo = PPAGE_MARK_RESERVED;
  
        /* Free : base ... BIOS */
        else if ((ppage_addr >= physmem_base)
                 && (ppage_addr < BIOS_N_VIDEO_START))
          todo = PPAGE_MARK_FREE;
  
        /* Used : BIOS */
        else if ((ppage_addr >= BIOS_N_VIDEO_START)
                 && (ppage_addr < BIOS_N_VIDEO_END))
          todo = PPAGE_MARK_HWMAP;
  
        /* Free : BIOS ... kernel */
        else if ((ppage_addr >= BIOS_N_VIDEO_END)
                 && (ppage_addr < (sos_paddr_t) (& __b_kernel)))
          todo = PPAGE_MARK_FREE;
  
        /* Used : Kernel code/data/bss + physcal page descr array */
        else if ((ppage_addr >= *kernel_core_base)
                  && (ppage_addr < *kernel_core_top))
          todo = PPAGE_MARK_KERNEL;
  
        /* Free : first page of descr ... end of RAM */
        else
          todo = PPAGE_MARK_FREE;
  
        /* Actually does the insertion in the used/free page lists */
        physmem_total_pages ++;
        switch (todo)
          {
          case PPAGE_MARK_FREE:
            ppage_descr->ref_cnt = 0;
            list_add_head(free_ppage, ppage_descr);
            break;
  
          case PPAGE_MARK_KERNEL:
          case PPAGE_MARK_HWMAP:
            ppage_descr->ref_cnt = 1;
            list_add_head(used_ppage, ppage_descr);
            physmem_used_pages ++;
            break;
  
          default:
            /* Reserved page: nop */
            break;
          }
      }
  
    return SOS_OK;
  }
  
  
  sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block)
  {
    struct physical_page_descr *ppage_descr;
  
    if (! free_ppage)
      return (sos_paddr_t)NULL;
  
    /* Retrieve a page in the free list */
    ppage_descr = list_pop_head(free_ppage);
  
    /* The page is assumed not to be already used */
    SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0);
  
    /* Mark the page as used (this of course sets the ref count to 1) */
    ppage_descr->ref_cnt ++;
  
    /* Put the page in the used list */
    list_add_tail(used_ppage, ppage_descr);
    physmem_used_pages ++;
  
    return ppage_descr->paddr;
  }
  
  
  /**
   * Helper function to get the physical page descriptor for the given
   * physical page address.
   *
   * @return NULL when out-of-bounds or non-page-aligned
   */
  inline static struct physical_page_descr *
  get_page_descr_at_paddr(sos_paddr_t ppage_paddr)
  {
    /* Don't handle non-page-aligned addresses */
    if (ppage_paddr & SOS_PAGE_MASK)
      return NULL;
    
    /* Don't support out-of-bounds requests */
    if ((ppage_paddr < physmem_base) || (ppage_paddr >= physmem_top))
      return NULL;
  
    return physical_page_descr_array + (ppage_paddr >> SOS_PAGE_SHIFT);
  }
  
  
  sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr)
  {
    struct physical_page_descr *ppage_descr
      = get_page_descr_at_paddr(ppage_paddr);
  
    if (! ppage_descr)
      return -SOS_EINVAL;
  
    /* Increment the reference count for the page */
    ppage_descr->ref_cnt ++;
  
    /* If the page is newly referenced (ie we are the only owners of the
       page => ref cnt == 1), transfer it in the used pages list */
    if (ppage_descr->ref_cnt == 1)
      {
        list_delete(free_ppage, ppage_descr);
        list_add_tail(used_ppage, ppage_descr);
        physmem_used_pages ++;
  
        /* The page is newly referenced */
        return FALSE;
      }
  
    /* The page was already referenced by someone */
    return TRUE;
  }
  
  
  sos_ret_t
  sos_physmem_unref_physpage(sos_paddr_t ppage_paddr)
  {
    /* By default the return value indicates that the page is still
       used */
    sos_ret_t retval = FALSE;
  
    struct physical_page_descr *ppage_descr
      = get_page_descr_at_paddr(ppage_paddr);
  
    if (! ppage_descr)
      return -SOS_EINVAL;
  
    /* Don't do anything if the page is not in the used list */
    if (ppage_descr->ref_cnt <= 0)
      return -SOS_EINVAL;
  
    /* Unreference the page, and, when no mapping is active anymore, put
       the page in the free list */
    ppage_descr->ref_cnt--;
    if (ppage_descr->ref_cnt <= 0)
      {
        /* Transfer the page, considered USED, to the free list */
        list_delete(used_ppage, ppage_descr);
        physmem_used_pages --;
        list_add_head(free_ppage, ppage_descr);
  
        /* Indicate that the page is now unreferenced */
        retval = TRUE;
      }
  
    return retval;
  }
  
 

/tmp/sos-code-article2/sos/physmem.h (1970-01-01 01:00:00.000000000 +0100 )
../sos-code-article3/sos/physmem.h (2004-08-31 14:49:21.000000000 +0200 )
(New file) 
Line 1 
  /* Copyright (C) 2004  David Decotigny
  
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
     as published by the Free Software Foundation; either version 2
     of the License, or (at your option) any later version.
     
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
     USA. 
  */
  #ifndef _SOS_PHYSMEM_H_
  #define _SOS_PHYSMEM_H_
  
  /**
   * @file physmem.h
   *
   * Physical pages of memory
   */
  
  #include <sos/errno.h>
  #include <sos/types.h>
  #include <sos/macros.h>
  
  /** The size of a physical page (arch-dependent) */
  #define SOS_PAGE_SIZE  (4*1024)
  
  /** The corresponding shift */
  #define SOS_PAGE_SHIFT 12 /* 4 kB = 2^12 B */
  
  /** The corresponding mask */
  #define SOS_PAGE_MASK  ((1<<12) - 1)
  
  #define SOS_PAGE_ALIGN_INF(val) \
    SOS_ALIGN_INF((val), SOS_PAGE_SIZE)
  #define SOS_PAGE_ALIGN_SUP(val) \
    SOS_ALIGN_SUP((val), SOS_PAGE_SIZE)
  
  
  /**
   * This is the reserved physical interval for the x86 video memory and
   * BIOS area. In physmem.c, we have to mark this area as "used" in
   * order to prevent from allocating it. And in paging.c, we'd better
   * map it in virtual space if we really want to be able to print to
   * the screen (for debugging purpose, at least): for this, the
   * simplest is to identity-map this area in virtual space (note
   * however that this mapping could also be non-identical).
   */
  #define BIOS_N_VIDEO_START 0xa0000
  #define BIOS_N_VIDEO_END   0x100000
  
  
  /**
   * Initialize the physical memory subsystem, for the physical area [0,
   * ram_size). This routine takes into account the BIOS and video
   * areas, to prevent them from future allocations.
   *
   * @param ram_size The size of the RAM that will be managed by this subsystem
   *
   * @param kernel_core_base The lowest address for which the kernel
   * assumes identity mapping (ie virtual address == physical address)
   * will be stored here
   *
   * @param kernel_core_top The top address for which the kernel
   * assumes identity mapping (ie virtual address == physical address)
   * will be stored here
   */
  sos_ret_t sos_physmem_setup(sos_size_t ram_size,
                              /* out */sos_paddr_t *kernel_core_base,
                              /* out */sos_paddr_t *kernel_core_top);
  
  /**
   * Retrieve the total number of pages, and the number of free pages
   */
  sos_ret_t sos_physmem_get_state(/* out */sos_count_t *total_ppages,
                                  /* out */sos_count_t *used_ppages);
  
  
  /**
   * Get a free page.
   *
   * @return The (physical) address of the (physical) page allocated, or
   * NULL when none currently available.
   *
   * @param can_block TRUE if the function is allowed to block
   * @note The page returned has a reference count equal to 1.
   */
  sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block);
  
  
  /**
   * Increment the reference count of a given physical page. Useful for
   * VM code which tries to map a precise physical address.
   *
   * @return TRUE when the page was previously in use, FALSE when the
   * page was previously in the free list, <0 when the page address is
   * invalid.
   */
  sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr);
  
  
  /**
   * Decrement the reference count of the given physical page. When this
   * reference count reaches 0, the page is marked free, ie is available
   * for future sos_physmem_get_physpage()
   *
   * @return FALSE when the page is still in use, TRUE when the page is now
   * unreferenced, <0 when the page address is invalid
   */
  sos_ret_t sos_physmem_unref_physpage(sos_paddr_t ppage_paddr);
  
  
  #endif /* _SOS_PHYSMEM_H_ */
  
 

/tmp/sos-code-article2/sos/types.h (2004-05-25 14:15:19.000000000 +0200 )
../sos-code-article3/sos/types.h (2004-08-31 14:49:21.000000000 +0200 )
Line 25 
Line 25 
  * SOS basic types definition  * SOS basic types definition
  */  */
  
  /** Physical address */
  typedef unsigned int       sos_paddr_t;
  
 /** Generic virtual address (kernel or user) */ /** Generic virtual address (kernel or user) */
 typedef unsigned int       sos_vaddr_t; typedef unsigned int       sos_vaddr_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 count of objects */
  typedef unsigned int       sos_count_t;
  
 /** Low-level sizes */ /** Low-level sizes */
 typedef unsigned long int  sos_ui32_t; /* 32b unsigned */ typedef unsigned long int  sos_ui32_t; /* 32b unsigned */
 typedef unsigned short int sos_ui16_t; /* 16b unsigned */ typedef unsigned short int sos_ui16_t; /* 16b unsigned */
 typedef unsigned char      sos_ui8_t; /* 8b unsigned */ typedef unsigned char      sos_ui8_t;  /* 8b unsigned */
 typedef enum { FALSE=0, TRUE } sos_bool_t; typedef enum { FALSE=0, TRUE } sos_bool_t;
  


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

File list:
    
../sos-code-article3/Makefile
    ../sos-code-article3/README
    ../sos-code-article3/VERSION
    ../sos-code-article3/bootstrap/multiboot.S
    ../sos-code-article3/drivers/x86_videomem.c
    ../sos-code-article3/extra/bootsect.S
    ../sos-code-article3/hwcore/exception.c
    ../sos-code-article3/sos/errno.h
    ../sos-code-article3/sos/klibc.c
    ../sos-code-article3/sos/list.h
    ../sos-code-article3/sos/macros.h
    ../sos-code-article3/sos/main.c
    ../sos-code-article3/sos/physmem.c
    ../sos-code-article3/sos/physmem.h
    ../sos-code-article3/sos/types.h