Main Page | Directories | File List | Globals

buddy_alloc.c

Go to the documentation of this file.
00001 /*
00002  * kernel_super/memory/buddy_alloc.c
00003  *
00004  * Copyright (c) 2003-2004 Lukasz Dembinski <dembol@nasa.com.pl>
00005  * All Rights Reserved
00006  * 
00007  * Date:        2004/09
00008  * Author:      Lukasz Dembinski
00009  * Info:        buddy_alloc.c core file
00010  * Contact:     mailto: <dembol@nasa.com.pl>
00011  *
00012  */
00013  
00014 #include <agnix/agnix.h>
00015 #include <asm/bitops.h>
00016 #include <agnix/memory.h>
00017 #include <agnix/panic.h>
00018 #include <agnix/console.h>
00019 
00020 #define MOD_NAME        "MEM: "
00021 #define NO_PAGE         0
00022 
00023 struct buddy_allocator_s buddy_alloc_normal = {
00024     .buddy_name                 = "Normal area buddy allocator",
00025     .buddy_alloc_req_areas      = BUDDY_ALLOC_NORMAL_AREAS 
00026 };
00027 
00028 struct buddy_allocator_s buddy_alloc_dma = {
00029     .buddy_name                 = "DMA area buddy allocator",
00030     .buddy_alloc_req_areas      = BUDDY_ALLOC_DMA_AREAS 
00031 };
00032 
00033 extern struct allocator_s main_alloc;
00034 extern void (*put_free_pages_fn)(u32 addr, u8 order);
00035 extern u32  (*get_free_pages_fn)(u8 order);
00036 extern void (*put_free_dma_pages_fn)(u32 addr, u8 order);
00037 extern u32  (*get_free_dma_pages_fn)(u8 order);
00038 struct page_desc_s *system_pages;
00039 
00040 void buddy_put_free_pages(struct buddy_allocator_s *buddy_alloc, u32 addr, u8 order)
00041 {
00042     u8 start_order;
00043     u32 bitmap_idx;
00044     struct buddy_area_s *area = &buddy_alloc->buddy_area[order];
00045     struct page_desc_s *page_desc;
00046     struct page_desc_s *page_buddy_desc;
00047     u32 page_idx = virt_to_page(addr);
00048     u32 page_buddy_idx;
00049     u32 page_mask;
00050     u32 flags;
00051 
00052     spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00053 
00054     page_mask  = (~0UL) << order;
00055     for (start_order = order; start_order < buddy_alloc->buddy_alloc_req_areas; start_order++) {
00056         bitmap_idx = page_idx >> (start_order + 1);
00057 
00058         if (!test_and_change_bit(bitmap_idx, area->area_bitmap)) {
00059             break;
00060         }
00061         
00062         page_buddy_idx  = page_idx ^ (1 + ~page_mask);
00063         page_buddy_desc = &system_pages[page_buddy_idx];
00064         list_del(&page_buddy_desc->page_list);
00065         area->free_units--;
00066         
00067         area++;
00068         page_mask <<= 1;
00069         page_idx &= page_mask;
00070     }
00071 
00072     page_desc = &system_pages[page_idx];
00073     list_add(&page_desc->page_list, &area->area_list);
00074     area->free_units++;
00075     
00076     spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00077 }
00078 
00079 struct page_desc_s *buddy_get_free_pages_back(struct buddy_allocator_s *buddy_alloc, u32 order, u32 cur_order)
00080 {
00081     struct buddy_area_s *area = &buddy_alloc->buddy_area[cur_order];
00082     struct page_desc_s *page_desc = NULL;
00083     u32 page_idx;
00084     u32 page_half_idx;
00085     u32 back_order;
00086     u32 area_size;
00087 
00088     page_desc = list_entry(area->area_list.next, struct page_desc_s, page_list);
00089     page_idx  = virt_to_page(page_desc->address_virt);
00090     list_del(area->area_list.next);
00091     change_bit(page_idx >> (cur_order + 1), area->area_bitmap);
00092     area->free_units--;
00093 
00094     for (back_order = cur_order - 1; back_order >= order; back_order--) {
00095         area = &buddy_alloc->buddy_area[back_order];
00096         area_size = 1 << back_order;
00097         page_idx  = virt_to_page(page_desc->address_virt);
00098         page_half_idx = page_idx + area_size;
00099         list_add(&page_desc->page_list, &area->area_list);
00100         area->free_units++;
00101 
00102         change_bit(page_idx >> (back_order + 1), area->area_bitmap);
00103         page_desc = &system_pages[page_half_idx];
00104         
00105         if (back_order == order)
00106             break;
00107     }   
00108         
00109     return page_desc;
00110 }
00111 
00112 u32 buddy_get_free_pages(struct buddy_allocator_s *buddy_alloc, u8 order)
00113 {
00114     struct buddy_area_s *area = &buddy_alloc->buddy_area[order];
00115     struct page_desc_s *page_desc = NULL;
00116     u32 cur_order;
00117     u32 flags;
00118     u8  *ptr;
00119     int i;
00120         
00121     spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00122 
00123     for (cur_order = order; cur_order < buddy_alloc->buddy_alloc_req_areas; cur_order++) {
00124 
00125         if (!list_empty(&area->area_list)) {
00126             if (cur_order == order) {
00127                 page_desc = list_entry(area->area_list.next, struct page_desc_s, page_list);
00128                 change_bit(virt_to_page(page_desc->address_virt) >> (order + 1), area->area_bitmap);
00129                 list_del(area->area_list.next);
00130                 area->free_units--;
00131             } else {
00132                 page_desc = buddy_get_free_pages_back(buddy_alloc, order, cur_order);
00133             }    
00134             
00135             break;
00136         }
00137         area++;
00138     }
00139     
00140     spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00141 
00142     if (cur_order == buddy_alloc->buddy_alloc_req_areas)
00143         return 0;
00144 
00145     if (page_desc->address_virt < 0xc0000000) {
00146         printk("address < 0xc0000000\n");
00147         for (i = 0; i < 1000000000; i++);
00148     }
00149 
00150     ptr = (u8 *)page_desc->address_virt;
00151     
00152     for (i = 0; i < PAGE_SIZE; i++) {
00153         ptr[i] = 0;
00154     }
00155         
00156     return page_desc->address_virt;
00157 }
00158 
00159 u32 buddy_get_free_pages_wrapper(u8 order)
00160 {
00161     return buddy_get_free_pages(&buddy_alloc_normal, order);
00162 }
00163 
00164 void buddy_put_free_pages_wrapper(u32 address, u8 order)
00165 {
00166     return buddy_put_free_pages(&buddy_alloc_normal, address, order);
00167 }
00168 
00169 u32 buddy_get_free_dma_pages_wrapper(u8 order)
00170 {
00171     return buddy_get_free_pages(&buddy_alloc_dma, order);
00172 }
00173 
00174 void buddy_put_free_dma_pages_wrapper(u32 address, u8 order)
00175 {
00176     return buddy_put_free_pages(&buddy_alloc_dma, address, order);
00177 }
00178 
00179 void buddy_alloc_fn_init(void)
00180 {
00181     get_free_pages_fn     = buddy_get_free_pages_wrapper;    
00182     put_free_pages_fn     = buddy_put_free_pages_wrapper;    
00183     get_free_dma_pages_fn = buddy_get_free_dma_pages_wrapper;    
00184     put_free_dma_pages_fn = buddy_put_free_dma_pages_wrapper;    
00185 }
00186 
00187 int buddy_alloc_areas_init(struct allocator_s *main_alloc, struct buddy_allocator_s *buddy_alloc)
00188 {
00189     int i;
00190     int area_size_pages = 0;
00191     
00192     for (i = 0; i < buddy_alloc->buddy_alloc_req_areas; i++) {
00193 
00194         area_size_pages = (((main_alloc->mem_size_pages + (1 << 3) - 1) >> 4) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
00195         if ((buddy_alloc->buddy_area[i].area_bitmap = (u32 *)bin_get_free_pages(area_size_pages)) == NULL) {
00196             kernel_panic(MOD_NAME "buddy_alloc_init() failed\n");
00197         }
00198 
00199         INIT_LIST_HEAD(&buddy_alloc->buddy_area[i].area_list);
00200         buddy_alloc->buddy_area[i].free_units = 0;      
00201     }    
00202     
00203     return 0;
00204 }
00205 
00206 void buddy_alloc_pages_init(struct allocator_s *main_alloc)
00207 {
00208     int system_pages_size;
00209     int i;
00210     
00211     system_pages_size = ((main_alloc->mem_size_pages * sizeof(struct page_desc_s)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
00212     
00213     if ((system_pages = (struct page_desc_s *)bin_get_free_pages(system_pages_size)) == NULL) {
00214         kernel_panic(MOD_NAME "buddy_alloc_pages_init() failed\n");
00215     }    
00216     
00217     for (i = 0; i < main_alloc->mem_size_pages; i++) {
00218         system_pages[i].address_phys = (u32)(i << PAGE_SHIFT);
00219         system_pages[i].address_virt = phys_to_virt(system_pages[i].address_phys);
00220 
00221         INIT_LIST_HEAD(&system_pages[i].page_list);
00222     }
00223 }
00224 
00225 void buddy_alloc_print_units(struct buddy_allocator_s *buddy_alloc, int broadcast)
00226 {
00227     struct buddy_area_s *area;
00228     int i;
00229     u32 flags;
00230     
00231     if (broadcast)
00232         printk("\n" MOD_NAME "%s free units\n", buddy_alloc->buddy_name);
00233     else
00234         printf("\n" MOD_NAME "%s free units\n", buddy_alloc->buddy_name);
00235 
00236     spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00237 
00238     for (i = 0; i < buddy_alloc->buddy_alloc_req_areas; i++) {
00239         area = &buddy_alloc->buddy_area[i];
00240         if (broadcast)
00241             printk(MOD_NAME "\torder %02d -> %d free units\n", i, area->free_units);
00242         else
00243             printf(MOD_NAME "\torder %02d -> %d free units\n", i, area->free_units);
00244     }
00245     
00246     if (broadcast)
00247         printk("\n");
00248     else
00249         printf("\n");
00250     
00251     spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00252 }
00253 
00254 u32 buddy_alloc_free(struct buddy_allocator_s *buddy_alloc)
00255 {
00256     struct buddy_area_s *area;
00257     u32 page_order;
00258     u32 free;
00259     u32 flags;
00260     int i;
00261     
00262     spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00263 
00264     free = 0;
00265     page_order = 1;
00266     for (i = 0; i < buddy_alloc->buddy_alloc_req_areas; i++) {
00267         area = &buddy_alloc->buddy_area[i];
00268         free += area->free_units * page_order;
00269         page_order <<= 1;
00270     }
00271     
00272     spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00273     
00274     return free;
00275 }
00276 
00277 void __init buddy_alloc_init(void)
00278 {
00279     spin_lock_init(&buddy_alloc->buddy_lock);
00280 
00281     buddy_alloc_areas_init(&main_alloc, &buddy_alloc_dma);
00282     buddy_alloc_areas_init(&main_alloc, &buddy_alloc_normal);
00283     buddy_alloc_pages_init(&main_alloc);
00284     buddy_alloc_fn_init();
00285     bin_put_all_free_pages();
00286     buddy_alloc_print_units(&buddy_alloc_dma, 1);
00287     buddy_alloc_print_units(&buddy_alloc_normal, 1);
00288 }
00289 
00290 void buddy_alloc_print_stats(void)
00291 {
00292     buddy_alloc_print_units(&buddy_alloc_dma, 0);
00293     buddy_alloc_print_units(&buddy_alloc_normal, 0);
00294 }
00295 
00296 void buddy_alloc_print_free(void)
00297 {
00298     u32 free_dma, free_normal;
00299 
00300     free_dma    = buddy_alloc_free(&buddy_alloc_dma);
00301     printf("DMA free:     %d KB\n", free_dma << (PAGE_SHIFT - 10));
00302 
00303     free_normal = buddy_alloc_free(&buddy_alloc_normal);
00304     printf("Normal free:  %d KB\n", free_normal << (PAGE_SHIFT - 10));
00305     
00306     printf("Total free:   %d KB\n", (free_normal + free_dma) << (PAGE_SHIFT - 10));
00307 }
Dokumentacje wygenerowano programem Doxygen 1.4.2 dla projektu Agnix