Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/riscv/mm/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 14 kB image not shown  

Quelle  kasan_init.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2019 Andes Technology Corporation

#include <linux/pfn.h>
#include <linux/init_task.h>
#include <linux/kasan.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/fixmap.h>
#include <asm/pgalloc.h>

/*
 * Kasan shadow region must lie at a fixed address across sv39, sv48 and sv57
 * which is right before the kernel.
 *
 * For sv39, the region is aligned on PGDIR_SIZE so we only need to populate
 * the page global directory with kasan_early_shadow_pmd.
 *
 * For sv48 and sv57, the region start is aligned on PGDIR_SIZE whereas the end
 * region is not and then we have to go down to the PUD level.
 */


static pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
static p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss;
static pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss;

static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end)
{
 phys_addr_t phys_addr;
 pte_t *ptep, *p;

 if (pmd_none(pmdp_get(pmd))) {
  p = memblock_alloc_or_panic(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
  set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(p)), PAGE_TABLE));
 }

 ptep = pte_offset_kernel(pmd, vaddr);

 do {
  if (pte_none(ptep_get(ptep))) {
   phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
   set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL));
   memset(__va(phys_addr), KASAN_SHADOW_INIT, PAGE_SIZE);
  }
 } while (ptep++, vaddr += PAGE_SIZE, vaddr != end);
}

static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned long end)
{
 phys_addr_t phys_addr;
 pmd_t *pmdp, *p;
 unsigned long next;

 if (pud_none(pudp_get(pud))) {
  p = memblock_alloc_or_panic(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
  set_pud(pud, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE));
 }

 pmdp = pmd_offset(pud, vaddr);

 do {
  next = pmd_addr_end(vaddr, end);

  if (pmd_none(pmdp_get(pmdp)) && IS_ALIGNED(vaddr, PMD_SIZE) &&
      (next - vaddr) >= PMD_SIZE) {
   phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE);
   if (phys_addr) {
    set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL));
    memset(__va(phys_addr), KASAN_SHADOW_INIT, PMD_SIZE);
    continue;
   }
  }

  kasan_populate_pte(pmdp, vaddr, next);
 } while (pmdp++, vaddr = next, vaddr != end);
}

static void __init kasan_populate_pud(p4d_t *p4d,
          unsigned long vaddr, unsigned long end)
{
 phys_addr_t phys_addr;
 pud_t *pudp, *p;
 unsigned long next;

 if (p4d_none(p4dp_get(p4d))) {
  p = memblock_alloc_or_panic(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE);
  set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE));
 }

 pudp = pud_offset(p4d, vaddr);

 do {
  next = pud_addr_end(vaddr, end);

  if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) &&
      (next - vaddr) >= PUD_SIZE) {
   phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE);
   if (phys_addr) {
    set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL));
    memset(__va(phys_addr), KASAN_SHADOW_INIT, PUD_SIZE);
    continue;
   }
  }

  kasan_populate_pmd(pudp, vaddr, next);
 } while (pudp++, vaddr = next, vaddr != end);
}

static void __init kasan_populate_p4d(pgd_t *pgd,
          unsigned long vaddr, unsigned long end)
{
 phys_addr_t phys_addr;
 p4d_t *p4dp, *p;
 unsigned long next;

 if (pgd_none(pgdp_get(pgd))) {
  p = memblock_alloc_or_panic(PTRS_PER_P4D * sizeof(p4d_t), PAGE_SIZE);
  set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE));
 }

 p4dp = p4d_offset(pgd, vaddr);

 do {
  next = p4d_addr_end(vaddr, end);

  if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) &&
      (next - vaddr) >= P4D_SIZE) {
   phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE);
   if (phys_addr) {
    set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL));
    memset(__va(phys_addr), KASAN_SHADOW_INIT, P4D_SIZE);
    continue;
   }
  }

  kasan_populate_pud(p4dp, vaddr, next);
 } while (p4dp++, vaddr = next, vaddr != end);
}

