Port shared core and platform services to native pointer widths
This commit is contained in:
1 parent
7a6be7f66e
commit
a27d9cb39d
59 files changed
+1888
-1291
No files matched your search
@@ -205,7 +205,7 @@ Key constants:
|
|||||||
- `DATA_OFFSET = $10000` — data area starts at 64 KB into each page
|
- `DATA_OFFSET = $10000` — data area starts at 64 KB into each page
|
||||||
- `LARGE_ALLOC_MAGIC = $FFFFFFFE` — sentinel for klalloc'd multi-page allocations
|
- `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
|
inline procedure that only restores IF via `sti`, avoiding dangerous EFLAGS restoration
|
||||||
(IOPL, NT, VM, AC bits that caused Bad-TSS on IRET).
|
(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 |
|
| 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 |
|
| 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 |
|
| 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.
|
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
|
## Dependencies
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ Returns the number of heap pages currently in the linked list.
|
|||||||
|
|
||||||
## Notes
|
## 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.
|
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. }
|
{ Shared PC interrupt-controller programming. Call with interrupts disabled. }
|
||||||
unit arch.common.legacyirq;
|
unit arch.common.legacyirq;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
const
|
const
|
||||||
PIT_INPUT_HZ = 1193182;
|
PIT_INPUT_HZ = 1193182;
|
||||||
PIT_DIVISOR = 149;
|
PIT_DIVISOR = 149;
|
||||||
procedure remap(masterMask, slaveMask: uint8);
|
procedure remap(masterMask, slaveMask: uint8);
|
||||||
procedure masks(masterMask, slaveMask: uint8);
|
procedure masks(masterMask, slaveMask: uint8);
|
||||||
|
procedure enableLine(line: uint8);
|
||||||
procedure timerStart;
|
procedure timerStart;
|
||||||
function realIRQ(line: uint8): boolean;
|
function realIRQ(line: uint8): boolean;
|
||||||
procedure acknowledge(line: uint8);
|
procedure acknowledge(line: uint8);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses arch.platform.cpu;
|
uses arch.platform.cpu;
|
||||||
|
|
||||||
procedure writeSlow(port: uint16; value: uint8);
|
procedure writeSlow(port: uint16; value: uint8);
|
||||||
begin
|
begin
|
||||||
outb(port, value);
|
outb(port, value);
|
||||||
outb($80, 0);
|
outb($80, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure masks(masterMask, slaveMask: uint8);
|
procedure masks(masterMask, slaveMask: uint8);
|
||||||
begin
|
begin
|
||||||
writeSlow($21, masterMask); writeSlow($A1, slaveMask);
|
writeSlow($21, masterMask);
|
||||||
|
writeSlow($A1, slaveMask);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure remap(masterMask, slaveMask: uint8);
|
procedure remap(masterMask, slaveMask: uint8);
|
||||||
begin
|
begin
|
||||||
writeSlow($20, $11); writeSlow($A0, $11);
|
writeSlow($20, $11);
|
||||||
writeSlow($21, $20); writeSlow($A1, $28);
|
writeSlow($A0, $11);
|
||||||
writeSlow($21, $04); writeSlow($A1, $02);
|
writeSlow($21, $20);
|
||||||
writeSlow($21, $01); writeSlow($A1, $01);
|
writeSlow($A1, $28);
|
||||||
|
writeSlow($21, $04);
|
||||||
|
writeSlow($A1, $02);
|
||||||
|
writeSlow($21, $01);
|
||||||
|
writeSlow($A1, $01);
|
||||||
masks(masterMask, slaveMask);
|
masks(masterMask, slaveMask);
|
||||||
end;
|
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;
|
procedure timerStart;
|
||||||
begin
|
begin
|
||||||
{ Channel 0, low/high byte, mode 2, binary. }
|
{ Channel 0, low/high byte, mode 2, binary. }
|
||||||
@@ -47,6 +74,7 @@ begin
|
|||||||
outb($40, PIT_DIVISOR and $FF);
|
outb($40, PIT_DIVISOR and $FF);
|
||||||
outb($40, PIT_DIVISOR shr 8);
|
outb($40, PIT_DIVISOR shr 8);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function realIRQ(line: uint8): boolean;
|
function realIRQ(line: uint8): boolean;
|
||||||
begin
|
begin
|
||||||
realIRQ := line < 16;
|
realIRQ := line < 16;
|
||||||
@@ -60,6 +88,7 @@ begin
|
|||||||
if not realIRQ then outb($20, $20);
|
if not realIRQ then outb($20, $20);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure acknowledge(line: uint8);
|
procedure acknowledge(line: uint8);
|
||||||
begin
|
begin
|
||||||
if line >= 16 then exit;
|
if line >= 16 then exit;
|
||||||
|
|||||||
@@ -15,6 +15,16 @@ function lock: PtrUInt;
|
|||||||
procedure unlock(flags: PtrUInt);
|
procedure unlock(flags: PtrUInt);
|
||||||
procedure outb(port: uint16; value: uint8);
|
procedure outb(port: uint16; value: uint8);
|
||||||
function inb(port: uint16): 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 copyBytes(source, dest: PtrUInt; bytes: SizeUInt);
|
||||||
procedure zero(dest: pointer; bytes: SizeUInt);
|
procedure zero(dest: pointer; bytes: SizeUInt);
|
||||||
procedure idle;
|
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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
unit arch.common.interrupts;
|
type
|
||||||
interface
|
TIRQHandler = procedure;
|
||||||
function lock: PtrUInt;
|
TTimerHandler = procedure(data: void);
|
||||||
procedure unlock(flags: PtrUInt);
|
procedure registerIRQ(vector: uint8; handler: TIRQHandler);
|
||||||
implementation
|
procedure registerTimer(handler: TTimerHandler);
|
||||||
uses arch.platform.cpu;
|
procedure routePCI(line, vector: uint8);
|
||||||
function lock: PtrUInt;
|
function timerTicks: uint64;
|
||||||
begin lock := arch.platform.cpu.lock; end;
|
|
||||||
procedure unlock(flags: PtrUInt);
|
|
||||||
begin arch.platform.cpu.unlock(flags); end;
|
|
||||||
end.
|
|
||||||
@@ -15,4 +15,7 @@ function allocateHeapPage: PtrUInt;
|
|||||||
function allocateLarge(pages: uint32): PtrUInt;
|
function allocateLarge(pages: uint32): PtrUInt;
|
||||||
procedure release(address: PtrUInt; pages: uint32);
|
procedure release(address: PtrUInt; pages: uint32);
|
||||||
function identityReserve(address: PtrUInt): pointer;
|
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). }
|
{ Commands extracted from io.stdio (Kieron Morris). }
|
||||||
unit arch.x86.console;
|
unit arch.x86.console;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
procedure init;
|
procedure init;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses io.stdio, core.version, driver.timer.rtc, arch.x86.util;
|
uses io.stdio, core.version, driver.timer.rtc, arch.x86.util;
|
||||||
|
|
||||||
procedure cmd_version(params: PParamList; stdin_buf, stdout_buf, stderr_buf: POutBuf);
|
procedure cmd_version(params: PParamList; stdin_buf, stdout_buf, stderr_buf: POutBuf);
|
||||||
begin
|
begin
|
||||||
bufWriteStr(stdout_buf, ' Asuro Version: ');
|
bufWriteStr(stdout_buf, ' Asuro Version: ');
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ type
|
|||||||
Pmemory_map_t = boot.multiboot.Pmemory_map_t;
|
Pmemory_map_t = boot.multiboot.Pmemory_map_t;
|
||||||
|
|
||||||
var
|
var
|
||||||
multibootinfo : Pmultiboot_info_t = nil;
|
multibootinfo : Pmultiboot_info_t absolute boot.multiboot.multibootinfo;
|
||||||
multibootmagic : uint32;
|
multibootmagic : uint32;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ procedure resetSystem();
|
|||||||
|
|
||||||
function getESP : uint32;
|
function getESP : uint32;
|
||||||
|
|
||||||
function RolDWord(AValue : uint32; Dist : uint8) : uint32;
|
|
||||||
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
|
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
|
||||||
|
|
||||||
function MsSinceSystemBoot : uint64;
|
function MsSinceSystemBoot : uint64;
|
||||||
@@ -380,29 +379,6 @@ begin
|
|||||||
getTSC:= (hi SHL 32) OR lo;
|
getTSC:= (hi SHL 32) OR lo;
|
||||||
end;
|
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;
|
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
|
||||||
var
|
var
|
||||||
result : uint32;
|
result : uint32;
|
||||||
|
|||||||
@@ -12,29 +12,67 @@
|
|||||||
|
|
||||||
{ Build-selected x86 adapter. }
|
{ Build-selected x86 adapter. }
|
||||||
unit arch.platform.cpu;
|
unit arch.platform.cpu;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
{$i ../../common/platform.cpu.inc}
|
{$i ../../common/platform.cpu.inc}
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses arch.x86.util, memory.raw;
|
uses arch.x86.util, memory.raw;
|
||||||
|
|
||||||
function lock: PtrUInt; assembler; nostackframe;
|
function lock: PtrUInt; assembler; nostackframe;
|
||||||
asm pushfd; cli; pop eax end;
|
asm
|
||||||
|
pushfd;
|
||||||
|
cli;
|
||||||
|
pop eax
|
||||||
|
end;
|
||||||
|
|
||||||
procedure unlock(flags: PtrUInt);
|
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;
|
procedure idle;
|
||||||
begin asm hlt end; end;
|
begin
|
||||||
|
asm
|
||||||
|
hlt
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure outb(port: uint16; value: uint8);
|
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;
|
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);
|
procedure copyBytes(source, dest: PtrUInt; bytes: SizeUInt);
|
||||||
begin
|
begin
|
||||||
if bytes >= 16 then arch.x86.util.__REP_MOVSB_memcpy(source, dest, bytes)
|
if bytes >= 16 then arch.x86.util.__REP_MOVSB_memcpy(source, dest, bytes)
|
||||||
else memory.raw.move(pointer(source), pointer(dest), bytes);
|
else memory.raw.move(pointer(source), pointer(dest), bytes);
|
||||||
end;
|
end;
|
||||||
procedure zero(dest: pointer; bytes: SizeUInt);
|
|
||||||
var d: pointer; b: SizeUInt;
|
procedure outw(port: uint16; value: uint16);
|
||||||
begin
|
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;
|
if b = 0 then exit;
|
||||||
asm
|
asm
|
||||||
push edi
|
push edi
|
||||||
@@ -50,4 +88,29 @@ begin
|
|||||||
pop edi
|
pop edi
|
||||||
end;
|
end;
|
||||||
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.
|
end.
|
||||||
@@ -12,22 +12,39 @@
|
|||||||
|
|
||||||
{ Build-selected x86 adapter. }
|
{ Build-selected x86 adapter. }
|
||||||
unit arch.platform.diagnostics;
|
unit arch.platform.diagnostics;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
{$i ../../common/platform.diagnostics.inc}
|
{$i ../../common/platform.diagnostics.inc}
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses io.syslog, debug.tracer, core.panic;
|
uses io.syslog, debug.tracer, core.panic;
|
||||||
|
|
||||||
procedure log(tag, message: pchar);
|
procedure log(tag, message: pchar);
|
||||||
begin io.syslog.logln(tag, message); end;
|
begin
|
||||||
|
io.syslog.logln(tag, message);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure push_trace(name: pchar);
|
procedure push_trace(name: pchar);
|
||||||
begin debug.tracer.push_trace(name); end;
|
begin
|
||||||
|
debug.tracer.push_trace(name);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure pop_trace;
|
procedure pop_trace;
|
||||||
begin debug.tracer.pop_trace; end;
|
begin
|
||||||
|
debug.tracer.pop_trace;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure fatal(tag, message: pchar);
|
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);
|
procedure testSummary(tag, passedKey, failedKey: pchar; passed, failed: uint32);
|
||||||
begin
|
begin
|
||||||
io.syslog.log(tag, '');
|
io.syslog.log(tag, '');
|
||||||
io.syslog.writeint(passed); io.syslog.writestring(' passed, ');
|
io.syslog.writeint(passed);
|
||||||
io.syslog.writeint(failed); io.syslog.writestringln(' failed.');
|
io.syslog.writestring(' passed, ');
|
||||||
|
io.syslog.writeint(failed);
|
||||||
|
io.syslog.writestringln(' failed.');
|
||||||
end;
|
end;
|
||||||
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). }
|
{ Mapping policy extracted from memory.heap (Kieron Morris). }
|
||||||
unit arch.platform.memory;
|
unit arch.platform.memory;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
const MAX_HEAP_REGIONS = 256;
|
const MAX_HEAP_REGIONS = 256;
|
||||||
{$i ../../common/platform.memory.inc}
|
{$i ../../common/platform.memory.inc}
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses arch.x86.memory.virtual, arch.x86.memory.physical, arch.platform.diagnostics;
|
uses arch.x86.memory.virtual, arch.x86.memory.physical, arch.platform.diagnostics;
|
||||||
|
|
||||||
function allocateHeapPage: PtrUInt;
|
function allocateHeapPage: PtrUInt;
|
||||||
var i: uint32;
|
var
|
||||||
|
i: uint32;
|
||||||
begin
|
begin
|
||||||
allocateHeapPage := 0;
|
allocateHeapPage := 0;
|
||||||
i := KERNEL_PAGE_NUMBER + 4;
|
i := KERNEL_PAGE_NUMBER + 4;
|
||||||
while i < 1024 do begin
|
while i < 1024 do begin
|
||||||
if arch.x86.memory.virtual.new_page(i) then begin
|
if arch.x86.memory.virtual.new_page(i) then begin
|
||||||
allocateHeapPage := i shl 22; exit;
|
allocateHeapPage := i shl 22;
|
||||||
|
exit;
|
||||||
end;
|
end;
|
||||||
inc(i);
|
inc(i);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function allocateLarge(pages: uint32): PtrUInt;
|
function allocateLarge(pages: uint32): PtrUInt;
|
||||||
var curr_page, i: uint16; miss: boolean;
|
var
|
||||||
|
curr_page, i: uint16;
|
||||||
|
miss: boolean;
|
||||||
begin
|
begin
|
||||||
allocateLarge := 0;
|
allocateLarge := 0;
|
||||||
if (pages = 0) or (pages > MAX_HEAP_REGIONS) then exit;
|
if (pages = 0) or (pages > MAX_HEAP_REGIONS) then exit;
|
||||||
@@ -39,7 +47,9 @@ begin
|
|||||||
miss := false;
|
miss := false;
|
||||||
for i := 0 to pages - 1 do begin
|
for i := 0 to pages - 1 do begin
|
||||||
if not page_mappable(curr_page + i) then 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;
|
||||||
end;
|
end;
|
||||||
if not miss then begin
|
if not miss then begin
|
||||||
@@ -47,7 +57,8 @@ begin
|
|||||||
while i < pages do begin
|
while i < pages do begin
|
||||||
if not arch.x86.memory.virtual.new_page(curr_page + i) then begin
|
if not arch.x86.memory.virtual.new_page(curr_page + i) then begin
|
||||||
while i > 0 do 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;
|
end;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@@ -59,23 +70,57 @@ begin
|
|||||||
inc(curr_page);
|
inc(curr_page);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure release(address: PtrUInt; pages: uint32);
|
procedure release(address: PtrUInt; pages: uint32);
|
||||||
var i: uint32; page_num: uint16;
|
var
|
||||||
|
i: uint32;
|
||||||
|
page_num: uint16;
|
||||||
begin
|
begin
|
||||||
if (pages = 0) or (pages > MAX_HEAP_REGIONS) then 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;
|
end;
|
||||||
page_num := address shr 22;
|
page_num := address shr 22;
|
||||||
for i := 0 to pages - 1 do arch.x86.memory.virtual.free_page(page_num + uint16(i));
|
for i := 0 to pages - 1 do arch.x86.memory.virtual.free_page(page_num + uint16(i));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function identityReserve(address: PtrUInt): pointer;
|
function identityReserve(address: PtrUInt): pointer;
|
||||||
var block: uint16;
|
var
|
||||||
|
block: uint16;
|
||||||
begin
|
begin
|
||||||
block := address shr 22;
|
block := address shr 22;
|
||||||
force_alloc_block(block, 0);
|
force_alloc_block(block, 0);
|
||||||
map_page(block, block);
|
map_page(block, block);
|
||||||
identityReserve := pointer(uint32(block) shl 22);
|
identityReserve := pointer(uint32(block) shl 22);
|
||||||
end;
|
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.
|
end.
|
||||||
@@ -12,12 +12,20 @@
|
|||||||
|
|
||||||
{ Build-selected x86 adapter. }
|
{ Build-selected x86 adapter. }
|
||||||
unit arch.platform.process;
|
unit arch.platform.process;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
{$i ../../common/platform.process.inc}
|
{$i ../../common/platform.process.inc}
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses arch.x86.proc.context, arch.x86.bda;
|
uses arch.x86.proc.context, arch.x86.bda;
|
||||||
|
|
||||||
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
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;
|
function timerTicks: uint32;
|
||||||
begin timerTicks := PUInt32(@Counters.c32)^; end;
|
begin
|
||||||
|
timerTicks := PUInt32(@Counters.c32)^;
|
||||||
|
end;
|
||||||
end.
|
end.
|
||||||
@@ -12,12 +12,17 @@
|
|||||||
|
|
||||||
{ i386 initial frame, extracted from proc.mgr (Kieron Morris). }
|
{ i386 initial frame, extracted from proc.mgr (Kieron Morris). }
|
||||||
unit arch.x86.proc.context;
|
unit arch.x86.proc.context;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses memory.raw;
|
uses memory.raw;
|
||||||
|
|
||||||
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
function prepare(stack: pointer; bytes: SizeUInt; entry: pointer): PtrUInt;
|
||||||
var top, frame: PtrUInt; i: uint32;
|
var
|
||||||
|
top, frame: PtrUInt;
|
||||||
|
i: uint32;
|
||||||
begin
|
begin
|
||||||
prepare := 0;
|
prepare := 0;
|
||||||
if (stack = nil) or (entry = nil) or (bytes < 64) or
|
if (stack = nil) or (entry = nil) or (bytes < 64) or
|
||||||
|
|||||||
+13
-34
@@ -119,7 +119,6 @@ function Round(d: Double): int64;
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ ---- Raw driver.io.serial debug helpers (COM1 $3F8, no dependencies) ---- }
|
{ ---- Raw driver.io.serial debug helpers (COM1 $3F8, no dependencies) ---- }
|
||||||
|
|
||||||
procedure serial_putch(ch: char); assembler;
|
procedure serial_putch(ch: char); assembler;
|
||||||
asm
|
asm
|
||||||
push edx
|
push edx
|
||||||
@@ -154,7 +153,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure serial_putstr(s: pchar);
|
procedure serial_putstr(s: pchar);
|
||||||
var i: uint32;
|
var
|
||||||
|
i: uint32;
|
||||||
begin
|
begin
|
||||||
i := 0;
|
i := 0;
|
||||||
while s[i] <> #0 do begin
|
while s[i] <> #0 do begin
|
||||||
@@ -196,20 +196,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$i ../common/system.init.inc}
|
||||||
|
|
||||||
procedure fpc_initializeunits; [public, alias: 'FPC_INITIALIZEUNITS']; compilerproc;
|
procedure fpc_initializeunits; [public, alias: 'FPC_INITIALIZEUNITS']; compilerproc;
|
||||||
var
|
|
||||||
i : longint;
|
|
||||||
proc : CodePointer;
|
|
||||||
begin
|
begin
|
||||||
{ Walk the compiler-generated INITFINAL table and call each unit's
|
initializeUnits;
|
||||||
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;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpc_do_exit; [public, alias: 'FPC_DO_EXIT']; compilerproc;
|
procedure fpc_do_exit; [public, alias: 'FPC_DO_EXIT']; compilerproc;
|
||||||
@@ -348,7 +339,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function fpc_mul_dword_to_qword(f1, f2: uint32): qword; [public, alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc;
|
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
|
begin
|
||||||
asm
|
asm
|
||||||
MOV EAX, f1
|
MOV EAX, f1
|
||||||
@@ -368,8 +360,10 @@ procedure udiv64(dividendLo, dividendHi, divisorLo, divisorHi: uint32;
|
|||||||
var
|
var
|
||||||
bit: longint;
|
bit: longint;
|
||||||
begin
|
begin
|
||||||
quotLo := 0; quotHi := 0;
|
quotLo := 0;
|
||||||
remLo := 0; remHi := 0;
|
quotHi := 0;
|
||||||
|
remLo := 0;
|
||||||
|
remHi := 0;
|
||||||
|
|
||||||
for bit := 63 downto 0 do begin
|
for bit := 63 downto 0 do begin
|
||||||
{ rem := rem shl 1 }
|
{ rem := rem shl 1 }
|
||||||
@@ -567,7 +561,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ ---------- Float-to-integer intrinsics ---------- }
|
{ ---------- Float-to-integer intrinsics ---------- }
|
||||||
|
|
||||||
function Trunc(d: Double): int64; [public, alias: 'FPC_TRUNC'];
|
function Trunc(d: Double): int64; [public, alias: 'FPC_TRUNC'];
|
||||||
var
|
var
|
||||||
oldcw, newcw: word;
|
oldcw, newcw: word;
|
||||||
@@ -599,8 +592,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ ---------- Memory allocation compilerprocs ---------- }
|
{ ---------- Memory allocation compilerprocs ---------- }
|
||||||
|
|
||||||
function kernel_kalloc(size: uint32): Pointer; external name 'kernel_kalloc';
|
function kernel_kalloc(size: uint32): Pointer; external name 'kernel_kalloc';
|
||||||
|
|
||||||
procedure kernel_kfree(p: Pointer); external name 'kernel_kfree';
|
procedure kernel_kfree(p: Pointer); external name 'kernel_kfree';
|
||||||
|
|
||||||
function fpc_getmem(size: PtrUInt): Pointer;
|
function fpc_getmem(size: PtrUInt): Pointer;
|
||||||
@@ -616,7 +609,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ ---------- Exception handling compilerprocs ---------- }
|
{ ---------- Exception handling compilerprocs ---------- }
|
||||||
|
|
||||||
procedure fpc_reraise; [public, alias: 'FPC_RERAISE']; compilerproc;
|
procedure fpc_reraise; [public, alias: 'FPC_RERAISE']; compilerproc;
|
||||||
begin
|
begin
|
||||||
{ In a bare-metal core.version re-raise is a fatal condition }
|
{ In a bare-metal core.version re-raise is a fatal condition }
|
||||||
@@ -641,9 +633,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure init();
|
procedure init();
|
||||||
var
|
|
||||||
i : longint;
|
|
||||||
proc : CodePointer;
|
|
||||||
begin
|
begin
|
||||||
ASURO_KERNEL_START := uint32(@AK_START);
|
ASURO_KERNEL_START := uint32(@AK_START);
|
||||||
ASURO_KERNEL_END := uint32(@AK_END);
|
ASURO_KERNEL_END := uint32(@AK_END);
|
||||||
@@ -654,17 +643,7 @@ begin
|
|||||||
ExitCode := 0;
|
ExitCode := 0;
|
||||||
ExitProc := nil;
|
ExitProc := nil;
|
||||||
|
|
||||||
{ Walk the INITFINAL table generated by compile_initcalls.sh and call
|
initializeUnits;
|
||||||
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;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -11,8 +11,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
unit arch.x86_64.debug;
|
unit arch.x86_64.debug;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
procedure init;
|
procedure init;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses debug.early;
|
uses debug.early;
|
||||||
{ The stub initializes COM1. Bounded polling also allows boot without a UART. }
|
{ 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