FPPS4/sys/kern/systm.pas

501 lines
13 KiB
Plaintext

unit systm;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
kern_mtx;
function copystr(from,_to:pchar;maxlen:ptruint;lencopied:pptruint):Integer;
function copyin(udaddr,kaddr:Pointer;len:ptruint):Integer;
function copyin_nofault(udaddr,kaddr:Pointer;len:ptruint):Integer;
function copyinstr(udaddr,kaddr:Pointer;len:ptruint;lencopied:pptruint):Integer;
function copyout(kaddr,udaddr:Pointer;len:ptruint):Integer;
function copyout_nofault(kaddr,udaddr:Pointer;len:ptruint):Integer;
function fubyte(var base:Byte):Byte;
function fuword32(var base:DWORD):DWORD;
function fuword64(var base:QWORD):QWORD;
function fuword(var base:Pointer):Pointer; external name 'fuword64';
function casuword32(var base:DWORD;oldval,newval:DWORD):DWORD;
function casuword64(var base:QWORD;oldval,newval:QWORD):QWORD;
function suword32(var base:DWORD;word:DWORD):DWORD;
function suword64(var base:QWORD;word:QWORD):QWORD;
function suword(var base:Pointer;word:Pointer):Pointer; external name 'suword64';
function fuptr(var base:Pointer):Pointer;
function fuptr(var base:QWORD):QWORD;
///
function msleep(ident :Pointer;
lock :p_mtx;
priority:Integer;
wmesg :PChar;
timo :Int64):Integer; external;
function tsleep(ident :Pointer;
priority:Integer;
wmesg :PChar;
timo :Int64):Integer; external;
function pause(wmesg:PChar;timo:Int64):Integer; external;
procedure wakeup(ident:Pointer); external;
procedure wakeup_one(ident:Pointer); external;
implementation
uses
errno,
md_systm,
vmparam,
kern_thr;
{
* copystr(from, to, maxlen, int *lencopied) - MP SAFE
* %rdi, %rsi, %rdx, %rcx
}
function copystr(from,_to:pchar;maxlen:ptruint;lencopied:pptruint):Integer; assembler; nostackframe;
label
v1b,
v4f,
v6f,
v7f;
asm
movq %rdx,%r8 { %r8 = maxlen }
xchgq %rdi,%rsi
incq %rdx
cld
v1b:
decq %rdx
jz v4f
lodsb
stosb
orb %al,%al
jnz v1b
{ Success -- 0 byte reached }
decq %rdx
xorl %eax,%eax
jmp v6f
v4f:
{ rdx is zero -- return ENAMETOOLONG }
movq $ENAMETOOLONG,%rax
v6f:
testq %rcx,%rcx
jz v7f
{ set *lencopied and return %rax }
subq %rdx,%r8
movq %r8,(%rcx)
v7f:
//ret
end;
{
* copyin(from_user, to_kernel, len) - MP SAFE
* %rdi, %rsi, %rdx
}
function copyin(udaddr,kaddr:Pointer;len:ptruint):Integer; assembler; nostackframe;
label
copyin_fault,
done_copyin;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle copyin_fault
movqq %gs:teb.thread,%rax
leaq copyin_fault(%rip),%rcx
movqq %rcx,kthread.pcb_onfault(%rax)
testq %rdx,%rdx { anything to do? }
jz done_copyin
{
* make sure address is valid
}
movq %rdi,%rax
addq %rdx,%rax
jc copyin_fault
movq $VM_MAXUSER_ADDRESS,%rcx
cmpq %rcx,%rax
ja copyin_fault
xchgq %rdi,%rsi
movq %rdx,%rcx
movb %cl,%al
shrq $3,%rcx { copy longword-wise }
cld
rep
movsq
movb %al,%cl
andb $7,%cl { copy remaining bytes }
rep
movsb
done_copyin:
xorl %eax,%eax
movq %gs:teb.thread,%rdx
movq %rax,kthread.pcb_onfault(%rdx)
ret
//ALIGN_TEXT
nop; nop; nop; nop;
nop; nop; nop; nop;
copyin_fault:
movq %gs:teb.thread,%rdx
movq $0,kthread.pcb_onfault(%rdx)
movq $EFAULT,%rax
//ret
end;
function copyin_nofault(udaddr,kaddr:Pointer;len:ptruint):Integer;
begin
Result:=md_copyin(udaddr,kaddr,len,nil);
end;
{
* copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
* %rdi, %rsi, %rdx, %rcx
*
* copy a string from from to to, stop when a 0 character is reached.
* return ENAMETOOLONG if string is longer than maxlen, and
* EFAULT on protection violations. If lencopied is non-zero,
* return the actual length in *lencopied.
}
function copyinstr(udaddr,kaddr:Pointer;len:ptruint;lencopied:pptruint):Integer; assembler; nostackframe;
label
cpystrflt,
cpystrflt_x,
v1f,
v2b,
v3f,
v4f;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle cpystrflt
movq %rdx,%r8 { %r8 = maxlen }
movq %rcx,%r9 { %r9 = *len }
xchgq %rdi,%rsi { %rdi = from, %rsi = to }
movq %gs:teb.thread,%rcx
leaq cpystrflt(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS,%rax
{ make sure 'from' is within bounds }
subq %rsi,%rax
jbe cpystrflt
{ restrict maxlen to <= VM_MAXUSER_ADDRESS-from }
cmpq %rdx,%rax
jae v1f
movq %rax,%rdx
movq %rax,%r8
v1f:
incq %rdx
cld
v2b:
decq %rdx
jz v3f
lodsb
stosb
orb %al,%al
jnz v2b
{ Success -- 0 byte reached }
decq %rdx
xorl %eax,%eax
jmp cpystrflt_x
v3f:
{ rdx is zero - return ENAMETOOLONG or EFAULT }
movq $VM_MAXUSER_ADDRESS,%rax
cmpq %rax,%rsi
jae cpystrflt
movq $ENAMETOOLONG,%rax
jmp cpystrflt_x
cpystrflt:
movq $EFAULT,%rax
cpystrflt_x:
{ set *lencopied and return %eax }
movq %gs:teb.thread,%rcx
movq $0,kthread.pcb_onfault(%rcx)
testq %r9,%r9
jz v4f
subq %rdx,%r8
movq %r8,(%r9)
v4f:
//ret
end;
{
* copyout(from_kernel, to_user, len) - MP SAFE
* %rdi, %rsi, %rdx
}
function copyout(kaddr,udaddr:Pointer;len:ptruint):Integer; assembler; nostackframe;
label
copyout_fault,
done_copyout;
asm
cmpq $0x4000,%rsi //rsi <= 0x4000
jle copyout_fault
movqq %gs:teb.thread,%rax
leaq copyout_fault(%rip),%rcx
movqq %rcx,kthread.pcb_onfault(%rax)
testq %rdx,%rdx { anything to do? }
jz done_copyout
{
* First, prevent address wrapping.
}
movq %rsi,%rax
addq %rdx,%rax
jc copyout_fault
movq $VM_MAXUSER_ADDRESS,%rcx
cmpq %rcx,%rax
ja copyout_fault
xchgq %rdi,%rsi
{ bcopy(%rsi, %rdi, %rdx) }
movq %rdx,%rcx
shrq $3,%rcx
cld
rep
movsq
movb %dl,%cl
andb $7,%cl
rep
movsb
done_copyout:
xorl %eax,%eax
movq %gs:teb.thread,%rdx
movq %rax,kthread.pcb_onfault(%rdx)
ret
//ALIGN_TEXT
nop; nop; nop; nop;
nop; nop; nop; nop;
nop; nop;
copyout_fault:
movqq %gs:teb.thread,%rdx
movq $0,kthread.pcb_onfault(%rdx)
movq $EFAULT,%rax
//ret
end;
function copyout_nofault(kaddr,udaddr:Pointer;len:ptruint):Integer;
begin
Result:=md_copyout(kaddr,udaddr,len,nil);
end;
function fusufault:QWORD; assembler; nostackframe;
asm
movq %gs:teb.thread,%rcx
xorl %eax,%eax
movq %rax,kthread.pcb_onfault(%rcx)
decq %rax
//ret
end;
function fubyte(var base:Byte):Byte; assembler; nostackframe;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-1,%rax
cmpq %rax,%rdi
ja fusufault
movzbl (%rdi),%eax
movq $0,kthread.pcb_onfault(%rcx)
//ret
end;
function fuword32(var base:DWORD):DWORD; assembler; nostackframe;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rdi { verify address is valid }
ja fusufault
movl (%rdi),%eax
movq $0,kthread.pcb_onfault(%rcx)
//ret
end;
function fuword64(var base:QWORD):QWORD; assembler; nostackframe; public;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-8,%rax
cmpq %rax,%rdi { verify address is valid }
ja fusufault
movq (%rdi),%rax
movq $0,kthread.pcb_onfault(%rcx)
//ret
end;
{
* casuword32. Compare and set user integer. Returns -1 or the current value.
* dst = %rdi, old = %rsi, new = %rdx
}
function casuword32(var base:DWORD;oldval,newval:DWORD):DWORD; assembler; nostackframe;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rdi { verify address is valid }
ja fusufault
movl %esi,%eax { old }
lock
cmpxchgl %edx,(%rdi) { new = %edx }
{
* The old value is in %eax. If the store succeeded it will be the
* value we expected (old) from before the store, otherwise it will
* be the current value.
}
movq %gs:teb.thread,%rcx
movq $0,kthread.pcb_onfault(%rcx)
//ret
end;
{
* casuword. Compare and set user word. Returns -1 or the current value.
* dst = %rdi, old = %rsi, new = %rdx
}
function casuword64(var base:QWORD;oldval,newval:QWORD):QWORD; assembler; nostackframe;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rdi { verify address is valid }
ja fusufault
movq %rsi,%rax { old }
lock
cmpxchgq %rdx,(%rdi) { new = %rdx }
{
* The old value is in %eax. If the store succeeded it will be the
* value we expected (old) from before the store, otherwise it will
* be the current value.
}
movq %gs:teb.thread,%rcx
movq $0,kthread.pcb_onfault(%rcx)
//ret
end;
{
* Store a 32-bit word to
* user memory. All these functions are MPSAFE.
* addr = %rdi, value = %rsi
}
function suword32(var base:DWORD;word:DWORD):DWORD; assembler; nostackframe;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rdi { verify address validity }
ja fusufault
movl %esi,(%rdi)
xorl %eax,%eax
movq %gs:teb.thread,%rcx
movq %rax,kthread.pcb_onfault(%rcx)
//ret
end;
{
* Store a 64-bit word to
* user memory. All these functions are MPSAFE.
* addr = %rdi, value = %rsi
}
function suword64(var base:QWORD;word:QWORD):QWORD; assembler; nostackframe; public;
asm
cmpq $0x4000,%rdi //rdi <= 0x4000
jle fusufault
movq %gs:teb.thread,%rcx
leaq fusufault(%rip),%rax
movq %rax,kthread.pcb_onfault(%rcx)
movq $VM_MAXUSER_ADDRESS-8,%rax
cmpq %rax,%rdi { verify address validity }
ja fusufault
movq %rsi,(%rdi)
xorl %eax,%eax
movq %gs:teb.thread,%rcx
movq %rax,kthread.pcb_onfault(%rcx)
//ret
end;
function fuptr(var base:Pointer):Pointer;
begin
Result:=nil;
md_copyin(@base,@Result,SizeOf(Pointer),nil);
end;
function fuptr(var base:QWORD):QWORD;
begin
Result:=0;
md_copyin(@base,@Result,SizeOf(QWORD),nil);
end;
end.