feature: preemptive process management & TCP/IP barebones #41

Merged
t3hn3rd merged 4 commits from feature/process-management into develop 2026-03-04 20:04:27 +00:00
27 changed files with 4360 additions and 381 deletions
+111 -5
View File
@@ -12,15 +12,121 @@
// 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.
{ {
ContextSwitcher - Switch Process Contexts when preempted. ContextSwitcher - Custom IRQ0 handler for preemptive context switching.
@author(Kieron Morris <[email protected]>) Replaces the default ISR_32 with a naked assembly stub that saves the
interrupted context (PUSHAD + segment regs), calls a Pascal helper to
dispatch timer hooks, send EOI, and run the scheduler, then restores
the next process context (or idles) via the returned ESP.
@author(Kieron Morris <[email protected]>)
} }
unit contextswitcher; unit contextswitcher;
{$ASMMODE intel}
interface interface
implementation; uses
idt, isrmanager, processmanager, proctypes, util, syslog, tracer;
{ Initialise: overwrite IDT gate 32 with our custom ISR. }
procedure init;
{ No idle ESP variable needed — idle is now a formal process (PID 0)
with its SavedESP managed like any other process. }
implementation
{ -----------------------------------------------------------------------
do_context_switch_work
Pascal helper called from the assembly ISR. Receives the current ESP
(pointing to the GS..EFLAGS save area), dispatches timer hooks, sends
EOI, runs the scheduler and returns the ESP for the next context.
Uses register calling convention: saved_esp in EAX, result in EAX.
----------------------------------------------------------------------- }
function do_context_switch_work(saved_esp : uint32) : uint32;
var
next : PProcessContext;
begin
{ 1. Save ESP into the current process }
processmanager.CurrentProcess^.SavedESP := saved_esp;
{ 2. Dispatch all hooks registered on interrupt 32 (timer hooks).
This fires TMR_0_ISR.Main which in turn fires BDA tick,
graphics refresh, USB hotplug, etc. }
isrmanager.dispatchHooks(32);
{ 3. Send End-Of-Interrupt to the master PIC }
outb($20, $20);
{ 4. Pick the next process to run (always returns non-nil; idle as fallback) }
next := processmanager.scheduler_pick_next;
processmanager.CurrentProcess := next;
{ 5. Return the selected process ESP }
do_context_switch_work := next^.SavedESP;
end;
{ -----------------------------------------------------------------------
context_switch_isr
Naked assembly ISR that replaces ISR_32 (IRQ0 / PIT timer).
Stack on entry (pushed by CPU):
[ESP+8] EFLAGS
[ESP+4] CS
[ESP+0] EIP
We push general-purpose and segment registers, call the Pascal helper,
switch ESP to the returned value, pop registers and IRETD.
----------------------------------------------------------------------- }
procedure context_switch_isr; assembler; nostackframe;
asm
{ Save all general-purpose registers (EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI) }
pushad
{ Save segment registers }
push ds
push es
push fs
push gs
{ Load kernel data segments }
mov ax, $10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
{ Call Pascal helper: EAX = current ESP (register calling convention).
Returns new ESP in EAX. }
mov eax, esp
call do_context_switch_work
mov esp, eax
{ Restore segment registers }
pop gs
pop fs
pop es
pop ds
{ Restore general-purpose registers }
popad
{ Return from interrupt }
iretd
end;
{ -----------------------------------------------------------------------
init
Override IDT gate 32 with our custom ISR. Must be called AFTER
isrmanager.init so that the default gate has been set up first.
----------------------------------------------------------------------- }
procedure init;
begin
idt.set_gate(32, uint32(@context_switch_isr), $08, ISR_RING_0);
tracer.push_trace('contextswitcher.init');
end;
end. end.
+2 -5
View File
@@ -22,7 +22,7 @@ unit cpu;
interface interface
uses uses
util, RTC; util, RTC, stdio;
type type
PCapabilities_Old = ^TCapabilities_Old; PCapabilities_Old = ^TCapabilities_Old;
@@ -113,12 +113,10 @@ var
CAP_OLD, CAP_NEW : uint32; CAP_OLD, CAP_NEW : uint32;
procedure init(); procedure init();
procedure Terminal_Command_CPU(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
implementation implementation
uses
stdio;
procedure getCPUIdentifier; procedure getCPUIdentifier;
var var
id0, id1, id2 : uint32; id0, id1, id2 : uint32;
@@ -325,7 +323,6 @@ end;
procedure init(); procedure init();
begin begin
stdio.registerCommand('CPU', @Terminal_Command_CPU, 'CPU Info.');
CPUID.Capabilities0:= PCapabilities_Old(@CAP_OLD); CPUID.Capabilities0:= PCapabilities_Old(@CAP_OLD);
CPUID.Capabilities1:= PCapabilities_New(@CAP_NEW); CPUID.Capabilities1:= PCapabilities_New(@CAP_NEW);
getCPUIdentifier; getCPUIdentifier;
+3 -1
View File
@@ -158,6 +158,9 @@ procedure init;
{ Unit Tests } { Unit Tests }
procedure UnitTest; procedure UnitTest;
{ Terminal command }
procedure terminal_command_usb(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
implementation implementation
{ ========================= Globals ========================= } { ========================= Globals ========================= }
@@ -1100,7 +1103,6 @@ begin
CompletionHookCount := 0; CompletionHookCount := 0;
for i := 0 to MAX_COMPLETION_HOOKS - 1 do for i := 0 to MAX_COMPLETION_HOOKS - 1 do
CompletionHooks[i] := nil; CompletionHooks[i] := nil;
stdio.registerCommand('USB', @terminal_command_usb, 'USB subsystem information.');
syslog.logln('USB Core', 'INIT END.'); syslog.logln('USB Core', 'INIT END.');
pop_trace; pop_trace;
end; end;
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -100,8 +100,8 @@ end;
procedure send(p_data : void; p_len : uint16); procedure send(p_data : void; p_len : uint16);
begin begin
//push_trace('net.send'); push_trace('net.send');
//writeToLogLn('L1: net.send'); writeToLogLn('L1/NET: send');
if CBSend <> nil then CBSend(p_data, p_len); if CBSend <> nil then CBSend(p_data, p_len);
pop_trace; pop_trace;
end; end;
@@ -111,8 +111,7 @@ var
context : PPacketContext; context : PPacketContext;
begin begin
//push_trace('net.recv'); push_trace('net.recv');
//writeToLogLn('L1: net.recv');
context:= newPacketContext; context:= newPacketContext;
if CBNext <> nil then CBNext(p_data, p_len, context); if CBNext <> nil then CBNext(p_data, p_len, context);
freePacketContext(context); freePacketContext(context);
@@ -129,6 +128,7 @@ end;
procedure init; procedure init;
begin begin
push_trace('net.init'); push_trace('net.init');
writeToLogLn('L1/NET: init');
//l2 //l2
eth2.register; eth2.register;
//l3 //l3
@@ -136,6 +136,7 @@ begin
ipv4.register; ipv4.register;
//l4 //l4
icmp.register; icmp.register;
tcp.register;
udp.register; udp.register;
//l5 //l5
dhcp.register; dhcp.register;
+4 -1
View File
@@ -46,6 +46,7 @@ var
procedure registerTypePromisc(eType : uint16; RecvCB : TRecvCallback); procedure registerTypePromisc(eType : uint16; RecvCB : TRecvCallback);
begin begin
push_trace('eth2.registerTypePromisc');
register; register;
if EthTypes[eType] = nil then EthTypes[eType]:= RecvCB; if EthTypes[eType] = nil then EthTypes[eType]:= RecvCB;
Promisc[eType]:= true; Promisc[eType]:= true;
@@ -53,6 +54,7 @@ end;
procedure registerType(eType : uint16; RecvCB : TRecvCallback); procedure registerType(eType : uint16; RecvCB : TRecvCallback);
begin begin
push_trace('eth2.registerType');
register; register;
if EthTypes[eType] = nil then EthTypes[eType]:= RecvCB; if EthTypes[eType] = nil then EthTypes[eType]:= RecvCB;
end; end;
@@ -93,7 +95,7 @@ var
buf : puint8; buf : puint8;
begin begin
//writeToLogLn(' L2: eth2.recv'); push_trace('eth2.recv');
buf:= puint8(p_data); buf:= puint8(p_data);
Header:= PEthernetHeader(buf); Header:= PEthernetHeader(buf);
@@ -120,6 +122,7 @@ var
begin begin
push_trace('eth2.register'); push_trace('eth2.register');
if not Registered then begin if not Registered then begin
writeToLogLn(' L2/ETH: register');
for i:=0 to 65535 do begin for i:=0 to 65535 do begin
EthTypes[i]:= nil; EthTypes[i]:= nil;
Promisc[i]:= false; Promisc[i]:= false;
+12 -3
View File
@@ -25,7 +25,7 @@ uses
tracer, lmemorymanager, tracer, lmemorymanager,
util, lists, util, lists,
net, nettypes, netutils, net, nettypes, netutils,
eth2, ipv4; eth2, ipv4, stdio;
type type
PARPCacheRecord = ^TARPCacheRecord; PARPCacheRecord = ^TARPCacheRecord;
@@ -41,11 +41,12 @@ procedure sendGratuitous;
procedure sendRequest(ip : puint8); procedure sendRequest(ip : puint8);
procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext); procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext);
function resolveIP(ip : puint8) : puint8; function resolveIP(ip : puint8) : puint8;
procedure terminal_command_arp(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
implementation implementation
uses uses
stdio, strings; strings;
var var
Registered : Boolean = false; Registered : Boolean = false;
@@ -96,6 +97,7 @@ var
hSize, pSize : uint8; hSize, pSize : uint8;
begin begin
push_trace('arp.send');
if p_context <> nil then begin if p_context <> nil then begin
buf:= kalloc(sizeof(TARPHeader)); buf:= kalloc(sizeof(TARPHeader));
hdr:= PARPHeader(buf); hdr:= PARPHeader(buf);
@@ -135,6 +137,8 @@ var
context : PPacketContext; context : PPacketContext;
begin begin
push_trace('arp.sendGratuitous');
writeToLogLn(' L3/ARP: sendGratuitous');
context:= newPacketContext; context:= newPacketContext;
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Destination[0]); CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Destination[0]);
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]); CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
@@ -150,6 +154,7 @@ var
CacheRecord : PARPCacheRecord; CacheRecord : PARPCacheRecord;
begin begin
push_trace('arp.sendRequestGateway');
context:= newPacketContext; context:= newPacketContext;
CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]); CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]);
if CacheRecord <> nil then begin if CacheRecord <> nil then begin
@@ -168,6 +173,8 @@ var
CacheRecord : PARPCacheRecord; CacheRecord : PARPCacheRecord;
begin begin
push_trace('arp.sendRequest');
writeToLogLn(' L3/ARP: sendRequest');
context:= newPacketContext; context:= newPacketContext;
CopyIPv4(ip, @context^.IP.Destination[0]); CopyIPv4(ip, @context^.IP.Destination[0]);
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]); CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
@@ -184,6 +191,7 @@ var
CacheRecord : PARPCacheRecord; CacheRecord : PARPCacheRecord;
begin begin
push_trace('arp.resolveIP');
CacheRecord:= findCacheRecordByIP(ip); CacheRecord:= findCacheRecordByIP(ip);
resolveIP:= nil; resolveIP:= nil;
if CacheRecord = nil then begin if CacheRecord = nil then begin
@@ -203,6 +211,7 @@ var
context : PPacketContext; context : PPacketContext;
begin begin
push_trace('arp.recv');
{ Get our converted Header } { Get our converted Header }
Header:= PARPHeader(p_data); Header:= PARPHeader(p_data);
AHeader.Hardware_Type:= (Header^.Hardware_Type_Hi SHL 8) + Header^.Hardware_Type_Lo; AHeader.Hardware_Type:= (Header^.Hardware_Type_Hi SHL 8) + Header^.Hardware_Type_Lo;
@@ -298,9 +307,9 @@ procedure register;
begin begin
push_trace('arp.register'); push_trace('arp.register');
if not Registered then begin if not Registered then begin
writeToLogLn(' L3/ARP: register');
Cache:= LL_New(sizeof(TARPCacheRecord)); Cache:= LL_New(sizeof(TARPCacheRecord));
eth2.registerTypePromisc($0806, @recv); eth2.registerTypePromisc($0806, @recv);
stdio.registerCommand('ARP', @terminal_command_arp, 'Get ARP Table.');
Registered:= true; Registered:= true;
end; end;
pop_trace; pop_trace;
+10 -3
View File
@@ -26,17 +26,18 @@ uses
util, strings, util, strings,
net, nettypes, netutils, net, nettypes, netutils,
lists, lists,
eth2; eth2, stdio;
procedure send(p_data : void; p_len : uint16; p_context : PPacketContext); procedure send(p_data : void; p_len : uint16; p_context : PPacketContext);
procedure registerProtocol(Protocol_ID : uint8; recv_callback : TRecvCallback); procedure registerProtocol(Protocol_ID : uint8; recv_callback : TRecvCallback);
function getIPv4Config : PIPv4Configuration; function getIPv4Config : PIPv4Configuration;
procedure register; procedure register;
procedure terminal_command_ifconfig(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
implementation implementation
uses uses
arp, stdio; arp;
var var
Registered : Boolean = false; Registered : Boolean = false;
@@ -46,7 +47,9 @@ var
function getIPv4Config : PIPv4Configuration; function getIPv4Config : PIPv4Configuration;
begin begin
push_trace('ipv4.getIPv4Config');
getIPv4Config:= @Config; getIPv4Config:= @Config;
pop_trace;
end; end;
procedure send(p_data : void; p_len : uint16; p_context : PPacketContext); procedure send(p_data : void; p_len : uint16; p_context : PPacketContext);
@@ -57,6 +60,7 @@ var
buffer : void; buffer : void;
begin begin
push_trace('ipv4.send');
inc(CurrentID); inc(CurrentID);
Header.version:= 4; Header.version:= 4;
Header.header_len:= 5; Header.header_len:= 5;
@@ -84,6 +88,7 @@ begin
memcpy(uint32(p_data), uint32(Buffer) + (Header.header_len * 4), p_len); memcpy(uint32(p_data), uint32(Buffer) + (Header.header_len * 4), p_len);
eth2.send(Buffer, (Header.header_len * 4) + p_len, $0800, p_context); eth2.send(Buffer, (Header.header_len * 4) + p_len, $0800, p_context);
kfree(Buffer); kfree(Buffer);
pop_trace;
end; end;
procedure recv(p_data : void; p_len : uint16; p_context : PPacketContext); procedure recv(p_data : void; p_len : uint16; p_context : PPacketContext);
@@ -95,6 +100,7 @@ var
len : uint16; len : uint16;
begin begin
push_trace('ipv4.recv');
Header:= PIPV4Header(p_data); Header:= PIPV4Header(p_data);
AHeader.version:= Header^.version; AHeader.version:= Header^.version;
AHeader.header_len:= Header^.header_len; AHeader.header_len:= Header^.header_len;
@@ -195,6 +201,7 @@ var
begin begin
push_trace('ipv4.register'); push_trace('ipv4.register');
if not Registered then begin if not Registered then begin
writeToLogLn(' L3/IPv4: register');
for i:=0 to 255 do begin for i:=0 to 255 do begin
Protocols[i]:= nil; Protocols[i]:= nil;
end; end;
@@ -205,7 +212,6 @@ begin
end; end;
Config.UP:= false; Config.UP:= false;
eth2.registerType($0800, @recv); eth2.registerType($0800, @recv);
stdio.registerCommand('IFCONFIG', @terminal_command_ifconfig, 'Configure Network Settings.');
Registered:= true; Registered:= true;
end; end;
pop_trace; pop_trace;
@@ -213,6 +219,7 @@ end;
procedure registerProtocol(Protocol_ID : uint8; recv_callback : TRecvCallback); procedure registerProtocol(Protocol_ID : uint8; recv_callback : TRecvCallback);
begin begin
push_trace('ipv4.registerProtocol');
register; register;
if Protocols[Protocol_ID] = nil then Protocols[Protocol_ID]:= recv_callback; if Protocols[Protocol_ID] = nil then Protocols[Protocol_ID]:= recv_callback;
pop_trace; pop_trace;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+8 -1
View File
@@ -25,7 +25,7 @@ uses
lmemorymanager, lmemorymanager,
nettypes, netutils, nettypes, netutils,
ipv4, net, ipv4, net,
util; tracer, util;
procedure register(); procedure register();
function bind(bindContext : PUDPBindContext) : TUDPError; function bind(bindContext : PUDPBindContext) : TUDPError;
@@ -71,6 +71,7 @@ begin
nullend:= true; nullend:= true;
end; end;
pseudoBuffer:= kalloc(sizeof(TUDPPseudoHeader) + pseudoSize); pseudoBuffer:= kalloc(sizeof(TUDPPseudoHeader) + pseudoSize);
push_trace('udp.CalculateChecksum');
pseudoBuffer8:= puint8(pseudoBuffer); pseudoBuffer8:= puint8(pseudoBuffer);
pseudoBuffer16:= puint16(pseudoBuffer); pseudoBuffer16:= puint16(pseudoBuffer);
pseudoBuffer32:= puint32(pseudoBuffer); pseudoBuffer32:= puint32(pseudoBuffer);
@@ -118,6 +119,7 @@ var
begin begin
push_trace('udp.send');
if udpContext <> nil then begin if udpContext <> nil then begin
size:= p_len + sizeof(TUDPHeader); size:= p_len + sizeof(TUDPHeader);
buffer:= kalloc(size); buffer:= kalloc(size);
@@ -152,6 +154,7 @@ var
context : PUDPBindContext; context : PUDPBindContext;
begin begin
push_trace('udp.bind');
result:= tueGenericError; result:= tueGenericError;
if bindContext <> nil then begin if bindContext <> nil then begin
if Ports[bindContext^.port] = nil then begin if Ports[bindContext^.port] = nil then begin
@@ -174,6 +177,7 @@ var
context : PUDPBindContext; context : PUDPBindContext;
begin begin
push_trace('udp.unbind');
result:= tueGenericError; result:= tueGenericError;
if bindContext <> nil then begin if bindContext <> nil then begin
context:= Ports[bindContext^.port]; context:= Ports[bindContext^.port];
@@ -203,6 +207,7 @@ var
size : uint16; size : uint16;
begin begin
push_trace('udp.ProcessPacket');
header:= PUDPHeader(p_data); header:= PUDPHeader(p_data);
if Ports[switchendian16(header^.DstPort)] <> nil then begin if Ports[switchendian16(header^.DstPort)] <> nil then begin
context:= PUDPPacketContext(kalloc(sizeof(TUDPPacketContext))); context:= PUDPPacketContext(kalloc(sizeof(TUDPPacketContext)));
@@ -245,6 +250,8 @@ var
Checksum : uint32; Checksum : uint32;
begin begin
push_trace('udp.register');
writeToLogLn(' L4/UDP: register');
for i:=0 to 65535 do begin for i:=0 to 65535 do begin
Ports[i]:= nil; Ports[i]:= nil;
end; end;
+6 -3
View File
@@ -415,7 +415,7 @@ end;
procedure processPacket_NAK(Header : PDHCPHeader; Options : PDHCPOptions); procedure processPacket_NAK(Header : PDHCPHeader; Options : PDHCPOptions);
begin begin
syslog.logln('DHCP', 'Process NAK.'); writeToLogLn(' L5/DHCP: Process NAK.');
{ Server provided a NAK, NULL configuration ready for next DISCOVER/Request } { Server provided a NAK, NULL configuration ready for next DISCOVER/Request }
nullConfiguration(); nullConfiguration();
end; end;
@@ -429,7 +429,7 @@ var
cfgopt : void; cfgopt : void;
begin begin
syslog.logln('DHCP', 'Process ACK.'); writeToLogLn(' L5/DHCP: Process ACK.');
getIPv4Config^.UP:= false; getIPv4Config^.UP:= false;
//Copy new address //Copy new address
@@ -484,7 +484,7 @@ Var
begin begin
syslog.logln('DHCP', 'Process OFFER.'); syslog.logln('DHCP', 'Process OFFER.');
writeToLogLn(' L5/DHCP: Process OFFER.');
{ Check the Transaction ID matches our stored ID, discard if not. } { Check the Transaction ID matches our stored ID, discard if not. }
if Header^.Transaction_ID = Configuration^.Transaction then begin if Header^.Transaction_ID = Configuration^.Transaction then begin
syslog.logln('DHCP', 'XID Match'); syslog.logln('DHCP', 'XID Match');
@@ -566,6 +566,7 @@ var
begin begin
tracer.push_trace('dhcp.processPacket.enter'); tracer.push_trace('dhcp.processPacket.enter');
writeToLogLn(' L5/DHCP: processPacket');
syslog.logln('DHCP','processPacket'); syslog.logln('DHCP','processPacket');
{ Give access to header values & process to correct endianness. } { Give access to header values & process to correct endianness. }
@@ -636,6 +637,7 @@ var
begin begin
tracer.push_trace('dhcp.DHCPDiscover.begin'); tracer.push_trace('dhcp.DHCPDiscover.begin');
writeToLogLn(' L5/DHCP: DHCPDiscover');
{ Ensure we have a socket bound. } { Ensure we have a socket bound. }
if Socket <> nil then begin if Socket <> nil then begin
{ Clear any current configuration } { Clear any current configuration }
@@ -711,6 +713,7 @@ var
begin begin
tracer.push_trace('dhcp.register'); tracer.push_trace('dhcp.register');
writeToLogLn(' L5/DHCP: register');
syslog.logln('DHCP', 'Register begin.'); syslog.logln('DHCP', 'Register begin.');
{ Kalloc our Configuration Data } { Kalloc our Configuration Data }
+1 -1
View File
@@ -112,6 +112,7 @@ function get_device_list() : PLinkedListBase;
procedure register_filesystem(filesystem : PFilesystem); procedure register_filesystem(filesystem : PFilesystem);
procedure register_volume(device : PStorage_Device; volume : PStorage_Volume); procedure register_volume(device : PStorage_Device; volume : PStorage_Volume);
procedure disk_command(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
//function writeNewFile(fileName : pchar; extension : pchar; buffer : puint32; size : uint32) : uint32; //function writeNewFile(fileName : pchar; extension : pchar; buffer : puint32; size : uint32) : uint32;
//function readFile(fileName : pchar; extension : pchar; buffer : puint32; byteCount : puint32) : puint32; //function readFile(fileName : pchar; extension : pchar; buffer : puint32; byteCount : puint32) : puint32;
@@ -231,7 +232,6 @@ begin
setworkingdirectory('.'); setworkingdirectory('.');
storageDevices:= ll_new(sizeof(TStorage_Device)); storageDevices:= ll_new(sizeof(TStorage_Device));
fileSystems:= ll_New(sizeof(TFilesystem)); fileSystems:= ll_New(sizeof(TFilesystem));
stdio.registerCommand('DISK', @disk_command, 'Disk utility');
pop_trace(); pop_trace();
end; end;
+67 -5
View File
@@ -104,6 +104,10 @@ function GetDirectories(Handle : uint32; Path : pchar) : PHashMap;
function PathValid(Path : pchar) : TIsPathValid; function PathValid(Path : pchar) : TIsPathValid;
function changeDirectory(Path : pchar) : TIsPathValid; function changeDirectory(Path : pchar) : TIsPathValid;
function getWorkingDirectory : pchar; function getWorkingDirectory : pchar;
function makeAbsolutePathFrom(Path : pchar; BaseDir : pchar) : pchar;
function resolvePathFrom(Path : pchar; BaseDir : pchar) : TIsPathValid;
function GetDirectoryListingFrom(Path : pchar; BaseDir : pchar) : PHashMap;
function changeDirectoryFrom(Path : pchar; BaseDir : pchar; var NewDir : pchar) : TIsPathValid;
//VFS Functions //VFS Functions
function newVirtualDirectory(Path : pchar) : TError; function newVirtualDirectory(Path : pchar) : TError;
@@ -608,6 +612,67 @@ begin
tracer.push_trace('vfs.getWorkingDirectory.exit'); tracer.push_trace('vfs.getWorkingDirectory.exit');
end; end;
function makeAbsolutePathFrom(Path : pchar; BaseDir : pchar) : pchar;
var
AbsPath : pchar;
TempPath : pchar;
begin
if Path[0] = '/' then
AbsPath := stringCopy(Path)
else begin
if BaseDir[StringSize(BaseDir)-1] <> '/' then
TempPath := StringConcat(BaseDir, '/')
else
TempPath := stringCopy(BaseDir);
AbsPath := StringConcat(TempPath, Path);
kfree(void(TempPath));
end;
makeAbsolutePathFrom := AbsPath;
end;
function resolvePathFrom(Path : pchar; BaseDir : pchar) : TIsPathValid;
var
TempPath : pchar;
AbsPath : pchar;
begin
TempPath := makeAbsolutePathFrom(Path, BaseDir);
AbsPath := evaluatePath(TempPath);
kfree(void(TempPath));
resolvePathFrom := PathValid(AbsPath);
kfree(void(AbsPath));
end;
function GetDirectoryListingFrom(Path : pchar; BaseDir : pchar) : PHashMap;
var
TempPath : pchar;
AbsPath : pchar;
begin
TempPath := makeAbsolutePathFrom(Path, BaseDir);
AbsPath := evaluatePath(TempPath);
kfree(void(TempPath));
GetDirectoryListingFrom := GetDirectoryListing(AbsPath);
kfree(void(AbsPath));
end;
function changeDirectoryFrom(Path : pchar; BaseDir : pchar; var NewDir : pchar) : TIsPathValid;
var
TempPath : pchar;
AbsPath : pchar;
Validity : TIsPathValid;
begin
TempPath := makeAbsolutePathFrom(Path, BaseDir);
AbsPath := evaluatePath(TempPath);
kfree(void(TempPath));
Validity := PathValid(AbsPath);
if Validity = pvDirectory then
NewDir := AbsPath
else begin
NewDir := nil;
kfree(void(AbsPath));
end;
changeDirectoryFrom := Validity;
end;
{ Terminal Commands } { Terminal Commands }
procedure VFS_COMMAND_PUSHD(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf); procedure VFS_COMMAND_PUSHD(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
@@ -746,11 +811,8 @@ begin
//outputln('VFS', makeRelative('/test/mydisk/mything', '/test/mydisk')); //outputln('VFS', makeRelative('/test/mydisk/mything', '/test/mydisk'));
//while true do begin end; //while true do begin end;
{ Register Terminal Commands } { LS, CD, PUSHD, POPD are now handled as per-terminal builtins
stdio.registerCommand('LS', @VFS_COMMAND_LS, 'List directory contents.'); in vterminal.pas so each terminal has its own working directory. }
stdio.registerCommand('CD', @VFS_COMMAND_CD, 'Set working directory.');
stdio.registerCommand('PUSHD', @VFS_COMMAND_PUSHD, 'Push the working directory.');
stdio.registerCommand('POPD', @VFS_COMMAND_POPD, 'Pop the working directory.');
//ht:= PHashMap(Root^.Reference); //ht:= PHashMap(Root^.Reference);
//hashmap.add(ht, 'VDirectory', void(newDummyObject(otVDIRECTORY))); //hashmap.add(ht, 'VDirectory', void(newDummyObject(otVDIRECTORY)));
+2
View File
@@ -21,6 +21,7 @@ uses
uidebug, uidebug,
lvgl, lvgl,
video, video,
windows,
syslog; syslog;
const const
@@ -35,6 +36,7 @@ begin
TickCounter := TickCounter + 1; TickCounter := TickCounter + 1;
if TickCounter >= TICKS_PER_FRAME then begin if TickCounter >= TICKS_PER_FRAME then begin
TickCounter := 0; TickCounter := 0;
windows.reapOrphanedWindows;
desktop.update; desktop.update;
uidebug.update; uidebug.update;
lvgl_handler; lvgl_handler;
+11
View File
@@ -467,6 +467,7 @@ const
LV_KEY_PREV = 11; LV_KEY_PREV = 11;
LV_KEY_HOME = 2; LV_KEY_HOME = 2;
LV_KEY_END = 3; LV_KEY_END = 3;
LV_KEY_CTRLC = 128; { Ctrl+C — terminal interrupt }
{ Arc mode } { Arc mode }
LV_ARC_MODE_NORMAL = 0; LV_ARC_MODE_NORMAL = 0;
@@ -1861,6 +1862,16 @@ begin
exit; exit;
end; end;
{ Ctrl+C — inject custom key code so focused terminal can handle it }
if key_info.is_down_code and key_info.CTRL_DOWN and (key_info.key_code = ord('c')) then begin
next_head := (kb_head + 1) mod KB_BUF_SIZE;
if next_head <> kb_tail then begin
kb_buf[kb_head] := LV_KEY_CTRLC;
kb_head := next_head;
end;
exit;
end;
{ Map Asuro key codes to LVGL key codes } { Map Asuro key codes to LVGL key codes }
case key_info.key_code of case key_info.key_code of
$1B: k := LV_KEY_ESC; $1B: k := LV_KEY_ESC;
+45 -1
View File
@@ -11,7 +11,7 @@ unit windows;
interface interface
uses uses
lvgl, mouse, serial, tracer; lvgl, mouse, serial, tracer, processmanager, proctypes;
const const
MAX_WINDOWS = 16; MAX_WINDOWS = 16;
@@ -55,6 +55,7 @@ type
on_close : TWinCloseCallback; on_close : TWinCloseCallback;
on_resize : TWinResizeCallback; on_resize : TWinResizeCallback;
cursor_obj : Plv_obj; { cursor to keep on top } cursor_obj : Plv_obj; { cursor to keep on top }
owner_pid : uint32; { owning process PID; 0 = unowned }
end; end;
{ Create a new window. Returns window ID (0 = failure). } { Create a new window. Returns window ID (0 = failure). }
@@ -81,6 +82,15 @@ function getWindowCount: uint32;
{ Set a callback to be notified when a window is resized. } { Set a callback to be notified when a window is resized. }
procedure setWindowResizeCallback(win_id: uint32; cb: TWinResizeCallback); procedure setWindowResizeCallback(win_id: uint32; cb: TWinResizeCallback);
{ Assign an owning process to a window.
When reapOrphanedWindows detects the process has died, the window
is automatically closed via its on_close callback. }
procedure setWindowOwner(win_id: uint32; pid: uint32);
{ Check all windows for dead owner processes and close them.
Called once per frame from graphicsrefresh. }
procedure reapOrphanedWindows;
implementation implementation
var var
@@ -641,6 +651,7 @@ begin
wins[id].on_close := closeCB; wins[id].on_close := closeCB;
wins[id].on_resize := nil; wins[id].on_resize := nil;
wins[id].cursor_obj := cursor; wins[id].cursor_obj := cursor;
wins[id].owner_pid := 0;
{ Bring to front } { Bring to front }
bringToFront(id); bringToFront(id);
@@ -698,6 +709,7 @@ begin
wins[win_id].on_close := nil; wins[win_id].on_close := nil;
wins[win_id].on_resize := nil; wins[win_id].on_resize := nil;
wins[win_id].cursor_obj := nil; wins[win_id].cursor_obj := nil;
wins[win_id].owner_pid := 0;
tracer.pop_trace; tracer.pop_trace;
end; end;
@@ -746,4 +758,36 @@ begin
wins[win_id].on_resize := cb; wins[win_id].on_resize := cb;
end; end;
{ ============================================================
Public: set window owner PID
============================================================ }
procedure setWindowOwner(win_id: uint32; pid: uint32);
begin
if (win_id < 1) or (win_id > MAX_WINDOWS) then exit;
if wins[win_id].state = wsNone then exit;
wins[win_id].owner_pid := pid;
end;
{ ============================================================
Public: reap windows whose owning process has died
============================================================ }
procedure reapOrphanedWindows;
var
i : uint32;
ctx : PProcessContext;
begin
for i := 1 to MAX_WINDOWS do begin
if wins[i].state = wsNone then continue;
if wins[i].owner_pid = 0 then continue;
ctx := processmanager.findByID(wins[i].owner_pid);
if (ctx = nil) or (ctx^.State = psFinished) or (ctx^.State = psError) then begin
{ Owner is dead — trigger close callback or destroy directly }
if wins[i].on_close <> nil then
wins[i].on_close(i)
else
destroyWindow(i);
end;
end;
end;
end. end.
+2 -4
View File
@@ -72,6 +72,8 @@ procedure register_driver(Driver_Name : PChar; DeviceID : PDeviceIdentifier; Loa
procedure register_driver_ex(Driver_Name : PChar; DeviceID : PDeviceIdentifier; Load_Callback : TDriverLoadCallback; force_load : boolean); procedure register_driver_ex(Driver_Name : PChar; DeviceID : PDeviceIdentifier; Load_Callback : TDriverLoadCallback; force_load : boolean);
procedure register_device(Device_Name : PChar; DeviceID : PDeviceIdentifier; ptr : void); procedure register_device(Device_Name : PChar; DeviceID : PDeviceIdentifier; ptr : void);
procedure terminal_command_dev(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
var var
Root : PDriverRegistration = nil; Root : PDriverRegistration = nil;
Dev : PDeviceRegistration = nil; Dev : PDeviceRegistration = nil;
@@ -328,10 +330,6 @@ end;
procedure init; procedure init;
begin begin
push_trace('driver_management.init'); push_trace('driver_management.init');
stdio.registerCommand('DEV', @terminal_command_dev, 'Driver Management Interface.');
//stdio.registerCommand('DRIVERSEX', @terminal_command_driversex, 'List all available drivers.');
//stdio.registerCommand('DRIVERS', @terminal_command_drivers, 'List loaded drivers.');
//stdio.registerCommand('DEVICES', @terminal_command_devices, 'List devices.');
pop_trace; pop_trace;
end; end;
+114
View File
@@ -0,0 +1,114 @@
{
ProcTypes - Type definitions for the preemptive process management system.
Defines process states, system messages, context records, and resource
bindings used by processmanager.pas and contextswitcher.pas.
@author(Kieron Morris <kjm@kieronmorris.me>)
}
unit proctypes;
interface
uses
stdio;
const
{ 8 KB per-process kernel stack }
PROCESS_STACK_SIZE = 8192;
{ Base quantum multiplier: quantum = Priority * BASE_QUANTUM ticks }
BASE_QUANTUM = 8;
type
{ Forward declaration }
PProcessContext = ^TProcessContext;
{ Process states }
TProcessState = (
psCreated, { Allocated, stack prepared, not yet scheduled }
psRunning, { Currently executing on the main thread }
psReady, { Runnable but not the current process }
psSuspended, { Paused - will not be scheduled }
psAwaiting, { Blocked on I/O or event - will not be scheduled }
psFinished, { Terminal state - safe to reap }
psError { Unrecoverable error - safe to reap }
);
{ System messages delivered to processes }
TProcessSysMsg = (
smNone, { No message }
smTerminate, { Graceful shutdown requested }
smKill, { Immediate forced shutdown }
smSuspend, { Pause execution }
smResume, { Resume from suspended }
smInput, { New data available on stdin }
smChildExited, { A child process has exited }
smCustom { User-defined message (payload in MsgData) }
);
{ Process entry point - a procedure that IS the process.
When this procedure returns, the process is finished. }
TProcessEntryPoint = procedure(ctx : PProcessContext);
{ Resource binding types }
TResourceKind = (
rkSocket, { TCP/UDP socket }
rkTimer, { A timer hook }
rkFileHandle, { VFS file descriptor }
rkCustom { Arbitrary pointer }
);
{ Resource cleanup callback }
TResourceCleanup = procedure(handle : void);
PResourceBinding = ^TResourceBinding;
TResourceBinding = record
Kind : TResourceKind;
Handle : void;
Cleanup : TResourceCleanup;
end;
{ Process context - the core data structure for each process }
TProcessContext = record
{ Identity }
ProcessID : uint32;
Name : array[0..31] of char;
ParentID : uint32;
{ State }
State : TProcessState;
ExitCode : uint32;
{ StdIO - per-process I/O buffers }
StdIn : POutBuf;
StdOut : POutBuf;
StdErr : POutBuf;
{ Entry point }
EntryPoint : TProcessEntryPoint;
{ Context switch state }
SavedESP : uint32;
StackBase : void;
StackTop : uint32;
{ Scheduling }
Priority : uint8;
Quantum : uint16;
TicksUsed : uint16;
{ System messages }
PendingMsg : TProcessSysMsg;
MsgData : void;
{ Resource bindings (PDList of TResourceBinding) }
Resources : void;
{ User-defined state }
Local : void;
end;
implementation
end.
+10
View File
@@ -31,6 +31,7 @@ type
procedure init; procedure init;
procedure registerISR(INT_N : uint8; callback : TISRHook); procedure registerISR(INT_N : uint8; callback : TISRHook);
procedure dispatchHooks(INT_N : uint8);
implementation implementation
@@ -51,6 +52,15 @@ begin
end; end;
end; end;
procedure dispatchHooks(INT_N : uint8);
var
i : uint8;
begin
for i:=0 to MAX_HOOKS do begin
if Hooks[INT_N][i] <> nil then Hooks[INT_N][i]();
end;
end;
procedure ISR_N(INT_N : uint8); procedure ISR_N(INT_N : uint8);
var var
i : uint8; i : uint8;

Some files were not shown because too many files have changed in this diff Show More