1 /*
2  * Copyright (c) 2011 - 2022, Intel Corporation.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *    * Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  *    * Redistributions in binary form must reproduce the above copyright
11  *      notice, this list of conditions and the following disclaimer
12  *      in the documentation and/or other materials provided with the
13  *      distribution.
14  *    * Neither the name of Intel Corporation nor the names of its
15  *      contributors may be used to endorse or promote products
16  *      derived from this software without specific prior written
17  *      permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <efi.h>
34 #include <efilib.h>
35 #include "efilinux.h"
36 #include "stdlib.h"
37 #include "boot.h"
38 
39 EFI_STATUS
emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS * addr,UINTN size,UINTN align,EFI_PHYSICAL_ADDRESS minaddr,EFI_PHYSICAL_ADDRESS maxaddr)40 emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS *addr, UINTN size, UINTN align,
41 		EFI_PHYSICAL_ADDRESS minaddr, EFI_PHYSICAL_ADDRESS maxaddr)
42 {
43 	struct efi_memmap_info mmap_info;
44 	UINTN msize, desc_sz, desc_addr, pages;
45 	EFI_MEMORY_DESCRIPTOR *mbuf;
46 	EFI_STATUS err;
47 
48 	pages = EFI_SIZE_TO_PAGES(size);
49 
50 	/* Memory map may change so we request it again */
51 	err = get_efi_memmap(&mmap_info, 0);
52 	if (err != EFI_SUCCESS)
53 		goto fail;
54 
55 	msize = mmap_info.map_size;
56 	desc_sz = mmap_info.desc_size;
57 	mbuf = mmap_info.mmap;
58 
59 	/* ACRN requests for lowest possible address that's greater than minaddr */
60 	/* TODO: in the future we may want to support both preferences */
61 	for (desc_addr = (UINTN)mbuf; desc_addr <= (UINTN)mbuf + msize - desc_sz; desc_addr += desc_sz) {
62 		EFI_MEMORY_DESCRIPTOR *desc;
63 		EFI_PHYSICAL_ADDRESS start, end;
64 
65 		desc = (EFI_MEMORY_DESCRIPTOR*)desc_addr;
66 		if (desc->Type != EfiConventionalMemory)
67 			continue;
68 
69 		start = desc->PhysicalStart;
70 		end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT);
71 
72 		/* 1MB low memory is allocated only if required/requested */
73 		if ((end <= MEM_ADDR_1MB) && (maxaddr > MEM_ADDR_1MB))
74 			continue;
75 
76 		/* starting allocation from 1M above unless requested */
77 		if ((start < MEM_ADDR_1MB) && (maxaddr > MEM_ADDR_1MB)) {
78 			start = MEM_ADDR_1MB;
79 		}
80 
81 		/* zero page won't be allocated */
82 		if (start < 4096) {
83 			start = 4096;
84 		}
85 
86 		if (start < minaddr) {
87 			start = minaddr;
88 		}
89 		start = (start + align - 1) & ~(align - 1);
90 
91 		 /* Since this routine is called during booting, memory block is large
92 		  * enought, the reduction of memory size for memory alignment won't
93 		  * impact allocation. It is true in most cases. if it is not true, loop
94 		  * again
95 		  */
96 		if ((start + size <= end) && (start + size <= maxaddr)) {
97 			err = allocate_pages(AllocateAddress, EfiReservedMemoryType, pages, &start);
98 			if (err == EFI_SUCCESS) {
99 				*addr = start;
100 				break;
101 			}
102 		}
103 	}
104 	if (desc_addr > (UINTN)mbuf + msize - desc_sz) {
105 		err = EFI_OUT_OF_RESOURCES;
106 	}
107 
108 	free_pool(mbuf);
109 
110 fail:
111 	return err;
112 }
113 
dump_e820(void)114 EFI_STATUS dump_e820(void)
115 {
116 	UINTN map_size, map_key, desc_size;
117 	EFI_MEMORY_DESCRIPTOR *map_buf;
118 	UINTN d, map_end;
119 	UINTN i;
120 	UINT32 desc_version;
121 	EFI_STATUS err;
122 
123 	err = memory_map(&map_buf, &map_size, &map_key,
124 			 &desc_size, &desc_version);
125 	if (err != EFI_SUCCESS)
126 		goto fail;
127 
128 	d = (UINTN)map_buf;
129 	map_end = (UINTN)map_buf + map_size;
130 
131 	for (i = 0; d < map_end; d += desc_size, i++) {
132 		EFI_MEMORY_DESCRIPTOR *desc;
133 		EFI_PHYSICAL_ADDRESS start, end;
134 
135 		desc = (EFI_MEMORY_DESCRIPTOR *)d;
136 		if (desc->Type != EfiConventionalMemory)
137 			continue;
138 
139 		start = desc->PhysicalStart;
140 		end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT);
141 
142 	    Print(L"[%d]start:%lx, end:%lx, type:%d\n", i, start, end, desc->Type);
143 	}
144 
145 	free_pool(map_buf);
146 fail:
147 	return err;
148 }
149 
150