长篇连载--arm linux演艺---第十一回 上回我们说到在paging_init中分配了三个页: zero_page=0xc0000000 bad page=0xc0001000 bad_table=0xc0002000 但是奇怪的很,在更新的linux代码中只分配了一个zero_page,而且在源代码中找不到zero_page,用在什么地方了,大家讨论讨论吧。 paging_init的主要工作是在 void __init memtable_init(struct meminfo *mi) 中完成的,为系统内存创建页表: meminfo结构如下: struct meminfo { int nr_banks; unsigned long end; struct { unsigned long start; unsigned long size; int node; } bank[NR_BANKS]; }; 是用来纪录系统中的内存区段的,因为在嵌入式系统中并不是所有的内存都能映射,例如sdram只有64m,flash 32m,而且不见得是连续的,所以用meminfo纪录这些区段。 void __init memtable_init(struct meminfo *mi) { struct map_desc *init_maps, *p, *q; unsigned long address = 0; int i; 其中map_desc定义为:
struct map_desc { unsigned long virtual; unsigned long physical; unsigned long length; int domain:4, //页表的domain prot_read:1, //保护标志 prot_write:1, //写保护标志 cacheable:1, //是否cache bufferable:1, //是否用write buffer last:1; //空 };init_maps map_desc是区段及其属性的定义,属性位的意义请参考ARM MMU的介绍。 下面对meminfo的区段进行遍历,同时填写init_maps中的各项内容: for (i = 0; i < mi->nr_banks; i++) { if (mi->bank[i].size == 0) continue; p->physical = mi->bank[i].start; p->virtual = __phys_to_virt(p->physical); p->length = mi->bank[i].size; p->domain = DOMAIN_KERNEL; p->prot_read = 0; p->prot_write = 1; p->cacheable = 1; //可以CACHE p->bufferable = 1; //使用write buffer p ++; //下一个区段 } 如果系统有flash, #ifdef FLUSH_BASE p->physical = FLUSH_BASE_PHYS; p->virtual = FLUSH_BASE; p->length = PGDIR_SIZE; p->domain = DOMAIN_KERNEL; p->prot_read = 1; p->prot_write = 0; p->cacheable = 1; p->bufferable = 1; p ++; #endif 其中的prot_read和prot_write是用来设置页表的domain的, 下面就是逐个区段建立页表: q = init_maps; do { if (address < q->virtual || q == p) { clear_mapping(address); address += PGDIR_SIZE; } else { create_mapping(q); address = q->virtual + q->length; address = (address + PGDIR_SIZE - 1) & PGDIR_MASK; q ++; } } while (address != 0); arm linux 第十一回完
|