Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to index page
Thread view  Board view
Laaca

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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

Homepage

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.

Back to index page
Thread view  Board view
22049 Postings in 2034 Threads, 396 registered users, 245 users online (1 registered, 244 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum