| /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_ */ |
| | |