162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * High memory handling common code and variables. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de 662306a36Sopenharmony_ci * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Redesigned the x86 32-bit VM architecture to deal with 1062306a36Sopenharmony_ci * 64-bit physical space. With current x86 CPUs this 1162306a36Sopenharmony_ci * means up to 64 Gigabytes physical RAM. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Rewrote high memory support to move the page cache into 1462306a36Sopenharmony_ci * high memory. Implemented permanent (schedulable) kmaps 1562306a36Sopenharmony_ci * based on Linus' idea. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/mm.h> 2162306a36Sopenharmony_ci#include <linux/export.h> 2262306a36Sopenharmony_ci#include <linux/swap.h> 2362306a36Sopenharmony_ci#include <linux/bio.h> 2462306a36Sopenharmony_ci#include <linux/pagemap.h> 2562306a36Sopenharmony_ci#include <linux/mempool.h> 2662306a36Sopenharmony_ci#include <linux/init.h> 2762306a36Sopenharmony_ci#include <linux/hash.h> 2862306a36Sopenharmony_ci#include <linux/highmem.h> 2962306a36Sopenharmony_ci#include <linux/kgdb.h> 3062306a36Sopenharmony_ci#include <asm/tlbflush.h> 3162306a36Sopenharmony_ci#include <linux/vmalloc.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#ifdef CONFIG_KMAP_LOCAL 3462306a36Sopenharmony_cistatic inline int kmap_local_calc_idx(int idx) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return idx + KM_MAX_IDX * smp_processor_id(); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#ifndef arch_kmap_local_map_idx 4062306a36Sopenharmony_ci#define arch_kmap_local_map_idx(idx, pfn) kmap_local_calc_idx(idx) 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci#endif /* CONFIG_KMAP_LOCAL */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Virtual_count is not a pure "count". 4662306a36Sopenharmony_ci * 0 means that it is not mapped, and has not been mapped 4762306a36Sopenharmony_ci * since a TLB flush - it is usable. 4862306a36Sopenharmony_ci * 1 means that there are no users, but it has been mapped 4962306a36Sopenharmony_ci * since the last TLB flush - so we can't use it. 5062306a36Sopenharmony_ci * n means that there are (n-1) current users of it. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci#ifdef CONFIG_HIGHMEM 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Architecture with aliasing data cache may define the following family of 5662306a36Sopenharmony_ci * helper functions in its asm/highmem.h to control cache color of virtual 5762306a36Sopenharmony_ci * addresses where physical memory pages are mapped by kmap. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#ifndef get_pkmap_color 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Determine color of virtual address where the page should be mapped. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic inline unsigned int get_pkmap_color(struct page *page) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci#define get_pkmap_color get_pkmap_color 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Get next index for mapping inside PKMAP region for page with given color. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic inline unsigned int get_next_pkmap_nr(unsigned int color) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci static unsigned int last_pkmap_nr; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK; 7862306a36Sopenharmony_ci return last_pkmap_nr; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Determine if page index inside PKMAP region (pkmap_nr) of given color 8362306a36Sopenharmony_ci * has wrapped around PKMAP region end. When this happens an attempt to 8462306a36Sopenharmony_ci * flush all unused PKMAP slots is made. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci return pkmap_nr == 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Get the number of PKMAP entries of the given color. If no free slot is 9362306a36Sopenharmony_ci * found after checking that many entries, kmap will sleep waiting for 9462306a36Sopenharmony_ci * someone to call kunmap and free PKMAP slot. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_cistatic inline int get_pkmap_entries_count(unsigned int color) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci return LAST_PKMAP; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * Get head of a wait queue for PKMAP entries of the given color. 10362306a36Sopenharmony_ci * Wait queues for different mapping colors should be independent to avoid 10462306a36Sopenharmony_ci * unnecessary wakeups caused by freeing of slots of other colors. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return &pkmap_map_wait; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci#endif 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciatomic_long_t _totalhigh_pages __read_mostly; 11562306a36Sopenharmony_ciEXPORT_SYMBOL(_totalhigh_pages); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciunsigned int __nr_free_highpages(void) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct zone *zone; 12062306a36Sopenharmony_ci unsigned int pages = 0; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci for_each_populated_zone(zone) { 12362306a36Sopenharmony_ci if (is_highmem(zone)) 12462306a36Sopenharmony_ci pages += zone_page_state(zone, NR_FREE_PAGES); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return pages; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int pkmap_count[LAST_PKMAP]; 13162306a36Sopenharmony_cistatic __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cipte_t *pkmap_page_table; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * Most architectures have no use for kmap_high_get(), so let's abstract 13762306a36Sopenharmony_ci * the disabling of IRQ out of the locking in that case to save on a 13862306a36Sopenharmony_ci * potential useless overhead. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci#ifdef ARCH_NEEDS_KMAP_HIGH_GET 14162306a36Sopenharmony_ci#define lock_kmap() spin_lock_irq(&kmap_lock) 14262306a36Sopenharmony_ci#define unlock_kmap() spin_unlock_irq(&kmap_lock) 14362306a36Sopenharmony_ci#define lock_kmap_any(flags) spin_lock_irqsave(&kmap_lock, flags) 14462306a36Sopenharmony_ci#define unlock_kmap_any(flags) spin_unlock_irqrestore(&kmap_lock, flags) 14562306a36Sopenharmony_ci#else 14662306a36Sopenharmony_ci#define lock_kmap() spin_lock(&kmap_lock) 14762306a36Sopenharmony_ci#define unlock_kmap() spin_unlock(&kmap_lock) 14862306a36Sopenharmony_ci#define lock_kmap_any(flags) \ 14962306a36Sopenharmony_ci do { spin_lock(&kmap_lock); (void)(flags); } while (0) 15062306a36Sopenharmony_ci#define unlock_kmap_any(flags) \ 15162306a36Sopenharmony_ci do { spin_unlock(&kmap_lock); (void)(flags); } while (0) 15262306a36Sopenharmony_ci#endif 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistruct page *__kmap_to_page(void *vaddr) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci unsigned long base = (unsigned long) vaddr & PAGE_MASK; 15762306a36Sopenharmony_ci struct kmap_ctrl *kctrl = ¤t->kmap_ctrl; 15862306a36Sopenharmony_ci unsigned long addr = (unsigned long)vaddr; 15962306a36Sopenharmony_ci int i; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* kmap() mappings */ 16262306a36Sopenharmony_ci if (WARN_ON_ONCE(addr >= PKMAP_ADDR(0) && 16362306a36Sopenharmony_ci addr < PKMAP_ADDR(LAST_PKMAP))) 16462306a36Sopenharmony_ci return pte_page(ptep_get(&pkmap_page_table[PKMAP_NR(addr)])); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* kmap_local_page() mappings */ 16762306a36Sopenharmony_ci if (WARN_ON_ONCE(base >= __fix_to_virt(FIX_KMAP_END) && 16862306a36Sopenharmony_ci base < __fix_to_virt(FIX_KMAP_BEGIN))) { 16962306a36Sopenharmony_ci for (i = 0; i < kctrl->idx; i++) { 17062306a36Sopenharmony_ci unsigned long base_addr; 17162306a36Sopenharmony_ci int idx; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci idx = arch_kmap_local_map_idx(i, pte_pfn(pteval)); 17462306a36Sopenharmony_ci base_addr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (base_addr == base) 17762306a36Sopenharmony_ci return pte_page(kctrl->pteval[i]); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return virt_to_page(vaddr); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ciEXPORT_SYMBOL(__kmap_to_page); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void flush_all_zero_pkmaps(void) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci int i; 18862306a36Sopenharmony_ci int need_flush = 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci flush_cache_kmaps(); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (i = 0; i < LAST_PKMAP; i++) { 19362306a36Sopenharmony_ci struct page *page; 19462306a36Sopenharmony_ci pte_t ptent; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * zero means we don't have anything to do, 19862306a36Sopenharmony_ci * >1 means that it is still in use. Only 19962306a36Sopenharmony_ci * a count of 1 means that it is free but 20062306a36Sopenharmony_ci * needs to be unmapped 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci if (pkmap_count[i] != 1) 20362306a36Sopenharmony_ci continue; 20462306a36Sopenharmony_ci pkmap_count[i] = 0; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* sanity check */ 20762306a36Sopenharmony_ci ptent = ptep_get(&pkmap_page_table[i]); 20862306a36Sopenharmony_ci BUG_ON(pte_none(ptent)); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* 21162306a36Sopenharmony_ci * Don't need an atomic fetch-and-clear op here; 21262306a36Sopenharmony_ci * no-one has the page mapped, and cannot get at 21362306a36Sopenharmony_ci * its virtual address (and hence PTE) without first 21462306a36Sopenharmony_ci * getting the kmap_lock (which is held here). 21562306a36Sopenharmony_ci * So no dangers, even with speculative execution. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci page = pte_page(ptent); 21862306a36Sopenharmony_ci pte_clear(&init_mm, PKMAP_ADDR(i), &pkmap_page_table[i]); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci set_page_address(page, NULL); 22162306a36Sopenharmony_ci need_flush = 1; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci if (need_flush) 22462306a36Sopenharmony_ci flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_civoid __kmap_flush_unused(void) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci lock_kmap(); 23062306a36Sopenharmony_ci flush_all_zero_pkmaps(); 23162306a36Sopenharmony_ci unlock_kmap(); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic inline unsigned long map_new_virtual(struct page *page) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci unsigned long vaddr; 23762306a36Sopenharmony_ci int count; 23862306a36Sopenharmony_ci unsigned int last_pkmap_nr; 23962306a36Sopenharmony_ci unsigned int color = get_pkmap_color(page); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistart: 24262306a36Sopenharmony_ci count = get_pkmap_entries_count(color); 24362306a36Sopenharmony_ci /* Find an empty entry */ 24462306a36Sopenharmony_ci for (;;) { 24562306a36Sopenharmony_ci last_pkmap_nr = get_next_pkmap_nr(color); 24662306a36Sopenharmony_ci if (no_more_pkmaps(last_pkmap_nr, color)) { 24762306a36Sopenharmony_ci flush_all_zero_pkmaps(); 24862306a36Sopenharmony_ci count = get_pkmap_entries_count(color); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci if (!pkmap_count[last_pkmap_nr]) 25162306a36Sopenharmony_ci break; /* Found a usable entry */ 25262306a36Sopenharmony_ci if (--count) 25362306a36Sopenharmony_ci continue; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* 25662306a36Sopenharmony_ci * Sleep for somebody else to unmap their entries 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci { 25962306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 26062306a36Sopenharmony_ci wait_queue_head_t *pkmap_map_wait = 26162306a36Sopenharmony_ci get_pkmap_wait_queue_head(color); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci __set_current_state(TASK_UNINTERRUPTIBLE); 26462306a36Sopenharmony_ci add_wait_queue(pkmap_map_wait, &wait); 26562306a36Sopenharmony_ci unlock_kmap(); 26662306a36Sopenharmony_ci schedule(); 26762306a36Sopenharmony_ci remove_wait_queue(pkmap_map_wait, &wait); 26862306a36Sopenharmony_ci lock_kmap(); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Somebody else might have mapped it while we slept */ 27162306a36Sopenharmony_ci if (page_address(page)) 27262306a36Sopenharmony_ci return (unsigned long)page_address(page); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Re-start */ 27562306a36Sopenharmony_ci goto start; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci vaddr = PKMAP_ADDR(last_pkmap_nr); 27962306a36Sopenharmony_ci set_pte_at(&init_mm, vaddr, 28062306a36Sopenharmony_ci &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot)); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci pkmap_count[last_pkmap_nr] = 1; 28362306a36Sopenharmony_ci set_page_address(page, (void *)vaddr); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return vaddr; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/** 28962306a36Sopenharmony_ci * kmap_high - map a highmem page into memory 29062306a36Sopenharmony_ci * @page: &struct page to map 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * Returns the page's virtual memory address. 29362306a36Sopenharmony_ci * 29462306a36Sopenharmony_ci * We cannot call this from interrupts, as it may block. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_civoid *kmap_high(struct page *page) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci unsigned long vaddr; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * For highmem pages, we can't trust "virtual" until 30262306a36Sopenharmony_ci * after we have the lock. 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci lock_kmap(); 30562306a36Sopenharmony_ci vaddr = (unsigned long)page_address(page); 30662306a36Sopenharmony_ci if (!vaddr) 30762306a36Sopenharmony_ci vaddr = map_new_virtual(page); 30862306a36Sopenharmony_ci pkmap_count[PKMAP_NR(vaddr)]++; 30962306a36Sopenharmony_ci BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2); 31062306a36Sopenharmony_ci unlock_kmap(); 31162306a36Sopenharmony_ci return (void *) vaddr; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ciEXPORT_SYMBOL(kmap_high); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#ifdef ARCH_NEEDS_KMAP_HIGH_GET 31662306a36Sopenharmony_ci/** 31762306a36Sopenharmony_ci * kmap_high_get - pin a highmem page into memory 31862306a36Sopenharmony_ci * @page: &struct page to pin 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * Returns the page's current virtual memory address, or NULL if no mapping 32162306a36Sopenharmony_ci * exists. If and only if a non null address is returned then a 32262306a36Sopenharmony_ci * matching call to kunmap_high() is necessary. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * This can be called from any context. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_civoid *kmap_high_get(struct page *page) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci unsigned long vaddr, flags; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci lock_kmap_any(flags); 33162306a36Sopenharmony_ci vaddr = (unsigned long)page_address(page); 33262306a36Sopenharmony_ci if (vaddr) { 33362306a36Sopenharmony_ci BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1); 33462306a36Sopenharmony_ci pkmap_count[PKMAP_NR(vaddr)]++; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci unlock_kmap_any(flags); 33762306a36Sopenharmony_ci return (void *) vaddr; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci#endif 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/** 34262306a36Sopenharmony_ci * kunmap_high - unmap a highmem page into memory 34362306a36Sopenharmony_ci * @page: &struct page to unmap 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called 34662306a36Sopenharmony_ci * only from user context. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_civoid kunmap_high(struct page *page) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci unsigned long vaddr; 35162306a36Sopenharmony_ci unsigned long nr; 35262306a36Sopenharmony_ci unsigned long flags; 35362306a36Sopenharmony_ci int need_wakeup; 35462306a36Sopenharmony_ci unsigned int color = get_pkmap_color(page); 35562306a36Sopenharmony_ci wait_queue_head_t *pkmap_map_wait; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci lock_kmap_any(flags); 35862306a36Sopenharmony_ci vaddr = (unsigned long)page_address(page); 35962306a36Sopenharmony_ci BUG_ON(!vaddr); 36062306a36Sopenharmony_ci nr = PKMAP_NR(vaddr); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* 36362306a36Sopenharmony_ci * A count must never go down to zero 36462306a36Sopenharmony_ci * without a TLB flush! 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci need_wakeup = 0; 36762306a36Sopenharmony_ci switch (--pkmap_count[nr]) { 36862306a36Sopenharmony_ci case 0: 36962306a36Sopenharmony_ci BUG(); 37062306a36Sopenharmony_ci case 1: 37162306a36Sopenharmony_ci /* 37262306a36Sopenharmony_ci * Avoid an unnecessary wake_up() function call. 37362306a36Sopenharmony_ci * The common case is pkmap_count[] == 1, but 37462306a36Sopenharmony_ci * no waiters. 37562306a36Sopenharmony_ci * The tasks queued in the wait-queue are guarded 37662306a36Sopenharmony_ci * by both the lock in the wait-queue-head and by 37762306a36Sopenharmony_ci * the kmap_lock. As the kmap_lock is held here, 37862306a36Sopenharmony_ci * no need for the wait-queue-head's lock. Simply 37962306a36Sopenharmony_ci * test if the queue is empty. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci pkmap_map_wait = get_pkmap_wait_queue_head(color); 38262306a36Sopenharmony_ci need_wakeup = waitqueue_active(pkmap_map_wait); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci unlock_kmap_any(flags); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* do wake-up, if needed, race-free outside of the spin lock */ 38762306a36Sopenharmony_ci if (need_wakeup) 38862306a36Sopenharmony_ci wake_up(pkmap_map_wait); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ciEXPORT_SYMBOL(kunmap_high); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_civoid zero_user_segments(struct page *page, unsigned start1, unsigned end1, 39362306a36Sopenharmony_ci unsigned start2, unsigned end2) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci unsigned int i; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci BUG_ON(end1 > page_size(page) || end2 > page_size(page)); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (start1 >= end1) 40062306a36Sopenharmony_ci start1 = end1 = 0; 40162306a36Sopenharmony_ci if (start2 >= end2) 40262306a36Sopenharmony_ci start2 = end2 = 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci for (i = 0; i < compound_nr(page); i++) { 40562306a36Sopenharmony_ci void *kaddr = NULL; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (start1 >= PAGE_SIZE) { 40862306a36Sopenharmony_ci start1 -= PAGE_SIZE; 40962306a36Sopenharmony_ci end1 -= PAGE_SIZE; 41062306a36Sopenharmony_ci } else { 41162306a36Sopenharmony_ci unsigned this_end = min_t(unsigned, end1, PAGE_SIZE); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (end1 > start1) { 41462306a36Sopenharmony_ci kaddr = kmap_local_page(page + i); 41562306a36Sopenharmony_ci memset(kaddr + start1, 0, this_end - start1); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci end1 -= this_end; 41862306a36Sopenharmony_ci start1 = 0; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (start2 >= PAGE_SIZE) { 42262306a36Sopenharmony_ci start2 -= PAGE_SIZE; 42362306a36Sopenharmony_ci end2 -= PAGE_SIZE; 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci unsigned this_end = min_t(unsigned, end2, PAGE_SIZE); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (end2 > start2) { 42862306a36Sopenharmony_ci if (!kaddr) 42962306a36Sopenharmony_ci kaddr = kmap_local_page(page + i); 43062306a36Sopenharmony_ci memset(kaddr + start2, 0, this_end - start2); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci end2 -= this_end; 43362306a36Sopenharmony_ci start2 = 0; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (kaddr) { 43762306a36Sopenharmony_ci kunmap_local(kaddr); 43862306a36Sopenharmony_ci flush_dcache_page(page + i); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!end1 && !end2) 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci BUG_ON((start1 | start2 | end1 | end2) != 0); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ciEXPORT_SYMBOL(zero_user_segments); 44862306a36Sopenharmony_ci#endif /* CONFIG_HIGHMEM */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci#ifdef CONFIG_KMAP_LOCAL 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci#include <asm/kmap_size.h> 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/* 45562306a36Sopenharmony_ci * With DEBUG_KMAP_LOCAL the stack depth is doubled and every second 45662306a36Sopenharmony_ci * slot is unused which acts as a guard page 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_KMAP_LOCAL 45962306a36Sopenharmony_ci# define KM_INCR 2 46062306a36Sopenharmony_ci#else 46162306a36Sopenharmony_ci# define KM_INCR 1 46262306a36Sopenharmony_ci#endif 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic inline int kmap_local_idx_push(void) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci WARN_ON_ONCE(in_hardirq() && !irqs_disabled()); 46762306a36Sopenharmony_ci current->kmap_ctrl.idx += KM_INCR; 46862306a36Sopenharmony_ci BUG_ON(current->kmap_ctrl.idx >= KM_MAX_IDX); 46962306a36Sopenharmony_ci return current->kmap_ctrl.idx - 1; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic inline int kmap_local_idx(void) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci return current->kmap_ctrl.idx - 1; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic inline void kmap_local_idx_pop(void) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci current->kmap_ctrl.idx -= KM_INCR; 48062306a36Sopenharmony_ci BUG_ON(current->kmap_ctrl.idx < 0); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci#ifndef arch_kmap_local_post_map 48462306a36Sopenharmony_ci# define arch_kmap_local_post_map(vaddr, pteval) do { } while (0) 48562306a36Sopenharmony_ci#endif 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci#ifndef arch_kmap_local_pre_unmap 48862306a36Sopenharmony_ci# define arch_kmap_local_pre_unmap(vaddr) do { } while (0) 48962306a36Sopenharmony_ci#endif 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci#ifndef arch_kmap_local_post_unmap 49262306a36Sopenharmony_ci# define arch_kmap_local_post_unmap(vaddr) do { } while (0) 49362306a36Sopenharmony_ci#endif 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci#ifndef arch_kmap_local_unmap_idx 49662306a36Sopenharmony_ci#define arch_kmap_local_unmap_idx(idx, vaddr) kmap_local_calc_idx(idx) 49762306a36Sopenharmony_ci#endif 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci#ifndef arch_kmap_local_high_get 50062306a36Sopenharmony_cistatic inline void *arch_kmap_local_high_get(struct page *page) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci return NULL; 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci#endif 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci#ifndef arch_kmap_local_set_pte 50762306a36Sopenharmony_ci#define arch_kmap_local_set_pte(mm, vaddr, ptep, ptev) \ 50862306a36Sopenharmony_ci set_pte_at(mm, vaddr, ptep, ptev) 50962306a36Sopenharmony_ci#endif 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/* Unmap a local mapping which was obtained by kmap_high_get() */ 51262306a36Sopenharmony_cistatic inline bool kmap_high_unmap_local(unsigned long vaddr) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci#ifdef ARCH_NEEDS_KMAP_HIGH_GET 51562306a36Sopenharmony_ci if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) { 51662306a36Sopenharmony_ci kunmap_high(pte_page(ptep_get(&pkmap_page_table[PKMAP_NR(vaddr)]))); 51762306a36Sopenharmony_ci return true; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci#endif 52062306a36Sopenharmony_ci return false; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic pte_t *__kmap_pte; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic pte_t *kmap_get_pte(unsigned long vaddr, int idx) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_KMAP_LOCAL_NON_LINEAR_PTE_ARRAY)) 52862306a36Sopenharmony_ci /* 52962306a36Sopenharmony_ci * Set by the arch if __kmap_pte[-idx] does not produce 53062306a36Sopenharmony_ci * the correct entry. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci return virt_to_kpte(vaddr); 53362306a36Sopenharmony_ci if (!__kmap_pte) 53462306a36Sopenharmony_ci __kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN)); 53562306a36Sopenharmony_ci return &__kmap_pte[-idx]; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_civoid *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci pte_t pteval, *kmap_pte; 54162306a36Sopenharmony_ci unsigned long vaddr; 54262306a36Sopenharmony_ci int idx; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* 54562306a36Sopenharmony_ci * Disable migration so resulting virtual address is stable 54662306a36Sopenharmony_ci * across preemption. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci migrate_disable(); 54962306a36Sopenharmony_ci preempt_disable(); 55062306a36Sopenharmony_ci idx = arch_kmap_local_map_idx(kmap_local_idx_push(), pfn); 55162306a36Sopenharmony_ci vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 55262306a36Sopenharmony_ci kmap_pte = kmap_get_pte(vaddr, idx); 55362306a36Sopenharmony_ci BUG_ON(!pte_none(ptep_get(kmap_pte))); 55462306a36Sopenharmony_ci pteval = pfn_pte(pfn, prot); 55562306a36Sopenharmony_ci arch_kmap_local_set_pte(&init_mm, vaddr, kmap_pte, pteval); 55662306a36Sopenharmony_ci arch_kmap_local_post_map(vaddr, pteval); 55762306a36Sopenharmony_ci current->kmap_ctrl.pteval[kmap_local_idx()] = pteval; 55862306a36Sopenharmony_ci preempt_enable(); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return (void *)vaddr; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__kmap_local_pfn_prot); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_civoid *__kmap_local_page_prot(struct page *page, pgprot_t prot) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci void *kmap; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci * To broaden the usage of the actual kmap_local() machinery always map 57062306a36Sopenharmony_ci * pages when debugging is enabled and the architecture has no problems 57162306a36Sopenharmony_ci * with alias mappings. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) && !PageHighMem(page)) 57462306a36Sopenharmony_ci return page_address(page); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* Try kmap_high_get() if architecture has it enabled */ 57762306a36Sopenharmony_ci kmap = arch_kmap_local_high_get(page); 57862306a36Sopenharmony_ci if (kmap) 57962306a36Sopenharmony_ci return kmap; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return __kmap_local_pfn_prot(page_to_pfn(page), prot); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ciEXPORT_SYMBOL(__kmap_local_page_prot); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_civoid kunmap_local_indexed(const void *vaddr) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci unsigned long addr = (unsigned long) vaddr & PAGE_MASK; 58862306a36Sopenharmony_ci pte_t *kmap_pte; 58962306a36Sopenharmony_ci int idx; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (addr < __fix_to_virt(FIX_KMAP_END) || 59262306a36Sopenharmony_ci addr > __fix_to_virt(FIX_KMAP_BEGIN)) { 59362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP)) { 59462306a36Sopenharmony_ci /* This _should_ never happen! See above. */ 59562306a36Sopenharmony_ci WARN_ON_ONCE(1); 59662306a36Sopenharmony_ci return; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * Handle mappings which were obtained by kmap_high_get() 60062306a36Sopenharmony_ci * first as the virtual address of such mappings is below 60162306a36Sopenharmony_ci * PAGE_OFFSET. Warn for all other addresses which are in 60262306a36Sopenharmony_ci * the user space part of the virtual address space. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci if (!kmap_high_unmap_local(addr)) 60562306a36Sopenharmony_ci WARN_ON_ONCE(addr < PAGE_OFFSET); 60662306a36Sopenharmony_ci return; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci preempt_disable(); 61062306a36Sopenharmony_ci idx = arch_kmap_local_unmap_idx(kmap_local_idx(), addr); 61162306a36Sopenharmony_ci WARN_ON_ONCE(addr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci kmap_pte = kmap_get_pte(addr, idx); 61462306a36Sopenharmony_ci arch_kmap_local_pre_unmap(addr); 61562306a36Sopenharmony_ci pte_clear(&init_mm, addr, kmap_pte); 61662306a36Sopenharmony_ci arch_kmap_local_post_unmap(addr); 61762306a36Sopenharmony_ci current->kmap_ctrl.pteval[kmap_local_idx()] = __pte(0); 61862306a36Sopenharmony_ci kmap_local_idx_pop(); 61962306a36Sopenharmony_ci preempt_enable(); 62062306a36Sopenharmony_ci migrate_enable(); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ciEXPORT_SYMBOL(kunmap_local_indexed); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/* 62562306a36Sopenharmony_ci * Invoked before switch_to(). This is safe even when during or after 62662306a36Sopenharmony_ci * clearing the maps an interrupt which needs a kmap_local happens because 62762306a36Sopenharmony_ci * the task::kmap_ctrl.idx is not modified by the unmapping code so a 62862306a36Sopenharmony_ci * nested kmap_local will use the next unused index and restore the index 62962306a36Sopenharmony_ci * on unmap. The already cleared kmaps of the outgoing task are irrelevant 63062306a36Sopenharmony_ci * because the interrupt context does not know about them. The same applies 63162306a36Sopenharmony_ci * when scheduling back in for an interrupt which happens before the 63262306a36Sopenharmony_ci * restore is complete. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_civoid __kmap_local_sched_out(void) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct task_struct *tsk = current; 63762306a36Sopenharmony_ci pte_t *kmap_pte; 63862306a36Sopenharmony_ci int i; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Clear kmaps */ 64162306a36Sopenharmony_ci for (i = 0; i < tsk->kmap_ctrl.idx; i++) { 64262306a36Sopenharmony_ci pte_t pteval = tsk->kmap_ctrl.pteval[i]; 64362306a36Sopenharmony_ci unsigned long addr; 64462306a36Sopenharmony_ci int idx; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* With debug all even slots are unmapped and act as guard */ 64762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL) && !(i & 0x01)) { 64862306a36Sopenharmony_ci WARN_ON_ONCE(pte_val(pteval) != 0); 64962306a36Sopenharmony_ci continue; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci if (WARN_ON_ONCE(pte_none(pteval))) 65262306a36Sopenharmony_ci continue; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* 65562306a36Sopenharmony_ci * This is a horrible hack for XTENSA to calculate the 65662306a36Sopenharmony_ci * coloured PTE index. Uses the PFN encoded into the pteval 65762306a36Sopenharmony_ci * and the map index calculation because the actual mapped 65862306a36Sopenharmony_ci * virtual address is not stored in task::kmap_ctrl. 65962306a36Sopenharmony_ci * For any sane architecture this is optimized out. 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci idx = arch_kmap_local_map_idx(i, pte_pfn(pteval)); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci addr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 66462306a36Sopenharmony_ci kmap_pte = kmap_get_pte(addr, idx); 66562306a36Sopenharmony_ci arch_kmap_local_pre_unmap(addr); 66662306a36Sopenharmony_ci pte_clear(&init_mm, addr, kmap_pte); 66762306a36Sopenharmony_ci arch_kmap_local_post_unmap(addr); 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_civoid __kmap_local_sched_in(void) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct task_struct *tsk = current; 67462306a36Sopenharmony_ci pte_t *kmap_pte; 67562306a36Sopenharmony_ci int i; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Restore kmaps */ 67862306a36Sopenharmony_ci for (i = 0; i < tsk->kmap_ctrl.idx; i++) { 67962306a36Sopenharmony_ci pte_t pteval = tsk->kmap_ctrl.pteval[i]; 68062306a36Sopenharmony_ci unsigned long addr; 68162306a36Sopenharmony_ci int idx; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* With debug all even slots are unmapped and act as guard */ 68462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL) && !(i & 0x01)) { 68562306a36Sopenharmony_ci WARN_ON_ONCE(pte_val(pteval) != 0); 68662306a36Sopenharmony_ci continue; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci if (WARN_ON_ONCE(pte_none(pteval))) 68962306a36Sopenharmony_ci continue; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* See comment in __kmap_local_sched_out() */ 69262306a36Sopenharmony_ci idx = arch_kmap_local_map_idx(i, pte_pfn(pteval)); 69362306a36Sopenharmony_ci addr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 69462306a36Sopenharmony_ci kmap_pte = kmap_get_pte(addr, idx); 69562306a36Sopenharmony_ci set_pte_at(&init_mm, addr, kmap_pte, pteval); 69662306a36Sopenharmony_ci arch_kmap_local_post_map(addr, pteval); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_civoid kmap_local_fork(struct task_struct *tsk) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci if (WARN_ON_ONCE(tsk->kmap_ctrl.idx)) 70362306a36Sopenharmony_ci memset(&tsk->kmap_ctrl, 0, sizeof(tsk->kmap_ctrl)); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci#endif 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci#if defined(HASHED_PAGE_VIRTUAL) 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci#define PA_HASH_ORDER 7 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/* 71362306a36Sopenharmony_ci * Describes one page->virtual association 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_cistruct page_address_map { 71662306a36Sopenharmony_ci struct page *page; 71762306a36Sopenharmony_ci void *virtual; 71862306a36Sopenharmony_ci struct list_head list; 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic struct page_address_map page_address_maps[LAST_PKMAP]; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci/* 72462306a36Sopenharmony_ci * Hash table bucket 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_cistatic struct page_address_slot { 72762306a36Sopenharmony_ci struct list_head lh; /* List of page_address_maps */ 72862306a36Sopenharmony_ci spinlock_t lock; /* Protect this bucket's list */ 72962306a36Sopenharmony_ci} ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER]; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic struct page_address_slot *page_slot(const struct page *page) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)]; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci/** 73762306a36Sopenharmony_ci * page_address - get the mapped virtual address of a page 73862306a36Sopenharmony_ci * @page: &struct page to get the virtual address of 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * Returns the page's virtual address. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_civoid *page_address(const struct page *page) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci unsigned long flags; 74562306a36Sopenharmony_ci void *ret; 74662306a36Sopenharmony_ci struct page_address_slot *pas; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!PageHighMem(page)) 74962306a36Sopenharmony_ci return lowmem_page_address(page); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci pas = page_slot(page); 75262306a36Sopenharmony_ci ret = NULL; 75362306a36Sopenharmony_ci spin_lock_irqsave(&pas->lock, flags); 75462306a36Sopenharmony_ci if (!list_empty(&pas->lh)) { 75562306a36Sopenharmony_ci struct page_address_map *pam; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci list_for_each_entry(pam, &pas->lh, list) { 75862306a36Sopenharmony_ci if (pam->page == page) { 75962306a36Sopenharmony_ci ret = pam->virtual; 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 76662306a36Sopenharmony_ci return ret; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ciEXPORT_SYMBOL(page_address); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci/** 77162306a36Sopenharmony_ci * set_page_address - set a page's virtual address 77262306a36Sopenharmony_ci * @page: &struct page to set 77362306a36Sopenharmony_ci * @virtual: virtual address to use 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_civoid set_page_address(struct page *page, void *virtual) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci unsigned long flags; 77862306a36Sopenharmony_ci struct page_address_slot *pas; 77962306a36Sopenharmony_ci struct page_address_map *pam; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci BUG_ON(!PageHighMem(page)); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci pas = page_slot(page); 78462306a36Sopenharmony_ci if (virtual) { /* Add */ 78562306a36Sopenharmony_ci pam = &page_address_maps[PKMAP_NR((unsigned long)virtual)]; 78662306a36Sopenharmony_ci pam->page = page; 78762306a36Sopenharmony_ci pam->virtual = virtual; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci spin_lock_irqsave(&pas->lock, flags); 79062306a36Sopenharmony_ci list_add_tail(&pam->list, &pas->lh); 79162306a36Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 79262306a36Sopenharmony_ci } else { /* Remove */ 79362306a36Sopenharmony_ci spin_lock_irqsave(&pas->lock, flags); 79462306a36Sopenharmony_ci list_for_each_entry(pam, &pas->lh, list) { 79562306a36Sopenharmony_ci if (pam->page == page) { 79662306a36Sopenharmony_ci list_del(&pam->list); 79762306a36Sopenharmony_ci break; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_civoid __init page_address_init(void) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci int i; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) { 81162306a36Sopenharmony_ci INIT_LIST_HEAD(&page_address_htable[i].lh); 81262306a36Sopenharmony_ci spin_lock_init(&page_address_htable[i].lock); 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci#endif /* defined(HASHED_PAGE_VIRTUAL) */ 817