先看相关的变量的意思:
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;
}