18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This code is used on x86_64 to create page table identity mappings on
48c2ecf20Sopenharmony_ci * demand by building up a new set of page tables (or appending to the
58c2ecf20Sopenharmony_ci * existing ones), and then switching over to them when ready.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2015-2016  Yinghai Lu
88c2ecf20Sopenharmony_ci * Copyright (C)      2016  Kees Cook
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * Since we're dealing with identity mappings, physical and virtual
138c2ecf20Sopenharmony_ci * addresses are the same, so override these defines which are ultimately
148c2ecf20Sopenharmony_ci * used by the headers in misc.h.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#define __pa(x)  ((unsigned long)(x))
178c2ecf20Sopenharmony_ci#define __va(x)  ((void *)((unsigned long)(x)))
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* No PAGE_TABLE_ISOLATION support needed either: */
208c2ecf20Sopenharmony_ci#undef CONFIG_PAGE_TABLE_ISOLATION
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "error.h"
238c2ecf20Sopenharmony_ci#include "misc.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* These actually do the work of building the kernel identity maps. */
268c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
278c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
288c2ecf20Sopenharmony_ci#include <asm/trap_pf.h>
298c2ecf20Sopenharmony_ci#include <asm/trapnr.h>
308c2ecf20Sopenharmony_ci#include <asm/init.h>
318c2ecf20Sopenharmony_ci/* Use the static base for this part of the boot process */
328c2ecf20Sopenharmony_ci#undef __PAGE_OFFSET
338c2ecf20Sopenharmony_ci#define __PAGE_OFFSET __PAGE_OFFSET_BASE
348c2ecf20Sopenharmony_ci#include "../../mm/ident_map.c"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define _SETUP
378c2ecf20Sopenharmony_ci#include <asm/setup.h>	/* For COMMAND_LINE_SIZE */
388c2ecf20Sopenharmony_ci#undef _SETUP
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciextern unsigned long get_cmd_line_ptr(void);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* Used by PAGE_KERN* macros: */
438c2ecf20Sopenharmony_cipteval_t __default_kernel_pte_mask __read_mostly = ~0;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* Used to track our page table allocation area. */
468c2ecf20Sopenharmony_cistruct alloc_pgt_data {
478c2ecf20Sopenharmony_ci	unsigned char *pgt_buf;
488c2ecf20Sopenharmony_ci	unsigned long pgt_buf_size;
498c2ecf20Sopenharmony_ci	unsigned long pgt_buf_offset;
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/*
538c2ecf20Sopenharmony_ci * Allocates space for a page table entry, using struct alloc_pgt_data
548c2ecf20Sopenharmony_ci * above. Besides the local callers, this is used as the allocation
558c2ecf20Sopenharmony_ci * callback in mapping_info below.
568c2ecf20Sopenharmony_ci */
578c2ecf20Sopenharmony_cistatic void *alloc_pgt_page(void *context)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct alloc_pgt_data *pages = (struct alloc_pgt_data *)context;
608c2ecf20Sopenharmony_ci	unsigned char *entry;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Validate there is space available for a new page. */
638c2ecf20Sopenharmony_ci	if (pages->pgt_buf_offset >= pages->pgt_buf_size) {
648c2ecf20Sopenharmony_ci		debug_putstr("out of pgt_buf in " __FILE__ "!?\n");
658c2ecf20Sopenharmony_ci		debug_putaddr(pages->pgt_buf_offset);
668c2ecf20Sopenharmony_ci		debug_putaddr(pages->pgt_buf_size);
678c2ecf20Sopenharmony_ci		return NULL;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* Consumed more tables than expected? */
718c2ecf20Sopenharmony_ci	if (pages->pgt_buf_offset == BOOT_PGT_SIZE_WARN) {
728c2ecf20Sopenharmony_ci		debug_putstr("pgt_buf running low in " __FILE__ "\n");
738c2ecf20Sopenharmony_ci		debug_putstr("Need to raise BOOT_PGT_SIZE?\n");
748c2ecf20Sopenharmony_ci		debug_putaddr(pages->pgt_buf_offset);
758c2ecf20Sopenharmony_ci		debug_putaddr(pages->pgt_buf_size);
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	entry = pages->pgt_buf + pages->pgt_buf_offset;
798c2ecf20Sopenharmony_ci	pages->pgt_buf_offset += PAGE_SIZE;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return entry;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/* Used to track our allocated page tables. */
858c2ecf20Sopenharmony_cistatic struct alloc_pgt_data pgt_data;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* The top level page table entry pointer. */
888c2ecf20Sopenharmony_cistatic unsigned long top_level_pgt;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciphys_addr_t physical_mask = (1ULL << __PHYSICAL_MASK_SHIFT) - 1;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * Mapping information structure passed to kernel_ident_mapping_init().
948c2ecf20Sopenharmony_ci * Due to relocation, pointers must be assigned at run time not build time.
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_cistatic struct x86_mapping_info mapping_info;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/*
998c2ecf20Sopenharmony_ci * Adds the specified range to the identity mappings.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic void add_identity_map(unsigned long start, unsigned long end)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	int ret;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* Align boundary to 2M. */
1068c2ecf20Sopenharmony_ci	start = round_down(start, PMD_SIZE);
1078c2ecf20Sopenharmony_ci	end = round_up(end, PMD_SIZE);
1088c2ecf20Sopenharmony_ci	if (start >= end)
1098c2ecf20Sopenharmony_ci		return;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Build the mapping. */
1128c2ecf20Sopenharmony_ci	ret = kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt, start, end);
1138c2ecf20Sopenharmony_ci	if (ret)
1148c2ecf20Sopenharmony_ci		error("Error: kernel_ident_mapping_init() failed\n");
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* Locates and clears a region for a new top level page table. */
1188c2ecf20Sopenharmony_civoid initialize_identity_maps(void *rmode)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	unsigned long cmdline;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* Exclude the encryption mask from __PHYSICAL_MASK */
1238c2ecf20Sopenharmony_ci	physical_mask &= ~sme_me_mask;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	/* Init mapping_info with run-time function/buffer pointers. */
1268c2ecf20Sopenharmony_ci	mapping_info.alloc_pgt_page = alloc_pgt_page;
1278c2ecf20Sopenharmony_ci	mapping_info.context = &pgt_data;
1288c2ecf20Sopenharmony_ci	mapping_info.page_flag = __PAGE_KERNEL_LARGE_EXEC | sme_me_mask;
1298c2ecf20Sopenharmony_ci	mapping_info.kernpg_flag = _KERNPG_TABLE;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * It should be impossible for this not to already be true,
1338c2ecf20Sopenharmony_ci	 * but since calling this a second time would rewind the other
1348c2ecf20Sopenharmony_ci	 * counters, let's just make sure this is reset too.
1358c2ecf20Sopenharmony_ci	 */
1368c2ecf20Sopenharmony_ci	pgt_data.pgt_buf_offset = 0;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/*
1398c2ecf20Sopenharmony_ci	 * If we came here via startup_32(), cr3 will be _pgtable already
1408c2ecf20Sopenharmony_ci	 * and we must append to the existing area instead of entirely
1418c2ecf20Sopenharmony_ci	 * overwriting it.
1428c2ecf20Sopenharmony_ci	 *
1438c2ecf20Sopenharmony_ci	 * With 5-level paging, we use '_pgtable' to allocate the p4d page table,
1448c2ecf20Sopenharmony_ci	 * the top-level page table is allocated separately.
1458c2ecf20Sopenharmony_ci	 *
1468c2ecf20Sopenharmony_ci	 * p4d_offset(top_level_pgt, 0) would cover both the 4- and 5-level
1478c2ecf20Sopenharmony_ci	 * cases. On 4-level paging it's equal to 'top_level_pgt'.
1488c2ecf20Sopenharmony_ci	 */
1498c2ecf20Sopenharmony_ci	top_level_pgt = read_cr3_pa();
1508c2ecf20Sopenharmony_ci	if (p4d_offset((pgd_t *)top_level_pgt, 0) == (p4d_t *)_pgtable) {
1518c2ecf20Sopenharmony_ci		pgt_data.pgt_buf = _pgtable + BOOT_INIT_PGT_SIZE;
1528c2ecf20Sopenharmony_ci		pgt_data.pgt_buf_size = BOOT_PGT_SIZE - BOOT_INIT_PGT_SIZE;
1538c2ecf20Sopenharmony_ci		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
1548c2ecf20Sopenharmony_ci	} else {
1558c2ecf20Sopenharmony_ci		pgt_data.pgt_buf = _pgtable;
1568c2ecf20Sopenharmony_ci		pgt_data.pgt_buf_size = BOOT_PGT_SIZE;
1578c2ecf20Sopenharmony_ci		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
1588c2ecf20Sopenharmony_ci		top_level_pgt = (unsigned long)alloc_pgt_page(&pgt_data);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * New page-table is set up - map the kernel image, boot_params and the
1638c2ecf20Sopenharmony_ci	 * command line. The uncompressed kernel requires boot_params and the
1648c2ecf20Sopenharmony_ci	 * command line to be mapped in the identity mapping. Map them
1658c2ecf20Sopenharmony_ci	 * explicitly here in case the compressed kernel does not touch them,
1668c2ecf20Sopenharmony_ci	 * or does not touch all the pages covering them.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	add_identity_map((unsigned long)_head, (unsigned long)_end);
1698c2ecf20Sopenharmony_ci	boot_params = rmode;
1708c2ecf20Sopenharmony_ci	add_identity_map((unsigned long)boot_params, (unsigned long)(boot_params + 1));
1718c2ecf20Sopenharmony_ci	cmdline = get_cmd_line_ptr();
1728c2ecf20Sopenharmony_ci	add_identity_map(cmdline, cmdline + COMMAND_LINE_SIZE);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* Load the new page-table. */
1758c2ecf20Sopenharmony_ci	sev_verify_cbit(top_level_pgt);
1768c2ecf20Sopenharmony_ci	write_cr3(top_level_pgt);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/*
1808c2ecf20Sopenharmony_ci * This switches the page tables to the new level4 that has been built
1818c2ecf20Sopenharmony_ci * via calls to add_identity_map() above. If booted via startup_32(),
1828c2ecf20Sopenharmony_ci * this is effectively a no-op.
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_civoid finalize_identity_maps(void)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	write_cr3(top_level_pgt);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic pte_t *split_large_pmd(struct x86_mapping_info *info,
1908c2ecf20Sopenharmony_ci			      pmd_t *pmdp, unsigned long __address)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	unsigned long page_flags;
1938c2ecf20Sopenharmony_ci	unsigned long address;
1948c2ecf20Sopenharmony_ci	pte_t *pte;
1958c2ecf20Sopenharmony_ci	pmd_t pmd;
1968c2ecf20Sopenharmony_ci	int i;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	pte = (pte_t *)info->alloc_pgt_page(info->context);
1998c2ecf20Sopenharmony_ci	if (!pte)
2008c2ecf20Sopenharmony_ci		return NULL;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	address     = __address & PMD_MASK;
2038c2ecf20Sopenharmony_ci	/* No large page - clear PSE flag */
2048c2ecf20Sopenharmony_ci	page_flags  = info->page_flag & ~_PAGE_PSE;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Populate the PTEs */
2078c2ecf20Sopenharmony_ci	for (i = 0; i < PTRS_PER_PMD; i++) {
2088c2ecf20Sopenharmony_ci		set_pte(&pte[i], __pte(address | page_flags));
2098c2ecf20Sopenharmony_ci		address += PAGE_SIZE;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/*
2138c2ecf20Sopenharmony_ci	 * Ideally we need to clear the large PMD first and do a TLB
2148c2ecf20Sopenharmony_ci	 * flush before we write the new PMD. But the 2M range of the
2158c2ecf20Sopenharmony_ci	 * PMD might contain the code we execute and/or the stack
2168c2ecf20Sopenharmony_ci	 * we are on, so we can't do that. But that should be safe here
2178c2ecf20Sopenharmony_ci	 * because we are going from large to small mappings and we are
2188c2ecf20Sopenharmony_ci	 * also the only user of the page-table, so there is no chance
2198c2ecf20Sopenharmony_ci	 * of a TLB multihit.
2208c2ecf20Sopenharmony_ci	 */
2218c2ecf20Sopenharmony_ci	pmd = __pmd((unsigned long)pte | info->kernpg_flag);
2228c2ecf20Sopenharmony_ci	set_pmd(pmdp, pmd);
2238c2ecf20Sopenharmony_ci	/* Flush TLB to establish the new PMD */
2248c2ecf20Sopenharmony_ci	write_cr3(top_level_pgt);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return pte + pte_index(__address);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void clflush_page(unsigned long address)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	unsigned int flush_size;
2328c2ecf20Sopenharmony_ci	char *cl, *start, *end;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/*
2358c2ecf20Sopenharmony_ci	 * Hardcode cl-size to 64 - CPUID can't be used here because that might
2368c2ecf20Sopenharmony_ci	 * cause another #VC exception and the GHCB is not ready to use yet.
2378c2ecf20Sopenharmony_ci	 */
2388c2ecf20Sopenharmony_ci	flush_size = 64;
2398c2ecf20Sopenharmony_ci	start      = (char *)(address & PAGE_MASK);
2408c2ecf20Sopenharmony_ci	end        = start + PAGE_SIZE;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/*
2438c2ecf20Sopenharmony_ci	 * First make sure there are no pending writes on the cache-lines to
2448c2ecf20Sopenharmony_ci	 * flush.
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci	asm volatile("mfence" : : : "memory");
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	for (cl = start; cl != end; cl += flush_size)
2498c2ecf20Sopenharmony_ci		clflush(cl);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int set_clr_page_flags(struct x86_mapping_info *info,
2538c2ecf20Sopenharmony_ci			      unsigned long address,
2548c2ecf20Sopenharmony_ci			      pteval_t set, pteval_t clr)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	pgd_t *pgdp = (pgd_t *)top_level_pgt;
2578c2ecf20Sopenharmony_ci	p4d_t *p4dp;
2588c2ecf20Sopenharmony_ci	pud_t *pudp;
2598c2ecf20Sopenharmony_ci	pmd_t *pmdp;
2608c2ecf20Sopenharmony_ci	pte_t *ptep, pte;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	/*
2638c2ecf20Sopenharmony_ci	 * First make sure there is a PMD mapping for 'address'.
2648c2ecf20Sopenharmony_ci	 * It should already exist, but keep things generic.
2658c2ecf20Sopenharmony_ci	 *
2668c2ecf20Sopenharmony_ci	 * To map the page just read from it and fault it in if there is no
2678c2ecf20Sopenharmony_ci	 * mapping yet. add_identity_map() can't be called here because that
2688c2ecf20Sopenharmony_ci	 * would unconditionally map the address on PMD level, destroying any
2698c2ecf20Sopenharmony_ci	 * PTE-level mappings that might already exist. Use assembly here so
2708c2ecf20Sopenharmony_ci	 * the access won't be optimized away.
2718c2ecf20Sopenharmony_ci	 */
2728c2ecf20Sopenharmony_ci	asm volatile("mov %[address], %%r9"
2738c2ecf20Sopenharmony_ci		     :: [address] "g" (*(unsigned long *)address)
2748c2ecf20Sopenharmony_ci		     : "r9", "memory");
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/*
2778c2ecf20Sopenharmony_ci	 * The page is mapped at least with PMD size - so skip checks and walk
2788c2ecf20Sopenharmony_ci	 * directly to the PMD.
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	p4dp = p4d_offset(pgdp, address);
2818c2ecf20Sopenharmony_ci	pudp = pud_offset(p4dp, address);
2828c2ecf20Sopenharmony_ci	pmdp = pmd_offset(pudp, address);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (pmd_large(*pmdp))
2858c2ecf20Sopenharmony_ci		ptep = split_large_pmd(info, pmdp, address);
2868c2ecf20Sopenharmony_ci	else
2878c2ecf20Sopenharmony_ci		ptep = pte_offset_kernel(pmdp, address);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (!ptep)
2908c2ecf20Sopenharmony_ci		return -ENOMEM;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/*
2938c2ecf20Sopenharmony_ci	 * Changing encryption attributes of a page requires to flush it from
2948c2ecf20Sopenharmony_ci	 * the caches.
2958c2ecf20Sopenharmony_ci	 */
2968c2ecf20Sopenharmony_ci	if ((set | clr) & _PAGE_ENC)
2978c2ecf20Sopenharmony_ci		clflush_page(address);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* Update PTE */
3008c2ecf20Sopenharmony_ci	pte = *ptep;
3018c2ecf20Sopenharmony_ci	pte = pte_set_flags(pte, set);
3028c2ecf20Sopenharmony_ci	pte = pte_clear_flags(pte, clr);
3038c2ecf20Sopenharmony_ci	set_pte(ptep, pte);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* Flush TLB after changing encryption attribute */
3068c2ecf20Sopenharmony_ci	write_cr3(top_level_pgt);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ciint set_page_decrypted(unsigned long address)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	return set_clr_page_flags(&mapping_info, address, 0, _PAGE_ENC);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ciint set_page_encrypted(unsigned long address)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	return set_clr_page_flags(&mapping_info, address, _PAGE_ENC, 0);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciint set_page_non_present(unsigned long address)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	return set_clr_page_flags(&mapping_info, address, 0, _PAGE_PRESENT);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic void do_pf_error(const char *msg, unsigned long error_code,
3278c2ecf20Sopenharmony_ci			unsigned long address, unsigned long ip)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	error_putstr(msg);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	error_putstr("\nError Code: ");
3328c2ecf20Sopenharmony_ci	error_puthex(error_code);
3338c2ecf20Sopenharmony_ci	error_putstr("\nCR2: 0x");
3348c2ecf20Sopenharmony_ci	error_puthex(address);
3358c2ecf20Sopenharmony_ci	error_putstr("\nRIP relative to _head: 0x");
3368c2ecf20Sopenharmony_ci	error_puthex(ip - (unsigned long)_head);
3378c2ecf20Sopenharmony_ci	error_putstr("\n");
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	error("Stopping.\n");
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_civoid do_boot_page_fault(struct pt_regs *regs, unsigned long error_code)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	unsigned long address = native_read_cr2();
3458c2ecf20Sopenharmony_ci	unsigned long end;
3468c2ecf20Sopenharmony_ci	bool ghcb_fault;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	ghcb_fault = sev_es_check_ghcb_fault(address);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	address   &= PMD_MASK;
3518c2ecf20Sopenharmony_ci	end        = address + PMD_SIZE;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	/*
3548c2ecf20Sopenharmony_ci	 * Check for unexpected error codes. Unexpected are:
3558c2ecf20Sopenharmony_ci	 *	- Faults on present pages
3568c2ecf20Sopenharmony_ci	 *	- User faults
3578c2ecf20Sopenharmony_ci	 *	- Reserved bits set
3588c2ecf20Sopenharmony_ci	 */
3598c2ecf20Sopenharmony_ci	if (error_code & (X86_PF_PROT | X86_PF_USER | X86_PF_RSVD))
3608c2ecf20Sopenharmony_ci		do_pf_error("Unexpected page-fault:", error_code, address, regs->ip);
3618c2ecf20Sopenharmony_ci	else if (ghcb_fault)
3628c2ecf20Sopenharmony_ci		do_pf_error("Page-fault on GHCB page:", error_code, address, regs->ip);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/*
3658c2ecf20Sopenharmony_ci	 * Error code is sane - now identity map the 2M region around
3668c2ecf20Sopenharmony_ci	 * the faulting address.
3678c2ecf20Sopenharmony_ci	 */
3688c2ecf20Sopenharmony_ci	add_identity_map(address, end);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_civoid do_boot_nmi_trap(struct pt_regs *regs, unsigned long error_code)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	/* Empty handler to ignore NMI during early boot */
3748c2ecf20Sopenharmony_ci}
375