linux/arch/i386/mm/boot_ioremap.c
<<
>>
Prefs
   1/*
   2 * arch/i386/mm/boot_ioremap.c
   3 * 
   4 * Re-map functions for early boot-time before paging_init() when the 
   5 * boot-time pagetables are still in use
   6 *
   7 * Written by Dave Hansen <haveblue@us.ibm.com>
   8 */
   9
  10
  11/*
  12 * We need to use the 2-level pagetable functions, but CONFIG_X86_PAE
  13 * keeps that from happenning.  If anyone has a better way, I'm listening.
  14 *
  15 * boot_pte_t is defined only if this all works correctly
  16 */
  17
  18#include <linux/config.h>
  19#undef CONFIG_X86_PAE
  20#include <asm/page.h>
  21#include <asm/pgtable.h>
  22#include <asm/tlbflush.h>
  23#include <linux/init.h>
  24#include <linux/stddef.h>
  25
  26/* 
  27 * I'm cheating here.  It is known that the two boot PTE pages are 
  28 * allocated next to each other.  I'm pretending that they're just
  29 * one big array. 
  30 */
  31
  32#define BOOT_PTE_PTRS (PTRS_PER_PTE*2)
  33#define boot_pte_index(address) \
  34             (((address) >> PAGE_SHIFT) & (BOOT_PTE_PTRS - 1))
  35
  36static inline boot_pte_t* boot_vaddr_to_pte(void *address)
  37{
  38        boot_pte_t* boot_pg = (boot_pte_t*)pg0;
  39        return &boot_pg[boot_pte_index((unsigned long)address)];
  40}
  41
  42/*
  43 * This is only for a caller who is clever enough to page-align
  44 * phys_addr and virtual_source, and who also has a preference
  45 * about which virtual address from which to steal ptes
  46 */
  47static void __boot_ioremap(unsigned long phys_addr, unsigned long nrpages, 
  48                    void* virtual_source)
  49{
  50        boot_pte_t* pte;
  51        int i;
  52        char *vaddr = virtual_source;
  53
  54        pte = boot_vaddr_to_pte(virtual_source);
  55        for (i=0; i < nrpages; i++, phys_addr += PAGE_SIZE, pte++) {
  56                set_pte(pte, pfn_pte(phys_addr>>PAGE_SHIFT, PAGE_KERNEL));
  57                __flush_tlb_one(&vaddr[i*PAGE_SIZE]);
  58        }
  59}
  60
  61/* the virtual space we're going to remap comes from this array */
  62#define BOOT_IOREMAP_PAGES 4
  63#define BOOT_IOREMAP_SIZE (BOOT_IOREMAP_PAGES*PAGE_SIZE)
  64__initdata char boot_ioremap_space[BOOT_IOREMAP_SIZE] 
  65                __attribute__ ((aligned (PAGE_SIZE)));
  66
  67/*
  68 * This only applies to things which need to ioremap before paging_init()
  69 * bt_ioremap() and plain ioremap() are both useless at this point.
  70 * 
  71 * When used, we're still using the boot-time pagetables, which only
  72 * have 2 PTE pages mapping the first 8MB
  73 *
  74 * There is no unmap.  The boot-time PTE pages aren't used after boot.
  75 * If you really want the space back, just remap it yourself.
  76 * boot_ioremap(&ioremap_space-PAGE_OFFSET, BOOT_IOREMAP_SIZE)
  77 */
  78__init void* boot_ioremap(unsigned long phys_addr, unsigned long size)
  79{
  80        unsigned long last_addr, offset;
  81        unsigned int nrpages;
  82        
  83        last_addr = phys_addr + size - 1;
  84
  85        /* page align the requested address */
  86        offset = phys_addr & ~PAGE_MASK;
  87        phys_addr &= PAGE_MASK;
  88        size = PAGE_ALIGN(last_addr) - phys_addr;
  89        
  90        nrpages = size >> PAGE_SHIFT;
  91        if (nrpages > BOOT_IOREMAP_PAGES)
  92                return NULL;
  93        
  94        __boot_ioremap(phys_addr, nrpages, boot_ioremap_space);
  95
  96        return &boot_ioremap_space[offset];
  97}
  98
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.