LCOV - code coverage report
Current view: top level - arch/x86/realmode - init.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 67 70 95.7 %
Date: 2022-04-01 14:17:54 Functions: 4 4 100.0 %
Branches: 11 18 61.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #include <linux/io.h>
       3                 :            : #include <linux/slab.h>
       4                 :            : #include <linux/memblock.h>
       5                 :            : #include <linux/mem_encrypt.h>
       6                 :            : 
       7                 :            : #include <asm/set_memory.h>
       8                 :            : #include <asm/pgtable.h>
       9                 :            : #include <asm/realmode.h>
      10                 :            : #include <asm/tlbflush.h>
      11                 :            : #include <asm/crash.h>
      12                 :            : 
      13                 :            : struct real_mode_header *real_mode_header;
      14                 :            : u32 *trampoline_cr4_features;
      15                 :            : 
      16                 :            : /* Hold the pgd entry used on booting additional CPUs */
      17                 :            : pgd_t trampoline_pgd_entry;
      18                 :            : 
      19                 :         11 : void __init reserve_real_mode(void)
      20                 :            : {
      21                 :         11 :         phys_addr_t mem;
      22         [ +  - ]:         11 :         size_t size = real_mode_size_needed();
      23                 :            : 
      24         [ +  - ]:         11 :         if (!size)
      25                 :            :                 return;
      26                 :            : 
      27         [ -  + ]:         11 :         WARN_ON(slab_is_available());
      28                 :            : 
      29                 :            :         /* Has to be under 1M so we can execute real-mode AP code. */
      30                 :         11 :         mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
      31         [ -  + ]:         11 :         if (!mem) {
      32                 :          0 :                 pr_info("No sub-1M memory is available for the trampoline\n");
      33                 :          0 :                 return;
      34                 :            :         }
      35                 :            : 
      36                 :         11 :         memblock_reserve(mem, size);
      37                 :         11 :         set_real_mode_mem(mem);
      38                 :         11 :         crash_reserve_low_1M();
      39                 :            : }
      40                 :            : 
      41                 :         11 : static void __init setup_real_mode(void)
      42                 :            : {
      43                 :         11 :         u16 real_mode_seg;
      44                 :         11 :         const u32 *rel;
      45                 :         11 :         u32 count;
      46                 :         11 :         unsigned char *base;
      47                 :         11 :         unsigned long phys_base;
      48                 :         11 :         struct trampoline_header *trampoline_header;
      49                 :         11 :         size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
      50                 :            : #ifdef CONFIG_X86_64
      51                 :         11 :         u64 *trampoline_pgd;
      52                 :         11 :         u64 efer;
      53                 :            : #endif
      54                 :            : 
      55                 :         11 :         base = (unsigned char *)real_mode_header;
      56                 :            : 
      57                 :            :         /*
      58                 :            :          * If SME is active, the trampoline area will need to be in
      59                 :            :          * decrypted memory in order to bring up other processors
      60                 :            :          * successfully. This is not needed for SEV.
      61                 :            :          */
      62                 :         11 :         if (sme_active())
      63                 :            :                 set_memory_decrypted((unsigned long)base, size >> PAGE_SHIFT);
      64                 :            : 
      65                 :         11 :         memcpy(base, real_mode_blob, size);
      66                 :            : 
      67         [ +  - ]:         11 :         phys_base = __pa(base);
      68                 :         11 :         real_mode_seg = phys_base >> 4;
      69                 :            : 
      70                 :         11 :         rel = (u32 *) real_mode_relocs;
      71                 :            : 
      72                 :            :         /* 16-bit segment relocations. */
      73                 :         11 :         count = *rel++;
      74         [ +  + ]:         55 :         while (count--) {
      75                 :         44 :                 u16 *seg = (u16 *) (base + *rel++);
      76                 :         44 :                 *seg = real_mode_seg;
      77                 :            :         }
      78                 :            : 
      79                 :            :         /* 32-bit linear relocations. */
      80                 :         11 :         count = *rel++;
      81         [ +  + ]:        297 :         while (count--) {
      82                 :        286 :                 u32 *ptr = (u32 *) (base + *rel++);
      83                 :        286 :                 *ptr += phys_base;
      84                 :            :         }
      85                 :            : 
      86                 :            :         /* Must be perfomed *after* relocation. */
      87                 :         11 :         trampoline_header = (struct trampoline_header *)
      88                 :         11 :                 __va(real_mode_header->trampoline_header);
      89                 :            : 
      90                 :            : #ifdef CONFIG_X86_32
      91                 :            :         trampoline_header->start = __pa_symbol(startup_32_smp);
      92                 :            :         trampoline_header->gdt_limit = __BOOT_DS + 7;
      93                 :            :         trampoline_header->gdt_base = __pa_symbol(boot_gdt);
      94                 :            : #else
      95                 :            :         /*
      96                 :            :          * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR
      97                 :            :          * so we need to mask it out.
      98                 :            :          */
      99                 :         11 :         rdmsrl(MSR_EFER, efer);
     100                 :         11 :         trampoline_header->efer = efer & ~EFER_LMA;
     101                 :            : 
     102                 :         11 :         trampoline_header->start = (u64) secondary_startup_64;
     103                 :         11 :         trampoline_cr4_features = &trampoline_header->cr4;
     104                 :         11 :         *trampoline_cr4_features = mmu_cr4_features;
     105                 :            : 
     106                 :         11 :         trampoline_header->flags = 0;
     107                 :         11 :         if (sme_active())
     108                 :            :                 trampoline_header->flags |= TH_FLAGS_SME_ACTIVE;
     109                 :            : 
     110                 :         11 :         trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
     111                 :         11 :         trampoline_pgd[0] = trampoline_pgd_entry.pgd;
     112                 :         11 :         trampoline_pgd[511] = init_top_pgt[511].pgd;
     113                 :            : #endif
     114                 :         11 : }
     115                 :            : 
     116                 :            : /*
     117                 :            :  * reserve_real_mode() gets called very early, to guarantee the
     118                 :            :  * availability of low memory. This is before the proper kernel page
     119                 :            :  * tables are set up, so we cannot set page permissions in that
     120                 :            :  * function. Also trampoline code will be executed by APs so we
     121                 :            :  * need to mark it executable at do_pre_smp_initcalls() at least,
     122                 :            :  * thus run it as a early_initcall().
     123                 :            :  */
     124                 :         11 : static void __init set_real_mode_permissions(void)
     125                 :            : {
     126                 :         11 :         unsigned char *base = (unsigned char *) real_mode_header;
     127                 :         11 :         size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
     128                 :            : 
     129                 :         22 :         size_t ro_size =
     130                 :         11 :                 PAGE_ALIGN(real_mode_header->ro_end) -
     131         [ +  - ]:         11 :                 __pa(base);
     132                 :            : 
     133                 :         11 :         size_t text_size =
     134                 :         11 :                 PAGE_ALIGN(real_mode_header->ro_end) -
     135                 :         11 :                 real_mode_header->text_start;
     136                 :            : 
     137                 :         11 :         unsigned long text_start =
     138                 :         11 :                 (unsigned long) __va(real_mode_header->text_start);
     139                 :            : 
     140                 :         11 :         set_memory_nx((unsigned long) base, size >> PAGE_SHIFT);
     141                 :         11 :         set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT);
     142                 :         11 :         set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT);
     143                 :         11 : }
     144                 :            : 
     145                 :         11 : static int __init init_real_mode(void)
     146                 :            : {
     147         [ -  + ]:         11 :         if (!real_mode_header)
     148                 :          0 :                 panic("Real mode trampoline was not allocated");
     149                 :            : 
     150                 :         11 :         setup_real_mode();
     151                 :         11 :         set_real_mode_permissions();
     152                 :            : 
     153                 :         11 :         return 0;
     154                 :            : }
     155                 :            : early_initcall(init_real_mode);

Generated by: LCOV version 1.14