linux内存固定映射,linux内核高端内存管理之固定内存区与映射

前面总结了高端内存中永久内核映射和临时内核映射。linux高端内存中的临时内存区为固定内存区的一部分,下面是Linux内存布局图

0818b9ca8b590ca3270a3433284dd417.png

对于固定内存在linux内核中有下面描述

enum fixed_addresses {

#ifdef CONFIG_X86_32

FIX_HOLE,

FIX_VDSO,

#else

VSYSCALL_LAST_PAGE,

VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE

+ ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,

VSYSCALL_HPET,

#endif

FIX_DBGP_BASE,

FIX_EARLYCON_MEM_BASE,

#ifdef CONFIG_X86_LOCAL_APIC

FIX_APIC_BASE,/* local (CPU) APIC) -- required for SMP or not */

#endif

#ifdef CONFIG_X86_IO_APIC

FIX_IO_APIC_BASE_0,

FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,

#endif

#ifdef CONFIG_X86_VISWS_APIC

FIX_CO_CPU,/* Cobalt timer */

FIX_CO_APIC,/* Cobalt APIC Redirection Table */

FIX_LI_PCIA,/* Lithium PCI Bridge A */

FIX_LI_PCIB,/* Lithium PCI Bridge B */

#endif

#ifdef CONFIG_X86_F00F_BUG

FIX_F00F_IDT,/* Virtual mapping for IDT */

#endif

#ifdef CONFIG_X86_CYCLONE_TIMER

FIX_CYCLONE_TIMER, /*cyclone timer register*/

#endif

#ifdef CONFIG_X86_32

FIX_KMAP_BEGIN,/* reserved pte's for temporary kernel mappings */

FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,

#ifdef CONFIG_PCI_MMCONFIG

FIX_PCIE_MCFG,

#endif

#endif

#ifdef CONFIG_PARAVIRT

FIX_PARAVIRT_BOOTMAP,

#endif

FIX_TEXT_POKE1,/* reserve 2 pages for text_poke() */

FIX_TEXT_POKE0, /* first page is last, because allocation is backward */

__end_of_permanent_fixed_addresses,

/*

* 256 temporary boot-time mappings, used by early_ioremap(),

* before ioremap() is functional.

*

* We round it up to the next 256 pages boundary so that we

* can have a single pgd entry and a single pte table:

*/

#define NR_FIX_BTMAPS64

#define FIX_BTMAPS_SLOTS4

FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -

(__end_of_permanent_fixed_addresses & 255),

FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,

#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT

FIX_OHCI1394_BASE,

#endif

#ifdef CONFIG_X86_32

FIX_WP_TEST,

#endif

#ifdef CONFIG_INTEL_TXT

FIX_TBOOT_BASE,

#endif

__end_of_fixed_addresses

};

固定映射

ioremap的作用是将IO和BIOS以及物理地址空间映射到在896M至1G的128M的地址空间内,使得kernel能够访问该空间并进行相应的读写操作。

start_kernel()->setup_arch()->early_ioremap_init()

void __init early_ioremap_init(void)

{

pmd_t *pmd;

int i;

if (early_ioremap_debug)

printk(KERN_INFO "early_ioremap_init()\n");

/*将fixed_address里的索引的虚拟地址放入slot_virt

,从代码里面可以看出,放入slot_virt中得虚拟地址为1M*/

for (i = 0; i < FIX_BTMAPS_SLOTS; i++)

slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i);

/*得到固定映射区的pmd

,此pmd为虚拟地址转换为物理地址的pmd*/

pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));

memset(bm_pte, 0, sizeof(bm_pte));

/*将bm_pte页表设置为固定映射区开始地址的pmd的第一个页表;*/

pmd_populate_kernel(&init_mm, pmd, bm_pte);

/*

* The boot-ioremap range spans multiple pmds, for which

* we are not prepared:

*/

/*系统要求所有的ioremap映射在一个pmd上,超出这个pmd将警告*/

if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) {

WARN_ON(1);

printk(KERN_WARNING "pmd %p != %p\n",

pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END)));

printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",

fix_to_virt(FIX_BTMAP_BEGIN));

printk(KERN_WARNING "fix_to_virt(FIX_BTMAP_END): %08lx\n",

fix_to_virt(FIX_BTMAP_END));

printk(KERN_WARNING "FIX_BTMAP_END: %d\n", FIX_BTMAP_END);

printk(KERN_WARNING "FIX_BTMAP_BEGIN: %d\n",

FIX_BTMAP_BEGIN);

}

}

static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;

#define __fix_to_virt(x)(FIXADDR_TOP - ((x) << PAGE_SHIFT))

其中FIXADDR_TOP为4G-4K。

对于ioremap的使用需要通过early_memremap和early_iounmap进行。由于对应于ioremap的内存空间是有限的,所以对于ioremap空间的使用遵照使用结束马上释放的原则。这就是说early_memremap和early_iounmap必须配对使用并且访问结束必须马上执行unmap。

static void __init __iomem *

__early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)

{

unsigned long offset;

resource_size_t last_addr;

unsigned int nrpages;

enum fixed_addresses idx0, idx;

int i, slot;

WARN_ON(system_state != SYSTEM_BOOTING);

slot = -1;

/*pre_map[]是一个索引与slot_virt[]一一对应,这段for

的含义在于找到一个没有被使用过的slot_virt[i]的页面,

该slot_virt[i]所指向的虚拟页面地址就是将会和实际物

理地址phys_addr相绑定的虚拟地址。*/

for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {

if (!prev_map[i]) {

slot = i;

break;

}

}

if (slot < 0) {

printk(KERN_INFO "early_iomap(%08llx, %08lx) not found slot\n",

(u64)phys_addr, size);

WARN_ON(1);

return NULL;

}

if (early_ioremap_debug) {

printk(KERN_INFO "early_ioremap(%08llx, %08lx) [%d] => ",

(u64)phys_addr, size, slot);

dump_stack();

}

/* Don't allow wraparound or zero size */

last_addr = phys_addr + size - 1;

if (!size || last_addr < phys_addr) {

WARN_ON(1);

return NULL;

}

prev_size[slot] = size;

/*

* Mappings have to be page-aligned

*/

offset = phys_addr & ~PAGE_MASK;/*offset是页内的偏移*/

phys_addr &= PAGE_MASK;/*现在phys_addr就是起始页面的地址*/

/*现在size就是指出了到底占据了多少个页面的大小*/

size = PAGE_ALIGN(last_addr + 1) - phys_addr;

/*

* Mappings have to fit in the FIX_BTMAP area.

*/

/*到底我们需要多少页面*/

nrpages = size >> PAGE_SHIFT;

if (nrpages > NR_FIX_BTMAPS) {

WARN_ON(1);

return NULL;

}

/*

* Ok, go for it..

*/

/*找到空闲slot所对应的fixed_address中的索引号*/

idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;

idx = idx0;

while (nrpages > 0) {

/*在bm_ptes中将指定的idx索引的页表项填充为对应的物理地址使得bm_pte[idx]指向正确的物理页面地址*/

early_set_fixmap(idx, phys_addr, prot);

phys_addr += PAGE_SIZE;

--idx;

--nrpages;

}

if (early_ioremap_debug)

printk(KERN_CONT "%08lx + %08lx\n", offset, slot_virt[slot]);

/*返回phys_addr所指向的虚拟地址*/

prev_map[slot] = (void __iomem *)(offset + slot_virt[slot]);

return prev_map[slot];

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值