From bb55beef914e7488350ad1d0419d4bc60ad63c99 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Fri, 28 Mar 2014 09:10:23 +0100 Subject: Import code for article1, 2, 3, 4 --- sos-code-article4/sos/assert.h | 42 ++++++ sos-code-article4/sos/errno.h | 40 ++++++ sos-code-article4/sos/klibc.c | 271 ++++++++++++++++++++++++++++++++++++ sos-code-article4/sos/klibc.h | 84 +++++++++++ sos-code-article4/sos/list.h | 186 +++++++++++++++++++++++++ sos-code-article4/sos/macros.h | 37 +++++ sos-code-article4/sos/main.c | 298 ++++++++++++++++++++++++++++++++++++++++ sos-code-article4/sos/physmem.c | 269 ++++++++++++++++++++++++++++++++++++ sos-code-article4/sos/physmem.h | 119 ++++++++++++++++ sos-code-article4/sos/types.h | 50 +++++++ 10 files changed, 1396 insertions(+) create mode 100644 sos-code-article4/sos/assert.h create mode 100644 sos-code-article4/sos/errno.h create mode 100644 sos-code-article4/sos/klibc.c create mode 100644 sos-code-article4/sos/klibc.h create mode 100644 sos-code-article4/sos/list.h create mode 100644 sos-code-article4/sos/macros.h create mode 100644 sos-code-article4/sos/main.c create mode 100644 sos-code-article4/sos/physmem.c create mode 100644 sos-code-article4/sos/physmem.h create mode 100644 sos-code-article4/sos/types.h (limited to 'sos-code-article4/sos') diff --git a/sos-code-article4/sos/assert.h b/sos-code-article4/sos/assert.h new file mode 100644 index 0000000..a14ca0b --- /dev/null +++ b/sos-code-article4/sos/assert.h @@ -0,0 +1,42 @@ +/* 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_ASSERT_H_ +#define _SOS_ASSERT_H_ + +#include +#include + +/** + * If the expr is FALSE, print a message and halt the machine + */ +#define SOS_ASSERT_FATAL(expr) \ + ({ \ + int __res=(int)(expr); \ + if (! __res) { \ + asm("cli\n"); /* disable interrupts -- x86 only */ \ + sos_bochs_printf("%s@%s:%d Assertion " # expr " failed\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + sos_x86_videomem_printf(24, 0, 12, \ + "%s@%s:%d Assertion " # expr " failed", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + for (;;) asm("hlt;") ; /* Infinite loop, ie simple system halt */ \ + } \ + }) + + +#endif /* _SOS_ASSERT_H_ */ diff --git a/sos-code-article4/sos/errno.h b/sos-code-article4/sos/errno.h new file mode 100644 index 0000000..2c7bada --- /dev/null +++ b/sos-code-article4/sos/errno.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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_ERRNO_H_ +#define _SOS_ERRNO_H_ + +/** + * @file errno.h + * + * SOS return value codes and errors. + */ + +/* Positive values of the error codes */ +#define SOS_OK 0 /* No error */ +#define SOS_EINVAL 1 /* Invalid argument */ +#define SOS_ENOSUP 2 /* Operation not supported */ +#define SOS_ENOMEM 3 /* No available memory */ +#define SOS_EFATAL 255 /* Internal fatal error */ + +/* A negative value means that an error occured. For + * example -SOS_EINVAL means that the error was "invalid + * argument" */ +typedef int sos_ret_t; + +#endif /* _SOS_ERRNO_H_ */ diff --git a/sos-code-article4/sos/klibc.c b/sos-code-article4/sos/klibc.c new file mode 100644 index 0000000..277a15c --- /dev/null +++ b/sos-code-article4/sos/klibc.c @@ -0,0 +1,271 @@ +/* Copyright (C) 2004 David Decotigny (with INSA Rennes for vsnprintf) + Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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 "klibc.h" + +/* For an optimized version, see BSD sources ;) */ +void *memcpy(void *dst0, const void *src0, register unsigned int size) +{ + char *dst; + const char *src; + for (dst = (char*)dst0, src = (const char*)src0 ; + size > 0 ; + dst++, src++, size--) + *dst = *src; + return dst0; +} + +/* ditto */ +void *memset(void *dst0, register int c, register unsigned int length) +{ + char *dst; + for (dst = (char*) dst0 ; + length > 0 ; + dst++, length --) + *dst = (char)c; + return dst0; +} + +int memcmp(const void *s1, const void *s2, sos_size_t len) +{ + const unsigned char *c1, *c2; + unsigned int i; + + for (i = 0, c1 = s1, c2 = s2; i < len; i++, c1++, c2++) + { + if(*c1 != *c2) + return *c1 - *c2; + } + + return 0; +} + + +unsigned int strlen(register const char *str) +{ + unsigned int retval = 0; + + while (*str++) + retval++; + + return retval; +} + + +unsigned int strnlen(const char * s, sos_size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */continue; + + return sc - s; +} + + +char *strzcpy(register char *dst, register const char *src, register int len) +{ + int i; + + if (len <= 0) + return dst; + + for (i = 0; i < len; i++) + { + dst[i] = src[i]; + if(src[i] == '\0') + return dst; + } + + dst[len-1] = '\0'; + return dst; +} + + +char *strzcat (char *dest, const char *src, sos_size_t n) +{ + char *res = dest; + + for ( ; *dest ; dest++); + + for ( ; *src ; src++, dest++) { + *dest = *src; + n--; + if (n <= 0) + break; + } + + *dest = '\0'; + return res; +} + +int strcmp(register const char *s1, register const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + + +int strncmp(register const char *s1, register const char *s2, register int len) +{ + char c1 = '\0', c2 = '\0'; + + while (len > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + len--; + } + + return c1 - c2; +} + + +/* I (d2) borrowed and rewrote this for Nachos/INSA Rennes. Thanks to + them for having kindly allowed me to do so. */ +int vsnprintf(char *buff, sos_size_t len, const char * format, va_list ap) +{ + sos_size_t i, result; + + if (!buff || !format || (len < 0)) + return -1; + +#define PUTCHAR(thechar) \ + do { \ + if (result < len-1) \ + *buff++ = (thechar); \ + result++; \ + } while (0) + + result = 0; + for(i=0 ; format[i] != '\0' ; i++){ + switch (format[i]) + { + case '%': + i++; + switch(format[i]) + { + case '%': + { + PUTCHAR('%'); + break; + } + case 'i':; + case 'd': + { + int integer = va_arg(ap,int); + int cpt2 = 0; + char buff_int[16]; + + if (integer<0) + PUTCHAR('-'); + /* Ne fait pas integer = -integer ici parce que INT_MIN + n'a pas d'equivalent positif (int = [-2^31, 2^31-1]) */ + + do { + int m10 = integer%10; + m10 = (m10 < 0)? -m10:m10; + buff_int[cpt2++]=(char)('0'+ m10); + integer=integer/10; + } while(integer!=0); + + for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) + PUTCHAR(buff_int[cpt2]); + + break; + } + + case 'c': + { + int value = va_arg(ap,int); + PUTCHAR((char)value); + break; + } + + case 's': + { + char *string = va_arg(ap,char *); + if (! string) + string = "(null)"; + for( ; *string != '\0' ; string++) + PUTCHAR(*string); + break; + } + + case 'x': + { + unsigned int hexa = va_arg(ap,int); + unsigned int nb; + int i, had_nonzero = 0; + for(i=0 ; i < 8 ; i++) + { + nb = (unsigned int)(hexa << (i*4)); + nb = (nb >> 28) & 0xf; + // Skip the leading zeros + if (nb == 0) + { + if (had_nonzero) + PUTCHAR('0'); + } + else + { + had_nonzero = 1; + if (nb < 10) + PUTCHAR('0'+nb); + else + PUTCHAR('a'+(nb-10)); + } + } + if (! had_nonzero) + PUTCHAR('0'); + break; + } + break; + + default: + PUTCHAR('%'); + PUTCHAR(format[i]); + } + break; + + default: + PUTCHAR(format[i]); + } + } + + *buff = '\0'; + return result; +} + + +int snprintf(char * buff, sos_size_t len, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + len = vsnprintf(buff, len, format, ap); + va_end(ap); + + return len; +} diff --git a/sos-code-article4/sos/klibc.h b/sos-code-article4/sos/klibc.h new file mode 100644 index 0000000..a8b9d49 --- /dev/null +++ b/sos-code-article4/sos/klibc.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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_KLIBC_H_ +#define _SOS_KLIBC_H_ + +/** + * @file klibc.h + * + * Basic libc-style support for common useful functions (string.h, + * stdarg.h), some with slight non-standard behavior (see comments). + */ + +#include + +/* string.h functions */ + +void *memcpy(void *dst, const void *src, register unsigned int size ) ; +void *memset(void *dst, register int c, register unsigned int length ) ; +int memcmp(const void *s1, const void *s2, sos_size_t n); + +unsigned int strlen( register const char *str) ; +unsigned int strnlen(const char * s, sos_size_t maxlen); + +/** + * @note Same as strncpy(), with a slightly different semantic. + * Actually, strncpy(3C) says " The result will not be null-terminated + * if the length of 'from' is n or more.". Here, 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcpy( register char *dst, register const char *src, + register int len ) ; + +/** + * @note Same as strncat(), with the same semantic : 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcat (char *dest, const char *src, + const sos_size_t len); + +int strcmp(register const char *s1, register const char *s2 ); +int strncmp(register const char *s1, register const char *s2, + register int len ); + +/* Basic stdarg.h macros. Taken from gcc support files */ +#define __GNUC_VA_LIST +typedef void *__gnuc_va_list; +typedef __gnuc_va_list va_list; +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) +#define va_end(AP) \ + ((void)0) +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#define __va_copy(dest, src) \ + (dest) = (src) + +/* stdarg.h functions. There might be a non-standard behavior: there + will always be a trailing '\0' in the resulting string */ +int vsnprintf(char *, sos_size_t, const char *, va_list); +int snprintf(char *, sos_size_t, const char *, /*args*/ ...) + __attribute__ ((format (printf, 3, 4))); + +#endif /* _SOS_KLIBC_H_ */ diff --git a/sos-code-article4/sos/list.h b/sos-code-article4/sos/list.h new file mode 100644 index 0000000..67e72f3 --- /dev/null +++ b/sos-code-article4/sos/list.h @@ -0,0 +1,186 @@ +/* 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_ */ diff --git a/sos-code-article4/sos/macros.h b/sos-code-article4/sos/macros.h new file mode 100644 index 0000000..b08f081 --- /dev/null +++ b/sos-code-article4/sos/macros.h @@ -0,0 +1,37 @@ +/* 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_ */ diff --git a/sos-code-article4/sos/main.c b/sos-code-article4/sos/main.c new file mode 100644 index 0000000..7f54f70 --- /dev/null +++ b/sos-code-article4/sos/main.c @@ -0,0 +1,298 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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 definitions of the multiboot standard */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Helper function to display each bits of a 32bits integer on the + screen as dark or light carrets */ +static void display_bits(unsigned char row, unsigned char col, + unsigned char attribute, + sos_ui32_t integer) +{ + int i; + /* Scan each bit of the integer, MSb first */ + for (i = 31 ; i >= 0 ; i--) + { + /* Test if bit i of 'integer' is set */ + int bit_i = (integer & (1 << i)); + /* Ascii 219 => dark carret, Ascii 177 => light carret */ + unsigned char ascii_code = bit_i?219:177; + sos_x86_videomem_putchar(row, col++, + attribute, + ascii_code); + } +} + + +/* Clock IRQ handler */ +static void clk_it(int intid) +{ + static sos_ui32_t clock_count = 0; + + display_bits(0, 48, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + clock_count); + clock_count++; + +} + +/* Page fault exception handler */ +static void pgflt_ex(int exid) +{ + sos_bochs_printf("Got page fault\n"); + sos_x86_videomem_printf(10, 30, + SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, + "Got EXPECTED (?) Page fault ! But where ???"); + for (;;) ; +} + +static void test_paging(sos_vaddr_t sos_kernel_core_top_vaddr) +{ + /* The (linear) address of the page holding the code we are + currently executing */ + sos_vaddr_t vpage_code = SOS_PAGE_ALIGN_INF(test_paging); + + /* The new physical page that will hold the code */ + sos_paddr_t ppage_new; + + /* Where this page will be mapped temporarily in order to copy the + code into it: right after the kernel code/data */ + sos_vaddr_t vpage_tmp = sos_kernel_core_top_vaddr; + + unsigned i; + + /* Bind the page fault exception to one of our routines */ + sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT, + pgflt_ex); + + /* + * Test 1: move the page where we execute the code elsewhere in + * physical memory + */ + sos_x86_videomem_printf(4, 0, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + "Moving current code elsewhere in physical memory:"); + + + /* Allocate a new physical page */ + ppage_new = sos_physmem_ref_physpage_new(FALSE); + if (! ppage_new) + { + /* STOP ! No memory left */ + sos_x86_videomem_putstring(20, 0, + SOS_X86_VIDEO_FG_LTRED + | SOS_X86_VIDEO_BG_BLUE, + "test_paging : Cannot allocate page"); + return; + } + + sos_x86_videomem_printf(5, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Hello from the address 0x%x in physical memory", + sos_paging_get_paddr(vpage_code)); + + sos_x86_videomem_printf(6, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Transfer vpage 0x%x: ppage 0x%x -> 0x%x (tmp vpage 0x%x)", + vpage_code, + sos_paging_get_paddr(vpage_code), + ppage_new, + (unsigned)vpage_tmp); + + /* Map the page somewhere (right after the kernel mapping) in order + to copy the code we are currently executing */ + sos_paging_map(ppage_new, vpage_tmp, + FALSE, + SOS_VM_MAP_ATOMIC + | SOS_VM_MAP_PROT_READ + | SOS_VM_MAP_PROT_WRITE); + + /* Ok, the new page is referenced by the mapping, we can release our + reference to it */ + sos_physmem_unref_physpage(ppage_new); + + /* Copy the contents of the current page of code to this new page + mapping */ + memcpy((void*)vpage_tmp, + (void*)vpage_code, + SOS_PAGE_SIZE); + + /* Transfer the mapping of the current page of code to this new page */ + sos_paging_map(ppage_new, vpage_code, + FALSE, + SOS_VM_MAP_ATOMIC + | SOS_VM_MAP_PROT_READ + | SOS_VM_MAP_PROT_WRITE); + + /* Ok, here we are: we have changed the physcal page that holds the + code we are executing ;). However, this new page is mapped at 2 + virtual addresses: + - vpage_tmp + - vpage_code + We can safely unmap it from sos_kernel_core_top_vaddr, while + still keeping the vpage_code mapping */ + sos_paging_unmap(vpage_tmp); + + sos_x86_videomem_printf(7, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Hello from the address 0x%x in physical memory", + sos_paging_get_paddr(vpage_code)); + + sos_x86_videomem_printf(9, 0, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + "Provoking a page fault:"); + + /* + * Test 2: make sure the #PF handler works + */ + + /* Scan part of the kernel up to a page fault. This page fault + should occur on the first page unmapped after the kernel area, + which is exactly the page we temporarily mapped/unmapped + (vpage_tmp) above to move the kernel code we are executing */ + for (i = vpage_code ; /* none */ ; i += SOS_PAGE_SIZE) + { + unsigned *pint = (unsigned *)SOS_PAGE_ALIGN_INF(i); + sos_bochs_printf("Test vaddr 0x%x : val=", (unsigned)pint); + sos_x86_videomem_printf(10, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Test vaddr 0x%x : val= ", + (unsigned)pint); + sos_bochs_printf("0x%x\n", *pint); + sos_x86_videomem_printf(10, 30, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "0x%x ", *pint); + } + + /* BAD ! Did not get the page fault... */ + sos_x86_videomem_printf(20, 0, + SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, + "We should have had a #PF at vaddr 0x%x !", + vpage_tmp); +} + +/* The C entry point of our operating system */ +void sos_main(unsigned long magic, unsigned long addr) +{ + 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 + precious informations about the system, see the multiboot + documentation for more information. */ + multiboot_info_t *mbi; + mbi = (multiboot_info_t *) addr; + + /* Setup bochs and console, and clear the console */ + sos_bochs_setup(); + + sos_x86_videomem_setup(); + sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); + + /* Greetings from SOS */ + if (magic == MULTIBOOT_BOOTLOADER_MAGIC) + /* Loaded with Grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", + "SOS", ',', + (unsigned)(mbi->mem_upper >> 10) + 1, + (unsigned)mbi->mem_upper); + else + /* Not loaded with grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome to SOS"); + + sos_bochs_putstring("Message in a bochs\n"); + + /* Setup CPU segmentation and IRQ subsystem */ + sos_gdt_setup(); + sos_idt_setup(); + + /* Setup SOS IRQs and exceptions subsystem */ + sos_exceptions_setup(); + sos_irq_setup(); + + /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */ + 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 */ + sos_irq_set_routine(SOS_IRQ_TIMER, + clk_it); + /* Enabling the HW interrupts here, this will make the timer HW + interrupt call our clk_it handler */ + asm volatile ("sti\n"); + /* Multiboot says: "The value returned for upper memory is maximally + the address of the first upper memory hole minus 1 megabyte.". It + also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */ + sos_physmem_setup((mbi->mem_upper<<10) + (1<<20), + & sos_kernel_core_base_paddr, + & sos_kernel_core_top_paddr); + + /* + * Switch to paged-memory mode + */ + + /* Disabling interrupts should seem more correct, but it's not really + necessary at this stage */ + if (sos_paging_setup(sos_kernel_core_base_paddr, + sos_kernel_core_top_paddr)) + sos_bochs_printf("Could not setup paged memory mode\n"); + sos_x86_videomem_printf(2, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Paged-memory mode is activated"); + + test_paging(sos_kernel_core_top_paddr); + + /* An operatig system never ends */ + for (;;) + continue; + + return; +} diff --git a/sos-code-article4/sos/physmem.c b/sos-code-article4/sos/physmem.c new file mode 100644 index 0000000..99cffb7 --- /dev/null +++ b/sos-code-article4/sos/physmem.c @@ -0,0 +1,269 @@ +/* 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 +#include +#include +#include + +#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; +} diff --git a/sos-code-article4/sos/physmem.h b/sos-code-article4/sos/physmem.h new file mode 100644 index 0000000..8b5d997 --- /dev/null +++ b/sos-code-article4/sos/physmem.h @@ -0,0 +1,119 @@ +/* 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 +#include +#include + +/** 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_ */ diff --git a/sos-code-article4/sos/types.h b/sos-code-article4/sos/types.h new file mode 100644 index 0000000..02d9f6d --- /dev/null +++ b/sos-code-article4/sos/types.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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_TYPES_H_ +#define _SOS_TYPES_H_ + +/** + * @file types.h + * + * SOS basic types definition + */ + +/** Physical address */ +typedef unsigned int sos_paddr_t; + +/** Generic virtual address (kernel or user) */ +typedef unsigned int sos_vaddr_t; + +/** Memory size of an object (positive) */ +typedef unsigned int sos_size_t; +/** Generic count of objects */ +typedef unsigned int sos_count_t; + +/** Low-level sizes */ +typedef unsigned long int sos_ui32_t; /* 32b unsigned */ +typedef unsigned short int sos_ui16_t; /* 16b unsigned */ +typedef unsigned char sos_ui8_t; /* 8b unsigned */ + +typedef enum { FALSE=0, TRUE } sos_bool_t; + +/** Not a proper type, but highly useful with basic type + manipulations */ +#define NULL ((void*)0) + +#endif /* _SOS_TYPES_H_ */ -- cgit v1.2.3