1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
|
#include <efi.h>
#include <efilib.h>
#include <efidef.h>
#include <string.h>
#include "disk.h"
#include "vga.h"
#include "vmmem.h"
#include "ELF.h"
#include "memorytypes.h"
#include "paging_struct.h"
#include "paging.h"
#include "other.h"
// pixel struct information(hardcoded to what qemu exposes)
typedef struct _Pixel
{
UINT8 B;
UINT8 G;
UINT8 R;
UINT8 Z;
} Pixel;
// struct that is going to be passed to the kernel about general system information
typedef struct _OSDATA
{
UINT32 Magic; // magic number to check
UINT32 FBWidth; // with of the framebuffer
UINT32 FBHeight; // height
UINT32 PixelSize; // size of each pixel(an rgb pixel might have a bigger size)
void * FBAddr; // address of the linear framebuffer
void * MEMMap; // pointer to the system memory map
void * RAMDisk; // pointer to a ramdisk loaded from the hdd
void* RSDP;
} OSDATA;
extern void BootDisableInterrupts(void); // asm code is not correct(callee doesn't set the stack correctly)
typedef void (*kfn)(OSDATA *); // typedef to setup the entry point of the kernel and do a "jump" into it
void
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
__asm__("hlt");
// Memory Map
UINTN mapsize = 0;
UINTN allocsize = 0;
EFI_MEMORY_DESCRIPTOR * map = NULL;
UINTN mapkey = 0;
UINTN descriptorsize = 0;
UINT32 version = 0;
InitializeLib(ImageHandle, SystemTable);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); // clear the screen
//Pixel * fb = SetVideoMode(1024, 768, 32);
Pixel * fb = SetVideoMode(800, 600, 24);
PrintImageAddr(ImageHandle);
// Print(L"Number of tables: %d\n", SystemTable->NumberOfTableEntries);
EFI_GUID acpi_10 = ACPI_TABLE_GUID;
EFI_GUID acpi_20 = ACPI_20_TABLE_GUID;
void* acpi20table = NULL;
for(int i = 0; i < SystemTable->NumberOfTableEntries; i++)
{
if(AreEqual(&(SystemTable->ConfigurationTable[i].VendorGuid), &acpi_10, sizeof(EFI_GUID)))
{
// Print(L"ACPI 1.0 Found\n");
}
if(AreEqual(&(SystemTable->ConfigurationTable[i].VendorGuid), &acpi_20, sizeof(EFI_GUID)))
{
// Print(L"ACPI 2.0 Found\n");
acpi20table = SystemTable->ConfigurationTable[i].VendorTable; // <- this should be the RSDP
}
}
// some uefi implementations time out with their default setting, disable the timer
BS->SetWatchdogTimer(0, 0, 0, NULL);
//Print(L"Firmware Vendor: %s Rev: 0x%08x\n", ST->FirmwareVendor, ST->FirmwareRevision);
//while(1){};
// allocate the datat for the kernel(need to specify memory time not to be a generic loader data type)
OSDATA * osdata = AllocatePool(sizeof(OSDATA));
if(osdata == NULL)
{
Print(L"Os Data allocation failed\n");
}
int32_t kernel_size;
ELF * kernel = LoadFile(L"kernel.bin", MEM_KERNEL, &kernel_size); // we set the memory type to the one from the kernel
{
PH* ph = (PH*)(((uint64_t)kernel) + kernel->e_phoff); // use this to know how much and what pages to map
uint64_t phcount = (((uint64_t)kernel) + kernel->e_phnum);
//kernel_size = ph->p_filesz;
uint64_t size = (uint64_t)(kernel_size = ph->p_memsz);
uint64_t entry = (uint64_t)(kernel + ph->p_offset);
/*
Print(L"Kernel Size: 0x%llX\n", size);
Print(L"Kernel Entry: 0x%llX\n", entry);
Print(L"Program Header Count: 0x%llX\n", phcount);
*/
}
// print general information about the kernel elf header
//PrintELFInfo(kernel);
Loaded_ELF* loaded_kernel = LoadELF(kernel);
// attempt to allocate the memory map, first try is going to be too small
// as such the firmware will return the correct size
EFI_STATUS memret = EFI_SUCCESS;
EFI_STATUS bootstatus = EFI_SUCCESS;
uefi_call_wrapper(BS->GetMemoryMap, 5, &mapsize, map, &mapkey, &descriptorsize, &version);
// as the allocation will probably modify the memory map allocate 4kb more(one page)
// so that the new memory map probably fits
allocsize = mapsize + 10*4098;
mapsize = allocsize;
uefi_call_wrapper(BS->AllocatePool, 3, EfiLoaderData, allocsize, (void**)&map);
uefi_call_wrapper(BS->GetMemoryMap, 5, &mapsize, map, &mapkey, &descriptorsize, &version);
// set virtual addresses in here
// try some paging
initCR3();
//uint64_t address = 0;
//uint64_t max = 0x400000000ull;//0x20000000;
// EFI_MEMORY_DESCRIPTOR * mapiterator = map;
uint64_t elements = mapsize/descriptorsize;
printCR3();
//Print(L"elements: %d\n", elements);
for(int entry = 0; entry < elements; ++entry)
{
// mapiterator = (EFI_MEMORY_DESCRIPTOR*)(((EFI_PHYSICAL_ADDRESS)mapiterator + descriptorsize));
EFI_MEMORY_DESCRIPTOR* mapiterator = (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)map) + entry*descriptorsize);
// EFI_MEMORY_DESCRIPTOR* mapiterator = &(map[entry]);
uint64_t page = mapiterator->PhysicalStart;
uint64_t Pstart = mapiterator->PhysicalStart;
uint64_t Vstart = mapiterator->VirtualStart;
uint64_t Npages = mapiterator->NumberOfPages;
uint64_t Tpage = mapiterator->Type;
uint64_t Att = mapiterator->Attribute;
//if(Pstart != Vstart)
/*
if(Vstart != 0)
{
Print(L"\n");
Print(L"---------------------------------------\n");
Print(L"NON MATCHING PHYSICAL AND VIRTUAL PAGES\n");
Print(L"Physical Start: 0x%llX\n", Pstart);
Print(L"Virtual Start: 0x%llX\n", Vstart);
Print(L"Number of Pages: 0x%llX\n", Npages);
Print(L"Type of Page: 0x%llX\n", Tpage);
Print(L"---------------------------------------\n");
Print(L"\n");
}
*/
// if((Npages > 0) && (Vstart != 0))
// if(Vstart != 0)
// if((Pstart == 0) && (Vstart == 0))
// if(Pstart == Vstart)
if(Tpage == EfiConventionalMemory) // free pages
{
Print(L"\n");
Print(L"---------------------------------------\n");
Print(L"MAPPED MEMORY\n");
Print(L"Physical Start: 0x%llX\n", Pstart);
Print(L"Virtual Start: 0x%llX\n", Vstart);
Print(L"Number of Pages: 0x%llX\n", Npages);
Print(L"Type of Page: 0x%llX\n", Tpage);
Print(L"Attribute of Page: 0x%llX\n", Att);
Print(L"---------------------------------------\n");
Print(L"\n");
}
//Print(L"page: 0x%llX\n", page);
/* for(int pageentry = 0; pageentry < mapiterator->NumberOfPages; pageentry++)
{
//Print(L"SetAddr\n");
SetVirtualAddress(page, page);
page += 0x1000;
} */
}
while(1) {};
uint64_t maxaddr = 0x0000001000000000ull;
for(uint64_t page = 0x0; page < maxaddr; page += 0x1000)
{
SetVirtualAddress(page, page); // <- This is chanigng the memorymap 100%
}
// need to map the physical address the kernel is in to -2GB virtual
//uint64_t startvm = 0xffffffff7fffffffull;
//uint64_t startvm = kernel->e_entry;
//uint64_t currentvm = 0;
//PH* ph = (PH*)(((uint64_t)kernel) + kernel->e_phoff); // use this to know how much and what pages to map
//kernel_size = ph->p_filesz;
//kernel_size = ph->p_memsz;
/*
while(currentvm < kernel_size)
{
SetVirtualAddress((uint64_t)kernel + ph->p_offset + currentvm, startvm + currentvm);
currentvm += 0x1000;
}
*/
Print(L"BEFORE MAPPING KERNEL ENTRY: 0x%llX\n", loaded_kernel->entry);
for(int i = 0; i < loaded_kernel->ph_num; i++)
{
Loaded_PH* ph = &(loaded_kernel->ph[i]);
Print(L"MAPPING PH: 0x%llX\n", (uint64_t)ph->vaddr);
uint64_t mapsize = ph->mem_size;
uint64_t mapped = 0;
while(mapped < mapsize)
{
SetVirtualAddress((uint64_t)ph->data + mapped, (uint64_t)ph->vaddr + mapped);
mapped += 0x1000;
}
}
// now map already allocated 8KB for the Kernel Stack
//printCR3();
//Print(L"kernel: 0x%llx\n", kernel);
// the call to exit boot services tells the firmware we are ready to take control of the system
// never ever call Print after the next line
// after the first call boot services can be partially disabled
// loop until the firmware reports a successful exit, the specification allows for partial shutdowns
// so more than one call might be necessary(on qemu with OVMF it is)
while((bootstatus = uefi_call_wrapper(BS->ExitBootServices, 2, ImageHandle, mapkey)) != EFI_SUCCESS) // <- actually we need an up to date mapkey, so maybe we could actually get a memorymap before, create a OS liked memory map and exit services?
{
mapsize = allocsize;
while((memret = uefi_call_wrapper(BS->GetMemoryMap, 5, &mapsize, map, &mapkey, &descriptorsize, &version)) == EFI_BUFFER_TOO_SMALL)
{
allocsize = allocsize + 2*4096; // add 8kb(2 pages)
uefi_call_wrapper(BS->FreePool, 1, map);
uefi_call_wrapper(BS->AllocatePool, 3, EfiLoaderData, allocsize, (void**)&map);
mapsize = allocsize;
}
}
SetCrc(&(SystemTable->Hdr)); // As we exited boot services we need to set the CRC32 again
// as we can't print to the screen the way of showing the return status of this function
// is to write a red or green square on the top left corner of the screen
if(SetVM(mapsize, descriptorsize, version, map, kernel) != EFI_SUCCESS)
{
int i = 0;
int j = 0;
for(i = 0; i < 256; ++i)
{
for(j = 0; j < 256; ++j)
{
Pixel p;
p.R = 255;
p.G = 0;
p.B = 0;
//p.Z = 255;
fb[j + 800*i] = p;
}
}
} else
{
int i = 0;
int j = 0;
for(i = 0; i < 64; ++i)
{
for(j = 0; j < 64; ++j)
{
Pixel p;
p.R = 0;
p.G = 255;
p.B = 0;
//p.Z = 255;
fb[j + 800*i] = p;
}
}
}
// we should now set s Print(L"Calling ExitBootServices\n");oe virtual mapping
//BootDisableInterrupts();
//OSDATA * osdata = (OSDATA*)(640*1024);
osdata->Magic = 0xDDEE;
osdata->FBWidth = 1024;
osdata->FBHeight = 768;
osdata->FBAddr = fb;
osdata->PixelSize = 24;
osdata->MEMMap = map;
osdata->RAMDisk = NULL;
osdata->RSDP = acpi20table;
// this while only serves not to call the kernel for now
// after calling exit boot services we can't return to the uefi environment because it's been destroyed
//
//kernel = (ELF*)0x280000000; // correct virtual pointer to 10GB (Sign: 0 PML4: 0 PDP:10 PD:0 Page:0)
// kfn kernel_jump = (void*)kernel->e_entry;//(void*)((EFI_PHYSICAL_ADDRESS)kernel + kernel->EntryPoint);
kfn kernel_jump = (void*)loaded_kernel->entry;//(void*)((EFI_PHYSICAL_ADDRESS)kernel + kernel->EntryPoint);
writeCR3();
//while(1){}
{
int i = 0;
int j = 0;
for(i = 0; i < 256; ++i)
{
for(j = 0; j < 256; ++j)
{
Pixel p;
p.R = 255;
p.G = 255;
p.B = 255;
p.Z = 255;
fb[j + 800*i] = p;
}
}
}
// disable interrupts
__asm__("cli");
//writeCR3();
//__asm__("hlt");
kernel_jump(osdata);
while(1){}
__asm__("hlt"); // sanity in case the kernel exists, should throw an error somehow
// not as if the kernel shouldn't have this same code at the end of the main though
// we should never ever reach this point(if kernel exists, it should shutdown the computer)
}
|