Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5548c878b | ||
|
|
33985afea1 | ||
|
|
a3b766464b | ||
|
|
262d064b6d | ||
|
|
738e5828f6 |
No files matched your search
@@ -29,14 +29,11 @@ unit contextswitcher;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
idt, isrmanager, processmanager, proctypes, util, syslog, tracer;
|
idt, isrmanager, processmanager, proctypes, util, tracer;
|
||||||
|
|
||||||
{ Initialise: overwrite IDT gate 32 with our custom ISR. }
|
{ Initialise: overwrite IDT gate 32 with our custom ISR. }
|
||||||
procedure init;
|
procedure init;
|
||||||
|
|
||||||
{ No idle ESP variable needed — idle is now a formal process (PID 0)
|
|
||||||
with its SavedESP managed like any other process. }
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ -----------------------------------------------------------------------
|
{ -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -957,11 +957,14 @@ end;
|
|||||||
procedure usb_check_hotplug;
|
procedure usb_check_hotplug;
|
||||||
var
|
var
|
||||||
i : uint32;
|
i : uint32;
|
||||||
|
count: uint32;
|
||||||
hc : PUSBHCDriver;
|
hc : PUSBHCDriver;
|
||||||
port : uint8;
|
port : uint8;
|
||||||
begin
|
begin
|
||||||
if HCList = nil then exit;
|
if HCList = nil then exit;
|
||||||
for i := 0 to LL_Size(HCList) - 1 do begin
|
count := LL_Size(HCList);
|
||||||
|
if count = 0 then exit;
|
||||||
|
for i := 0 to count - 1 do begin
|
||||||
hc := PUSBHCDriver(LL_Get(HCList, i));
|
hc := PUSBHCDriver(LL_Get(HCList, i));
|
||||||
if (hc <> nil) and hc^.PortChangePending then begin
|
if (hc <> nil) and hc^.PortChangePending then begin
|
||||||
hc^.PortChangePending := false;
|
hc^.PortChangePending := false;
|
||||||
|
|||||||
@@ -119,8 +119,12 @@ var
|
|||||||
x32, y32 : sint32;
|
x32, y32 : sint32;
|
||||||
r : pchar;
|
r : pchar;
|
||||||
begin
|
begin
|
||||||
|
{ mouse_wait(0) checks OBF with a short timeout (100 iterations).
|
||||||
|
When it returns true, data is ready — read it directly with inb($60).
|
||||||
|
Do NOT call mouse_read here: it uses mouse_wait_long (100k iterations)
|
||||||
|
and would spin-block the ISR if the next packet byte hasn't arrived yet. }
|
||||||
while mouse_wait(0) do begin
|
while mouse_wait(0) do begin
|
||||||
b := mouse_read;
|
b := inb($60);
|
||||||
if Cycle = 0 then begin
|
if Cycle = 0 then begin
|
||||||
if (b AND $08) = $08 then begin
|
if (b AND $08) = $08 then begin
|
||||||
Mouse_Byte[Cycle] := b;
|
Mouse_Byte[Cycle] := b;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
{
|
{
|
||||||
Driver->Timer->TMR_0_ISR - 1024hz Timer Driver.
|
Driver->Timer->TMR_0_ISR - 8khz Timer Driver.
|
||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
@author(Kieron Morris <[email protected]>)
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ var
|
|||||||
Hooks : Array[1..MAX_HOOKS] of pp_hook_method;
|
Hooks : Array[1..MAX_HOOKS] of pp_hook_method;
|
||||||
Registered : boolean = false;
|
Registered : boolean = false;
|
||||||
|
|
||||||
procedure Main; //IRQ0, 1024.19hz aprox
|
procedure Main; //IRQ0, ~8001hz
|
||||||
var
|
var
|
||||||
i : integer;
|
i : integer;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ procedure register();
|
|||||||
begin
|
begin
|
||||||
if not registered then begin
|
if not registered then begin
|
||||||
asm
|
asm
|
||||||
mov ax, 1193
|
mov ax, 149
|
||||||
out $40, al
|
out $40, al
|
||||||
mov al, ah
|
mov al, ah
|
||||||
out $40, al
|
out $40, al
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
Driver->Timer->GraphicsRefresh - Timer-driven graphics refresh at ~120FPS.
|
|
||||||
|
|
||||||
Hooks into the 1024Hz timer (TMR_0_ISR) and calls the desktop, uidebug,
|
|
||||||
LVGL and video flush routines every ~9 ticks (1024/9 ≈ 113.8 FPS).
|
|
||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
|
||||||
}
|
|
||||||
unit graphicsrefresh;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
uses
|
|
||||||
util,
|
|
||||||
TMR_0_ISR,
|
|
||||||
desktop,
|
|
||||||
uidebug,
|
|
||||||
lvgl,
|
|
||||||
video,
|
|
||||||
windows,
|
|
||||||
syslog;
|
|
||||||
|
|
||||||
const
|
|
||||||
{ 1024 / 4 ≈ 256 FPS }
|
|
||||||
TICKS_PER_FRAME = 4;
|
|
||||||
|
|
||||||
var
|
|
||||||
TickCounter : uint32;
|
|
||||||
|
|
||||||
procedure on_tick(data : void);
|
|
||||||
begin
|
|
||||||
TickCounter := TickCounter + 1;
|
|
||||||
if TickCounter >= TICKS_PER_FRAME then begin
|
|
||||||
TickCounter := 0;
|
|
||||||
windows.reapOrphanedWindows;
|
|
||||||
desktop.update;
|
|
||||||
uidebug.update;
|
|
||||||
lvgl_handler;
|
|
||||||
video.Flush;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
begin
|
|
||||||
TickCounter := 0;
|
|
||||||
TMR_0_ISR.hook(uint32(@on_tick));
|
|
||||||
syslog.logln('GFXREFRESH', 'Hooked into 1024Hz timer (~120 FPS).');
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
Driver->Timer->USBHotplug - Timer-driven USB hotplug polling at ~1Hz.
|
|
||||||
|
|
||||||
Hooks into the 1024Hz timer (TMR_0_ISR) and calls
|
|
||||||
usbcore.usb_check_hotplug every 1024 ticks (approximately once per second).
|
|
||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
|
||||||
}
|
|
||||||
unit usbhotplug;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
uses
|
|
||||||
util,
|
|
||||||
TMR_0_ISR,
|
|
||||||
usbcore,
|
|
||||||
syslog;
|
|
||||||
|
|
||||||
const
|
|
||||||
{ 1024 ticks at 1024Hz ≈ 1 second }
|
|
||||||
TICKS_PER_POLL = 1024;
|
|
||||||
|
|
||||||
var
|
|
||||||
TickCounter : uint32;
|
|
||||||
|
|
||||||
procedure on_tick(data : void);
|
|
||||||
begin
|
|
||||||
TickCounter := TickCounter + 1;
|
|
||||||
if TickCounter >= TICKS_PER_POLL then begin
|
|
||||||
TickCounter := 0;
|
|
||||||
usbcore.usb_check_hotplug;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
begin
|
|
||||||
TickCounter := 0;
|
|
||||||
TMR_0_ISR.hook(uint32(@on_tick));
|
|
||||||
syslog.logln('USBHOTPLUG', 'Hooked into 1024Hz timer (~1Hz polling).');
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
|
||||||
@@ -18,7 +18,7 @@ const
|
|||||||
PROCESS_STACK_SIZE = 8192;
|
PROCESS_STACK_SIZE = 8192;
|
||||||
|
|
||||||
{ Base quantum multiplier: quantum = Priority * BASE_QUANTUM ticks }
|
{ Base quantum multiplier: quantum = Priority * BASE_QUANTUM ticks }
|
||||||
BASE_QUANTUM = 8;
|
BASE_QUANTUM = 5;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ Forward declaration }
|
{ Forward declaration }
|
||||||
|
|||||||
+23
-10
@@ -25,7 +25,7 @@ interface
|
|||||||
uses
|
uses
|
||||||
multiboot, bios_data_area,
|
multiboot, bios_data_area,
|
||||||
util,
|
util,
|
||||||
gdt, idt, isr, irq, tss, v86,
|
gdt, idt, isr, irq,
|
||||||
TMR_0_ISR,
|
TMR_0_ISR,
|
||||||
syslog, stdio,
|
syslog, stdio,
|
||||||
keyboard, mouse,
|
keyboard, mouse,
|
||||||
@@ -33,7 +33,6 @@ uses
|
|||||||
vmemorymanager, pmemorymanager, lmemorymanager,
|
vmemorymanager, pmemorymanager, lmemorymanager,
|
||||||
tracer,
|
tracer,
|
||||||
drivermanagement,
|
drivermanagement,
|
||||||
scheduler,
|
|
||||||
progmanager,
|
progmanager,
|
||||||
processmanager, contextswitcher,
|
processmanager, contextswitcher,
|
||||||
testprocs,
|
testprocs,
|
||||||
@@ -66,12 +65,29 @@ uses
|
|||||||
md5,
|
md5,
|
||||||
base64,
|
base64,
|
||||||
rand,
|
rand,
|
||||||
hashmap, vfs,
|
hashmap,
|
||||||
video, vesa, doublebuffer, color, lvgl, desktop, uidebug,
|
vfs,
|
||||||
gpu, bga,
|
video,
|
||||||
|
vesa,
|
||||||
|
doublebuffer,
|
||||||
|
color,
|
||||||
|
lvgl,
|
||||||
|
desktop,
|
||||||
|
uidebug,
|
||||||
|
gpu,
|
||||||
|
bga,
|
||||||
vterminal,
|
vterminal,
|
||||||
graphicsrefresh, usbhotplug,
|
graphicsrefresh,
|
||||||
fifo, cfifo, cfifols, lifo, circ, minh, maxh, prio;
|
usbhotplug,
|
||||||
|
fifo,
|
||||||
|
cfifo,
|
||||||
|
cfifols,
|
||||||
|
lifo,
|
||||||
|
circ,
|
||||||
|
minh,
|
||||||
|
maxh,
|
||||||
|
prio,
|
||||||
|
v86;
|
||||||
|
|
||||||
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
|
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
|
||||||
|
|
||||||
@@ -174,9 +190,6 @@ begin
|
|||||||
stdio.init();
|
stdio.init();
|
||||||
stdio.registerCommand('BSOD', @terminal_command_bsod, 'Force a Panic Screen.');
|
stdio.registerCommand('BSOD', @terminal_command_bsod, 'Force a Panic Screen.');
|
||||||
|
|
||||||
tss.init();
|
|
||||||
scheduler.init();
|
|
||||||
|
|
||||||
{ CPUID }
|
{ CPUID }
|
||||||
syslog.logln('CPU', 'Init begin');
|
syslog.logln('CPU', 'Init begin');
|
||||||
cpu.init();
|
cpu.init();
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
prog->GraphicsRefresh - Continuous graphics rendering process.
|
||||||
|
|
||||||
|
Spawns a dedicated render process that loops indefinitely, driving the
|
||||||
|
desktop, LVGL and video-flush pipeline. The loop does real work every
|
||||||
|
iteration (especially the 7.3 MB SSE framebuffer copy in video.Flush),
|
||||||
|
which keeps the vCPU active so the NEM/Hyper-V back-end never
|
||||||
|
deschedules it and starves the PIT of interrupts.
|
||||||
|
|
||||||
|
@author(Kieron Morris <[email protected]>)
|
||||||
|
}
|
||||||
|
unit graphicsrefresh;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
procedure init;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
desktop,
|
||||||
|
uidebug,
|
||||||
|
lvgl,
|
||||||
|
video,
|
||||||
|
windows,
|
||||||
|
processmanager,
|
||||||
|
proctypes,
|
||||||
|
syslog,
|
||||||
|
TMR_0_ISR;
|
||||||
|
|
||||||
|
{ Render process entry point — runs as a normal scheduled process with
|
||||||
|
interrupts enabled. Continuously drives the full render pipeline so
|
||||||
|
the vCPU is always executing real work (no HLT / PAUSE spin-waits
|
||||||
|
that would trigger pause-loop exits under NEM/Hyper-V). }
|
||||||
|
|
||||||
|
const
|
||||||
|
TICKS_PER_FRAME = 32; { target ticks per frame; adjust as needed to balance refresh rate and CPU usage }
|
||||||
|
|
||||||
|
var
|
||||||
|
LAST_UPDATE : uint32 = 0;
|
||||||
|
CURRENT_TICK : uint32 = 0;
|
||||||
|
|
||||||
|
procedure render_loop(ctx : PProcessContext);
|
||||||
|
var
|
||||||
|
should_update : boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
while true do begin
|
||||||
|
should_update := (CURRENT_TICK - LAST_UPDATE) >= TICKS_PER_FRAME;
|
||||||
|
should_update := should_update or (CURRENT_TICK < LAST_UPDATE); { handle tick counter wraparound }
|
||||||
|
if (should_update) then begin
|
||||||
|
LAST_UPDATE := CURRENT_TICK;
|
||||||
|
windows.reapOrphanedWindows;
|
||||||
|
desktop.update;
|
||||||
|
uidebug.update;
|
||||||
|
lvgl_handler;
|
||||||
|
video.Flush;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure tick;
|
||||||
|
begin
|
||||||
|
{ This function is called on every timer tick (interrupt 32) via the ISR hooks.
|
||||||
|
It can be used to trigger periodic tasks without needing a dedicated process. }
|
||||||
|
CURRENT_TICK := CURRENT_TICK + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure init;
|
||||||
|
begin
|
||||||
|
TMR_0_ISR.hook(uint32(@tick)); { Register the tick handler to run on every timer interrupt }
|
||||||
|
processmanager.create('gfxd', @render_loop, nil, 5);
|
||||||
|
syslog.logln('gfxd', 'Render process spawned.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
@@ -365,7 +365,7 @@ begin
|
|||||||
now_tick := lvgl_get_ticks;
|
now_tick := lvgl_get_ticks;
|
||||||
|
|
||||||
if (now_tick - last_tick) >= FPS_INTERVAL then begin
|
if (now_tick - last_tick) >= FPS_INTERVAL then begin
|
||||||
current_fps := safeDiv32(frame_count * 1000, now_tick - last_tick);
|
current_fps := safeDiv32(frame_count * 8000, now_tick - last_tick);
|
||||||
frame_count := 0;
|
frame_count := 0;
|
||||||
last_tick := now_tick;
|
last_tick := now_tick;
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
Prog->USBHotplug - USB hotplug daemon process.
|
||||||
|
|
||||||
|
Spawns a dedicated 'usbd' process that polls for USB port changes
|
||||||
|
approximately once per second using processmanager.proc_sleep_ms.
|
||||||
|
|
||||||
|
@author(Kieron Morris <[email protected]>)
|
||||||
|
}
|
||||||
|
unit usbhotplug;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
procedure init;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
usbcore,
|
||||||
|
processmanager,
|
||||||
|
proctypes,
|
||||||
|
syslog;
|
||||||
|
|
||||||
|
{ USB daemon process entry point — polls for hotplug events once per second. }
|
||||||
|
procedure usbd_loop(ctx : PProcessContext);
|
||||||
|
begin
|
||||||
|
while true do begin
|
||||||
|
usbcore.usb_check_hotplug;
|
||||||
|
processmanager.proc_sleep_ms(1000);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure init;
|
||||||
|
begin
|
||||||
|
processmanager.create('usbd', @usbd_loop, nil, 2);
|
||||||
|
syslog.logln('usbd', 'USB hotplug daemon spawned.');
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
// Copyright 2021 Kieron Morris
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
{
|
|
||||||
Scheduler - Schedules Context Switches.
|
|
||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
|
||||||
}
|
|
||||||
|
|
||||||
unit scheduler;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
uses
|
|
||||||
syslog, stdio,
|
|
||||||
TMR_0_ISR,
|
|
||||||
lmemorymanager;
|
|
||||||
|
|
||||||
const
|
|
||||||
Quantum = 64;
|
|
||||||
|
|
||||||
type
|
|
||||||
TTaskState = packed record
|
|
||||||
//EAX, EDX,
|
|
||||||
end;
|
|
||||||
TScheduler_Entry = packed record
|
|
||||||
ThreadID : uint32;
|
|
||||||
Priority : uint8;
|
|
||||||
Delta : uint32;
|
|
||||||
Next : void;
|
|
||||||
end;
|
|
||||||
PScheduler_Entry = ^TScheduler_Entry;
|
|
||||||
|
|
||||||
var
|
|
||||||
Active : Boolean;
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
procedure add_task(priority : uint8);
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
var
|
|
||||||
Tick : uint32;
|
|
||||||
Root_Task : PScheduler_Entry = nil;
|
|
||||||
Current_Task : PScheduler_Entry = nil;
|
|
||||||
|
|
||||||
procedure context_switch();
|
|
||||||
begin
|
|
||||||
Current_Task:= PScheduler_Entry(Current_Task^.Next);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure add_task(priority : uint8);
|
|
||||||
var
|
|
||||||
new_task : PScheduler_Entry;
|
|
||||||
task : PScheduler_Entry;
|
|
||||||
i : uint32;
|
|
||||||
|
|
||||||
begin
|
|
||||||
new_task:= PScheduler_Entry(kalloc(sizeof(TScheduler_Entry)));
|
|
||||||
new_task^.Priority:= priority;
|
|
||||||
new_task^.Delta:= Tick;
|
|
||||||
new_task^.Next:= void(Root_Task);
|
|
||||||
task:= Root_Task;
|
|
||||||
i:= 1;
|
|
||||||
while PScheduler_Entry(task^.next) <> Root_Task do begin
|
|
||||||
i:= i+1;
|
|
||||||
task:= PScheduler_Entry(task^.next);
|
|
||||||
end;
|
|
||||||
task^.next:= void(new_task);
|
|
||||||
new_task^.ThreadID:= i;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure delta(data : void);
|
|
||||||
begin
|
|
||||||
If Active then begin
|
|
||||||
Tick:= Tick + 1;
|
|
||||||
If Tick = 0 then context_switch();
|
|
||||||
If (Current_Task^.Delta + (Current_Task^.Priority * Quantum)) <= Tick then context_switch();
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure terminal_command_tasks(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
|
|
||||||
var
|
|
||||||
list : PScheduler_Entry;
|
|
||||||
|
|
||||||
begin
|
|
||||||
stdio.bufWriteStrLn(stdout_buf, 'ThreadID - Priority - Delta');
|
|
||||||
list:= Root_Task;
|
|
||||||
stdio.bufWriteInt(stdout_buf, list^.ThreadID);
|
|
||||||
stdio.bufWriteStr(stdout_buf, ' - ');
|
|
||||||
stdio.bufWriteInt(stdout_buf, list^.Priority);
|
|
||||||
stdio.bufWriteStr(stdout_buf, ' - ');
|
|
||||||
stdio.bufWriteIntLn(stdout_buf, list^.Delta);
|
|
||||||
list:= PScheduler_Entry(list^.Next);
|
|
||||||
while list <> Root_Task do begin
|
|
||||||
stdio.bufWriteInt(stdout_buf, list^.ThreadID);
|
|
||||||
stdio.bufWriteStr(stdout_buf, ' - ');
|
|
||||||
stdio.bufWriteInt(stdout_buf, list^.Priority);
|
|
||||||
stdio.bufWriteStr(stdout_buf, ' - ');
|
|
||||||
stdio.bufWriteIntLn(stdout_buf, list^.Delta);
|
|
||||||
list:= PScheduler_Entry(list^.Next);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
begin
|
|
||||||
syslog.logln('SCHEDULER','INIT BEGIN.');
|
|
||||||
Root_Task:= PScheduler_Entry(kalloc(sizeof(TScheduler_Entry)));
|
|
||||||
Root_Task^.ThreadID:= 0;
|
|
||||||
Root_Task^.Priority:= 1;
|
|
||||||
Root_Task^.Delta:= 0;
|
|
||||||
Root_Task^.Next:= void(Root_Task);
|
|
||||||
Current_Task:= Root_Task;
|
|
||||||
Tick:= 0;
|
|
||||||
Active:= False;
|
|
||||||
TMR_0_ISR.hook(uint32(@delta));
|
|
||||||
//stdio.registerCommand('TASKS', @terminal_command_tasks, 'List Active Processes.');
|
|
||||||
syslog.logln('SCHEDULER','INIT END.');
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
|
||||||
-123
@@ -1,123 +0,0 @@
|
|||||||
// Copyright 2021 Kieron Morris
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
{
|
|
||||||
TSS - Task State Segment (stub).
|
|
||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
|
||||||
}
|
|
||||||
unit tss;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
uses
|
|
||||||
gdt,
|
|
||||||
vmemorymanager,
|
|
||||||
syslog;
|
|
||||||
|
|
||||||
type
|
|
||||||
TTaskStateSegment = packed record
|
|
||||||
link : uint16;
|
|
||||||
link_h : uint16;
|
|
||||||
|
|
||||||
esp0 : uint32;
|
|
||||||
ss0 : uint16;
|
|
||||||
ss0_h : uint16;
|
|
||||||
|
|
||||||
esp1 : uint32;
|
|
||||||
ss1 : uint16;
|
|
||||||
ss1_h : uint16;
|
|
||||||
|
|
||||||
esp2 : uint32;
|
|
||||||
ss2 : uint16;
|
|
||||||
ss2_h : uint16;
|
|
||||||
|
|
||||||
cr3 : uint32;
|
|
||||||
eip : uint32;
|
|
||||||
eflags : uint32;
|
|
||||||
|
|
||||||
eax : uint32;
|
|
||||||
ecx : uint32;
|
|
||||||
edx : uint32;
|
|
||||||
ebx : uint32;
|
|
||||||
|
|
||||||
esp : uint32;
|
|
||||||
ebp : uint32;
|
|
||||||
esi : uint32;
|
|
||||||
edi : uint32;
|
|
||||||
es : uint16;
|
|
||||||
es_h : uint16;
|
|
||||||
cs : uint16;
|
|
||||||
cs_h : uint16;
|
|
||||||
ss : uint16;
|
|
||||||
ss_h : uint16;
|
|
||||||
ds : uint16;
|
|
||||||
ds_h : uint16;
|
|
||||||
fs : uint16;
|
|
||||||
fs_h : uint16;
|
|
||||||
gs : uint16;
|
|
||||||
gs_h : uint16;
|
|
||||||
ldt : uint16;
|
|
||||||
ldt_h : uint16;
|
|
||||||
trap : uint16;
|
|
||||||
iomap : uint16;
|
|
||||||
end;
|
|
||||||
PTaskStateSegment = ^TTaskStateSegment;
|
|
||||||
|
|
||||||
var
|
|
||||||
TaskStateSegment : TTaskStateSegment;
|
|
||||||
ptrTaskStateSegment : PTaskStateSegment = @TaskStateSegment;
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
procedure set_esp0(esp0 : uint32);
|
|
||||||
function get_esp0 : uint32;
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
procedure set_esp0(esp0 : uint32);
|
|
||||||
begin
|
|
||||||
ptrTaskStateSegment^.esp0 := esp0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function get_esp0 : uint32;
|
|
||||||
begin
|
|
||||||
get_esp0 := ptrTaskStateSegment^.esp0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure init;
|
|
||||||
var
|
|
||||||
cESP : uint32;
|
|
||||||
cCR3 : uint32;
|
|
||||||
|
|
||||||
begin
|
|
||||||
syslog.logln('TSS','INIT BEGIN.');
|
|
||||||
ptrTaskStateSegment^.ss0:= $10;
|
|
||||||
ptrTaskStateSegment^.iomap:= sizeof(TTaskStateSegment)-1;
|
|
||||||
asm
|
|
||||||
MOV cESP, ESP
|
|
||||||
MOV EAX, CR3
|
|
||||||
MOV cCR3, EAX
|
|
||||||
end;
|
|
||||||
ptrTaskStateSegment^.esp0:= cESP;
|
|
||||||
ptrTaskStateSegment^.CR3:= cCR3;
|
|
||||||
gdt.set_gate($05, uint32(ptrTaskStateSegment) - KERNEL_VIRTUAL_BASE, sizeof(TTaskStateSegment) - 1, $89, $40); //OFFSET: 40
|
|
||||||
gdt.reload;
|
|
||||||
asm
|
|
||||||
mov AX, 40
|
|
||||||
ltr AX
|
|
||||||
end;
|
|
||||||
syslog.logln('TSS','INIT END.');
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
|
||||||
+34
-8
@@ -20,7 +20,7 @@ unit v86;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
util, syslog, tracer, vmemorymanager, tss, idt, isr_types;
|
util, syslog, tracer, vmemorymanager, gdt, idt, isr_types;
|
||||||
|
|
||||||
const
|
const
|
||||||
{ V86 EFLAGS: VM=1 ($20000), IOPL=3 ($3000), IF=0 }
|
{ V86 EFLAGS: VM=1 ($20000), IOPL=3 ($3000), IF=0 }
|
||||||
@@ -34,6 +34,12 @@ const
|
|||||||
V86_EXIT_INT = $FF;
|
V86_EXIT_INT = $FF;
|
||||||
{ Size of the ring-0 stack used for V86 GPF handling }
|
{ Size of the ring-0 stack used for V86 GPF handling }
|
||||||
V86_R0_STACK_SIZE = 4096;
|
V86_R0_STACK_SIZE = 4096;
|
||||||
|
{ GDT gate index for the TSS descriptor }
|
||||||
|
V86_TSS_GDT_GATE = 5;
|
||||||
|
{ TSS segment selector: gate 5 * 8 bytes per descriptor }
|
||||||
|
V86_TSS_SELECTOR = V86_TSS_GDT_GATE * 8;
|
||||||
|
{ Minimum x86 TSS size (104 bytes / $68) }
|
||||||
|
V86_TSS_SIZE = 104;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ Register state for V86 BIOS calls }
|
{ Register state for V86 BIOS calls }
|
||||||
@@ -103,6 +109,11 @@ var
|
|||||||
{ Ring-0 stack for V86 exception handling }
|
{ Ring-0 stack for V86 exception handling }
|
||||||
V86Ring0Stack : array[0..V86_R0_STACK_SIZE - 1] of uint8;
|
V86Ring0Stack : array[0..V86_R0_STACK_SIZE - 1] of uint8;
|
||||||
|
|
||||||
|
{ Minimal TSS — only ESP0 (offset 4) and SS0 (offset 8) matter.
|
||||||
|
We allocate the full 104-byte minimum so the CPU is happy. }
|
||||||
|
V86TSS : array[0..V86_TSS_SIZE - 1] of uint8;
|
||||||
|
V86TSSPtr : PUInt32 = nil;
|
||||||
|
|
||||||
{ ========================================================================= }
|
{ ========================================================================= }
|
||||||
{ V86 real-mode memory helpers (access via kernel mapping at 0xC0000000) }
|
{ V86 real-mode memory helpers (access via kernel mapping at 0xC0000000) }
|
||||||
{ ========================================================================= }
|
{ ========================================================================= }
|
||||||
@@ -608,8 +619,8 @@ asm
|
|||||||
TSS ESP0 is restored by the exit handler so that normal interrupts
|
TSS ESP0 is restored by the exit handler so that normal interrupts
|
||||||
use the correct ring-0 stack again. }
|
use the correct ring-0 stack again. }
|
||||||
mov eax, dword ptr [V86OldESP0]
|
mov eax, dword ptr [V86OldESP0]
|
||||||
mov ebx, dword ptr [ptrTaskStateSegment]
|
mov ebx, dword ptr [V86TSSPtr]
|
||||||
mov dword ptr [ebx + 4], eax { TTaskStateSegment.esp0 is at offset 4 }
|
mov dword ptr [ebx + 4], eax { TSS esp0 is at offset 4 }
|
||||||
|
|
||||||
{ Restore kernel stack frame and jump back into v86_int }
|
{ Restore kernel stack frame and jump back into v86_int }
|
||||||
mov esp, dword ptr [V86SavedESP]
|
mov esp, dword ptr [V86SavedESP]
|
||||||
@@ -646,11 +657,9 @@ begin
|
|||||||
V86ShadowIF := true;
|
V86ShadowIF := true;
|
||||||
V86RegsPtr := @regs;
|
V86RegsPtr := @regs;
|
||||||
|
|
||||||
{ Save current TSS ESP0 }
|
{ Save current TSS ESP0 and point it to our dedicated ring-0 stack }
|
||||||
V86OldESP0 := tss.get_esp0;
|
V86OldESP0 := PUInt32(uint32(@V86TSS) + 4)^;
|
||||||
|
PUInt32(uint32(@V86TSS) + 4)^ := uint32(@V86Ring0Stack) + V86_R0_STACK_SIZE;
|
||||||
{ Set TSS ESP0 to our dedicated ring-0 stack for V86 traps }
|
|
||||||
tss.set_esp0(uint32(@V86Ring0Stack) + V86_R0_STACK_SIZE);
|
|
||||||
|
|
||||||
{ Write thunk code into physical memory at 0x7C00 }
|
{ Write thunk code into physical memory at 0x7C00 }
|
||||||
setup_thunk(intNo);
|
setup_thunk(intNo);
|
||||||
@@ -730,10 +739,27 @@ end;
|
|||||||
{ ========================================================================= }
|
{ ========================================================================= }
|
||||||
|
|
||||||
procedure init;
|
procedure init;
|
||||||
|
var
|
||||||
|
tss_base : uint32;
|
||||||
begin
|
begin
|
||||||
push_trace('v86.init');
|
push_trace('v86.init');
|
||||||
syslog.logln('V86', 'INIT BEGIN.');
|
syslog.logln('V86', 'INIT BEGIN.');
|
||||||
|
|
||||||
|
{ Set up a minimal TSS so the CPU can find ESP0 on V86 ring 3→0 traps }
|
||||||
|
memset(uint32(@V86TSS[0]), 0, V86_TSS_SIZE);
|
||||||
|
tss_base := uint32(@V86TSS[0]);
|
||||||
|
V86TSSPtr := PUInt32(tss_base);
|
||||||
|
{ SS0 at offset 8 = kernel data segment $10 }
|
||||||
|
PUInt16(tss_base + 8)^ := $10;
|
||||||
|
{ Install TSS descriptor in GDT gate 5 (access $89 = present, DPL 0, TSS available) }
|
||||||
|
gdt.set_gate(V86_TSS_GDT_GATE, tss_base, V86_TSS_SIZE - 1, $89, $00);
|
||||||
|
gdt.reload;
|
||||||
|
{ Load the task register }
|
||||||
|
asm
|
||||||
|
mov ax, V86_TSS_SELECTOR
|
||||||
|
ltr ax
|
||||||
|
end;
|
||||||
|
|
||||||
{ Identity-map the first 4MB at virtual 0x00000000 with User bit.
|
{ Identity-map the first 4MB at virtual 0x00000000 with User bit.
|
||||||
This allows V86 code to access the IVT, BDA, video ROM, and
|
This allows V86 code to access the IVT, BDA, video ROM, and
|
||||||
VGA memory as real-mode linear addresses go through paging. }
|
VGA memory as real-mode linear addresses go through paging. }
|
||||||
|
|||||||
Reference in new issue
Block a user