PADDR宏
在pmm.c文件中的pmm_init(void)函数中存在一个奇怪的PADDR宏,以前从未见,该宏完成了去除内核的虚拟起始地址,这个宏是如何工作的?
//pmm.c
//pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism
// - check the correctness of pmm & paging mechanism, print PDT&PT
void
pmm_init(void) {
// create boot_pgdir, an initial page directory(Page Directory Table, PDT)
boot_pgdir = boot_alloc_page();
memset(boot_pgdir, 0, PGSIZE);
boot_cr3 = PADDR(boot_pgdir);
// recursively insert boot_pgdir in itself
// to form a virtual page table at virtual address VPT
boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_W;
}
//pmm.h
/* *
* PADDR - takes a kernel virtual address (an address that points above KERNBASE),
* where the machine's maximum 256MB of physical memory is mapped and returns the
* corresponding physical address. It panics if you pass it a non-kernel virtual address.
* */
#define PADDR(kva) ({ \
uintptr_t __m_kva = (uintptr_t)(kva); \
if (__m_kva < KERNBASE) { \
panic("PADDR called with invalid kva %08lx", __m_kva); \
} \
__m_kva - KERNBASE; \
})
QT平台测试PADDR宏
#include <stdio.h>
/* All physical memory mapped at this address */
#define KERNBASE 0xC0000000
/* *
* PADDR - takes a kernel virtual address (an address that points above KERNBASE),
* where the machine's maximum 256MB of physical memory is mapped and returns the
* corresponding physical address. It panics if you pass it a non-kernel virtual address.
* */
#define PADDR(kva) ({ \
uintptr_t __m_kva = (uintptr_t)(kva); \
if (__m_kva < KERNBASE) { \
printf("PADDR called with invalid kva %08lx", __m_kva); \
} \
__m_kva - KERNBASE; \
})
int main()
{
printf("Hello World!\n");
uintptr_t boot_pgdir = 0xC0000000+0x500;
uintptr_t a = PADDR(boot_pgdir);
printf("addr %08lx\n", a);
return 0;
}
程序能够输出
Hello World!
addr 00000500
因此PADDR宏仍然采用替换的方式,左边的PADDR(kva)替换成右边小括号内的东西,而括号内部执行完最后的一行代码完成赋值给指针变量a,即a = __m_kva - KERNBASE;