~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/s390/mm/vmem.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  *    Copyright IBM Corp. 2006
  4  */
  5 
  6 #include <linux/memory_hotplug.h>
  7 #include <linux/memblock.h>
  8 #include <linux/pfn.h>
  9 #include <linux/mm.h>
 10 #include <linux/init.h>
 11 #include <linux/list.h>
 12 #include <linux/hugetlb.h>
 13 #include <linux/slab.h>
 14 #include <linux/sort.h>
 15 #include <asm/page-states.h>
 16 #include <asm/abs_lowcore.h>
 17 #include <asm/cacheflush.h>
 18 #include <asm/maccess.h>
 19 #include <asm/nospec-branch.h>
 20 #include <asm/ctlreg.h>
 21 #include <asm/pgalloc.h>
 22 #include <asm/setup.h>
 23 #include <asm/tlbflush.h>
 24 #include <asm/sections.h>
 25 #include <asm/set_memory.h>
 26 #include <asm/physmem_info.h>
 27 
 28 static DEFINE_MUTEX(vmem_mutex);
 29 
 30 static void __ref *vmem_alloc_pages(unsigned int order)
 31 {
 32         unsigned long size = PAGE_SIZE << order;
 33 
 34         if (slab_is_available())
 35                 return (void *)__get_free_pages(GFP_KERNEL, order);
 36         return memblock_alloc(size, size);
 37 }
 38 
 39 static void vmem_free_pages(unsigned long addr, int order, struct vmem_altmap *altmap)
 40 {
 41         if (altmap) {
 42                 vmem_altmap_free(altmap, 1 << order);
 43                 return;
 44         }
 45         /* We don't expect boot memory to be removed ever. */
 46         if (!slab_is_available() ||
 47             WARN_ON_ONCE(PageReserved(virt_to_page((void *)addr))))
 48                 return;
 49         free_pages(addr, order);
 50 }
 51 
 52 void *vmem_crst_alloc(unsigned long val)
 53 {
 54         unsigned long *table;
 55 
 56         table = vmem_alloc_pages(CRST_ALLOC_ORDER);
 57         if (!table)
 58                 return NULL;
 59         crst_table_init(table, val);
 60         __arch_set_page_dat(table, 1UL << CRST_ALLOC_ORDER);
 61         return table;
 62 }
 63 
 64 pte_t __ref *vmem_pte_alloc(void)
 65 {
 66         unsigned long size = PTRS_PER_PTE * sizeof(pte_t);
 67         pte_t *pte;
 68 
 69         if (slab_is_available())
 70                 pte = (pte_t *) page_table_alloc(&init_mm);
 71         else
 72                 pte = (pte_t *) memblock_alloc(size, size);
 73         if (!pte)
 74                 return NULL;
 75         memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE);
 76         __arch_set_page_dat(pte, 1);
 77         return pte;
 78 }
 79 
 80 static void vmem_pte_free(unsigned long *table)
 81 {
 82         /* We don't expect boot memory to be removed ever. */
 83         if (!slab_is_available() ||
 84             WARN_ON_ONCE(PageReserved(virt_to_page(table))))
 85                 return;
 86         page_table_free(&init_mm, table);
 87 }
 88 
 89 #define PAGE_UNUSED 0xFD
 90 
 91 /*
 92  * The unused vmemmap range, which was not yet memset(PAGE_UNUSED) ranges
 93  * from unused_sub_pmd_start to next PMD_SIZE boundary.
 94  */
 95 static unsigned long unused_sub_pmd_start;
 96 
 97 static void vmemmap_flush_unused_sub_pmd(void)
 98 {
 99         if (!unused_sub_pmd_start)
100                 return;
101         memset((void *)unused_sub_pmd_start, PAGE_UNUSED,
102                ALIGN(unused_sub_pmd_start, PMD_SIZE) - unused_sub_pmd_start);
103         unused_sub_pmd_start = 0;
104 }
105 
106 static void vmemmap_mark_sub_pmd_used(unsigned long start, unsigned long end)
107 {
108         /*
109          * As we expect to add in the same granularity as we remove, it's
110          * sufficient to mark only some piece used to block the memmap page from
111          * getting removed (just in case the memmap never gets initialized,
112          * e.g., because the memory block never gets onlined).
113          */
114         memset((void *)start, 0, sizeof(struct page));
115 }
116 
117 static void vmemmap_use_sub_pmd(unsigned long start, unsigned long end)
118 {
119         /*
120          * We only optimize if the new used range directly follows the
121          * previously unused range (esp., when populating consecutive sections).
122          */
123         if (unused_sub_pmd_start == start) {
124                 unused_sub_pmd_start = end;
125                 if (likely(IS_ALIGNED(unused_sub_pmd_start, PMD_SIZE)))
126                         unused_sub_pmd_start = 0;
127                 return;
128         }
129         vmemmap_flush_unused_sub_pmd();
130         vmemmap_mark_sub_pmd_used(start, end);
131 }
132 
133 static void vmemmap_use_new_sub_pmd(unsigned long start, unsigned long end)
134 {
135         unsigned long page = ALIGN_DOWN(start, PMD_SIZE);
136 
137         vmemmap_flush_unused_sub_pmd();
138 
139         /* Could be our memmap page is filled with PAGE_UNUSED already ... */
140         vmemmap_mark_sub_pmd_used(start, end);
141 
142         /* Mark the unused parts of the new memmap page PAGE_UNUSED. */
143         if (!IS_ALIGNED(start, PMD_SIZE))
144                 memset((void *)page, PAGE_UNUSED, start - page);
145         /*
146          * We want to avoid memset(PAGE_UNUSED) when populating the vmemmap of
147          * consecutive sections. Remember for the last added PMD the last
148          * unused range in the populated PMD.
149          */
150         if (!IS_ALIGNED(end, PMD_SIZE))
151                 unused_sub_pmd_start = end;
152 }
153 
154 /* Returns true if the PMD is completely unused and can be freed. */
155 static bool vmemmap_unuse_sub_pmd(unsigned long start, unsigned long end)
156 {
157         unsigned long page = ALIGN_DOWN(start, PMD_SIZE);
158 
159         vmemmap_flush_unused_sub_pmd();
160         memset((void *)start, PAGE_UNUSED, end - start);
161         return !memchr_inv((void *)page, PAGE_UNUSED, PMD_SIZE);
162 }
163 
164 /* __ref: we'll only call vmemmap_alloc_block() via vmemmap_populate() */
165 static int __ref modify_pte_table(pmd_t *pmd, unsigned long addr,
166                                   unsigned long end, bool add, bool direct,
167                                   struct vmem_altmap *altmap)
168 {
169         unsigned long prot, pages = 0;
170         int ret = -ENOMEM;
171         pte_t *pte;
172 
173         prot = pgprot_val(PAGE_KERNEL);
174         if (!MACHINE_HAS_NX)
175                 prot &= ~_PAGE_NOEXEC;
176 
177         pte = pte_offset_kernel(pmd, addr);
178         for (; addr < end; addr += PAGE_SIZE, pte++) {
179                 if (!add) {
180                         if (pte_none(*pte))
181                                 continue;
182                         if (!direct)
183                                 vmem_free_pages((unsigned long)pfn_to_virt(pte_pfn(*pte)), get_order(PAGE_SIZE), altmap);
184                         pte_clear(&init_mm, addr, pte);
185                 } else if (pte_none(*pte)) {
186                         if (!direct) {
187                                 void *new_page = vmemmap_alloc_block_buf(PAGE_SIZE, NUMA_NO_NODE, altmap);
188 
189                                 if (!new_page)
190                                         goto out;
191                                 set_pte(pte, __pte(__pa(new_page) | prot));
192                         } else {
193                                 set_pte(pte, __pte(__pa(addr) | prot));
194                         }
195                 } else {
196                         continue;
197                 }
198                 pages++;
199         }
200         ret = 0;
201 out:
202         if (direct)
203                 update_page_count(PG_DIRECT_MAP_4K, add ? pages : -pages);
204         return ret;
205 }
206 
207 static void try_free_pte_table(pmd_t *pmd, unsigned long start)
208 {
209         pte_t *pte;
210         int i;
211 
212         /* We can safely assume this is fully in 1:1 mapping & vmemmap area */
213         pte = pte_offset_kernel(pmd, start);
214         for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
215                 if (!pte_none(*pte))
216                         return;
217         }
218         vmem_pte_free((unsigned long *) pmd_deref(*pmd));
219         pmd_clear(pmd);
220 }
221 
222 /* __ref: we'll only call vmemmap_alloc_block() via vmemmap_populate() */
223 static int __ref modify_pmd_table(pud_t *pud, unsigned long addr,
224                                   unsigned long end, bool add, bool direct,
225                                   struct vmem_altmap *altmap)
226 {
227         unsigned long next, prot, pages = 0;
228         int ret = -ENOMEM;
229         pmd_t *pmd;
230         pte_t *pte;
231 
232         prot = pgprot_val(SEGMENT_KERNEL);
233         if (!MACHINE_HAS_NX)
234                 prot &= ~_SEGMENT_ENTRY_NOEXEC;
235 
236         pmd = pmd_offset(pud, addr);
237         for (; addr < end; addr = next, pmd++) {
238                 next = pmd_addr_end(addr, end);
239                 if (!add) {
240                         if (pmd_none(*pmd))
241                                 continue;
242                         if (pmd_leaf(*pmd)) {
243                                 if (IS_ALIGNED(addr, PMD_SIZE) &&
244                                     IS_ALIGNED(next, PMD_SIZE)) {
245                                         if (!direct)
246                                                 vmem_free_pages(pmd_deref(*pmd), get_order(PMD_SIZE), altmap);
247                                         pmd_clear(pmd);
248                                         pages++;
249                                 } else if (!direct && vmemmap_unuse_sub_pmd(addr, next)) {
250                                         vmem_free_pages(pmd_deref(*pmd), get_order(PMD_SIZE), altmap);
251                                         pmd_clear(pmd);
252                                 }
253                                 continue;
254                         }
255                 } else if (pmd_none(*pmd)) {
256                         if (IS_ALIGNED(addr, PMD_SIZE) &&
257                             IS_ALIGNED(next, PMD_SIZE) &&
258                             MACHINE_HAS_EDAT1 && direct &&
259                             !debug_pagealloc_enabled()) {
260                                 set_pmd(pmd, __pmd(__pa(addr) | prot));
261                                 pages++;
262                                 continue;
263                         } else if (!direct && MACHINE_HAS_EDAT1) {
264                                 void *new_page;
265 
266                                 /*
267                                  * Use 1MB frames for vmemmap if available. We
268                                  * always use large frames even if they are only
269                                  * partially used. Otherwise we would have also
270                                  * page tables since vmemmap_populate gets
271                                  * called for each section separately.
272                                  */
273                                 new_page = vmemmap_alloc_block_buf(PMD_SIZE, NUMA_NO_NODE, altmap);
274                                 if (new_page) {
275                                         set_pmd(pmd, __pmd(__pa(new_page) | prot));
276                                         if (!IS_ALIGNED(addr, PMD_SIZE) ||
277                                             !IS_ALIGNED(next, PMD_SIZE)) {
278                                                 vmemmap_use_new_sub_pmd(addr, next);
279                                         }
280                                         continue;
281                                 }
282                         }
283                         pte = vmem_pte_alloc();
284                         if (!pte)
285                                 goto out;
286                         pmd_populate(&init_mm, pmd, pte);
287                 } else if (pmd_leaf(*pmd)) {
288                         if (!direct)
289                                 vmemmap_use_sub_pmd(addr, next);
290                         continue;
291                 }
292                 ret = modify_pte_table(pmd, addr, next, add, direct, altmap);
293                 if (ret)
294                         goto out;
295                 if (!add)
296                         try_free_pte_table(pmd, addr & PMD_MASK);
297         }
298         ret = 0;
299 out:
300         if (direct)
301                 update_page_count(PG_DIRECT_MAP_1M, add ? pages : -pages);
302         return ret;
303 }
304 
305 static void try_free_pmd_table(pud_t *pud, unsigned long start)
306 {
307         pmd_t *pmd;
308         int i;
309 
310         pmd = pmd_offset(pud, start);
311         for (i = 0; i < PTRS_PER_PMD; i++, pmd++)
312                 if (!pmd_none(*pmd))
313                         return;
314         vmem_free_pages(pud_deref(*pud), CRST_ALLOC_ORDER, NULL);
315         pud_clear(pud);
316 }
317 
318 static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end,
319                             bool add, bool direct, struct vmem_altmap *altmap)
320 {
321         unsigned long next, prot, pages = 0;
322         int ret = -ENOMEM;
323         pud_t *pud;
324         pmd_t *pmd;
325 
326         prot = pgprot_val(REGION3_KERNEL);
327         if (!MACHINE_HAS_NX)
328                 prot &= ~_REGION_ENTRY_NOEXEC;
329         pud = pud_offset(p4d, addr);
330         for (; addr < end; addr = next, pud++) {
331                 next = pud_addr_end(addr, end);
332                 if (!add) {
333                         if (pud_none(*pud))
334                                 continue;
335                         if (pud_leaf(*pud)) {
336                                 if (IS_ALIGNED(addr, PUD_SIZE) &&
337                                     IS_ALIGNED(next, PUD_SIZE)) {
338                                         pud_clear(pud);
339                                         pages++;
340                                 }
341                                 continue;
342                         }
343                 } else if (pud_none(*pud)) {
344                         if (IS_ALIGNED(addr, PUD_SIZE) &&
345                             IS_ALIGNED(next, PUD_SIZE) &&
346                             MACHINE_HAS_EDAT2 && direct &&
347                             !debug_pagealloc_enabled()) {
348                                 set_pud(pud, __pud(__pa(addr) | prot));
349                                 pages++;
350                                 continue;
351                         }
352                         pmd = vmem_crst_alloc(_SEGMENT_ENTRY_EMPTY);
353                         if (!pmd)
354                                 goto out;
355                         pud_populate(&init_mm, pud, pmd);
356                 } else if (pud_leaf(*pud)) {
357                         continue;
358                 }
359                 ret = modify_pmd_table(pud, addr, next, add, direct, altmap);
360                 if (ret)
361                         goto out;
362                 if (!add)
363                         try_free_pmd_table(pud, addr & PUD_MASK);
364         }
365         ret = 0;
366 out:
367         if (direct)
368                 update_page_count(PG_DIRECT_MAP_2G, add ? pages : -pages);
369         return ret;
370 }
371 
372 static void try_free_pud_table(p4d_t *p4d, unsigned long start)
373 {
374         pud_t *pud;
375         int i;
376 
377         pud = pud_offset(p4d, start);
378         for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
379                 if (!pud_none(*pud))
380                         return;
381         }
382         vmem_free_pages(p4d_deref(*p4d), CRST_ALLOC_ORDER, NULL);
383         p4d_clear(p4d);
384 }
385 
386 static int modify_p4d_table(pgd_t *pgd, unsigned long addr, unsigned long end,
387                             bool add, bool direct, struct vmem_altmap *altmap)
388 {
389         unsigned long next;
390         int ret = -ENOMEM;
391         p4d_t *p4d;
392         pud_t *pud;
393 
394         p4d = p4d_offset(pgd, addr);
395         for (; addr < end; addr = next, p4d++) {
396                 next = p4d_addr_end(addr, end);
397                 if (!add) {
398                         if (p4d_none(*p4d))
399                                 continue;
400                 } else if (p4d_none(*p4d)) {
401                         pud = vmem_crst_alloc(_REGION3_ENTRY_EMPTY);
402                         if (!pud)
403                                 goto out;
404                         p4d_populate(&init_mm, p4d, pud);
405                 }
406                 ret = modify_pud_table(p4d, addr, next, add, direct, altmap);
407                 if (ret)
408                         goto out;
409                 if (!add)
410                         try_free_pud_table(p4d, addr & P4D_MASK);
411         }
412         ret = 0;
413 out:
414         return ret;
415 }
416 
417 static void try_free_p4d_table(pgd_t *pgd, unsigned long start)
418 {
419         p4d_t *p4d;
420         int i;
421 
422         p4d = p4d_offset(pgd, start);
423         for (i = 0; i < PTRS_PER_P4D; i++, p4d++) {
424                 if (!p4d_none(*p4d))
425                         return;
426         }
427         vmem_free_pages(pgd_deref(*pgd), CRST_ALLOC_ORDER, NULL);
428         pgd_clear(pgd);
429 }
430 
431 static int modify_pagetable(unsigned long start, unsigned long end, bool add,
432                             bool direct, struct vmem_altmap *altmap)
433 {
434         unsigned long addr, next;
435         int ret = -ENOMEM;
436         pgd_t *pgd;
437         p4d_t *p4d;
438 
439         if (WARN_ON_ONCE(!PAGE_ALIGNED(start | end)))
440                 return -EINVAL;
441         /* Don't mess with any tables not fully in 1:1 mapping & vmemmap area */
442         if (WARN_ON_ONCE(end > __abs_lowcore))
443                 return -EINVAL;
444         for (addr = start; addr < end; addr = next) {
445                 next = pgd_addr_end(addr, end);
446                 pgd = pgd_offset_k(addr);
447 
448                 if (!add) {
449                         if (pgd_none(*pgd))
450                                 continue;
451                 } else if (pgd_none(*pgd)) {
452                         p4d = vmem_crst_alloc(_REGION2_ENTRY_EMPTY);
453                         if (!p4d)
454                                 goto out;
455                         pgd_populate(&init_mm, pgd, p4d);
456                 }
457                 ret = modify_p4d_table(pgd, addr, next, add, direct, altmap);
458                 if (ret)
459                         goto out;
460                 if (!add)
461                         try_free_p4d_table(pgd, addr & PGDIR_MASK);
462         }
463         ret = 0;
464 out:
465         if (!add)
466                 flush_tlb_kernel_range(start, end);
467         return ret;
468 }
469 
470 static int add_pagetable(unsigned long start, unsigned long end, bool direct,
471                          struct vmem_altmap *altmap)
472 {
473         return modify_pagetable(start, end, true, direct, altmap);
474 }
475 
476 static int remove_pagetable(unsigned long start, unsigned long end, bool direct,
477                             struct vmem_altmap *altmap)
478 {
479         return modify_pagetable(start, end, false, direct, altmap);
480 }
481 
482 /*
483  * Add a physical memory range to the 1:1 mapping.
484  */
485 static int vmem_add_range(unsigned long start, unsigned long size)
486 {
487         start = (unsigned long)__va(start);
488         return add_pagetable(start, start + size, true, NULL);
489 }
490 
491 /*
492  * Remove a physical memory range from the 1:1 mapping.
493  */
494 static void vmem_remove_range(unsigned long start, unsigned long size)
495 {
496         start = (unsigned long)__va(start);
497         remove_pagetable(start, start + size, true, NULL);
498 }
499 
500 /*
501  * Add a backed mem_map array to the virtual mem_map array.
502  */
503 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
504                                struct vmem_altmap *altmap)
505 {
506         int ret;
507 
508         mutex_lock(&vmem_mutex);
509         /* We don't care about the node, just use NUMA_NO_NODE on allocations */
510         ret = add_pagetable(start, end, false, altmap);
511         if (ret)
512                 remove_pagetable(start, end, false, altmap);
513         mutex_unlock(&vmem_mutex);
514         return ret;
515 }
516 
517 #ifdef CONFIG_MEMORY_HOTPLUG
518 
519 void vmemmap_free(unsigned long start, unsigned long end,
520                   struct vmem_altmap *altmap)
521 {
522         mutex_lock(&vmem_mutex);
523         remove_pagetable(start, end, false, altmap);
524         mutex_unlock(&vmem_mutex);
525 }
526 
527 #endif
528 
529 void vmem_remove_mapping(unsigned long start, unsigned long size)
530 {
531         mutex_lock(&vmem_mutex);
532         vmem_remove_range(start, size);
533         mutex_unlock(&vmem_mutex);
534 }
535 
536 struct range arch_get_mappable_range(void)
537 {
538         struct range mhp_range;
539 
540         mhp_range.start = 0;
541         mhp_range.end = max_mappable - 1;
542         return mhp_range;
543 }
544 
545 int vmem_add_mapping(unsigned long start, unsigned long size)
546 {
547         struct range range = arch_get_mappable_range();
548         int ret;
549 
550         if (start < range.start ||
551             start + size > range.end + 1 ||
552             start + size < start)
553                 return -ERANGE;
554 
555         mutex_lock(&vmem_mutex);
556         ret = vmem_add_range(start, size);
557         if (ret)
558                 vmem_remove_range(start, size);
559         mutex_unlock(&vmem_mutex);
560         return ret;
561 }
562 
563 /*
564  * Allocate new or return existing page-table entry, but do not map it
565  * to any physical address. If missing, allocate segment- and region-
566  * table entries along. Meeting a large segment- or region-table entry
567  * while traversing is an error, since the function is expected to be
568  * called against virtual regions reserved for 4KB mappings only.
569  */
570 pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc)
571 {
572         pte_t *ptep = NULL;
573         pgd_t *pgd;
574         p4d_t *p4d;
575         pud_t *pud;
576         pmd_t *pmd;
577         pte_t *pte;
578 
579         pgd = pgd_offset_k(addr);
580         if (pgd_none(*pgd)) {
581                 if (!alloc)
582                         goto out;
583                 p4d = vmem_crst_alloc(_REGION2_ENTRY_EMPTY);
584                 if (!p4d)
585                         goto out;
586                 pgd_populate(&init_mm, pgd, p4d);
587         }
588         p4d = p4d_offset(pgd, addr);
589         if (p4d_none(*p4d)) {
590                 if (!alloc)
591                         goto out;
592                 pud = vmem_crst_alloc(_REGION3_ENTRY_EMPTY);
593                 if (!pud)
594                         goto out;
595                 p4d_populate(&init_mm, p4d, pud);
596         }
597         pud = pud_offset(p4d, addr);
598         if (pud_none(*pud)) {
599                 if (!alloc)
600                         goto out;
601                 pmd = vmem_crst_alloc(_SEGMENT_ENTRY_EMPTY);
602                 if (!pmd)
603                         goto out;
604                 pud_populate(&init_mm, pud, pmd);
605         } else if (WARN_ON_ONCE(pud_leaf(*pud))) {
606                 goto out;
607         }
608         pmd = pmd_offset(pud, addr);
609         if (pmd_none(*pmd)) {
610                 if (!alloc)
611                         goto out;
612                 pte = vmem_pte_alloc();
613                 if (!pte)
614                         goto out;
615                 pmd_populate(&init_mm, pmd, pte);
616         } else if (WARN_ON_ONCE(pmd_leaf(*pmd))) {
617                 goto out;
618         }
619         ptep = pte_offset_kernel(pmd, addr);
620 out:
621         return ptep;
622 }
623 
624 int __vmem_map_4k_page(unsigned long addr, unsigned long phys, pgprot_t prot, bool alloc)
625 {
626         pte_t *ptep, pte;
627 
628         if (!IS_ALIGNED(addr, PAGE_SIZE))
629                 return -EINVAL;
630         ptep = vmem_get_alloc_pte(addr, alloc);
631         if (!ptep)
632                 return -ENOMEM;
633         __ptep_ipte(addr, ptep, 0, 0, IPTE_GLOBAL);
634         pte = mk_pte_phys(phys, prot);
635         set_pte(ptep, pte);
636         return 0;
637 }
638 
639 int vmem_map_4k_page(unsigned long addr, unsigned long phys, pgprot_t prot)
640 {
641         int rc;
642 
643         mutex_lock(&vmem_mutex);
644         rc = __vmem_map_4k_page(addr, phys, prot, true);
645         mutex_unlock(&vmem_mutex);
646         return rc;
647 }
648 
649 void vmem_unmap_4k_page(unsigned long addr)
650 {
651         pte_t *ptep;
652 
653         mutex_lock(&vmem_mutex);
654         ptep = virt_to_kpte(addr);
655         __ptep_ipte(addr, ptep, 0, 0, IPTE_GLOBAL);
656         pte_clear(&init_mm, addr, ptep);
657         mutex_unlock(&vmem_mutex);
658 }
659 
660 void __init vmem_map_init(void)
661 {
662         __set_memory_rox(_stext, _etext);
663         __set_memory_ro(_etext, __end_rodata);
664         __set_memory_rox(__stext_amode31, __etext_amode31);
665         /*
666          * If the BEAR-enhancement facility is not installed the first
667          * prefix page is used to return to the previous context with
668          * an LPSWE instruction and therefore must be executable.
669          */
670         if (!static_key_enabled(&cpu_has_bear))
671                 set_memory_x(0, 1);
672         if (debug_pagealloc_enabled())
673                 __set_memory_4k(__va(0), __va(0) + ident_map_size);
674         pr_info("Write protected kernel read-only data: %luk\n",
675                 (unsigned long)(__end_rodata - _stext) >> 10);
676 }
677 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php