/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
) |
|
|
|
| /* 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/main.c (2004-05-25 14:15:19.000000000 +0200
) |
|
../sos-code-article3/sos/main.c (2004-08-31 14:49:21.000000000 +0200
) |
|
|
|
#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> |
|
|
| |
} | } |
| |
/* 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 |
|
|
/* 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
) |
|
|
|
| /* 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
) |
|
|
|
| /* 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_ */ |
| |