x86_64 do not merge #76
No files matched your search
@@ -205,7 +205,7 @@ Key constants:
|
||||
- `DATA_OFFSET = $10000` — data area starts at 64 KB into each page
|
||||
- `LARGE_ALLOC_MAGIC = $FFFFFFFE` — sentinel for klalloc'd multi-page allocations
|
||||
|
||||
Interrupt safety: `pushfd; cli; pop saved_flags` (stack-balanced) + `restore_if(saved_flags)`
|
||||
Interrupt safety: `pushfd; cli; pop saved_flags` (stack-balanced) + `arch.platform.cpu.unlock(saved_flags)`
|
||||
inline procedure that only restores IF via `sti`, avoiding dangerous EFLAGS restoration
|
||||
(IOPL, NT, VM, AC bits that caused Bad-TSS on IRET).
|
||||
|
||||
@@ -256,7 +256,7 @@ list, fixes Search_Page, calls `free_page_at_address`). Skips Root_Page.
|
||||
|
||||
| Bug | Root Cause | Fix |
|
||||
|-----|-----------|-----|
|
||||
| Bad TSS exception during network processing | `pushfd`/`popfd` across separate asm blocks: FPC doesn't track ESP changes in asm, causing EFLAGS corruption (NT=1, IOPL wrong) → Bad TSS on IRET | Stack-balanced `pushfd; cli; pop local_var` + `restore_if()` that only does `sti` if IF was set |
|
||||
| Bad TSS exception during network processing | `pushfd`/`popfd` across separate asm blocks: FPC doesn't track ESP changes in asm, causing EFLAGS corruption (NT=1, IOPL wrong) → Bad TSS on IRET | Stack-balanced `pushfd; cli; pop local_var` + `arch.platform.cpu.unlock()` that only does `sti` if IF was set |
|
||||
| GPF from SSE MOVAPS in doublebuffer flush | `SIZE_PREFIX=4`→8 gave 8-byte alignment; `MOVAPS` needs 16-byte. `klalloc` returned `page+8` (not 16-aligned) | `SIZE_PREFIX=16` (4B size + 12B pad), klalloc header expanded to 16 bytes |
|
||||
| Pages never freed (historic) | `free_page` extracted wrong block index from PDE Address field | Fixed extraction to `Address SHR 10` — page freeing works for the first time |
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Every allocation is preceded by a 16-byte prefix: 4 bytes for the unit count, 12
|
||||
|
||||
Allocations larger than a single heap page's capacity are handled by `klalloc`, which maps contiguous virtual pages and stores a magic sentinel (`$FFFFFFFE`) in the header so `kfree` can identify them and call `klfree` instead of the normal bitmap path.
|
||||
|
||||
`kalloc` and `kfree` disable interrupts for the duration of their critical sections using a stack-balanced `pushfd`/`cli`/`pop` sequence and restore the interrupt flag via `restore_if` on all exit paths.
|
||||
`kalloc` and `kfree` disable interrupts for the duration of their critical sections using a stack-balanced `pushfd`/`cli`/`pop` sequence and restore the interrupt flag via `arch.platform.cpu.unlock` on all exit paths.
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -132,7 +132,7 @@ Returns the number of heap pages currently in the linked list.
|
||||
|
||||
## Notes
|
||||
|
||||
The `restore_if` helper checks bit 9 (IF) of the saved EFLAGS word and issues `STI` only if interrupts were enabled on entry. It uses `STI` rather than `POPFD` to avoid restoring potentially dangerous EFLAGS bits (IOPL, NT, VM, AC) that could trigger a General Protection Fault or Bad-TSS on the next `IRET`.
|
||||
The `arch.platform.cpu.unlock` helper checks bit 9 (IF) of the saved EFLAGS word and issues `STI` only if interrupts were enabled on entry. It uses `STI` rather than `POPFD` to avoid restoring potentially dangerous EFLAGS bits (IOPL, NT, VM, AC) that could trigger a General Protection Fault or Bad-TSS on the next `IRET`.
|
||||
|
||||
When `DEBUG_LMM` is defined, `kalloc` allocates one additional unit and writes `GUARD_MAGIC` at the end of the allocation. `kfree` verifies this sentinel before freeing; a mismatch triggers a GPF with a syslog error, catching buffer overruns at free time.
|
||||
|
||||
|
||||
@@ -12,34 +12,61 @@
|
||||
|
||||
{ Shared PC interrupt-controller programming. Call with interrupts disabled. }
|
||||
unit arch.common.legacyirq;
|
||||
|
||||
interface
|
||||
const
|
||||
PIT_INPUT_HZ = 1193182;
|
||||
PIT_DIVISOR = 149;
|
||||
procedure remap(masterMask, slaveMask: uint8);
|
||||
procedure masks(masterMask, slaveMask: uint8);
|
||||
procedure enableLine(line: uint8);
|
||||
procedure timerStart;
|
||||
function realIRQ(line: uint8): boolean;
|
||||
procedure acknowledge(line: uint8);
|
||||
|
||||
implementation
|
||||
uses arch.platform.cpu;
|
||||
|
||||
procedure writeSlow(port: uint16; value: uint8);
|
||||
begin
|
||||
outb(port, value);
|
||||
outb($80, 0);
|
||||
end;
|
||||
|
||||
procedure masks(masterMask, slaveMask: uint8);
|
||||
begin
|
||||
writeSlow($21, masterMask); writeSlow($A1, slaveMask);
|
||||
writeSlow($21, masterMask);
|
||||
writeSlow($A1, slaveMask);
|
||||
end;
|
||||
|
||||
procedure remap(masterMask, slaveMask: uint8);
|
||||
begin
|
||||
writeSlow($20, $11); writeSlow($A0, $11);
|
||||
writeSlow($21, $20); writeSlow($A1, $28);
|
||||
writeSlow($21, $04); writeSlow($A1, $02);
|
||||
writeSlow($21, $01); writeSlow($A1, $01);
|
||||
writeSlow($20, $11);
|
||||
writeSlow($A0, $11);
|
||||
writeSlow($21, $20);
|
||||
writeSlow($A1, $28);
|
||||
writeSlow($21, $04);
|
||||
writeSlow($A1, $02);
|
||||
writeSlow($21, $01);
|
||||
writeSlow($A1, $01);
|
||||
masks(masterMask, slaveMask);
|
||||
end;
|
||||
|
||||
procedure enableLine(line: uint8);
|
||||
var
|
||||
flags: PtrUInt;
|
||||
begin
|
||||
if line >= 16 then exit;
|
||||
flags := arch.platform.cpu.lock;
|
||||
if line < 8 then
|
||||
outb($21, inb($21) and not uint8(1 shl line))
|
||||
else begin
|
||||
outb($A1, inb($A1) and not uint8(1 shl (line - 8)));
|
||||
outb($21, inb($21) and not uint8(4));
|
||||
end;
|
||||
arch.platform.cpu.unlock(flags);
|
||||
end;
|
||||
|
||||
procedure timerStart;
|
||||
begin
|
||||
{ Channel 0, low/high byte, mode 2, binary. }
|
||||
@@ -47,6 +74,7 @@ begin
|
||||
outb($40, PIT_DIVISOR and $FF);
|
||||
outb($40, PIT_DIVISOR shr 8);
|
||||
end;
|
||||
|
||||
function realIRQ(line: uint8): boolean;
|
||||
begin
|
||||
realIRQ := line < 16;
|
||||
@@ -60,6 +88,7 @@ begin
|
||||
if not realIRQ then outb($20, $20);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure acknowledge(line: uint8);
|
||||
begin
|
||||
if line >= 16 then exit;
|
||||
|
||||
@@ -15,6 +15,16 @@ function lock: PtrUInt;
|
||||
procedure unlock(flags: PtrUInt);
|
||||
procedure outb(port: uint16; value: uint8);
|
||||
function inb(port: uint16): uint8;
|
||||
procedure outw(port: uint16; value: uint16);
|
||||
function inw(port: uint16): uint16;
|
||||
procedure copyBytes(source, dest: PtrUInt; bytes: SizeUInt);
|
||||
procedure zero(dest: pointer; bytes: SizeUInt);
|
||||
procedure idle;
|
||||
procedure outl(port: uint16; value: uint32);
|
||||
function inl(port: uint16): uint32;
|
||||
|
||||
type
|
||||
TCPURegisters = record
|
||||
eax, ebx, ecx, edx: uint32;
|
||||
end;
|
||||
procedure queryCPU(leaf, subleaf: uint32; var registers: TCPURegisters);
|
||||
+7
-11
@@ -10,14 +10,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
unit arch.common.interrupts;
|
||||
interface
|
||||
function lock: PtrUInt;
|
||||
procedure unlock(flags: PtrUInt);
|
||||
implementation
|
||||
uses arch.platform.cpu;
|
||||
function lock: PtrUInt;
|
||||
begin lock := arch.platform.cpu.lock; end;
|
||||
procedure unlock(flags: PtrUInt);
|
||||
begin arch.platform.cpu.unlock(flags); end;
|
||||
end.
|
||||
type
|
||||
TIRQHandler = procedure;
|
||||
TTimerHandler = procedure(data: void);
|
||||
procedure registerIRQ(vector: uint8; handler: TIRQHandler);
|
||||
procedure registerTimer(handler: TTimerHandler);
|
||||
procedure routePCI(line, vector: uint8);
|
||||
function timerTicks: uint64;
|
||||
@@ -15,4 +15,7 @@ function allocateHeapPage: PtrUInt;
|
||||
function allocateLarge(pages: uint32): PtrUInt;
|
||||
procedure release(address: PtrUInt; pages: uint32);
|
||||
function identityReserve(address: PtrUInt): pointer;
|
||||
function freeBacking: uint64;
|
||||
function freePhysicalBytes: uint64;
|
||||
function totalPhysicalBytes: uint64;
|
||||
function physicalAddress(address: PtrUInt): uint64;
|
||||
function mapDevice(address: uint64; bytes: SizeUInt): pointer;
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Kieron Morris & Aaron Hance
|
||||
// Copyright 2026 Aaron Hance
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
{ Shared dispatch for the table emitted by compile_initcalls.sh.
|
||||
Initializers only register boot work or set globals; they cannot depend on
|
||||
heap, hardware setup, or the alphabetical order of this generated table. }
|
||||
var
|
||||
unitsInitialized: boolean;
|
||||
|
||||
procedure initializeUnits;
|
||||
var
|
||||
i: longint;
|
||||
entry: CodePointer;
|
||||
begin
|
||||
if unitsInitialized then exit;
|
||||
unitsInitialized := true;
|
||||
|
||||
for i := 1 to InitFinalTable.TableCount do begin
|
||||
entry := InitFinalTable.Procs[i].InitProc;
|
||||
if entry <> nil then
|
||||
TProcedure(entry)();
|
||||
end;
|
||||
end;
|
||||
@@ -12,10 +12,13 @@
|
||||
|
||||
{ Commands extracted from io.stdio (Kieron Morris). }
|
||||
unit arch.x86.console;
|
||||
|
||||
interface
|
||||
procedure init;
|
||||
|
||||
implementation
|
||||
uses io.stdio, core.version, driver.timer.rtc, arch.x86.util;
|
||||
|
||||
procedure cmd_version(params: PParamList; stdin_buf, stdout_buf, stderr_buf: POutBuf);
|
||||
begin
|
||||
bufWriteStr(stdout_buf, ' Asuro Version: ');
|
||||
|
||||
@@ -38,7 +38,7 @@ type
|
||||
Pmemory_map_t = boot.multiboot.Pmemory_map_t;
|
||||
|
||||
var
|
||||
multibootinfo : Pmultiboot_info_t = nil;
|
||||
multibootinfo : Pmultiboot_info_t absolute boot.multiboot.multibootinfo;
|
||||
multibootmagic : uint32;
|
||||
|
||||
implementation
|
||||
|
||||
@@ -62,7 +62,6 @@ procedure resetSystem();
|
||||
|
||||
function getESP : uint32;
|
||||
|
||||
function RolDWord(AValue : uint32; Dist : uint8) : uint32;
|
||||
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
|
||||
|
||||
function MsSinceSystemBoot : uint64;
|
||||
@@ -380,29 +379,6 @@ begin
|
||||
getTSC:= (hi SHL 32) OR lo;
|
||||
end;
|
||||
|
||||
function RolDWord(AValue : uint32; Dist : uint8) : uint32;
|
||||
var
|
||||
result : uint32;
|
||||
i : uint8;
|
||||
|
||||
begin
|
||||
result:= AValue;
|
||||
asm
|
||||
PUSH EAX
|
||||
end;
|
||||
for i:=0 to Dist-1 do begin
|
||||
asm
|
||||
MOV EAX, result
|
||||
ROL EAX, 1
|
||||
MOV result, EAX
|
||||
end;
|
||||
end;
|
||||
asm
|
||||
POP EAX
|
||||
end;
|
||||
RolDWord:= result;
|
||||
end;
|
||||
|
||||
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
|
||||
var
|
||||
result : uint32;
|
||||
|
||||
@@ -12,29 +12,67 @@
|
||||
|
||||
{ Build-selected x86 adapter. }
|
||||
unit arch.platform.cpu;
|
||||
|
||||
interface
|
||||
{$i ../../common/platform.cpu.inc}
|
||||
|
||||
implementation
|
||||
uses arch.x86.util, memory.raw;
|
||||
|
||||
function lock: PtrUInt; assembler; nostackframe;
|
||||
asm pushfd; cli; pop eax end;
|
||||
asm
|
||||
pushfd;
|
||||
cli;
|
||||
pop eax
|
||||
end;
|
||||
|
||||
procedure unlock(flags: PtrUInt);
|
||||
begin if (flags and $200) <> 0 then asm sti end; end;
|
||||
begin
|
||||
if (flags and $200) <> 0 then asm
|
||||
sti
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure idle;
|
||||
begin asm hlt end; end;
|
||||
begin
|
||||
asm
|
||||
hlt
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure outb(port: uint16; value: uint8);
|
||||
begin arch.x86.util.outb(port, value); end;
|
||||
begin
|
||||
arch.x86.util.outb(port, value);
|
||||
end;
|
||||
|
||||
function inb(port: uint16): uint8;
|
||||
begin inb := arch.x86.util.inb(port); end;
|
||||
begin
|
||||
inb := arch.x86.util.inb(port);
|
||||
end;
|
||||
|
||||
procedure copyBytes(source, dest: PtrUInt; bytes: SizeUInt);
|
||||
begin
|
||||
if bytes >= 16 then arch.x86.util.__REP_MOVSB_memcpy(source, dest, bytes)
|
||||
else memory.raw.move(pointer(source), pointer(dest), bytes);
|
||||
end;
|
||||
procedure zero(dest: pointer; bytes: SizeUInt);
|
||||
var d: pointer; b: SizeUInt;
|
||||
|
||||
procedure outw(port: uint16; value: uint16);
|
||||
begin
|
||||
d := dest; b := bytes;
|
||||
arch.x86.util.outw(port, value);
|
||||
end;
|
||||
|
||||
function inw(port: uint16): uint16;
|
||||
begin
|
||||
inw := arch.x86.util.inw(port);
|
||||
end;
|
||||
|
||||
procedure zero(dest: pointer; bytes: SizeUInt);
|
||||
var
|
||||
d: pointer;
|
||||
b: SizeUInt;
|
||||
begin
|
||||
d := dest;
|
||||
b := bytes;
|
||||
if b = 0 then exit;
|
||||
asm
|
||||
push edi
|
||||
@@ -50,4 +88,29 @@ begin
|
||||
pop edi
|
||||
end;
|
||||
end;
|
||||
procedure outl(port: uint16; value: uint32);
|
||||
begin
|
||||
arch.x86.util.outl(port, value);
|
||||
end;
|
||||
|
||||
function inl(port: uint16): uint32;
|
||||
begin
|
||||
inl := arch.x86.util.inl(port);
|
||||
end;
|
||||
|
||||
procedure queryCPU(leaf, subleaf: uint32; var registers: TCPURegisters); assembler; nostackframe;
|
||||
asm
|
||||
push ebx
|
||||
push edi
|
||||
mov edi, ecx
|
||||
mov ecx, edx
|
||||
cpuid
|
||||
mov [edi], eax
|
||||
mov [edi + 4], ebx
|
||||
mov [edi + 8], ecx
|
||||
mov [edi + 12], edx
|
||||
pop edi
|
||||
pop ebx
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -12,22 +12,39 @@
|
||||
|
||||
{ Build-selected x86 adapter. }
|
||||
unit arch.platform.diagnostics;
|
||||
|
||||
interface
|
||||
{$i ../../common/platform.diagnostics.inc}
|
||||
|
||||
implementation
|
||||
uses io.syslog, debug.tracer, core.panic;
|
||||
|
||||
procedure log(tag, message: pchar);
|
||||
begin io.syslog.logln(tag, message); end;
|
||||
begin
|
||||
io.syslog.logln(tag, message);
|
||||
end;
|
||||
|
||||
procedure push_trace(name: pchar);
|
||||
begin debug.tracer.push_trace(name); end;
|
||||
begin
|
||||
debug.tracer.push_trace(name);
|
||||
end;
|
||||
|
||||
procedure pop_trace;
|
||||
begin debug.tracer.pop_trace; end;
|
||||
begin
|
||||
debug.tracer.pop_trace;
|
||||
end;
|
||||
|
||||
procedure fatal(tag, message: pchar);
|
||||
begin core.panic.panic(tag, message, nil); end;
|
||||
begin
|
||||
core.panic.panic(tag, message, nil);
|
||||
end;
|
||||
|
||||
procedure testSummary(tag, passedKey, failedKey: pchar; passed, failed: uint32);
|
||||
begin
|
||||
io.syslog.log(tag, '');
|
||||
io.syslog.writeint(passed); io.syslog.writestring(' passed, ');
|
||||
io.syslog.writeint(failed); io.syslog.writestringln(' failed.');
|
||||
io.syslog.writeint(passed);
|
||||
io.syslog.writestring(' passed, ');
|
||||
io.syslog.writeint(failed);
|
||||
io.syslog.writestringln(' failed.');
|
||||
end;
|
||||
end.
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2026 Aaron Hance
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
unit arch.platform.interrupts;
|
||||
|
||||
interface
|
||||
{$i ../../common/platform.interrupts.inc}
|
||||
|
||||
implementation
|
||||
uses arch.x86.isr.mgr, arch.x86.isr.tmr0, arch.x86.isr.ioapic,
|
||||
arch.x86.bda, arch.platform.cpu;
|
||||
|
||||
function timerTicks: uint64;
|
||||
var
|
||||
flags: PtrUInt;
|
||||
begin
|
||||
flags := arch.platform.cpu.lock;
|
||||
timerTicks := Counters.c64;
|
||||
arch.platform.cpu.unlock(flags);
|
||||
end;
|
||||
|
||||
procedure registerIRQ(vector: uint8; handler: TIRQHandler);
|
||||
begin
|
||||
arch.x86.isr.mgr.registerISR(vector, handler);
|
||||
end;
|
||||
|
||||
procedure registerTimer(handler: TTimerHandler);
|
||||
begin
|
||||
arch.x86.isr.tmr0.hook(PtrUInt(handler));
|
||||
end;
|
||||
|
||||
procedure routePCI(line, vector: uint8);
|
||||
begin
|
||||
arch.x86.isr.ioapic.init;
|
||||
arch.x86.isr.ioapic.route_pci_irq(line, vector);
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -12,25 +12,33 @@
|
||||
|
||||
{ Mapping policy extracted from memory.heap (Kieron Morris). }
|
||||
unit arch.platform.memory;
|
||||
|
||||
interface
|
||||
const MAX_HEAP_REGIONS = 256;
|
||||
{$i ../../common/platform.memory.inc}
|
||||
|
||||
implementation
|
||||
uses arch.x86.memory.virtual, arch.x86.memory.physical, arch.platform.diagnostics;
|
||||
|
||||
function allocateHeapPage: PtrUInt;
|
||||
var i: uint32;
|
||||
var
|
||||
i: uint32;
|
||||
begin
|
||||
allocateHeapPage := 0;
|
||||
i := KERNEL_PAGE_NUMBER + 4;
|
||||
while i < 1024 do begin
|
||||
if arch.x86.memory.virtual.new_page(i) then begin
|
||||
allocateHeapPage := i shl 22; exit;
|
||||
allocateHeapPage := i shl 22;
|
||||
exit;
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
function allocateLarge(pages: uint32): PtrUInt;
|
||||
var curr_page, i: uint16; miss: boolean;
|
||||
var
|
||||
curr_page, i: uint16;
|
||||
miss: boolean;
|
||||
begin
|
||||
allocateLarge := 0;
|
||||
if (pages = 0) or (pages > MAX_HEAP_REGIONS) then exit;
|
||||
@@ -39,7 +47,9 @@ begin
|
||||
miss := false;
|
||||
for i := 0 to pages - 1 do begin
|
||||
if not page_mappable(curr_page + i) then begin
|
||||
miss := true; curr_page := curr_page + i; break;
|
||||
miss := true;
|
||||
curr_page := curr_page + i;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if not miss then begin
|
||||
@@ -47,7 +57,8 @@ begin
|
||||
while i < pages do begin
|
||||
if not arch.x86.memory.virtual.new_page(curr_page + i) then begin
|
||||
while i > 0 do begin
|
||||
dec(i); arch.x86.memory.virtual.free_page(curr_page + i);
|
||||
dec(i);
|
||||
arch.x86.memory.virtual.free_page(curr_page + i);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
@@ -59,23 +70,57 @@ begin
|
||||
inc(curr_page);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure release(address: PtrUInt; pages: uint32);
|
||||
var i: uint32; page_num: uint16;
|
||||
var
|
||||
i: uint32;
|
||||
page_num: uint16;
|
||||
begin
|
||||
if (pages = 0) or (pages > MAX_HEAP_REGIONS) then begin
|
||||
fatal('LMM', 'Invalid heap region release'); exit;
|
||||
fatal('LMM', 'Invalid heap region release');
|
||||
exit;
|
||||
end;
|
||||
page_num := address shr 22;
|
||||
for i := 0 to pages - 1 do arch.x86.memory.virtual.free_page(page_num + uint16(i));
|
||||
end;
|
||||
|
||||
function identityReserve(address: PtrUInt): pointer;
|
||||
var block: uint16;
|
||||
var
|
||||
block: uint16;
|
||||
begin
|
||||
block := address shr 22;
|
||||
force_alloc_block(block, 0);
|
||||
map_page(block, block);
|
||||
identityReserve := pointer(uint32(block) shl 22);
|
||||
end;
|
||||
function freeBacking: uint64;
|
||||
begin freeBacking := pmm_free_blocks; end;
|
||||
|
||||
function freePhysicalBytes: uint64;
|
||||
begin
|
||||
freePhysicalBytes := uint64(pmm_free_blocks) * $400000;
|
||||
end;
|
||||
|
||||
function totalPhysicalBytes: uint64;
|
||||
begin
|
||||
totalPhysicalBytes := uint64(pmm_total_blocks) * $400000;
|
||||
end;
|
||||
function physicalAddress(address: PtrUInt): uint64;
|
||||
begin
|
||||
physicalAddress := arch.x86.memory.virtual.vtop(address);
|
||||
end;
|
||||
|
||||
function mapDevice(address: uint64; bytes: SizeUInt): pointer;
|
||||
var
|
||||
page, last: uint32;
|
||||
begin
|
||||
mapDevice := nil;
|
||||
if (bytes = 0) or (address > $FFFFFFFF) or (bytes - 1 > $FFFFFFFF - address) then exit;
|
||||
page := uint32(address) shr 22;
|
||||
last := uint32(address + bytes - 1) shr 22;
|
||||
while page <= last do begin
|
||||
identityReserve(page shl 22);
|
||||
inc(page);
|
||||
end;
|
||||
mapDevice := pointer(PtrUInt(address));
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -12,12 +12,20 @@
|
||||
|
||||
{ Build-selected x86 adapter. }
|
||||
unit arch.platform.process;
|
||||
|
||||
interface
|
||||
{$i ../../common/platform.process.inc}
|
||||
|
||||
implementation
|
||||
uses arch.x86.proc.context, arch.x86.bda;
|
||||
|
||||
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
||||
begin prepare := arch.x86.proc.context.prepare(stack, bytes, entry); end;
|
||||
begin
|
||||
prepare := arch.x86.proc.context.prepare(stack, bytes, entry);
|
||||
end;
|
||||
|
||||
function timerTicks: uint32;
|
||||
begin timerTicks := PUInt32(@Counters.c32)^; end;
|
||||
begin
|
||||
timerTicks := PUInt32(@Counters.c32)^;
|
||||
end;
|
||||
end.
|
||||
@@ -12,12 +12,17 @@
|
||||
|
||||
{ i386 initial frame, extracted from proc.mgr (Kieron Morris). }
|
||||
unit arch.x86.proc.context;
|
||||
|
||||
interface
|
||||
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
||||
|
||||
implementation
|
||||
uses memory.raw;
|
||||
|
||||
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
||||
var top, frame: PtrUInt; i: uint32;
|
||||
var
|
||||
top, frame: PtrUInt;
|
||||
i: uint32;
|
||||
begin
|
||||
prepare := 0;
|
||||
if (stack = nil) or (entry = nil) or (bytes < 64) or
|
||||
|
||||
+14
-35
@@ -119,7 +119,6 @@ function Round(d: Double): int64;
|
||||
implementation
|
||||
|
||||
{ ---- Raw driver.io.serial debug helpers (COM1 $3F8, no dependencies) ---- }
|
||||
|
||||
procedure serial_putch(ch: char); assembler;
|
||||
asm
|
||||
push edx
|
||||
@@ -154,7 +153,8 @@ begin
|
||||
end;
|
||||
|
||||
procedure serial_putstr(s: pchar);
|
||||
var i: uint32;
|
||||
var
|
||||
i: uint32;
|
||||
begin
|
||||
i := 0;
|
||||
while s[i] <> #0 do begin
|
||||
@@ -196,20 +196,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{$i ../common/system.init.inc}
|
||||
|
||||
procedure fpc_initializeunits; [public, alias: 'FPC_INITIALIZEUNITS']; compilerproc;
|
||||
var
|
||||
i : longint;
|
||||
proc : CodePointer;
|
||||
begin
|
||||
{ Walk the compiler-generated INITFINAL table and call each unit's
|
||||
initialization procedure (if non-nil). This runs before kmain, so
|
||||
initialization sections must only do trivial work — write to static
|
||||
globals, register boot entries, etc. No I/O or heap allocation. }
|
||||
for i := 1 to InitFinalTable.TableCount do begin
|
||||
proc := InitFinalTable.Procs[i].InitProc;
|
||||
if proc <> nil then
|
||||
TProcedure(proc)();
|
||||
end;
|
||||
initializeUnits;
|
||||
end;
|
||||
|
||||
procedure fpc_do_exit; [public, alias: 'FPC_DO_EXIT']; compilerproc;
|
||||
@@ -348,7 +339,8 @@ begin
|
||||
end;
|
||||
|
||||
function fpc_mul_dword_to_qword(f1, f2: uint32): qword; [public, alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc;
|
||||
var res: qword;
|
||||
var
|
||||
res: qword;
|
||||
begin
|
||||
asm
|
||||
MOV EAX, f1
|
||||
@@ -368,8 +360,10 @@ procedure udiv64(dividendLo, dividendHi, divisorLo, divisorHi: uint32;
|
||||
var
|
||||
bit: longint;
|
||||
begin
|
||||
quotLo := 0; quotHi := 0;
|
||||
remLo := 0; remHi := 0;
|
||||
quotLo := 0;
|
||||
quotHi := 0;
|
||||
remLo := 0;
|
||||
remHi := 0;
|
||||
|
||||
for bit := 63 downto 0 do begin
|
||||
{ rem := rem shl 1 }
|
||||
@@ -567,7 +561,6 @@ begin
|
||||
end;
|
||||
|
||||
{ ---------- Float-to-integer intrinsics ---------- }
|
||||
|
||||
function Trunc(d: Double): int64; [public, alias: 'FPC_TRUNC'];
|
||||
var
|
||||
oldcw, newcw: word;
|
||||
@@ -599,8 +592,8 @@ begin
|
||||
end;
|
||||
|
||||
{ ---------- Memory allocation compilerprocs ---------- }
|
||||
|
||||
function kernel_kalloc(size: uint32): Pointer; external name 'kernel_kalloc';
|
||||
|
||||
procedure kernel_kfree(p: Pointer); external name 'kernel_kfree';
|
||||
|
||||
function fpc_getmem(size: PtrUInt): Pointer;
|
||||
@@ -616,7 +609,6 @@ begin
|
||||
end;
|
||||
|
||||
{ ---------- Exception handling compilerprocs ---------- }
|
||||
|
||||
procedure fpc_reraise; [public, alias: 'FPC_RERAISE']; compilerproc;
|
||||
begin
|
||||
{ In a bare-metal core.version re-raise is a fatal condition }
|
||||
@@ -641,30 +633,17 @@ begin
|
||||
end;
|
||||
|
||||
procedure init();
|
||||
var
|
||||
i : longint;
|
||||
proc : CodePointer;
|
||||
begin
|
||||
ASURO_KERNEL_START := uint32(@AK_START);
|
||||
ASURO_KERNEL_END := uint32(@AK_END);
|
||||
ASURO_KERNEL_SIZE:= ASURO_KERNEL_END - ASURO_KERNEL_START;
|
||||
ASURO_KERNEL_SIZE := ASURO_KERNEL_END - ASURO_KERNEL_START;
|
||||
ExceptAddrStack := nil;
|
||||
ErrorAddr := nil;
|
||||
ErrorCode := 0;
|
||||
ExitCode := 0;
|
||||
ExitProc := nil;
|
||||
|
||||
{ Walk the INITFINAL table generated by compile_initcalls.sh and call
|
||||
each unit's initialization section. FPC with -n does not insert this
|
||||
call automatically, so we do it explicitly here — after basic system
|
||||
globals are set up but before kmain proceeds.
|
||||
Note: we inline the walk rather than calling fpc_initializeunits
|
||||
because compilerproc procedures cannot be called from Pascal code. }
|
||||
for i := 1 to InitFinalTable.TableCount do begin
|
||||
proc := InitFinalTable.Procs[i].InitProc;
|
||||
if proc <> nil then
|
||||
TProcedure(proc)();
|
||||
end;
|
||||
initializeUnits;
|
||||
end;
|
||||
|
||||
end.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -11,8 +11,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
unit arch.x86_64.debug;
|
||||
|
||||
interface
|
||||
procedure init;
|
||||
|
||||
implementation
|
||||
uses debug.early;
|
||||
{ The stub initializes COM1. Bounded polling also allows boot without a UART. }
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Loaded 20 of 59 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user