Laaca

Czech republic, 12.08.2019, 22:19 |
Need help with DPMI function 301h (Developers) |
Hello all!
I need your help with my routine using DPMI function 301h. In my task I want to talk with legacy (non-ACPI) PnP BIOS interface.
I want it to be compilable with TurboPascal-realmode and Freepascal-32bitPM.
The original code is quite bit but I simplified the code to be as small as possible and to use rather assembler that pascal.
In my code I call the PNP-BIOS function 00h - GetNumber_and_size_of_PNP_nodes
(for reference please see specification - relevant pages 26-31)
THIS REALMODE CODE WORKS PERFECT:
(Note: in line "InternalCallPNP($F000,24114,$F000,p1,p2);" just change the magic numbers for numbers you get from scan of your machine - see the 3rd snipet of code)
Program TestPNP;
Procedure InternalCallPNP(seg_entry,offs_entry,ds_seg:word;var param1,param2:word);
var p:pointer;
begin
asm
mov ax,ds_seg
push ax
push $b800 {for simplicity we will not mess with transfer buffers stuff}
push 0 {but we just use some safe realmode address like videobuffer}
push $b800
push 2
push 0
mov ax,offs_entry
mov bx,seg_entry
mov p.word[0],ax
mov p.word[2],bx
call p
pop ax
pop ax
pop ax
pop ax
pop ax
pop ax
end;
param1:=MemW[$B800:0];
param2:=MemW[$B800:2];
end;
var p1,p2:word;
begin
InternalCallPNP($F000,24114,$F000,p1,p2);
writeln('p1: ',p1);
writeln('p2: ',p2);
end.
BUT IN THE CODE BELOW IS THE PROBLEM - this code should be analogical to previous one but works in 32-bit protected mode using Freepascal.
I can not just call the realmode BIOS entrypoint from protected mode so I have to use the emulation via DPMI function 301h. But it does not work at all. In FreeDOS the computer freezes after instruction INT31h and in Windows98 freezes the task.
Program TestPNP;
uses Go32;
Procedure InternalCallPNP(seg_entry,offs_entry,ds_seg:word;var param1,param2:word);
var r:TRealRegs;
begin
FillChar(r,sizeof(TRealRegs),0);
r.cs:=seg_entry;
r.ip:=offs_entry;
asm
mov ax,ds_seg
push ax
push $b800 {for simplicity we will not mess with transfer buffers stuff}
push 0 {but we just use some safe realmode address like videobuffer}
push $b800
push 2
push 0
mov edi,r
mov ebx,0
mov ecx,6
mov eax,301h;
int 31h
pop ax
pop ax
pop ax
pop ax
pop ax
pop ax
end;
param1:=MemW[$B800:0];
param2:=MemW[$B800:2];
end;
var p1,p2:word;
begin
InternalCallPNP($F000,24114,$F000,p1,p2);
writeln('p1: ',p1);
writeln('p2: ',p2);
end.
AND THE LAST PIECE OF CODE - the detection of the PNP BIOS and detection of the entrypoint.
This code works in both Turbopascal and Freepascal. (no problem here)
Function RMString(segm,offs:word;len:byte):string;
var a:longint;
s:string;
begin
s:='';
for a:=0 to len-1 do s:=s+char(Mem[segm:offs+a]);
RMstring:=s;
end;
Function ScanSegment(segm:word;var offs:longint;limit:word;gran:word;const SearchStr:string):boolean;
var l:byte;
begin
l:=Length(SearchStr);
repeat
if RMstring(segm,offs,l)=SearchStr then
begin
ScanSegment:=true;
Exit;
end;
inc(offs,gran);
until offs>limit-gran;
offs:=0;
ScanSegment:=false;
end;
Function Get_PNP_BIOS_Entry_Info(var seg_entry,offs_entry,ds_seg:word):boolean;
var scan_seg:word;
scan_ofs:longint;
begin
scan_seg:=$F000;
scan_ofs:=0;
if not ScanSegment(scan_seg,scan_ofs,$FFFF,16,'$PnP')
then begin
seg_entry:=0;
offs_entry:=0;
ds_seg:=0;
Get_PNP_BIOS_Entry_Info:=false;
end
else begin
ds_seg:=MemW[scan_seg:scan_ofs+27];
offs_entry:=MemW[scan_seg:scan_ofs+13];
seg_entry:=MemW[scan_seg:scan_ofs+15];
Get_PNP_BIOS_Entry_Info:=true;
end;
end;
var s,o,d:word;
begin
if not Get_PNP_BIOS_Entry_Info(s,o,d)
then writeln('No PNP BIOS found!')
else begin
writeln('PNP BIOS found!');
writeln('Entrypoint segment: ',s);
writeln('Entrypoint offset: ',o);
writeln('DS register for routine: ',d);
end;
end. --- DOS-u-akbar! |
RayeR

