Skip to content

Commit

Permalink
[BOOT] Fixes & checks
Browse files Browse the repository at this point in the history
  • Loading branch information
PeyTy committed Jan 11, 2025
1 parent 570f0bf commit c666e45
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 32 deletions.
1 change: 1 addition & 0 deletions boot/loader/trampoline.asm
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ trampolineCR3:

; Enter main [with rcx]
o64 call r9
times 64 - ($-$$) db 0 ; Padding
; TODO times 64 - ($-$$) db 0 ; Padding
; TODO size: dw $-$$ to store a size in the bootloader that you could look at in an asm listing or hexdump. But that takes up 2 bytes.

Expand Down
43 changes: 31 additions & 12 deletions boot/shared/paging.hexa
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// The Tofita Engine
// Copyright (C) 2022-2024 Oleh Petrenko
// Copyright (C) 2022-2025 Oleh Petrenko
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
Expand Down Expand Up @@ -67,15 +67,15 @@ fun mapEfiRuntime(memoryMap UefiMemoryMap) {
serialPrintf("[paging] efi runtime mapped %8 pages\n", sum)
}

@struct class Buffa {
@struct class ZeroBuffer {
let value UInt64 = 0
new () { }
}
let buffaStorage = new Buffa()
let buffa = buffaStorage as! ArrayPointer<UInt8>
let zeroBufferStorage = new ZeroBuffer()
let zeroBuffer = zeroBufferStorage as! ArrayPointer<UInt8>
// TODO ^ simple array by value

fun conventionalAllocateLargest(memoryMap UefiMemoryMap) {
fun conventionalAllocateLargest(memoryMap UefiMemoryMap) Void {
var descriptor = memoryMap.memoryMap
let descriptorSize UInt64 = memoryMap.descriptorSize
var result UInt64 = 0u64
Expand All @@ -100,25 +100,44 @@ fun conventionalAllocateLargest(memoryMap UefiMemoryMap) {
serialPrintf("[paging] conventionalAllocateLargest is %8 bytes, %8 pages\n",
pageSize * largestPages, largestPages)

return result
conventionalBuffer = result
conventionalOffset = conventionalBuffer
conventionalPagesAvailable = largestPages
}

var conventionalBuffer UInt64 = 0u64
var conventionalOffset UInt64 = 0u64
var conventionalPages UInt64 = 0u64
var conventionalPagesAvailable UInt64 = 0u64
var conventionalFramebufferForErrors FrameBuffer? = null

/// Simplistic memory allocator
fun conventionalAllocateNext(bytes UInt64) UInt64 {
let result = conventionalOffset
let pageSize = pageSize as! UInt64 // TODO Hexa: is it needed?
let pages = bytes / pageSize // Math.floor TODO Hexa: `\`
let pages = bytes / pageSize + 1u64 // Math.floor TODO Hexa: `\`
conventionalOffset += pages * pageSize
conventionalPages += pages
// TODO meaning
if (bytes - (pages * pageSize)) > 0 {
conventionalOffset += pageSize
conventionalPages++

// Overflow check
if conventionalPages > conventionalPagesAvailable {
serialPrintf("[paging] conventionalAllocateNext %u bytes == exhausted\n", bytes)
while true {
if let fb = conventionalFramebufferForErrors {
drawError("[ERROR] Conventional buffer exhausted [ERROR]", fb)
}
__sync_synchronize()
}
}

// Zero-fill allocated memory
{
var b = result as! ArrayPointer<UInt8>
for i in bytes {
b[i] = zeroBuffer[0]
}
}
__sync_synchronize() // Ensure zero-fill is complete before returning

return result
}

Expand Down
4 changes: 3 additions & 1 deletion boot/shared/params.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ let frameBufferVirtualBase UInt64 = (upper + 768u64 * 1024u64 * 1024u64)
// Mapping of 1:1 of physical memory as virtual = physical + wholePhysicalStart
// Note: Mapping is done on-demand per-page for faster loading
let wholePhysicalStart UInt64 = (frameBufferVirtualBase + 128 * 1024 * 1024)
let pageSize UInt16 = 4096u16 // 4 KiB
let pageSize UInt64 = 4096u64 // 4 KiB
// TODO Hexa: could be inlining in normalizer of u16 value instead of u64
// let pageSize UInt64 = 4096u16 // 4 KiB

// Helpers
@struct
Expand Down
45 changes: 30 additions & 15 deletions boot/uefi/boot.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ declare fun pause() Void
// Entry point
fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STATUS {
// Workaround for Clang `memset`, but it may be not needed anymore
buffa[0] = 0
zeroBuffer[0] = 0

initSerial()

Expand Down Expand Up @@ -158,7 +158,7 @@ fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STAT
var b = efiMemoryMap.memoryMap as! ArrayPointer<UInt8>
for i in efiMemoryMap.memoryMapSize {
// TODO faster with uint64_t
b[i] = buffa[0]
b[i] = zeroBuffer[0]
// TODO zero-fill buffer for EFI memory map -< unify to zeroFill()
}
}
Expand Down Expand Up @@ -247,17 +247,24 @@ fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STAT

drawVerbose("Allocate memory...", framebuffer)
// TODO how to ensure the memory is preserved by UEFI and memory map is unchanged when Exit B S called?
conventionalBuffer = conventionalAllocateLargest(efiMemoryMap)
conventionalAllocateLargest(efiMemoryMap)
conventionalFramebufferForErrors = framebuffer
serialPrintf("[[[uefi]]] large buffer allocated at %u\n", conventionalBuffer)
conventionalOffset = conventionalBuffer

var addressOfEntryPoint UInt64 = 0

drawVerbose("Parse engine file...", framebuffer)
{
let ptr = asset.data as! ArrayPointer<UInt8>
// TODO `@readonly PeHeader` just make all fields `let` also decided to disallow `@` on types
let peHeader = ((ptr as! UInt64) + ptr[0x3C] + ptr[0x3C + 1] * 256) as! @readonly PeHeader
let peHeaderOffset UInt64 =
(ptr[0x3C] as! UInt64) +
(ptr[0x3C + 1] as! UInt64) * 256u64 +
(ptr[0x3C + 2] as! UInt64) * 65536u64 +
(ptr[0x3C + 3] as! UInt64) * 16777216u64
let peHeader = (
(ptr as! UInt64) + peHeaderOffset
) as! @readonly PeHeader
serialPrintf("PE header signature 'PE' == '%s'\n", peHeader)
let peOptionalHeader = ((peHeader as! UInt64) + sizeOf<PeHeader>()) as! @readonly Pe32OptionalHeader
serialPrintf("PE32(+) optional header signature 0x020B == %d == %d\n", peOptionalHeader.mMagic,
Expand Down Expand Up @@ -295,7 +302,7 @@ fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STAT
{
var b = params as! ArrayPointer<UInt8>
for i in sizeOf<UefiPayload>() {
b[i] = buffa[0]
b[i] = zeroBuffer[0]
}
}

Expand All @@ -312,11 +319,11 @@ fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STAT

// Note: stack grows from X to X-N, not X+N
// TODO: map empty page for stack overflow protection + map larger stack (~4 MB)
let stack = conventionalAllocateNext(1024u64 * 1024) + 1024 * 1024
let stack = conventionalAllocateNext(1024u64 * 1024u64) + 1024u64 * 1024u64
{
var b = (stack - 1024 * 1024) as! ArrayPointer<UInt8>
for i in 1024 * 1024 {
b[i] = buffa[0]
var b = (stack - 1024u64 * 1024u64) as! ArrayPointer<UInt8>
for i in 1024u64 * 1024u64 {
b[i] = zeroBuffer[0]
}
}

Expand Down Expand Up @@ -350,10 +357,14 @@ fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STAT
serialPrintf("[paging] available RAM is ~%8 bytes\n", ram)
serialPrintf("[paging] available RAM is ~%u megabytes\n", megs)

while megs < 1234 {
// TODO check only physical memory in this case (but map whole range reported by UEFI)
drawError("[ERROR] Tofita requires at least 2 GB of memory [ERROR]", framebuffer)
if megs < 1234u64 {
// This code intentionally hangs forever and keeps printing text to VGA screen
// to ensure that it is sent to GPU (cause halting may stop firmware copy mem process)
serialPrintf("Tofita requires at least 2 GB of memory\n")
while true {
drawError("[ERROR] Tofita requires at least 2 GB of memory [ERROR]", framebuffer)
}
}

params.ramBytes = ram
Expand All @@ -372,33 +383,37 @@ fun uefi(imageHandle ByValue<EFI_HANDLE>, systemTable EFI_SYSTEM_TABLE) EFI_STAT
var b = pml4entries as! ArrayPointer<UInt8>
for i in pageTableEntriesSize {
// TODO faster with uint64_t
b[i] = buffa[0]
b[i] = zeroBuffer[0]
}
}

__sync_synchronize() // Ensure PML4 zeroing is complete before mapping

// Map memory
drawVerbose("Setup virtual memory...", framebuffer)

serialPrintln("[[[uefi]]] mapping pages for the engine loader")

let pageSize = 4096u64

mapMemory(upper, conventionalBuffer, conventionalPages + 1u64, 1, global: true)
mapMemory(upper, conventionalBuffer, conventionalPages + 1u64, 1u8, global: true)

// Note: framebuffer is *not* within physical memory
drawVerbose("Setup display memory...", framebuffer)
mapFrameBuffer(params.framebuffer.ref)
drawLoading(framebuffer, 2)

__sync_synchronize() // Ensure all memory mappings are complete

drawVerbose("Setup runtime memory...", framebuffer)
mapEfiRuntime(params.efiMemoryMap.ref)
// TODO is +1 needed? better make helper function
mapMemoryHuge(wholePhysicalStart, 0, (ram / pageSize) + 1u64, global: true)

drawVerbose("Setup engine modes...", framebuffer)
// TODO somehow ensure size is enough to copy whole trampoline (-D arg same as version)
let startFunction = (conventionalOffset + pageSize) as! InitEngineTrampoline

// Size is defined with padding within .asm file
tmemcpy(startFunction as! ArrayPointer<UInt8>, trampolineCR3 as! ConstArrayPointer<UInt8>, 64)
mapMemory((startFunction as! UInt64), (startFunction as! UInt64), 1, 0, global: false)

Expand Down
2 changes: 1 addition & 1 deletion boot/uefi/memory.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fun uefiAllocate(bootServices EFI_BOOT_SERVICES, bytes ArrayPointer<UInt64>, des
EFI_MEMORY_TYPE.EfiLoaderCode // Use `*Code` not `*Data` to avoid NX-bit crash if data executed

// Round to page size
var pages UInt64 = ((bytes[0] - 1) / pageSize) + 1
var pages UInt64 = ((bytes[0] - 1u64) / pageSize) + 1u64
var addr EFI_PHYSICAL_ADDRESS = destination[0] as! EFI_PHYSICAL_ADDRESS
var saddr ArrayByValue<EFI_PHYSICAL_ADDRESS, 1> = [addr]

Expand Down
15 changes: 12 additions & 3 deletions boot/uefiMain.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
@rename('imageHandle') declare let imageHandle ByValue<EFI_HANDLE>
@rename('systemTable') declare let systemTable EFI_SYSTEM_TABLE

fun heapOverflow() Void {
if let fb = conventionalFramebufferForErrors {
drawError("[ERROR] Heap overflow [ERROR]", fb)
}

while true {
__sync_synchronize()
}
}

@customHeader('
extern const uint8_t binFont[];
extern const uint8_t binFontBitmap[];
Expand Down Expand Up @@ -56,9 +66,8 @@
heapOffset += 8;
heapOffset += size;
if (heapOffset >= HEAP_C) {
//serialPrint_(L"Heap overflow\n");
//serialPrint_(L"Heap overflow\n");
//serialPrint_(L"Heap overflow\n");
serialPrint_(L"Heap overflow (HeapAlloc). Halt.\n");
heapOverflow_();
while (1) {};
}
return &heap[heapOffset - size];
Expand Down

0 comments on commit c666e45

Please sign in to comment.