PMON中的虚拟内存问题
net_init函数中通过vminit和kmeminit函数来完成虚拟内存映射以及内存分配的初始化,暂时先将看的笔记放上来,以后整理:
#define PGOFSET 4095
size = (size + PGOFSET)& ~PGOFSET // 0x0fff
该语句的作用在于:
每次分配都按PGOFSET为单位进行分配,size不足PGOFSET的则分配PGOFSET大小,size大于PGOFSET的则分配
(size / PGOFSET+1)*PGOFSET 大小;
假设size = PGOFSET + 1,那么分配时将会分配2*PGOFSET大小;
- 1.virtua memory init(在sys/kern/kern_misc.c中)
- /*
- * Initialise "virtual memory" maps
- */
- void vminit __P((void));
- /* sys/sys/cdefs.h
- #define __P(protos) protos /*full-blown ANSI C*/
- Void vminit __P((void ))也就是说vminit不带任何参数
- */
- void
- vminit ()
- {
- extern int memorysize; // 定义在pmon/common/main.c中
- /* memorysize在initmips中被初始化为:
- * memorysize = memsz > 256 ? 256 << 20 : memsz << 20;
- * memsz是在start.S中初始化的,为240
- * memorysize = 0x0f00 0000
- */
- if (!kmem) { // static u_char *kmem;
- /* grab a chunk at the top of memory */
- if (memorysize < VM_KMEM_SIZE * 2) {
- panic ("not enough memory for network");
- }
- memorysize = (memorysize - VM_KMEM_SIZE) & ~PGOFSET;
- #ifdef __mips__
- if ((u_int32_t)&kmem < (u_int32_t)UNCACHED_MEMORY_ADDR) {
- /* if linked for data in kseg0, keep kmem there too */
- kmem = (u_char *) PHYS_TO_CACHED (memorysize);
- }
- else {
- kmem = (u_char *) PHYS_TO_UNCACHED (memorysize);
- }
- #else
- kmem = (u_char *)memorysize;
- #endif
- }
- vminit函数所作的事归纳起来就一件,即初始化kem这个静态全局变量:
- kmem = (u_char *) ((memorysize - VM_KMEM_SIZE) & ~PGOFSET);
- #define VM_KMEM_SIZE (NKMEMCLUSTERS * CLBYTES) // 2MB
- #define NKMEMCLUSTERS (2048 * 1024 / CLBYTES) /* 0.5Mb */
- #define CLBYTES (CLSIZE*NBPG) // 4096
- #define CLSIZE 1 // 1
- #define PGOFSET (NBPG-1) /* byte offset into page */
- #define NBPG 4096 /* bytes/page */
- PGOFSET 即为 4095(即一页的大小,4KB),4095 = 0x0FFF。
- 可以算得VM_KMEM_SIZE为 0x0020 0000,而memorysize为0x0F00 0000,
- memory – VM_KMEM_SIZE = 0x0EE0 0000,
- kmem = (u_char *) PHYS_TO_UNCACHED (memorysize);
- = 0x8ee0 0000
- 240 MB – 2MB;
- 0……….………………………238MB(0x0ee0 0000)………..240MB
- kmem(0x8ee0 0000)
- vminit函数:
- 将kmem指向内存的最后2MB处,并将其映射到kseg0地址空间;
- 2.kmeminit(sys/kern/kern_malloc.c)
- /*
- * Initialise memory allocator
- */
- void
- kmeminit()
- {
- int npg;
- // 检查MAXALLOCSAVE是否是2的幂
- /*
- #define MAXALLOCSAVE (MINALLOCSIZE * 32768)
- 0x8000 * 0x10 = 0x80000
- #define MINALLOCSIZE (1 << MINBUCKET) // 0x10
- #define MINBUCKET 4 /* 4 => min allocation of 16 bytes */
- */
- #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
- ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
- #endif
- #if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
- ERROR!_kmeminit:_MAXALLOCSAVE_too_big
- #endif
- #if (MAXALLOCSAVE < CLBYTES)
- ERROR!_kmeminit:_MAXALLOCSAVE_too_small
- #endif
- #ifdef DIAGNOSTIC
- if (sizeof(struct freelist) > (1 << MINBUCKET))
- panic("kmeminit: minbucket too small/struct freelist too big");
- #endif
- npg = VM_KMEM_SIZE/ NBPG;
- /*
- 2MB/4096 = 512 (0x200)
- */
- kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
- (vsize_t)(npg * sizeof(struct kmemusage)));
- /*
- kmemusage是kern_malloc.c中定义的一个kmemusage结构体变量:用于记录页的使用情况;
- struct kmemusage结构体说明:
- Array of descriptors that describe the contents of each page
- struct kmemusage {
- short ku_indx; /* bucket index */
- union {
- u_short freecnt;/* for small allocations, free pieces in page */
- u_short pagecnt;/* for large allocations, pages alloced */
- } ku_un;
- };
- */
- kmem_map = kmem_suballoc(kernel_map, (vaddr_t *)&kmembase,
- (vaddr_t *)&kmemlimit, (vsize_t)(npg * NBPG), FALSE);
- /*
- kmem_map是sys/vm/vm_kern.h中定义的一个vm_map_t变量;
- typedef struct vm_map *vm_map_t;
- */
- }
- 2.1 kmem_alloc函数
- kmem_alloc函数只调用了kmem_malloc (map, size, 0),其中map对应于kernel_map,size对应于(vsize_t)(npg * sizeof(struct kmemusage)),size = 512 * 4 = 2048
- kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
- (vsize_t)(npg * sizeof(struct kmemusage)));
- 下面即是kmem_malloc函数:
- vm_offset_t
- kmem_malloc (map, size, canwait)
- vm_map_t map;
- vm_size_t size;
- {
- vm_offset_t p;
- if(!kmem) { /* In case we call this before vminit() */
- vminit();
- }
- /*PGOFSET 为4095 ,0x0FFF*/
- size = (size + PGOFSET) & ~PGOFSET; //size = 4096 = 0x1000 每次分配4KB对齐
- if (kmem_offs + size > VM_KMEM_SIZE) {
- log (LOG_DEBUG, "kmem_malloc: request for %d bytes fails/n", size);
- return 0;
- }
- p = (vm_offset_t) &kmem[kmem_offs]; // kmem = 0x8ee0 0000
- kmem_offs += size; // kmem_offs = 4096
- return p;
- }
- kernel_map = p = 0x8ee0 0000(kseg0段虚拟地址),即指向物理内存的238MB处;
- 2.2 kmem_suballoc函数
- vm_map_t
- kmem_suballoc (map, base, lim, size, canwait)
- vm_map_t map;
- vm_offset_t *base, *lim;
- vm_size_t size;
- {
- if (size > VM_KMEM_SIZE)
- panic ("kmem_suballoc");
- *base = (vm_offset_t) kmem;
- /*
- kmem在vminit中被初始化为(u_char *) 0x0EE0 0000(指向物理内存238MB)
- typedef unsigned long vm_offset_t;
- typedef unsigned long vaddr_t;
- base指向238MB
- */
- typedef unsigned long vaddr_t;
- *lim = (vm_offset_t) kmem + VM_KMEM_SIZE;
- /*lim指向240MB*/
- return map;
- }
- 在kmeminit函数中:
- kmem_map = kmem_suballoc(kernel_map, (vaddr_t *)&kmembase,
- (vaddr_t *)&kmemlimit, (vsize_t)(npg * NBPG), FALSE);
- 最终执行的结果为:
- kmembase === > 0x8ee0 0000(物理内存238MB )
- kmemlimit === > 0x0F00 0000(物理内存240MB)
- kmem_map = kernel_map = 0x8ee0 0000
kmembase、kmemlimit、kmem_map在内存分配函数中都会用到。