static void __init kasan_populate_pgd(pgd_t *pgdp,
          unsigned long vaddr, unsigned long end)
{
 phys_addr_t phys_addr;
 unsigned long next;

 do {
  next = pgd_addr_end(vaddr, end);

  if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
      (next - vaddr) >= PGDIR_SIZE) {
   phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE);
   if (phys_addr) {
    set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_KERNEL));
    memset(__va(phys_addr), KASAN_SHADOW_INIT, PGDIR_SIZE);
    continue;
   }
  }

  kasan_populate_p4d(pgdp, vaddr, next);
 } while (pgdp++, vaddr = next, vaddr != end);
}

static void __init kasan_early_clear_pud(p4d_t *p4dp,
      unsigned long vaddr, unsigned long end)
{
 pud_t *pudp, *base_pud;
 unsigned long next;

 if (!pgtable_l4_enabled) {
  pudp = (pud_t *)p4dp;
 } else {
  base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp))));
  pudp = base_pud + pud_index(vaddr);
 }

 do {
  next = pud_addr_end(vaddr, end);

  if (IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) {
   pud_clear(pudp);
   continue;
  }

  BUG();
 } while (pudp++, vaddr = next, vaddr != end);
}

static void __init kasan_early_clear_p4d(pgd_t *pgdp,
      unsigned long vaddr, unsigned long end)
{
 p4d_t *p4dp, *base_p4d;
 unsigned long next;

 if (!pgtable_l5_enabled) {
  p4dp = (p4d_t *)pgdp;
 } else {
  base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp))));
  p4dp = base_p4d + p4d_index(vaddr);
 }

 do {
  next = p4d_addr_end(vaddr, end);

  if (pgtable_l4_enabled && IS_ALIGNED(vaddr, P4D_SIZE) &&
      (next - vaddr) >= P4D_SIZE) {
   p4d_clear(p4dp);
   continue;
  }

  kasan_early_clear_pud(p4dp, vaddr, next);
 } while (p4dp++, vaddr = next, vaddr != end);
}

static void __init kasan_early_clear_pgd(pgd_t *pgdp,
      unsigned long vaddr, unsigned long end)
{
 unsigned long next;

 do {
  next = pgd_addr_end(vaddr, end);

  if (pgtable_l5_enabled && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
      (next - vaddr) >= PGDIR_SIZE) {
   pgd_clear(pgdp);
   continue;
  }

  kasan_early_clear_p4d(pgdp, vaddr, next);
 } while (pgdp++, vaddr = next, vaddr != end);
}

static void __init kasan_early_populate_pud(p4d_t *p4dp,
         unsigned long vaddr,
         unsigned long end)
{
 pud_t *pudp, *base_pud;
 phys_addr_t phys_addr;
 unsigned long next;

 if (!pgtable_l4_enabled) {
  pudp = (pud_t *)p4dp;
 } else {
  base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp))));
  pudp = base_pud + pud_index(vaddr);
 }

 do {
  next = pud_addr_end(vaddr, end);

  if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) &&
      (next - vaddr) >= PUD_SIZE) {
   phys_addr = __pa((uintptr_t)kasan_early_shadow_pmd);
   set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE));
   continue;
  }

  BUG();
 } while (pudp++, vaddr = next, vaddr != end);
}

static void __init kasan_early_populate_p4d(pgd_t *pgdp,
         unsigned long vaddr,
         unsigned long end)
{
 p4d_t *p4dp, *base_p4d;
 phys_addr_t phys_addr;
 unsigned long next;

 /*
 * We can't use pgd_page_vaddr here as it would return a linear
 * mapping address but it is not mapped yet, but when populating
 * early_pg_dir, we need the physical address and when populating
 * swapper_pg_dir, we need the kernel virtual address so use
 * pt_ops facility.
 * Note that this test is then completely equivalent to
 * p4dp = p4d_offset(pgdp, vaddr)
 */

 if (!pgtable_l5_enabled) {
  p4dp = (p4d_t *)pgdp;
 } else {
  base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp))));
  p4dp = base_p4d + p4d_index(vaddr);
 }

 do {
  next = p4d_addr_end(vaddr, end);

  if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) &&
      (next - vaddr) >= P4D_SIZE) {
   phys_addr = __pa((uintptr_t)kasan_early_shadow_pud);
   set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE));
   continue;
  }

  kasan_early_populate_pud(p4dp, vaddr, next);
 } while (p4dp++, vaddr = next, vaddr != end);
}

