1#include "pedigree/kernel/BootstrapInfo.h"
3#include "../../../machine/mach_virt/DeviceTree.h"
6extern "C" char kernel_physical_start, kernel_physical_end;
9constexpr size_t MaximumMemoryRegions = 128;
10constexpr uint64_t DirectMapBase = 0xffff000000000000ULL;
12BootstrapStruct_t::Module initrdModule = {};
13char uefiCommandLine[4096] = {};
15struct ReservedRegion {
20uint64_t alignDown(uint64_t value) {
21 return value & ~uint64_t(PAGE_SIZE - 1);
24uint64_t alignUp(uint64_t value) {
25 return (value + PAGE_SIZE - 1) & ~uint64_t(PAGE_SIZE - 1);
28bool readHex(
const char*& text, uint64_t& value) {
31 if (text[0] ==
'0' && (text[1] ==
'x' || text[1] ==
'X')) {
37 if (c >=
'0' && c <=
'9') {
39 }
else if (c >=
'a' && c <=
'f') {
41 }
else if (c >=
'A' && c <=
'F') {
46 if (value > (UINT64_MAX - digit) / 16) {
49 value = value * 16 + digit;
56bool initrdFromBootargs(
const char* bootargs, uint64_t& start, uint64_t& end) {
57 static const char prefix[] =
"pedigree.initrd=";
62 while (*bootargs ==
' ') {
65 const char* token = bootargs;
66 while (*bootargs && *bootargs !=
' ') {
69 const char* cursor = token;
70 for (
size_t i = 0; i <
sizeof(prefix) - 1 && cursor < bootargs; ++i) {
71 if (*cursor++ != prefix[i]) {
74 if (i ==
sizeof(prefix) - 2) {
75 return readHex(cursor, start) && cursor < bootargs && *cursor++ ==
':' &&
76 readHex(cursor, end) && cursor == bootargs && start < end;
83bool initrdInMemory(uint64_t start, uint64_t end,
const void* deviceTree,
85 if (!start || start >= end) {
88 const uint64_t kernelStart =
reinterpret_cast<uintptr_t
>(&kernel_physical_start);
89 const uint64_t kernelEnd =
reinterpret_cast<uintptr_t
>(&kernel_physical_end);
90 const uint64_t dtbStart =
reinterpret_cast<uintptr_t
>(deviceTree);
91 const uint64_t dtbEnd = dtbStart + VirtDeviceTree::blobSize();
92 if (!(end <= kernelStart || start >= kernelEnd) ||
93 (deviceTree && !(end <= dtbStart || start >= dtbEnd))) {
97 for (
size_t i = 0; i < uefiCount; ++i) {
98 const auto& entry = uefiMap[i];
99 if (entry.type == 2 && entry.address <= start && entry.length &&
100 entry.address <= UINT64_MAX - entry.length && end <= entry.address + entry.length) {
106 for (
size_t i = 0; i < MaximumMemoryRegions; ++i) {
107 uint64_t base = 0, size = 0;
108 if (!virtGetMemoryRegion(i, &base, &size)) {
111 if (base <= start && size && base <= UINT64_MAX - size && end <= base + size) {
118void addUsable(uint64_t start, uint64_t end,
size_t& count) {
119 start = alignUp(start);
120 end = alignDown(end);
121 if (start >= end || count == MaximumMemoryRegions) {
128extern "C" void arm64BootMain(
const void* deviceTree, uint64_t uefiInitrdStart,
129 uint64_t uefiInitrdEnd, uint64_t uefiCommandLineAddress,
130 uint64_t uefiMemoryMapAddress, uint64_t uefiMemoryMapBytes,
131 uint64_t uefiAcpiRsdp) {
132 const bool uefi = uefiCommandLineAddress != 0;
133 if (uefi && (!uefiMemoryMapAddress || !uefiMemoryMapBytes ||
135 uefiMemoryMapBytes > 16 * PAGE_SIZE)) {
141 DirectMapBase + uefiMemoryMapAddress)
143 const size_t uefiCount =
146 virtSetDeviceTree(deviceTree);
147 }
else if (uefi && uefiAcpiRsdp) {
148 VirtDeviceTree::initialiseAcpi(uefiAcpiRsdp, uefiMemoryMap, uefiCount);
150 if (!VirtDeviceTree::valid()) {
156 const char* bootargs =
nullptr;
157 virtGetBootargs(&bootargs);
159 const char* supplied =
reinterpret_cast<const char*
>(DirectMapBase + uefiCommandLineAddress);
161 while (length <
sizeof(uefiCommandLine) - 1 && supplied[length]) {
162 uefiCommandLine[length] = supplied[length];
165 uefiCommandLine[length] = 0;
166 bootargs = uefiCommandLine;
168 uint64_t initrdStart = 0, initrdEnd = 0;
169 if (uefiInitrdStart && uefiInitrdEnd) {
170 initrdStart = uefiInitrdStart;
171 initrdEnd = uefiInitrdEnd;
173 const bool hasInitrd =
174 ((initrdStart && initrdEnd) || virtGetInitrd(&initrdStart, &initrdEnd) ||
175 initrdFromBootargs(bootargs, initrdStart, initrdEnd)) &&
176 initrdInMemory(initrdStart, initrdEnd, deviceTree, uefiMemoryMap, uefiCount);
177 ReservedRegion reserved[3] = {
178 {alignDown(
reinterpret_cast<uintptr_t
>(&kernel_physical_start)),
179 alignUp(
reinterpret_cast<uintptr_t
>(&kernel_physical_end))},
180 {alignDown(
reinterpret_cast<uintptr_t
>(deviceTree)),
181 alignUp(
reinterpret_cast<uintptr_t
>(deviceTree) + VirtDeviceTree::blobSize())},
182 {hasInitrd ? alignDown(initrdStart) : 0, hasInitrd ? alignUp(initrdEnd) : 0}};
183 for (
size_t i = 1; i < 3; ++i) {
184 for (
size_t j = i; j && reserved[j].start < reserved[j - 1].start; --j) {
185 const ReservedRegion previous = reserved[j - 1];
186 reserved[j - 1] = reserved[j];
187 reserved[j] = previous;
192 const size_t sourceCount = uefi ? uefiCount : MaximumMemoryRegions / 4;
193 for (
size_t i = 0; i < sourceCount; ++i) {
194 uint64_t base = 0, size = 0;
196 if (uefiMemoryMap[i].type != 1) {
199 base = uefiMemoryMap[i].address;
200 size = uefiMemoryMap[i].length;
202 if (!virtGetMemoryRegion(i, &base, &size)) {
206 if (!size || base + size < base) {
210 uint64_t cursor = base;
211 const uint64_t end = base + size;
212 for (
size_t r = 0; r < 3; ++r) {
213 if (!reserved[r].end || reserved[r].start >= end) {
216 if (reserved[r].start > cursor) {
217 addUsable(cursor, reserved[r].start < end ? reserved[r].start : end, count);
219 if (reserved[r].end > cursor) {
220 cursor = reserved[r].end;
223 addUsable(cursor, end, count);
227 bootstrap.setMemoryMap(memoryMap, count);
232 bootstrap.setAcpiRsdp(DirectMapBase + uefiAcpiRsdp);
235 static const char name[] =
"rootfs.img";
236 initrdModule = {DirectMapBase + initrdStart, DirectMapBase + initrdEnd,
237 reinterpret_cast<uintptr_t
>(name), 0};
238 bootstrap.setModules(&initrdModule, 1);
241 bootstrap.setCommandLine(uefi ? bootargs
242 : reinterpret_cast<const char*>(
243 DirectMapBase + reinterpret_cast<uintptr_t>(bootargs)));