CZ, 15.08.2019, 03:35
@ Laaca
|
Need help with DPMI function 301h |
Hi,
I don't know FP specific but do you really need to write it in ASM?
DJGPP has DPMI wrapper C functions like
__dpmi_simulate_real_mode_procedure_retf()
http://www.delorie.com/djgpp/doc/libc/libc_275.html
that should do what you want. Maybe you have to take care about saving and restoring some other registers. Here's some info about DPMI 0301h
http://www.delorie.com/djgpp/doc/dpmi/api/310301.html --- DOS gives me freedom to unlimited HW access. |
Laaca

Czech republic, 16.08.2019, 08:09
@ RayeR
|
Need help with DPMI function 301h |
> Hi,
> I don't know FP specific but do you really need to write it in ASM?
> DJGPP has DPMI wrapper C functions like
> __dpmi_simulate_real_mode_procedure_retf()
> http://www.delorie.com/djgpp/doc/libc/libc_275.html
> that should do what you want. Maybe you have to take care about saving and
> restoring some other registers. Here's some info about DPMI 0301h
> http://www.delorie.com/djgpp/doc/dpmi/api/310301.html
No, Freepascal does not have equivalent to this function. For DPMI 300h has, for DPMI 301h not. But even if it would be - other problém is; I don't know how to give the parameters via stack with this DJGPP function. I think it is not possible at all. And this PnP standard uses the communication not via registers but via stack.
In my old other project I use the DPMI 301h function without problems but here is not parameters passing through stack (I use it in my port of Digpak/Midpak sound library). --- DOS-u-akbar! |
Laaca

Czech republic, 16.08.2019, 08:11
@ Laaca
|
Need help with DPMI function 301h |
> > Hi,
> > I don't know FP specific but do you really need to write it in ASM?
> > DJGPP has DPMI wrapper C functions like
> > __dpmi_simulate_real_mode_procedure_retf()
> > http://www.delorie.com/djgpp/doc/libc/libc_275.html
> > that should do what you want. Maybe you have to take care about saving
> and
> > restoring some other registers. Here's some info about DPMI 0301h
> > http://www.delorie.com/djgpp/doc/dpmi/api/310301.html
>
No, Freepascal does not have equivalent to this function. For DPMI 300h
has, for DPMI 301h not. But even if it would be - other problém is; I don't
know how to give the parameters via stack with this DJGPP function. I think
it is not possible at all. And this PnP standard uses the communication not
via registers but via stack.
In my old other project I use the DPMI 301h function without problems but here is not parameters passing through stack (I use it in my port of
Digpak/Midpak sound library).
Rayer, are you able to convert the Freepascal version of code into DJGPP to more people be interrested to analyze the problem? --- DOS-u-akbar! |
marcov
17.08.2019, 23:34
@ Laaca
|
Need help with DPMI function 301h |
> push $b800 {for simplicity we will not mess with transfer buffers stuff}
> push 0 {but we just use some safe realmode address like videobuffer}
> push $b800
> push 2
>
> push 0
Push word (pushw) maybe ? In 32-bit mode the default will be a 32-bit push. |
Japheth

Germany (South), 18.08.2019, 09:56 (edited by Japheth, 18.08.2019, 10:23)
@ Laaca
|
Need help with DPMI function 301h |
> I can not just call the realmode BIOS entrypoint from protected mode so I
> have to use the emulation via DPMI function 301h.
Yes
> FillChar(r,sizeof(TRealRegs),0);
> r.cs:=seg_entry;
> r.ip:=offs_entry;
So far it's ok, real-mode CS:IP and SS:SP are set.
> push $b800
> push 0
> push $b800
> push 2
>
> push 0
In 32-bit protected-mode, when you're pushing a constant value, a 32-bit value is pushed! So the code above pushes 5 DWORDS, not 5 WORDS ( as was your intention, probably ).
Simplest workround: replace "push CONST" by "mov ax,CONST" & "push ax". --- MS-DOS forever! |
Laaca

Czech republic, 18.08.2019, 21:21
@ Japheth
|
Need help with DPMI function 301h |
> In 32-bit protected-mode, when you're pushing a constant value, a 32-bit
> value is pushed! So the code above pushes 5 DWORDS, not 5 WORDS ( as was
> your intention, probably ).
>
> Simplest workround: replace "push CONST" by "mov ax,CONST" & "push ax".
Thank you! Yes, you are right. The only concern I have about it is the feeling that I had it done in this way in the first version of my code before the attempt to maximal simplification.
Well, we will see. I cannot trest it until friday but then I will tell you the result.  --- DOS-u-akbar! |
Japheth