static void __init kasan_early_populate_pgd(pgd_t *pgdp,
         unsigned long vaddr,
         unsigned long end)
{
 phys_addr_t phys_addr;
 unsigned long next;

 do {
  next = pgd_addr_end(vaddr, end);

  if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
      (next - vaddr) >= PGDIR_SIZE) {
   phys_addr = __pa((uintptr_t)kasan_early_shadow_p4d);
   set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE));
   continue;
  }

  kasan_early_populate_p4d(pgdp, vaddr, next);
 } while (pgdp++, vaddr = next, vaddr != end);
}

asmlinkage void __init kasan_early_init(void)
{
 uintptr_t i;

 BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
  KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));

 for (i = 0; i < PTRS_PER_PTE; ++i)
  set_pte(kasan_early_shadow_pte + i,
   pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL));

 for (i = 0; i < PTRS_PER_PMD; ++i)
  set_pmd(kasan_early_shadow_pmd + i,
   pfn_pmd(PFN_DOWN
    (__pa((uintptr_t)kasan_early_shadow_pte)),
    PAGE_TABLE));

 if (pgtable_l4_enabled) {
  for (i = 0; i < PTRS_PER_PUD; ++i)
   set_pud(kasan_early_shadow_pud + i,
    pfn_pud(PFN_DOWN
     (__pa(((uintptr_t)kasan_early_shadow_pmd))),
     PAGE_TABLE));
 }

 if (pgtable_l5_enabled) {
  for (i = 0; i < PTRS_PER_P4D; ++i)
   set_p4d(kasan_early_shadow_p4d + i,
    pfn_p4d(PFN_DOWN
     (__pa(((uintptr_t)kasan_early_shadow_pud))),
     PAGE_TABLE));
 }

 kasan_early_populate_pgd(early_pg_dir + pgd_index(KASAN_SHADOW_START),
     KASAN_SHADOW_START, KASAN_SHADOW_END);

 local_flush_tlb_all();
}

void __init kasan_swapper_init(void)
{
 kasan_early_populate_pgd(pgd_offset_k(KASAN_SHADOW_START),
     KASAN_SHADOW_START, KASAN_SHADOW_END);

 local_flush_tlb_all();
}

static void __init kasan_populate(void *start, void *end)
{
 unsigned long vaddr = (unsigned long)start & PAGE_MASK;
 unsigned long vend = PAGE_ALIGN((unsigned long)end);

 kasan_populate_pgd(pgd_offset_k(vaddr), vaddr, vend);
}

static void __init kasan_shallow_populate_pud(p4d_t *p4d,
           unsigned long vaddr, unsigned long end)
{
 unsigned long next;
 void *p;
 pud_t *pud_k = pud_offset(p4d, vaddr);

 do {
  next = pud_addr_end(vaddr, end);

  if (pud_none(pudp_get(pud_k))) {
   p = memblock_alloc_or_panic(PAGE_SIZE, PAGE_SIZE);
   set_pud(pud_k, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE));
   continue;
  }

  BUG();
 } while (pud_k++, vaddr = next, vaddr != end);
}

static void __init kasan_shallow_populate_p4d(pgd_t *pgd,
           unsigned long vaddr, unsigned long end)
{
 unsigned long next;
 void *p;
 p4d_t *p4d_k = p4d_offset(pgd, vaddr);

 do {
  next = p4d_addr_end(vaddr, end);

  if (p4d_none(p4dp_get(p4d_k))) {
   p = memblock_alloc_or_panic(PAGE_SIZE, PAGE_SIZE);
   set_p4d(p4d_k, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE));
   continue;
  }

  kasan_shallow_populate_pud(p4d_k, vaddr, end);
 } while (p4d_k++, vaddr = next, vaddr != end);
}

static void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long end)
{
 unsigned long next;
 void *p;
 pgd_t *pgd_k = pgd_offset_k(vaddr);

 do {
  next = pgd_addr_end(vaddr, end);

  if (pgd_none(pgdp_get(pgd_k))) {
   p = memblock_alloc_or_panic(PAGE_SIZE, PAGE_SIZE);
   set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE));
   continue;
  }

  kasan_shallow_populate_p4d(pgd_k, vaddr, next);
 } while (pgd_k++, vaddr = next, vaddr != end);
}

