openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

memory.c (7619B)


      1 /* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
      2 ** Distributed under the terms of the OpenBLT License
      3 */
      4 
      5 #include "kernel.h"
      6 #include "memory.h"
      7 
      8 static unsigned char size_map[513] = {
      9     KM16,                                      
     10     
     11     KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16,
     12     KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16,
     13 
     14     KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32,
     15     KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32,
     16 
     17     KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
     18     KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
     19     KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
     20     KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
     21 
     22     KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
     23     KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
     24     KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
     25     KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
     26 	
     27     KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
     28     KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
     29     KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
     30     KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
     31 
     32 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     33 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     34 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     35 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     36 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     37 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     38 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     39 	KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
     40     
     41     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     42     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     43     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     44     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     45     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     46     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     47     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     48     KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
     49 };
     50 
     51 
     52 void *kmallocB(int size)
     53 {
     54 	if(size < 256) return kmallocP(size_map[size]);
     55 	panic("invalid kmallocB");
     56 }
     57 
     58 void kfreeB(int size, void *block)
     59 {
     60 	if(size < 256) return kfreeP(size_map[size],block);
     61 	panic("invalid kmallocB");
     62 }
     63 
     64 
     65 
     66 struct km_mnode 
     67 {
     68     struct km_mnode *next;    
     69 };
     70 
     71 static struct _km_map
     72 {
     73     int size;
     74     int used_count;
     75     int fresh_count;
     76     int free_count;
     77     struct km_mnode *free_chain;
     78     void *fresh_chain;    
     79 } km_map[KMMAX] = {
     80     {   16,   0, 256, 0, NULL, NULL },
     81     {   32,   0, 128, 0, NULL, NULL },
     82     {   64,   0,  64, 0, NULL, NULL },
     83 	{   96,   0,  42, 0, NULL, NULL },
     84     {  128,   0,  32, 0, NULL, NULL },
     85     {  192,   0,  21, 0, NULL, NULL },
     86     {  256,   0,  16, 0, NULL, NULL } 
     87 };        
     88 
     89 extern uint32 memsize;
     90 extern uint32 memtotal;
     91 
     92 static uint32 total_pages;
     93 static uint32 used_pages;
     94 
     95 void memory_status(void)
     96 {
     97     int i;
     98 	int inuse = 0, allocated = 0;
     99 	
    100     kprintf("");
    101     kprintf("size used free fresh");    
    102     for(i=0;i<KMMAX;i++){
    103         kprintf("%U %U %U %U", km_map[i].size, km_map[i].used_count,
    104                 km_map[i].free_count, km_map[i].fresh_count);
    105 		inuse += km_map[i].size * km_map[i].used_count;
    106 		allocated += km_map[i].size * 
    107 		    (km_map[i].free_count+km_map[i].used_count+km_map[i].fresh_count);
    108 		
    109     }
    110 	inuse /= 1024;
    111 	allocated /= 1024;
    112 	kprintf("");
    113 	kprintf("%dkb allocated, %dkb in use",allocated,inuse);
    114 	kprintf("%d (of %d) pages in use",used_pages, total_pages);
    115 	 
    116 }
    117 
    118 
    119 /* kernel 'heap' is allocated top down ... top three pages used by the bootstrap */
    120 static uint32 nextmem = 0x80400000 - 4*4096;
    121 static node_t *freevpagelist = NULL;
    122 
    123 static uint32 *pagelist = NULL;
    124 static uint32 freepage = 0;
    125 
    126 extern aspace_t *flat;
    127 
    128 void putpage(uint32 number)
    129 {
    130 //	kprintf("- %d",number);
    131 				
    132 	pagelist[number] = freepage;
    133 	freepage = number;
    134 	used_pages--;
    135 }
    136 
    137 uint32 getpage(void)
    138 {
    139 	uint32 n = freepage;
    140 	
    141 //	kprintf("+ %d",n);
    142 
    143 	if(n){
    144 		freepage = pagelist[n];
    145 	} else {
    146 		panic("Out of physical memory");
    147 	}
    148 	used_pages++;
    149 	return n;
    150 }
    151 
    152 void kfreepage(void *vaddr)
    153 {
    154 	node_t *n;
    155 	int pageno;
    156 	int vpage = (((uint32)vaddr)/0x1000) & 0x3ff;
    157 	
    158 	if(!flat->high[vpage]){
    159 		kprintf("vpage %d / %x unmapped already?!",vpage,vaddr);
    160 		DEBUGGER();
    161 	}
    162 	
    163 	/* release the underlying page */
    164 	pageno = flat->high[vpage] / 0x1000;	
    165 //	kprintf("kfreepage(%x) high[%d] = %d",vaddr,vpage,pageno);
    166 	putpage( pageno );
    167 	
    168 	flat->high[vpage] = 0;
    169 	local_flush_pte(vaddr);
    170 	
    171 	/* stick it on the virtual page freelist */
    172 	n = kmalloc(node_t);
    173 	n->next = freevpagelist;
    174 	n->data = vaddr;
    175 	freevpagelist = n;
    176 }
    177 
    178 void *kgetpage(uint32 *phys)
    179 {
    180 	uint32 pg = getpage();
    181 	*phys = pg * 0x1000;
    182 
    183 	if(nextmem < 0x80050000) panic("kernel vspace exhausted");
    184 	
    185 	if(freevpagelist){
    186 		node_t *n = freevpagelist;
    187 		void *page = n->data;
    188 		freevpagelist = n->next;
    189 		kfree(node_t, n);
    190 		if(flat->high[(((uint32)page)/0x1000) & 0x3ff]){
    191 			kprintf("page collision @ %x",page);
    192 			DEBUGGER();
    193 		}
    194 		aspace_maphi(flat, pg, (((uint32)page)/0x1000) , 1, 3);
    195 		return page;		
    196 	} else {	
    197 		nextmem -= 4096;
    198 		aspace_maphi(flat, pg, nextmem/0x1000, 1, 3);
    199 		return (void *) nextmem;
    200 	}
    201 }
    202 
    203 void *kgetpages(int count)
    204 {
    205 	if(count == 1){
    206 		uint32 phys;
    207 		return kgetpage(&phys);
    208 	} else {
    209 		int i,n;
    210 		nextmem -= 4096*count;
    211 		for(n=nextmem/0x1000,i=0;i<count;n++,i++){
    212 			aspace_maphi(flat, getpage(), n, 1, 3); 
    213 		}
    214 		return (void *) nextmem;
    215 	}
    216 }
    217 
    218 /* map specific physical pages into kernel space, return virtaddr */
    219 void *kmappages(int phys, int count, int flags)
    220 {
    221     nextmem -= 4096*count;
    222     aspace_maphi(flat, phys, nextmem/0x1000, count, flags); 
    223     return (void *) nextmem;
    224 }
    225 
    226 void memory_init(uint32 bottom_page, uint32 top_page) 
    227 {
    228 	int i,count;
    229 	
    230 	/* we can track 1024 pages for every 4K of pagelist */
    231 	count = ((top_page - bottom_page) / 1024) + 1;
    232 	
    233 	/* allocate the pagelist */
    234 	top_page -= count;
    235 	total_pages = 0;
    236 	used_pages = 0;
    237 	
    238 	nextmem -= 4096*count;
    239 	pagelist = (uint32 *) nextmem;
    240 	aspace_maphi(flat, top_page, nextmem/0x1000, count, 3);
    241 		
    242 	/* setup the pagelist */
    243 	freepage = 0;
    244 	for(i=top_page;i>=bottom_page;i--){
    245 		total_pages++;
    246 		pagelist[i] = freepage;
    247 		freepage = i;
    248 	}
    249 	
    250 	/* setup the memory pools */
    251     for(i=0;i<KMMAX;i++){
    252         km_map[i].fresh_chain = kgetpages(1);
    253 	}
    254 }
    255 
    256 
    257 void *kmallocP(int size)
    258 {
    259     struct _km_map *km;    
    260     void *block;    
    261     if(size >= KMMAX) panic("illegal size in kmalloc()");
    262     km = &km_map[size];
    263 
    264     km->used_count++;
    265 
    266     if(km->free_chain) {
    267             /* recycle free'd blocks if available */
    268         km->free_count--;
    269         block = (void *) km->free_chain;
    270         km->free_chain = km->free_chain->next;
    271     } else {
    272             /* shave a new block off of the fresh page if
    273                we can't recycle */
    274         km->fresh_count--;
    275         block = km->fresh_chain;
    276 
    277         if(km->fresh_count){
    278                 /* still some left, just bump us to the next chunk */
    279             km->fresh_chain = (void *)
    280                 (((char *) km->fresh_chain) + km->size);        
    281         } else {
    282                 /* gotta grab a new page */
    283             km->fresh_count = 4096 / km->size;        
    284             km->fresh_chain = kgetpages(1);            
    285         }
    286     }
    287     
    288     return block;    
    289 }
    290 
    291 void kfreeP(int size, void *block)
    292 {
    293     struct _km_map *km;    
    294     if(size > KMMAX) panic("illegal size in kmalloc()");
    295     km = &km_map[size];
    296     
    297     km->free_count++;    
    298     km->used_count--;
    299     ((struct km_mnode *) block)->next = km->free_chain;    
    300     km->free_chain = (struct km_mnode *) block;    
    301 }
    302