高端内存(临时内存映射)

先看相关的变量的意思:

enum km_type {
D(
0) KM_BOUNCE_READ,
D(
1) KM_SKB_SUNRPC_DATA,
D(
2) KM_SKB_DATA_SOFTIRQ,
D(
3) KM_USER0,
D(
4) KM_USER1,
D(
5) KM_BIO_SRC_IRQ,
D(
6) KM_BIO_DST_IRQ,
D(
7) KM_PTE0,
D(
8) KM_PTE1,
D(
9) KM_IRQ0,
D(
10) KM_IRQ1,
D(
11) KM_SOFTIRQ0,
D(
12) KM_SOFTIRQ1,
D(
13) KM_TYPE_NR
};

还有一个是:



enum fixed_addresses {
FIX_HOLE,
FIX_VDSO,
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_HIGHMEM
FIX_KMAP_BEGIN,
/* reserved pte's for temporary kernel mappings */
FIX_KMAP_END
= FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
#ifdef CONFIG_ACPI
FIX_ACPI_BEGIN,
FIX_ACPI_END
= FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
#endif
#ifdef CONFIG_PCI_MMCONFIG
FIX_PCIE_MCFG,
#endif
#ifdef CONFIG_PARAVIRT
FIX_PARAVIRT_BOOTMAP,
#endif
__end_of_permanent_fixed_addresses,
#define NR_FIX_BTMAPS 64
#define FIX_BTMAPS_NESTING 4
FIX_BTMAP_END
=
__end_of_permanent_fixed_addresses
+ 512 -
(__end_of_permanent_fixed_addresses
& 511),
FIX_BTMAP_BEGIN
= FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
FIX_WP_TEST,
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
FIX_OHCI1394_BASE,
#endif
__end_of_fixed_addresses
};

下面进入正题,临时映射的入口:

# define kmap_atomic(page, type)        __kmap_atomic(page, type)
/* 临时映射的入口 */
void *__kmap_atomic(struct page *page, enum km_type type)
{
return kmap_atomic_prot(page, type, kmap_prot);
}

具体实现的代码(有些地方还不是非常清楚,以后弄清楚来再来补充):

# define kmap_atomic_prot(page, type, prot)     __kmap_atomic_prot(page, type, prot)
/* 和kmap相比会快一点,应为不需要全局锁,并且不需要处理global tlb(并且kmap是不能睡眠的,这里type没什么用) */
void *__kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
{
/* 编译期间特别的线性地址 */
enum fixed_addresses idx;
unsigned
long vaddr;
/*
* 原子映射是基于每个CPU的,因此在当前cpu上禁止抢占,直到unmap
* 的时候才开启,这样就不会到时原子映射的重入,毕竟如果禁用抢占
* 的话,调用者进程就很可能在同一cpu重入kmap_atomic_prot,然后就
* 映射到同一虚拟地址。一次不允许睡眠。
*/
preempt_disable();
pagefault_disable();
/* 如果不是高端内存 */
if (!PageHighMem(page))
return page_address(page);

/* 递增type,保证下面公式起作用 */
debug_kmap_atomic_prot(type);

/* 下面的两行用来保证N个CPU调用kmap_atomic不会将page映射到一个地址 */
idx
= type + KM_TYPE_NR*smp_processor_id();
vaddr
= __fix_to_virt(FIX_KMAP_BEGIN + idx);

WARN_ON_ONCE(
!pte_none(*(kmap_pte-idx)));
set_pte(kmap_pte
-idx, mk_pte(page, prot));
arch_flush_lazy_mmu_mode();

return (void *)vaddr;
}
posted @ 2011-08-10 14:39  GG大婶  阅读(552)  评论(0编辑  收藏  举报