Germany (South), 20.08.2019, 12:34
@ Laaca
|
Need help with DPMI function 301h |
> Well, we will see. I cannot trest it until friday but then I will tell you
> the result. 
If it doesn't work, try to change the "mov ebx,r" line. I don't know the assembler used by FreePascal, so I'm not absolutely sure, but usually you have to use LEA instead of MOV to address a stack variable. --- MS-DOS forever! |
Laaca

Czech republic, 22.08.2019, 17:42
@ Japheth
|
Need help with DPMI function 301h |
> If it doesn't work, try to change the "mov ebx,r" line. I don't know the
> assembler used by FreePascal, so I'm not absolutely sure, but usually you
> have to use LEA instead of MOV to address a stack variable.
YES!
You have got it! The problem in my original code was the "mov ebx,r". When I changed it to "lea ebx,r" everything works perfectly. --- DOS-u-akbar! |
Japheth

Germany (South), 23.08.2019, 09:09
@ Laaca
|
Need help with DPMI function 301h |
> YES!
> You have got it! The problem in my original code was the "mov ebx,r". When
> I changed it to "lea ebx,r" everything works perfectly.
Good. I assume you (and I) meant register EDI instead of EBX.
It's kind of a bug in FreePascal that the assembler doesn't report an error/warning for line "mov edi,r". --- MS-DOS forever! |
marcov
24.08.2019, 15:53
@ Japheth
|
Need help with DPMI function 301h |
> It's kind of a bug in FreePascal that the assembler doesn't report an
> error/warning for line "mov edi,r".
Why? It is valid code. It moves the value of variable r into edi. So if it is a local variable or stack param it translates to
mov edi,dword ptr [bp+xx]
if it is a register param, it translates to a register move etc. I'm not sure if it automatically does RIP relative addressing though. |
Japheth

Germany (South), 24.08.2019, 17:52
@ marcov
|
Need help with DPMI function 301h |
>
> Why? It is valid code. It moves the value of variable r into edi.
Ok, there is no "official" assembler standard, so it's a bit vague here.
For the MASM family of assemblers, the line "mov edi,r" would indeed load the CONTENT of data label "r" into EDI. However, since these assemblers do size checks, they will report an error like "sizes don't match", because variable "r" has a size of 32h bytes.
For the NASM family of assemblers, the line "mov edi,r" usually will load the ADDRESS of data label "r" into EDI. To load the contents, you have to add square brackets: "mov edi,[r]". Since "mov edi,r" CANNOT load the address of a stack variable (because it is register related), nasm-style assemblers should also report an error in this case ( I haven't tried ). --- MS-DOS forever! |
marcov
24.08.2019, 18:18
@ Japheth
|
Need help with DPMI function 301h |
> >
> > Why? It is valid code. It moves the value of variable r into edi.
>
> Ok, there is no "official" assembler standard, so it's a bit vague here.
>
> For the MASM family of assemblers, the line "mov edi,r" would indeed load
> the CONTENT of data label "r" into EDI. However, since these assemblers do
> size checks, they will report an error like "sizes don't match", because
> variable "r" has a size of 32h bytes.
>
> For the NASM family of assemblers, the line "mov edi,r" usually will load
> the ADDRESS of data label "r" into EDI.
Freepascal is originally primary AT&T (GNU AS). Early on the assembler mode was just passing it through to the backend assembler. In the late nineties intel mode was added, mostly based on NASM tables.
But things like this (interaction with Pascal identifiers) is mostly Borland Pascal/Delphi (BASM) style.
This goes for the primary x86/x86_64 targets. The 16-bit x86 is afaik more styled after watcom, and e.g. PowerPC probably more to OS X' proprietary AS |
Rugxulo

Usono, 30.08.2019, 02:43
@ Japheth
|
Need help with DPMI function 301h |
> Ok, there is no "official" assembler standard, so it's a bit vague here.
>
> For the MASM family of assemblers, the line "mov edi,r" would indeed load
> the CONTENT of data label "r" into EDI.
>
> For the NASM family of assemblers, the line "mov edi,r" usually will load
> the ADDRESS of data label "r" into EDI.
I think this is also because of a preference for brevity. That it, it's shorter to not have to specify brackets.
MOV AX,MyVar
... is shorter (to read, easier to type) than ...
MOV AX,[MyVar]
... especially if done hundreds of times. But ...
MOV AX, OFFSET MyLabel
... is more verbose than ...
MOV AX, MyLabel
... which is why some people prefer ...
LEA AX, MyLabel ; (only some few require brackets here)
... which is often translated into a simple "MOV" (to save a single byte per instance). But even that LEA->MOV translation "behind your back" is explicitly avoided in many assemblers, even later versions of MASM (where you were expected to use "opattr" inside a macro instead).
Borland obviously supported both MASM syntax (but barely any v6) in TASM as well as their own "Ideal" mode. Unfortunately, a lot of legacy MASM/TASM code never got translated to NASM or FASM or similar. |