Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a733b1559 | ||
|
|
deb513c925 | ||
|
|
789fb7971a | ||
|
|
4e3acd6af7 | ||
|
|
262d064b6d | ||
|
|
738e5828f6 | ||
|
|
9fa1c859ac | ||
|
|
d01b534a3d | ||
|
|
491b0ea5c3 | ||
|
|
de6fde05cc | ||
|
|
fb675a2299 | ||
|
|
aa374b6816 |
No files matched your search
+157
File diff suppressed because it is too large.
Load diff
+7
-1
@@ -4,4 +4,10 @@ echo "======================="
|
||||
echo " "
|
||||
echo "Compiling FPC Sources..."
|
||||
echo " "
|
||||
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/include/* -Fusrc/driver/* -Fusrc/driver/net/* -Fusrc/driver/bus/* -Fusrc/driver/bus/usb/* -Fusrc/driver/hid/* src/kernel.pas
|
||||
# Build -Fu flags for all directories under src/ and wasuro/
|
||||
FU_PATHS="-Fusrc -Fuwasuro"
|
||||
for dir in $(find src wasuro -type d 2>/dev/null); do
|
||||
FU_PATHS="$FU_PATHS -Fu$dir"
|
||||
done
|
||||
|
||||
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/kernel.pas
|
||||
@@ -0,0 +1,32 @@
|
||||
#Flat filesystem
|
||||
|
||||
A super simple filesystem for asuro. Folders are emulated in filenames.
|
||||
|
||||
Starts with disk info sector, sector 0 of volume
|
||||
|
||||
---
|
||||
#### disk info
|
||||
|
||||
jmp2boot : ubit24;
|
||||
OEMName : array[0..7] of char;
|
||||
version : uint16 // numerical version of filesystem
|
||||
sectorCount : uint16;
|
||||
fileCount : uint16
|
||||
signature : uint32 = 0x0B00B1E5
|
||||
|
||||
|
||||
the Rest of the sector is reserved
|
||||
|
||||
---
|
||||
|
||||
Starting from sector 1 is the file table. Table size is determined by entry size (64) * fileCount
|
||||
|
||||
---
|
||||
####File entry
|
||||
|
||||
name : array[0..59] of char //file name max 60 chars
|
||||
fileStart : 16bit // start sector of data
|
||||
fileSize : 16bit // data size in sectors
|
||||
|
||||
---
|
||||
|
||||
Binary file not shown.
Generated
+1
@@ -0,0 +1 @@
|
||||
Hello from the Asuro ISO!
|
||||
@@ -0,0 +1,40 @@
|
||||
# Lessons Learnt
|
||||
|
||||
## 1. File Pickers Must Be Proper Reusable OS Components
|
||||
Inline pickers hacked into app code are broken and not reusable. Build file pickers as a standalone unit (`filepicker.pas`) that any program can call via a callback.
|
||||
|
||||
## 2. All Errors Need Visible In-App Feedback
|
||||
Never use `syslog.logln` as the only error output. Always show the user a dialog, msgbox, or status bar message. Syslog is supplemental only.
|
||||
|
||||
## 4. Shell Command Output Goes to stdout_buf, Not syslog
|
||||
Use `stdio.bufWriteStr(stdout_buf, ...)` for all shell command output. `syslog` is for kernel diagnostics only.
|
||||
|
||||
## 5. Unit Test Convention
|
||||
New subsystem units get a `procedure UnitTest` (called at boot from kernel.pas) and a `procedure init` that registers a CLI command so tests can be re-run at runtime. Tests use a nested `Assert(condition, name)` that increments `passed`/`failed` and logs failures via `syslog.logln`. At-boot tests must not do disk I/O — only test in-memory/virtual structures.
|
||||
|
||||
## 6. ISR-Visible Spin-Wait Flags Must Use Pointer Dereferencing
|
||||
FPC has no `volatile` keyword. Any `while flag = 0 do asm hlt end` loop where `flag` is set by an ISR will hang forever because FPC hoists the load into a register before the loop and never re-reads memory. Always access the flag through a pointer: `while puint32(@flag)^ = 0 do proc_yield()`. This applies everywhere in the kernel that spins waiting for ISR-written state (e.g. `submit_io_wait`, `proc_await`-style loops, DMA done flags).
|
||||
|
||||
## 7. Never Spawn a Process Per I/O Operation
|
||||
Spawning a new kernel process for each FAT32 read/write/dir operation is pure overhead: process creation (kalloc 8 KB stack, fake IRET frame, DList insertion), an extra context switch, and a double-wait (VFS spins on the worker, worker spins on AHCI). Instead, submit the I/O directly and park the calling process via `psAwaiting` until the AHCI ISR fires the completion callback — zero extra processes, zero wasted scheduler ticks.
|
||||
|
||||
## 8. Use psAwaiting to Park a Process Pending Async I/O (not proc_yield spin)
|
||||
The correct way to block a process on an async I/O result is: (1) set up a completion callback that sets `State := psReady` then `Done := 1`, (2) atomically check if the operation is already done (under CLI) and set `CurrentProcess^.State := psAwaiting` if not, (3) spin on `Done` via `puint32(@wait.Done)^` per Lesson #6 with `asm hlt end` inside the loop. The process is removed from the runnable set while hardware works. **Do NOT call `proc_await` from `submit_io_wait`** — `proc_await` spins on `CurrentProcess^.State = psAwaiting` without pointer indirection and FPC caches the value in a register, causing it to return immediately before the I/O completes. The calling code then reads garbage from the DMA buffer, causing invalid pointer dereferences and page faults.
|
||||
|
||||
## 9. VFS GetDirectoryListing Must Return a Snapshot, Not a Live Tree Reference
|
||||
`GetDirectoryListing` for `otVDIRECTORY` nodes previously returned `PHashMap(Obj^.Reference)` — a direct pointer into the live VFS tree. When callers called `FreeDirectoryListing` on the returned map, it freed the live VFSObjects and their name strings, destroying the VFS tree. Any subsequent `GetObjectFromPath` call would then dereference the trashed memory and page fault. **Fix**: always return a heap-allocated snapshot copy of the directory (new `PHashMap`, new `PVFSObject` entries with `stringCopy`'d keys). `FreeDirectoryListing` can then safely own and free the snapshot without touching the live tree. The rule: any function that returns a `PHashMap` to a caller who will call `FreeDirectoryListing` must allocate a fresh map — never return a raw interior pointer to a live data structure.
|
||||
|
||||
## 10. Never Call Synchronous Disk I/O From an LVGL Timer or Event Callback
|
||||
LVGL timer callbacks (`lv_timer_create`) and event callbacks run synchronously inside the LVGL render loop. Calling any function that parks the current process waiting for disk I/O (e.g. `vfs.FileSize`, `vfs.OpenFile`, `vfs.ReadFile`) from inside a timer or event callback will hang the entire UI — the process blocks mid-callback and the LVGL loop never resumes. All disk I/O that must occur in a UI context must either: (a) use the async VFS API (`OpenFileAsync`, `WriteFileAsync`) with a completion callback that triggers a deferred LVGL update, or (b) be deferred to a dedicated worker process that signals back via a flag the UI can poll. `GetDirectoryListingFrom` is the one bulk exception — it was already present in the original picker and works because it loads into a snapshot synchronously as a single operation; per-file calls like `FileSize` in a loop are the problem.
|
||||
|
||||
## 11. Never Allocate Large Arrays as Local Variables in Deep Kernel Call Chains
|
||||
Local variables are stack-allocated in Pascal. Kernel processes have a fixed, limited stack (≈8 KB). In deep LVGL callback chains (kernel → LVGL render loop → timer callback → app code), there may only be a few KB of usable stack remaining by the time app code executes. Declaring local arrays larger than ~200–400 bytes (e.g. `array[0..255] of pchar` = 1024 bytes) inside any procedure that runs in this context will silently overflow the stack, corruptung adjacent memory and causing a page fault with a garbled call trace. **Rule**: any local variable array larger than ~128 bytes in a UI callback or procedure called from one must be moved to the heap with `kalloc`/`kfree`. The corruption pattern is a page fault with a call stack full of completely unrelated function names.
|
||||
|
||||
## 12. Pascal Silently Ignores Everything After `end.` — Dead Code Masquerades as Live Code
|
||||
FPC compiles everything up to and including the first `end.` and silently discards the rest of the file. If a file is partially rewritten by prepending a new implementation but the old implementation is not deleted, the old code survives after `end.`. Forward declarations resolve to the **last** implementation before `end.` — so if the new code was added before the old `end.` but the old procedures were in the "dead" zone they have no effect. However the reverse is dangerous: if the old `end.` was replaced/removed and the new code placed before it, the old procedures in the dead zone still compile to nothing but pollute the source. **Rule**: after any large-scale replacement of a Pascal unit, explicitly check where `end.` falls with a text search and PowerShell-truncate the file at the first `end.`. Never assume a multi-step replacement tool correctly removed all old code — always verify with `Select-String -Pattern "^end\.$"`.
|
||||
|
||||
## 13. `for i := 0 to uint32_count - 1` Wraps to 4 Billion When Count is Zero
|
||||
In Free Pascal, `uint32` arithmetic wraps: if `dir_count` is `uint32` and equals `0`, then `dir_count - 1 = 0xFFFFFFFF`. A `for i := 0 to dir_count - 1 do` loop with zero count does NOT skip — it runs 4 billion iterations, immediately accessing invalid memory and page faulting. FPC does not emit a warning for this. **Rule**: always guard `uint32`-bounded for loops: `if count > 0 then for i := 0 to count - 1 do`. Alternatively, use `sint32` for loop counters that might legitimately be zero.
|
||||
|
||||
## 14. FAT32 Deleted Entries ($E5) Must Be Filtered in getDirEntries
|
||||
When a FAT32 directory entry is deleted, `fileName[0]` is overwritten with `$E5` but the rest of the entry (including the cluster pointer) remains intact on disk. `getDirEntries` must explicitly skip entries where `fileName[0] = char($E5)` — stopping only at `char(0)` (end-of-directory) is not enough. If `$E5` entries are returned to callers, they appear in directory listings with a garbage first character, and navigating into them follows a stale/freed cluster chain, which causes reads into arbitrary memory or FAT data, leading to a triple fault. Fix location: the `while i < maxEntries` loop in `fat32.getDirEntries`.
|
||||
+105
-2
@@ -13,14 +13,117 @@
|
||||
// limitations under the License.
|
||||
|
||||
{
|
||||
ContextSwitcher - Switch Process Contexts when preempted.
|
||||
ContextSwitcher - Custom IRQ0 handler for preemptive context switching.
|
||||
|
||||
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;
|
||||
|
||||
{$ASMMODE intel}
|
||||
|
||||
interface
|
||||
|
||||
implementation;
|
||||
uses
|
||||
idt, isrmanager, processmanager, proctypes, util, tracer;
|
||||
|
||||
{ Initialise: overwrite IDT gate 32 with our custom ISR. }
|
||||
procedure init;
|
||||
|
||||
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.
|
||||
+2
-5
@@ -22,7 +22,7 @@ unit cpu;
|
||||
interface
|
||||
|
||||
uses
|
||||
util, RTC;
|
||||
util, RTC, stdio;
|
||||
|
||||
type
|
||||
PCapabilities_Old = ^TCapabilities_Old;
|
||||
@@ -113,12 +113,10 @@ var
|
||||
CAP_OLD, CAP_NEW : uint32;
|
||||
|
||||
procedure init();
|
||||
procedure Terminal_Command_CPU(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
stdio;
|
||||
|
||||
procedure getCPUIdentifier;
|
||||
var
|
||||
id0, id1, id2 : uint32;
|
||||
@@ -325,7 +323,6 @@ end;
|
||||
|
||||
procedure init();
|
||||
begin
|
||||
stdio.registerCommand('CPU', @Terminal_Command_CPU, 'CPU Info.');
|
||||
CPUID.Capabilities0:= PCapabilities_Old(@CAP_OLD);
|
||||
CPUID.Capabilities1:= PCapabilities_New(@CAP_NEW);
|
||||
getCPUIdentifier;
|
||||
|
||||
+585
File diff suppressed because it is too large.
Load diff
@@ -91,6 +91,7 @@ function getDeviceInfo(class_code : uint8; subclass_code : uint8; prog_if : uint
|
||||
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
|
||||
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
|
||||
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
|
||||
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
|
||||
|
||||
implementation
|
||||
|
||||
@@ -442,4 +443,34 @@ begin
|
||||
pop_trace;
|
||||
end;
|
||||
|
||||
//Enable device inturrupts and set bus master
|
||||
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
|
||||
var
|
||||
addr : uint32;
|
||||
cmd : uint32;
|
||||
begin
|
||||
push_trace('PCI.enableDevice');
|
||||
|
||||
addr := ($1 shl 31);
|
||||
addr := addr or (bus shl 16);
|
||||
addr := addr or ((slot) shl 11);
|
||||
addr := addr or ((func) shl 8);
|
||||
addr := addr or ($04 and $FC);
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||
cmd := inl(PCI_CONFIG_DATA_PORT);
|
||||
cmd := cmd or PCI_COMMAND_MEM_SPACE;
|
||||
cmd := cmd or PCI_COMMAND_BUS_MASTER;
|
||||
cmd := cmd or (3 shl 1);
|
||||
|
||||
//enable interrupts, remove disable interrupt bit maybe
|
||||
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
|
||||
// cmd := cmd and not (1 shl 9);
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||
outl(PCI_CONFIG_DATA_PORT, cmd);
|
||||
|
||||
pop_trace;
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -158,6 +158,9 @@ procedure init;
|
||||
{ Unit Tests }
|
||||
procedure UnitTest;
|
||||
|
||||
{ Terminal command }
|
||||
procedure terminal_command_usb(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
|
||||
|
||||
implementation
|
||||
|
||||
{ ========================= Globals ========================= }
|
||||
@@ -954,11 +957,14 @@ end;
|
||||
procedure usb_check_hotplug;
|
||||
var
|
||||
i : uint32;
|
||||
count: uint32;
|
||||
hc : PUSBHCDriver;
|
||||
port : uint8;
|
||||
begin
|
||||
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));
|
||||
if (hc <> nil) and hc^.PortChangePending then begin
|
||||
hc^.PortChangePending := false;
|
||||
@@ -1100,7 +1106,6 @@ begin
|
||||
CompletionHookCount := 0;
|
||||
for i := 0 to MAX_COMPLETION_HOOKS - 1 do
|
||||
CompletionHooks[i] := nil;
|
||||
stdio.registerCommand('USB', @terminal_command_usb, 'USB subsystem information.');
|
||||
syslog.logln('USB Core', 'INIT END.');
|
||||
pop_trace;
|
||||
end;
|
||||
|
||||
@@ -119,8 +119,12 @@ var
|
||||
x32, y32 : sint32;
|
||||
r : pchar;
|
||||
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
|
||||
b := mouse_read;
|
||||
b := inb($60);
|
||||
if Cycle = 0 then begin
|
||||
if (b AND $08) = $08 then begin
|
||||
Mouse_Byte[Cycle] := b;
|
||||
|
||||
@@ -21,6 +21,29 @@ unit drivertypes;
|
||||
|
||||
interface
|
||||
|
||||
const
|
||||
PCI_CONFIG_ADDRESS_PORT = $0CF8;
|
||||
PCI_CONFIG_DATA_PORT = $0CFC;
|
||||
|
||||
PCI_COMMAND_IO_SPACE = $0001;
|
||||
PCI_COMMAND_MEM_SPACE = $0002;
|
||||
PCI_COMMAND_BUS_MASTER = $0004;
|
||||
PCI_COMMAND_SPECIAL_CYC = $0008;
|
||||
PCI_COMMAND_MEM_WRITE = $0010;
|
||||
PCI_COMMAND_VGA_PALETTE = $0020;
|
||||
PCI_COMMAND_PARITY = $0040;
|
||||
PCI_COMMAND_WAIT = $0080;
|
||||
PCI_COMMAND_SERR = $0100;
|
||||
PCI_COMMAND_FAST_BACK = $0200;
|
||||
PCI_COMMAND_INT_DISABLE = $0400;
|
||||
PCI_COMMAND_SERR_ENABLE = $8000;
|
||||
|
||||
PCI_CAP_ID_MSI = $05;
|
||||
|
||||
// Bits in the MSI Control register (16-bit):
|
||||
MSI_CONTROL_ENABLE = 1 shl 0; // Bit 0
|
||||
MSI_CONTROL_64BIT = 1 shl 7; // Bit 7
|
||||
MSI_CONTROL_PVMASK = 1 shl 8; // Bit 8 (optional: per-vector masking)
|
||||
type
|
||||
|
||||
PPCI_Device = ^TPCI_Device;
|
||||
@@ -44,6 +67,7 @@ type
|
||||
address1 : uint32;
|
||||
address2 : uint32;
|
||||
address3 : uint32;
|
||||
|
||||
address4 : uint32;
|
||||
address5 : uint32;
|
||||
CIS_pointer : uint32;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -100,8 +100,8 @@ end;
|
||||
|
||||
procedure send(p_data : void; p_len : uint16);
|
||||
begin
|
||||
//push_trace('net.send');
|
||||
//writeToLogLn('L1: net.send');
|
||||
push_trace('net.send');
|
||||
writeToLogLn('L1/NET: send');
|
||||
if CBSend <> nil then CBSend(p_data, p_len);
|
||||
pop_trace;
|
||||
end;
|
||||
@@ -111,8 +111,7 @@ var
|
||||
context : PPacketContext;
|
||||
|
||||
begin
|
||||
//push_trace('net.recv');
|
||||
//writeToLogLn('L1: net.recv');
|
||||
push_trace('net.recv');
|
||||
context:= newPacketContext;
|
||||
if CBNext <> nil then CBNext(p_data, p_len, context);
|
||||
freePacketContext(context);
|
||||
@@ -129,6 +128,7 @@ end;
|
||||
procedure init;
|
||||
begin
|
||||
push_trace('net.init');
|
||||
writeToLogLn('L1/NET: init');
|
||||
//l2
|
||||
eth2.register;
|
||||
//l3
|
||||
@@ -136,6 +136,7 @@ begin
|
||||
ipv4.register;
|
||||
//l4
|
||||
icmp.register;
|
||||
tcp.register;
|
||||
udp.register;
|
||||
//l5
|
||||
dhcp.register;
|
||||
|
||||
@@ -46,6 +46,7 @@ var
|
||||
|
||||
procedure registerTypePromisc(eType : uint16; RecvCB : TRecvCallback);
|
||||
begin
|
||||
push_trace('eth2.registerTypePromisc');
|
||||
register;
|
||||
if EthTypes[eType] = nil then EthTypes[eType]:= RecvCB;
|
||||
Promisc[eType]:= true;
|
||||
@@ -53,6 +54,7 @@ end;
|
||||
|
||||
procedure registerType(eType : uint16; RecvCB : TRecvCallback);
|
||||
begin
|
||||
push_trace('eth2.registerType');
|
||||
register;
|
||||
if EthTypes[eType] = nil then EthTypes[eType]:= RecvCB;
|
||||
end;
|
||||
@@ -93,7 +95,7 @@ var
|
||||
buf : puint8;
|
||||
|
||||
begin
|
||||
//writeToLogLn(' L2: eth2.recv');
|
||||
push_trace('eth2.recv');
|
||||
buf:= puint8(p_data);
|
||||
|
||||
Header:= PEthernetHeader(buf);
|
||||
@@ -120,6 +122,7 @@ var
|
||||
begin
|
||||
push_trace('eth2.register');
|
||||
if not Registered then begin
|
||||
writeToLogLn(' L2/ETH: register');
|
||||
for i:=0 to 65535 do begin
|
||||
EthTypes[i]:= nil;
|
||||
Promisc[i]:= false;
|
||||
|
||||
@@ -25,7 +25,7 @@ uses
|
||||
tracer, lmemorymanager,
|
||||
util, lists,
|
||||
net, nettypes, netutils,
|
||||
eth2, ipv4;
|
||||
eth2, ipv4, stdio;
|
||||
|
||||
type
|
||||
PARPCacheRecord = ^TARPCacheRecord;
|
||||
@@ -41,11 +41,12 @@ procedure sendGratuitous;
|
||||
procedure sendRequest(ip : puint8);
|
||||
procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext);
|
||||
function resolveIP(ip : puint8) : puint8;
|
||||
procedure terminal_command_arp(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
stdio, strings;
|
||||
strings;
|
||||
|
||||
var
|
||||
Registered : Boolean = false;
|
||||
@@ -96,6 +97,7 @@ var
|
||||
hSize, pSize : uint8;
|
||||
|
||||
begin
|
||||
push_trace('arp.send');
|
||||
if p_context <> nil then begin
|
||||
buf:= kalloc(sizeof(TARPHeader));
|
||||
hdr:= PARPHeader(buf);
|
||||
@@ -135,6 +137,8 @@ var
|
||||
context : PPacketContext;
|
||||
|
||||
begin
|
||||
push_trace('arp.sendGratuitous');
|
||||
writeToLogLn(' L3/ARP: sendGratuitous');
|
||||
context:= newPacketContext;
|
||||
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Destination[0]);
|
||||
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
||||
@@ -150,6 +154,7 @@ var
|
||||
CacheRecord : PARPCacheRecord;
|
||||
|
||||
begin
|
||||
push_trace('arp.sendRequestGateway');
|
||||
context:= newPacketContext;
|
||||
CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]);
|
||||
if CacheRecord <> nil then begin
|
||||
@@ -168,6 +173,8 @@ var
|
||||
CacheRecord : PARPCacheRecord;
|
||||
|
||||
begin
|
||||
push_trace('arp.sendRequest');
|
||||
writeToLogLn(' L3/ARP: sendRequest');
|
||||
context:= newPacketContext;
|
||||
CopyIPv4(ip, @context^.IP.Destination[0]);
|
||||
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
||||
@@ -184,6 +191,7 @@ var
|
||||
CacheRecord : PARPCacheRecord;
|
||||
|
||||
begin
|
||||
push_trace('arp.resolveIP');
|
||||
CacheRecord:= findCacheRecordByIP(ip);
|
||||
resolveIP:= nil;
|
||||
if CacheRecord = nil then begin
|
||||
@@ -203,6 +211,7 @@ var
|
||||
context : PPacketContext;
|
||||
|
||||
begin
|
||||
push_trace('arp.recv');
|
||||
{ Get our converted Header }
|
||||
Header:= PARPHeader(p_data);
|
||||
AHeader.Hardware_Type:= (Header^.Hardware_Type_Hi SHL 8) + Header^.Hardware_Type_Lo;
|
||||
@@ -298,9 +307,9 @@ procedure register;
|
||||
begin
|
||||
push_trace('arp.register');
|
||||
if not Registered then begin
|
||||
writeToLogLn(' L3/ARP: register');
|
||||
Cache:= LL_New(sizeof(TARPCacheRecord));
|
||||
eth2.registerTypePromisc($0806, @recv);
|
||||
stdio.registerCommand('ARP', @terminal_command_arp, 'Get ARP Table.');
|
||||
Registered:= true;
|
||||
end;
|
||||
pop_trace;
|
||||
|
||||
@@ -26,17 +26,18 @@ uses
|
||||
util, strings,
|
||||
net, nettypes, netutils,
|
||||
lists,
|
||||
eth2;
|
||||
eth2, stdio;
|
||||
|
||||
procedure send(p_data : void; p_len : uint16; p_context : PPacketContext);
|
||||
procedure registerProtocol(Protocol_ID : uint8; recv_callback : TRecvCallback);
|
||||
function getIPv4Config : PIPv4Configuration;
|
||||
procedure register;
|
||||
procedure terminal_command_ifconfig(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
arp, stdio;
|
||||
arp;
|
||||
|
||||
var
|
||||
Registered : Boolean = false;
|
||||
@@ -46,7 +47,9 @@ var
|
||||
|
||||
function getIPv4Config : PIPv4Configuration;
|
||||
begin
|
||||
push_trace('ipv4.getIPv4Config');
|
||||
getIPv4Config:= @Config;
|
||||
pop_trace;
|
||||
end;
|
||||
|
||||
procedure send(p_data : void; p_len : uint16; p_context : PPacketContext);
|
||||
@@ -57,6 +60,7 @@ var
|
||||
buffer : void;
|
||||
|
||||
begin
|
||||
push_trace('ipv4.send');
|
||||
inc(CurrentID);
|
||||
Header.version:= 4;
|
||||
Header.header_len:= 5;
|
||||
@@ -84,6 +88,7 @@ begin
|
||||
memcpy(uint32(p_data), uint32(Buffer) + (Header.header_len * 4), p_len);
|
||||
eth2.send(Buffer, (Header.header_len * 4) + p_len, $0800, p_context);
|
||||
kfree(Buffer);
|
||||
pop_trace;
|
||||
end;
|
||||
|
||||
procedure recv(p_data : void; p_len : uint16; p_context : PPacketContext);
|
||||
@@ -95,6 +100,7 @@ var
|
||||
len : uint16;
|
||||
|
||||
begin
|
||||
push_trace('ipv4.recv');
|
||||
Header:= PIPV4Header(p_data);
|
||||
AHeader.version:= Header^.version;
|
||||
AHeader.header_len:= Header^.header_len;
|
||||
@@ -195,6 +201,7 @@ var
|
||||
begin
|
||||
push_trace('ipv4.register');
|
||||
if not Registered then begin
|
||||
writeToLogLn(' L3/IPv4: register');
|
||||
for i:=0 to 255 do begin
|
||||
Protocols[i]:= nil;
|
||||
end;
|
||||
@@ -205,7 +212,6 @@ begin
|
||||
end;
|
||||
Config.UP:= false;
|
||||
eth2.registerType($0800, @recv);
|
||||
stdio.registerCommand('IFCONFIG', @terminal_command_ifconfig, 'Configure Network Settings.');
|
||||
Registered:= true;
|
||||
end;
|
||||
pop_trace;
|
||||
@@ -213,6 +219,7 @@ end;
|
||||
|
||||
procedure registerProtocol(Protocol_ID : uint8; recv_callback : TRecvCallback);
|
||||
begin
|
||||
push_trace('ipv4.registerProtocol');
|
||||
register;
|
||||
if Protocols[Protocol_ID] = nil then Protocols[Protocol_ID]:= recv_callback;
|
||||
pop_trace;
|
||||
|
||||
+18
-87
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Loaded 20 of 84 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user