static void __init kasan_shallow_populate(void *start, void *end)
{
 unsigned long vaddr = (unsigned long)start & PAGE_MASK;
 unsigned long vend = PAGE_ALIGN((unsigned long)end);

 kasan_shallow_populate_pgd(vaddr, vend);
}

#ifdef CONFIG_KASAN_VMALLOC
void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)
{
 kasan_populate(kasan_mem_to_shadow(start),
         kasan_mem_to_shadow(start + size));
}
#endif

static void __init create_tmp_mapping(void)
{
 void *ptr;
 p4d_t *base_p4d;

 /*
 * We need to clean the early mapping: this is hard to achieve "in-place",
 * so install a temporary mapping like arm64 and x86 do.
 */

 memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(pgd_t) * PTRS_PER_PGD);

 /* Copy the last p4d since it is shared with the kernel mapping. */
 if (pgtable_l5_enabled) {
  ptr = (p4d_t *)pgd_page_vaddr(pgdp_get(pgd_offset_k(KASAN_SHADOW_END)));
  memcpy(tmp_p4d, ptr, sizeof(p4d_t) * PTRS_PER_P4D);
  set_pgd(&tmp_pg_dir[pgd_index(KASAN_SHADOW_END)],
   pfn_pgd(PFN_DOWN(__pa(tmp_p4d)), PAGE_TABLE));
  base_p4d = tmp_p4d;
 } else {
  base_p4d = (p4d_t *)tmp_pg_dir;
 }

 /* Copy the last pud since it is shared with the kernel mapping. */
 if (pgtable_l4_enabled) {
  ptr = (pud_t *)p4d_page_vaddr(p4dp_get(base_p4d + p4d_index(KASAN_SHADOW_END)));
  memcpy(tmp_pud, ptr, sizeof(pud_t) * PTRS_PER_PUD);
  set_p4d(&base_p4d[p4d_index(KASAN_SHADOW_END)],
   pfn_p4d(PFN_DOWN(__pa(tmp_pud)), PAGE_TABLE));
 }
}

void __init kasan_init(void)
{
 phys_addr_t p_start, p_end;
 u64 i;

 create_tmp_mapping();
 csr_write(CSR_SATP, PFN_DOWN(__pa(tmp_pg_dir)) | satp_mode);

 kasan_early_clear_pgd(pgd_offset_k(KASAN_SHADOW_START),
         KASAN_SHADOW_START, KASAN_SHADOW_END);

 kasan_populate_early_shadow((void *)kasan_mem_to_shadow((void *)FIXADDR_START),
        (void *)kasan_mem_to_shadow((void *)VMALLOC_START));

 if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) {
  kasan_shallow_populate(
   (void *)kasan_mem_to_shadow((void *)VMALLOC_START),
   (void *)kasan_mem_to_shadow((void *)VMALLOC_END));
  /* Shallow populate modules and BPF which are vmalloc-allocated */
  kasan_shallow_populate(
   (void *)kasan_mem_to_shadow((void *)MODULES_VADDR),
   (void *)kasan_mem_to_shadow((void *)MODULES_END));
 } else {
  kasan_populate_early_shadow((void *)kasan_mem_to_shadow((void *)VMALLOC_START),
         (void *)kasan_mem_to_shadow((void *)VMALLOC_END));
 }

 /* Populate the linear mapping */
 for_each_mem_range(i, &p_start, &p_end) {
  void *start = (void *)__va(p_start);
  void *end = (void *)__va(p_end);

  if (start >= end)
   break;

  kasan_populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end));
 }

 /* Populate kernel */
 kasan_populate(kasan_mem_to_shadow((const void *)MODULES_END),
         kasan_mem_to_shadow((const void *)MODULES_VADDR + SZ_2G));

 for (i = 0; i < PTRS_PER_PTE; i++)
  set_pte(&kasan_early_shadow_pte[i],
   mk_pte(virt_to_page(kasan_early_shadow_page),
          __pgprot(_PAGE_PRESENT | _PAGE_READ |
     _PAGE_ACCESSED)));

 memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
 init_task.kasan_depth = 0;

 csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | satp_mode);
 local_flush_tlb_all();
}

Messung V0.5
C=99 H=74 G=87

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.