Asuro/src/include/util.pas
Kieron Morris 64b3c9a7ba Apache License
Added the apache license to all source files, accounting for authors. Also added a license.md containing the apache license + contributors.md listing all contributors.
2021-06-22 21:31:17 +01:00

629 lines
15 KiB
ObjectPascal

// 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.
{
Include->Util - Data Manipulation Utlities.
@author(Kieron Morris <kjm@kieronmorris.me>)
}
unit util;
{$ASMMODE intel}
interface
uses
bios_data_area, tracer;
function INTE : boolean;
procedure CLI();
procedure STI();
procedure GPF();
function hi(b : uint8) : uint8;
function lo(b : uint8) : uint8;
function switchendian(b : uint8) : uint8;
function switchendian16(b : uint16) : uint16;
function switchendian32(b : uint32) : uint32;
function getWord(i : uint32; hi : boolean) : uint16;
function getByte(i : uint32; index : uint8) : uint8;
procedure outb(port : uint16; val : uint8);
procedure outw(port : uint16; val : uint16);
procedure outl(port : uint16; val : uint32);
function inb(port : uint16) : uint8;
function inw(port : uint16) : uint16;
function inl(port : uint16) : uint32;
procedure io_wait;
procedure memset(location : uint32; value : uint8; size : uint32);
procedure memcpy(source : uint32; dest : uint32; size : uint32);
procedure printmemory(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean);
procedure printmemoryWND(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean; WND : HWND);
procedure halt_and_catch_fire();
procedure halt_and_dont_catch_fire();
procedure BSOD(fault : pchar; info : pchar);
procedure psleep(t : uint16);
procedure sleep(seconds : uint32);
function get16bitcounter : uint16;
function get32bitcounter : uint32;
function get64bitcounter : uint64;
function getTSC : uint64;
function div6432(dividend : uint64; divisor : uint32) : uint64;
function BCDToUint8(bcd : uint8) : uint8;
function HexCharToDecimal(hex : char) : uint8;
procedure resetSystem();
function getESP : uint32;
function RolDWord(AValue : uint32; Dist : uint8) : uint32;
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
function MsSinceSystemBoot : uint64;
var
endptr : uint32; external name '__end';
stack : uint32; external name 'KERNEL_STACK';
implementation
uses
console, RTC, cpu, serial, strings, isr_types;
function MsSinceSystemBoot : uint64;
begin
MsSinceSystemBoot:= div6432(getTSC, (CPUID.ClockSpeed.Hz div 1000));
end;
function div6432(dividend : uint64; divisor : uint32) : uint64;
var
d0, d4 : uint32;
r0, r4 : uint32;
begin
d4:= dividend SHR 32;
d0:= dividend AND $FFFFFFFF;
asm
PUSHAD
xor edx, edx
mov eax, d4
div divisor
mov r4, eax
mov eax, d0
div divisor
mov r0, eax
POPAD
end;
div6432:= (r0 SHL 32) OR r4;
end;
function switchendian16(b : uint16) : uint16;
begin
switchendian16:= ((b AND $FF00) SHR 8) OR ((b AND $00FF) SHL 8);
end;
function switchendian32(b : uint32) : uint32;
begin
switchendian32:= ((b AND $FF000000) SHR 24) OR
((b AND $00FF0000) SHR 8) OR
((b AND $0000FF00) SHL 8) OR
((b AND $000000FF) SHL 24);
end;
function getESP : uint32;
begin
asm
MOV getESP, ESP
end;
end;
function HexCharToDecimal(hex : char) : uint8;
begin
case hex of
'0':HexCharToDecimal:=0;
'1':HexCharToDecimal:=1;
'2':HexCharToDecimal:=2;
'3':HexCharToDecimal:=3;
'4':HexCharToDecimal:=4;
'5':HexCharToDecimal:=5;
'6':HexCharToDecimal:=6;
'7':HexCharToDecimal:=7;
'8':HexCharToDecimal:=8;
'9':HexCharToDecimal:=9;
'a':HexCharToDecimal:=10;
'A':HexCharToDecimal:=10;
'b':HexCharToDecimal:=11;
'B':HexCharToDecimal:=11;
'c':HexCharToDecimal:=12;
'C':HexCharToDecimal:=12;
'd':HexCharToDecimal:=13;
'D':HexCharToDecimal:=13;
'e':HexCharToDecimal:=14;
'E':HexCharToDecimal:=14;
'f':HexCharToDecimal:=15;
'F':HexCharToDecimal:=15;
else HexCharToDecimal:= 0;
end;
end;
procedure sleep1;
var
DateTimeStart, DateTimeEnd : TDateTime;
begin
DateTimeStart:= getDateTime;
DateTimeEnd:= DateTimeStart;
while DateTimeStart.seconds = DateTimeEnd.seconds do begin
DateTimeEnd:= getDateTime;
end;
end;
procedure sleep(seconds : uint32);
var
i : uint32;
begin
for i:=1 to seconds do begin
sleep1;
end;
end;
function INTE : boolean;
var
flags : uint32;
begin
asm
PUSH EAX
PUSHF
POP EAX
MOV flags, EAX
POP EAX
end;
INTE:= (flags AND (1 SHL 9)) > 0;
end;
procedure io_wait;
var
port : uint8;
val : uint8;
begin
port:= $80;
val:= 0;
asm
PUSH EAX
PUSH EDX
MOV DX, port
MOV AL, val
OUT DX, AL
POP EDX
POP EAX
end;
end;
procedure printmemoryWND(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean; WND : HWND);
var
buf : puint8;
i : uint32;
begin
buf:= puint8(source);
for i:=0 to length-1 do begin
if offset_row and (i = 0) then begin
console.writehexWND(source + (i), WND);
console.writestringWND(': ', WND);
end;
console.writehexpairWND(buf[i], WND);
if ((i+1) MOD col) = 0 then begin
console.writestringlnWND(' ', WND);
if offset_row then begin
console.writehexWND(source + (i + 1), WND);
console.writestringWND(': ', WND);
end;
end else begin
console.writestringWND(delim, WND);
end;
end;
console.writestringlnWND(' ', WND);
end;
procedure printmemory(source : uint32; length : uint32; col : uint32; delim : PChar; offset_row : boolean);
begin
printmemoryWND(source, length, col, delim, offset_row, 0);
end;
function hi(b : uint8) : uint8; [public, alias: 'util_hi'];
begin
hi:= (b AND $F0) SHR 4;
end;
function lo(b : uint8) : uint8; [public, alias: 'util_lo'];
begin
lo:= b AND $0F;
end;
procedure CLI(); assembler; nostackframe;
asm
CLI
end;
procedure STI(); assembler; nostackframe;
asm
STI
end;
procedure GPF(); assembler;
asm
INT 13
end;
function switchendian(b : uint8) : uint8; [public, alias: 'util_switchendian'];
begin
switchendian:= (lo(b) SHL 4) OR hi(b);
end;
//Was broken, now does nothing.
procedure psleep(t : uint16);
var
t1, t2 : uint16;
begin
t1:= BDA^.Ticks;
t2:= BDA^.Ticks;
while t2-t1 < t do begin
break;
t2:= BDA^.Ticks;
if t2 < t1 then break;
end;
end;
procedure outl(port : uint16; val : uint32); [public, alias: 'util_outl'];
begin
//serial.sendString('[outl]');
//serial.sendHex(port);
//serial.sendHex(val);
asm
PUSH EAX
PUSH EDX
MOV DX, port
MOV EAX, val
OUT DX, EAX
POP EDX
POP EAX
end;
io_wait;
end;
procedure outw(port : uint16; val : uint16); [public, alias: 'util_outw'];
begin
//serial.sendString('[outw]');
//serial.sendHex(port);
//serial.sendHex(val);
asm
PUSH EAX
PUSH EDX
MOV DX, port
MOV AX, val
OUT DX, AX
POP EDX
POP EAX
end;
io_wait;
end;
procedure outb(port : uint16; val : uint8); [public, alias: 'util_outb'];
begin
//serial.sendString('[outb]');
//serial.sendHex(port);
//serial.sendHex(val);
asm
PUSH EAX
PUSH EDX
MOV DX, port
MOV AL, val
OUT DX, AL
POP EDX
POP EAX
end;
io_wait;
end;
procedure halt_and_catch_fire(); [public, alias: 'util_halt_and_catch_fire'];
begin
asm
cli
hlt
end;
end;
procedure halt_and_dont_catch_fire(); [public, alias: 'util_halt_and_dont_catch_fire'];
begin
while true do begin
end;
end;
function inl(port : uint16) : uint32; [public, alias: 'util_inl'];
begin
//serial.sendString('[inl]');
//serial.sendHex(port);
asm
PUSH EAX
PUSH EDX
MOV DX, port
IN EAX, DX
MOV inl, EAX
POP EDX
POP EAX
end;
io_wait;
end;
function inw(port : uint16) : uint16; [public, alias: 'util_inw'];
begin
//serial.sendString('[inw]');
//serial.sendHex(port);
asm
PUSH EAX
PUSH EDX
MOV DX, port
IN AX, DX
MOV inw, AX
POP EDX
POP EAX
end;
io_wait;
end;
function inb(port : uint16) : uint8; [public, alias: 'util_inb'];
begin
//serial.sendString('[inb]');
//serial.sendHex(port);
asm
PUSH EAX
PUSH EDX
MOV DX, port
IN AL, DX
MOV inb, AL
POP EDX
POP EAX
end;
io_wait;
end;
procedure memset(location : uint32; value : uint8; size : uint32);
var
loc : puint8;
i : uint32;
begin
//push_trace('util.memset');
for i:=0 to size-1 do begin
loc:= puint8(location + i);
loc^:= value;
end;
//pop_trace;
end;
procedure memcpy(source : uint32; dest : uint32; size : uint32);
var
src, dst : puint8;
i : uint32;
begin
//push_trace('util.memcpy');
for i:=0 to size-1 do begin
src:= puint8(source + i);
dst:= puint8(dest + i);
dst^:= src^;
end;
//pop_trace;
end;
function getWord(i : uint32; hi : boolean) : uint16;
begin
if hi then begin
getWord:= (i AND $FFFF0000) SHR 16;
end else begin
getWord:= (i AND $0000FFFF);
end;
end;
function getByte(i : uint32; index : uint8) : uint8;
var
mask : uint32;
begin
mask:= ($FF SHL (8*index));
getByte:= (i AND mask) SHR (8*index);
end;
function BCDToUint8(bcd : uint8) : uint8;
begin
BCDToUint8:= ((bcd SHR 4) * 10) + (bcd AND $0F);
end;
procedure resetSystem();
var
good : uint8;
begin
CLI;
good:= $02;
while (good AND $02) > 0 do good:= inb($64);
outb($64, $FE);
halt_and_catch_fire;
end;
function get16bitcounter : uint16;
begin
get16bitcounter:= bios_data_area.Counters.c16;
end;
function get32bitcounter : uint32;
begin
get32bitcounter:= bios_data_area.Counters.c32;
end;
function get64bitcounter : uint64;
begin
get64bitcounter:= bios_data_area.Counters.c64;
end;
function getTSC : uint64;
var
hi, lo : uint32;
begin
asm
PUSH EAX
PUSH EDX
RDTSC
MOV hi, EDX
MOV lo, EAX
POP EDX
POP EAX
end;
getTSC:= (hi SHL 32) OR lo;
end;
function RolDWord(AValue : uint32; Dist : uint8) : uint32;
var
result : uint32;
i : uint8;
begin
result:= AValue;
asm
PUSH EAX
end;
for i:=0 to Dist-1 do begin
asm
MOV EAX, result
ROL EAX, 1
MOV result, EAX
end;
end;
asm
POP EAX
end;
RolDWord:= result;
end;
function RorDWord(AValue : uint32; Dist : uint8) : uint32;
var
result : uint32;
i : uint8;
begin
result:= AValue;
asm
PUSH EAX
end;
for i:=0 to Dist-1 do begin
asm
MOV EAX, result
ROR EAX, 1
MOV result, EAX
end;
end;
asm
POP EAX
end;
RorDWord:= result;
end;
procedure BSOD(fault : pchar; info : pchar);
var
trace : pchar;
i : uint32;
z : uint32;
begin
console.disable_cursor;
console.mouseEnabled(false);
console.forceQuitAll;
if not BSOD_ENABLE then exit;
console.setdefaultattribute(console.combinecolors($FFFF, $F800));
console.clear;
console.writestringln(' ');
console.writestringln(' ');
console.writestring(' ');
console.setdefaultattribute(console.combinecolors($0000, $FFFF));
console.writestring(' ');
console.setdefaultattribute(console.combinecolors($FFFF, $F800));
console.writestringln(' ');
console.writestring(' ');
console.setdefaultattribute(console.combinecolors($0000, $FFFF));
console.writestring(' ASURO DID A WHOOPSIE! :( ');
console.setdefaultattribute(console.combinecolors($FFFF, $F800));
console.writestringln(' ');
console.writestring(' ');
console.setdefaultattribute(console.combinecolors($0000, $FFFF));
console.writestring(' ');
console.setdefaultattribute(console.combinecolors($FFFF, $F800));
console.writestringln(' ');
console.writestringln(' ');
console.writestringln(' ');
console.writestringln(' Asuro encountered an error and your computer is now a teapot.');
console.writestringln(' ');
console.writestringln(' Your data is almost certainly safe.');
console.writestringln(' ');
console.writestringln(' Details of the fault (for those boring enough to read) are as follows: ');
console.writestringln(' ');
console.writestring(' Fault ID: ');
console.writestringln(fault);
console.writestring(' Fault Info: ');
console.writestringln(info);
console.writestringln(' ');
if IntReg <> nil then begin
console.writestringln(' Processor Info: ');
console.writestring(' EBP: '); console.writehex(IntReg^.EBP); console.writestring(' EAX: '); console.writehex(IntReg^.EAX); console.writestring(' EBX: '); console.writehexln(IntReg^.EBX);
console.writestring(' ECX: '); console.writehex(IntReg^.ECX); console.writestring(' EDX: '); console.writehex(IntReg^.EDX); console.writestring(' ESI: '); console.writehexln(IntReg^.ESI);
console.writestring(' EDI: '); console.writehex(IntReg^.EDI); console.writestring(' DS: '); console.writehex(IntReg^.DS); console.writestring(' ES: '); console.writehexln(IntReg^.ES);
console.writestring(' FS: '); console.writehex(IntReg^.FS); console.writestring(' GS: '); console.writehex(IntReg^.GS); console.writestring(' ERROR: '); console.writehexln(IntErr^.Error);
console.writestring(' EIP: '); console.writehex(IntSpec^.EIP); console.writestring(' CS: '); console.writehex(IntSpec^.CS); console.writestring(' EFLAGS: '); console.writehexln(IntSpec^.EFLAGS);
console.writestringln(' ');
end;
console.writestring(' Call Stack: ');
trace:= tracer.get_last_trace;
if trace <> nil then begin
console.writestring('[-0] ');
console.writestringln(trace);
for i:=1 to tracer.get_trace_count-7 do begin
trace:= tracer.get_trace_N(i);
if trace <> nil then begin
console.writestring(' [');
console.writestring('-');
console.writeint(i);
console.writestring('] ');
console.writestringln(trace);
end;
end;
end else begin
console.writestringln('Unknown.');
end;
console.redrawWindows;
halt_and_catch_fire();
end;
end.