xref: /aosp_15_r20/external/coreboot/src/security/memory/memory_clear.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #if ENV_X86
4 #include <cpu/x86/pae.h>
5 #else
6 #define memset_pae(a, b, c, d, e) 0
7 #define PAE_PGTL_ALIGN 0
8 #define PAE_PGTL_SIZE 0
9 #define PAE_VMEM_ALIGN 0
10 #define PAE_VMEM_SIZE 0
11 #endif
12 
13 #include <memrange.h>
14 #include <bootmem.h>
15 #include <bootstate.h>
16 #include <symbols.h>
17 #include <console/console.h>
18 #include <arch/memory_clear.h>
19 #include <string.h>
20 #include <security/memory/memory.h>
21 #include <cbmem.h>
22 #include <acpi/acpi.h>
23 
24 /* Helper to find free space for memset_pae. */
get_free_memory_range(struct memranges * mem,const resource_t align,const resource_t size)25 static uintptr_t get_free_memory_range(struct memranges *mem,
26 				       const resource_t align,
27 				       const resource_t size)
28 {
29 	const struct range_entry *r;
30 
31 	/* Find a spot for virtual memory address */
32 	memranges_each_entry(r, mem) {
33 		if (range_entry_tag(r) != BM_MEM_RAM)
34 			continue;
35 
36 		if (ALIGN_UP(range_entry_base(r) + size, align) + size >
37 		    range_entry_end(r))
38 			continue;
39 
40 		return ALIGN_UP(range_entry_base(r) + size, align);
41 	}
42 	printk(BIOS_ERR, "%s: Couldn't find free memory range\n", __func__);
43 
44 	return 0;
45 }
46 
47 /*
48  * Clears all memory regions marked as BM_MEM_RAM.
49  * Uses memset_pae if the memory region can't be accessed by memset and
50  * architecture is x86.
51  *
52  * @return 0 on success, 1 on error
53  */
clear_memory(void * unused)54 static void clear_memory(void *unused)
55 {
56 	const struct range_entry *r;
57 	struct memranges mem;
58 	uintptr_t pgtbl, vmem_addr;
59 
60 	if (acpi_is_wakeup_s3())
61 		return;
62 
63 	if (!security_clear_dram_request())
64 		return;
65 
66 	/* FSP1.0 is marked as MMIO and won't appear here */
67 
68 	memranges_init(&mem, IORESOURCE_MEM | IORESOURCE_FIXED |
69 			IORESOURCE_STORED | IORESOURCE_ASSIGNED |
70 			IORESOURCE_CACHEABLE,
71 			IORESOURCE_MEM | IORESOURCE_FIXED |
72 			IORESOURCE_STORED | IORESOURCE_ASSIGNED |
73 			IORESOURCE_CACHEABLE,
74 			BM_MEM_RAM);
75 
76 	/* Add reserved entries */
77 	void *baseptr = NULL;
78 	size_t size = 0;
79 
80 	/* Only skip CBMEM, stage program, stack and heap are included there. */
81 
82 	cbmem_get_region(&baseptr, &size);
83 	memranges_insert(&mem, (uintptr_t)baseptr, size, BM_MEM_TABLE);
84 
85 	if (ENV_X86) {
86 		/* Find space for PAE enabled memset */
87 		pgtbl = get_free_memory_range(&mem, PAE_PGTL_ALIGN, PAE_PGTL_SIZE);
88 
89 		/* Don't touch page tables while clearing */
90 		memranges_insert(&mem, pgtbl, PAE_PGTL_SIZE, BM_MEM_TABLE);
91 
92 		vmem_addr = get_free_memory_range(&mem, PAE_VMEM_ALIGN, PAE_VMEM_SIZE);
93 
94 		printk(BIOS_SPEW, "%s: pgtbl at %p, virt memory at %p\n",
95 		__func__, (void *)pgtbl, (void *)vmem_addr);
96 	}
97 
98 	/* Now clear all usable DRAM */
99 	memranges_each_entry(r, &mem) {
100 		if (range_entry_tag(r) != BM_MEM_RAM)
101 			continue;
102 		printk(BIOS_DEBUG, "%s: Clearing DRAM %016llx-%016llx\n",
103 		       __func__, range_entry_base(r), range_entry_end(r));
104 
105 		/* Does regular memset work? */
106 		if (sizeof(resource_t) == sizeof(void *) ||
107 		    !(range_entry_end(r) >> (sizeof(void *) * 8))) {
108 			/* fastpath */
109 			memset((void *)(uintptr_t)range_entry_base(r), 0,
110 			       range_entry_size(r));
111 		}
112 		/* Use PAE if available */
113 		else if (ENV_X86) {
114 			if (memset_pae(range_entry_base(r), 0,
115 			    range_entry_size(r), (void *)pgtbl,
116 			    (void *)vmem_addr))
117 				printk(BIOS_ERR, "%s: Failed to memset "
118 				       "memory\n", __func__);
119 		} else {
120 			printk(BIOS_ERR, "%s: Failed to memset memory\n",
121 			       __func__);
122 		}
123 	}
124 
125 	if (ENV_X86) {
126 		/* Clear previously skipped memory reserved for pagetables */
127 		printk(BIOS_DEBUG, "%s: Clearing DRAM %016lx-%016lx\n",
128 		__func__, pgtbl, pgtbl + PAE_PGTL_SIZE);
129 
130 		memset((void *)pgtbl, 0, PAE_PGTL_SIZE);
131 	}
132 
133 	memranges_teardown(&mem);
134 }
135 
136 /* After DEV_INIT as MTRRs needs to be configured on x86 */
137 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, clear_memory, NULL);
138