Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to the board
Thread view  Mix view  Order
Laaca

Homepage

Czech republic,
16.02.2023, 00:02
 

PSP manipulation from DPMI programs (Developers)

I am trying to debug my test program which should create a new environment variable and then call the child process with normal Exec call.

I have no problems to do it in real mode:
1) Get my PSP (INT 21h/62h)
2) from PSP:2Ch get the segment address of the buffer with environment
3) Copy it to new buffer, modify it and place the PSP:2Ch to my new buffer.

OK.
But when I try to follow this scheme in DPMI (Freepascal) I am not able to get it to work.
I thought that oroginal PSP:2Ch is a segment somewhere to low DOS memory and my new buffer bust be also in the DOS memory.
But after some googling I found this article:
http://www.delorie.com/djgpp/doc/dpmi/ch4.1.html

And mainly this part is confusing to me:
The environment pointer in the client program's PSP is automatically converted to a selector during the mode switch. If the client wishes to free the memory occupied by the environment, it should do so before entering protected mode and zero the word at PSP:2CH (segment address of the environment>. The client may change the environment point in the PSP after entering protected mode but it must restore it to the selector created by the DPMI host before terminating. The client should not modify or free the PSP or environment descriptors supplied by the DPMI host.

So this means that the PSP:2Ch does not point to common DOS memory pool but to some own selector?
Why?
And if I want to create a new environment variable I have to do all the boring stuff with allocating DPMI selector, set its base, limit and so on?

---
DOS-u-akbar!

Japheth

Homepage

Germany (South),
16.02.2023, 05:25

@ Laaca

PSP manipulation from DPMI programs

> And if I want to create a new environment variable I have to do all the
> boring stuff with allocating DPMI selector, set its base, limit and so on?

Not necessarily. I guess you could just call int 31h, ax=100h to get both a selector and a compatible DOS memory block.

---
MS-DOS forever!

tkchia

Homepage

16.02.2023, 11:18
(edited by tkchia, 16.02.2023, 11:32)

@ Laaca

PSP manipulation from DPMI programs

Hello Laaca,

> I have no problems to do it in real mode:
> 1) Get my PSP (INT 21h/62h)
> 2) from PSP:2Ch get the segment address of the buffer with environment
> 3) Copy it to new buffer, modify it and place the PSP:2Ch to my new

??? You do not need to modify your parent's PSP:0x2c to get your child process to use a different environment.

In real/V86 mode, the parameter block that you pass to int 0x21, ax = 0x4b00 will directly specify the environment block you want to pass to the child process:
Format of EXEC parameter block for AL=00h,01h,04h:
Offset  Size    Description     (Table 01590)
 00h    WORD    segment of environment to copy for child process (copy caller's
                  environment if 0000h)
 02h    DWORD   pointer to command tail to be copied into child's PSP
 06h    DWORD   pointer to first FCB to be copied into child's PSP
 0Ah    DWORD   pointer to second FCB to be copied into child's PSP
 0Eh    DWORD   (AL=01h) will hold subprogram's initial SS:SP on return
 12h    DWORD   (AL=01h) will hold entry point (CS:IP) on return
SeeAlso: #01591,#01592


In DPMI mode, it seems that different DOS extenders may accept different kinds of parameter blocks for ax = 0x4b00. But most likely they will also offer a way to directly specify what environment variables you want the child to use.

You probably need to look up the documentation — or the source code — of FreePascal's DOS extender (go32?) to see what it does; then work out what to do from there.

(Alternatively, use DPMI's int 0x31, ax = 0x300 ("Simulate Real Mode Interrupt") to do the call. This should work under all DPMI hosts, but is troublesome to set up.)

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

tkchia

Homepage

16.02.2023, 11:26

@ Laaca

PSP manipulation from DPMI programs

Hello Laaca,

> And mainly this part is confusing to me:
> The environment pointer in the client program's PSP is automatically converted to a selector during the mode switch.

Also: this part is not really that confusing, at least not to me.

It just means that the value in PSP:0x2c is a segment selector value which you can directly use in protected mode, not a real/V86 mode paragraph value.

Since your program is already running in protected mode anyway, there should not be any difficulty in copying bytes from a protected mode segment:offset address (vs. copying from a real/V86 mode segment:offset address).

E.g. 0x123:0 means you can read straight away from 0x123:0 in protected mode, rather than having to convert 0x123 to a linear address 0x00001230 and then mapping virtual memory for it etc.

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

tkchia

Homepage

16.02.2023, 17:14

@ Laaca

PSP manipulation from DPMI programs

Hello Laaca,

By the way... depending on what Free Pascal's DOS extender does, you might be able to build the child process's new environment variable block in extended memory (without having to purposely place it into base memory (!)). The key thing will be to check how int 0x21, ax = 0x4b00 is handled.

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

Laaca

Homepage

Czech republic,
16.02.2023, 19:46

@ tkchia

PSP manipulation from DPMI programs

Well, I don't know. It seems to me that "int 0x21, ax = 0x4b00" is maybe overkill. Modification of the parent's PSP (which will be inherited to child) seems to be easier for me. For now I solve it using a program parameters (like "CHILD.EXE param1 param2"). It works but it is very ugly. So I am looking for some better solution. The newly created environment variable seems to be quite elegant.

---
DOS-u-akbar!

tom

Homepage

Germany (West),
16.02.2023, 20:16

@ Laaca

PSP manipulation from DPMI programs

> For now I solve it using a program
> parameters (like "CHILD.EXE param1 param2"). It works but it is very ugly.
> So I am looking for some better solution. The newly created environment
> variable seems to be quite elegant.

wow. You solved your problems - without giving any details.

and wasted everybody else time.

Please just go away.

Laaca

Homepage

Czech republic,
16.02.2023, 20:48

@ tom

PSP manipulation from DPMI programs

> > For now I solve it using a program
> > parameters (like "CHILD.EXE param1 param2"). It works but it is very
> ugly.
> > So I am looking for some better solution. The newly created environment
> > variable seems to be quite elegant.
>
> wow. You solved your problems - without giving any details.
>
> and wasted everybody else time.
>
> Please just go away.

WTF?

---
DOS-u-akbar!

tkchia

Homepage

16.02.2023, 21:23
(edited by tkchia, 16.02.2023, 21:51)

@ Laaca

PSP manipulation from DPMI programs

Hello Laaca,

> Well, I don't know. It seems to me that "int 0x21, ax = 0x4b00" is maybe
> overkill. Modification of the parent's PSP (which will be inherited to
> child) seems to be easier for me. For now I solve it using a program

I am quite sure that Free Pascal's Exec() procedure, at the end of the day, invokes int 0x21, ax = 0x4b00 or something similar, and passes an explicit environment segment to the function. Because that is how the underlying MS-DOS system spawns child processes.

I think, rather than try to mess with the parent PSP data structures, a better way is to ask the Free Pascal maintainers whether there is a procedure that is like Exec() but allows you to add/replace environment variables for the child process — or if they intend to add such a procedure.

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

tkchia

Homepage

16.02.2023, 21:28

@ Laaca

PSP manipulation from DPMI programs

Hello Laaca,

By the way, the Exec() implementation for Free Pascal's go32v2 target is apparently here. Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

tkchia

Homepage

16.02.2023, 21:35

@ Laaca

PSP manipulation from DPMI programs

(Also by the way, I am surprised that this whole thing is even a problem at all in Pascal land. Classical C compilers that target MS-DOS have (mostly) included functions named _spawnve, _spawnvpe, _spawnle etc. which allow a programmer to directly specify the child process's environment variables, without having to jump through silly hoops.)

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

Rugxulo

Homepage

Usono,
17.02.2023, 08:35

@ tkchia

PSP manipulation from DPMI programs

> (Also by the way, I am surprised that this whole thing is even a problem at
> all in Pascal land. Classical C compilers that target MS-DOS have (mostly)
> included functions named _spawnve, _spawnvpe,
> _spawnle etc. which allow a programmer to directly specify the
> child process's environment variables, without having to jump through silly
> hoops.)

FPC's baseunix unit apparently has the FPexecve function.

Laaca

Homepage

Czech republic,
17.02.2023, 08:56

@ tkchia

PSP manipulation from DPMI programs

I see! I understood why you think that I should reimplement the Exec function.
Under Turbopascal the Exec copies the environment for child from _actual_ PSP/environment.
So in our case we do not have to change the Exec (int 21h/4b00h) implementation because it is enough to change PSP.
But it is not sure whether Freepascal also copies evironment from current PSP.
So you advice to write own Exec (int 21h/4b00h)

I looked to the FP/Exec sources and it is clear that it behaves differently.
It takes PSP/environment not from actual state but from time of the program start. So if I change the PSP/environment it will not have any influence to Freepascal's Exec. The FP/Exec creates the child's environemnt using the EnvStr(i:byte) function. So we have to look how the EnvStr works. The answer is that it extracts the environment variables from buffer ENVP.
The ENVP buffer is defined in the SYSTEM.PP:
  envp:PPchar;public name 'operatingsystem_parameter_envp';

So we see that ENVP points to internal structure 'operatingsystem_parameter_envp'. I don't know when and when is this structire created (maybe even in the realmode before the protected mode is entered)

But the important thing is that the ENVP pointer can be redirected to own buffer.
If we do it we change the behaviour of the EnvStr function and also the Exec function. :hungry:

---
DOS-u-akbar!

tkchia

Homepage

17.02.2023, 11:07
(edited by tkchia, 17.02.2023, 13:54)

@ Laaca

PSP manipulation from DPMI programs

Hello Laaca,

> I see! I understood why you think that I should reimplement the Exec
> function.
> Under Turbopascal the Exec copies the environment for child from _actual_
> PSP/environment.
> So in our case we do not have to change the Exec (int 21h/4b00h)
> implementation because it is enough to change PSP.

You are (still) overthinking this (in my opinion). What I would propose is to implement a procedure that is sort of like Exec() but allows you to explicitly say what environment variables you want inside the child process, e.g.

procedure ExecWithEnv(
  const path: PathStr;
  const comline: ComStr;
  const childenv: Array [1..$7fff] of String[255]
);


(OK, childenv should really be a variable-length array. But I am not sure how to specify those in Free Pascal. And anyway you get the basic idea.)

Currently Exec() sets the child process's environment from the parent process:

{ copy environment }
  for i:=1 to envcount do
    paste_to_dos(envstr(i),false,false);


But it does not have to do that! You can get it to read environment variables from a different place altogether, e.g.

{ set child environment }
  for i:=1 to $7fff do
    if childenv[i] <> '' then
      paste_to_dos(childenv[i], false, false);


Then wham, the child will get its environment from the childenv[] array instead. This is basically how things are done when coding in C.

(You will need make sure that childenv[] does not contain multiple settings for the same environment variable.)

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

tkchia

Homepage

17.02.2023, 11:21

@ Rugxulo

PSP manipulation from DPMI programs

Hello Rugxulo,

> FPC's baseunix unit apparently has the
> FPexecve
> function.

I am curious to know whether this is supported on the go32v2 target. And, whether there is a corresponding spawnve function or similar (which creates a child process rather than replacing the calling process).

Thank you!

---
https://gitlab.com/tkchia · https://codeberg.org/tkchia · 😴 "MOV AX,0D500H+CMOS_REG_D+NMI"

marcov

17.02.2023, 16:00

@ tkchia

PSP manipulation from DPMI programs

> I am curious to know whether this is supported on the go32v2 target. And,
> whether there is a corresponding spawnve function or similar
> (which creates a child process rather than replacing the calling process).

Most OSes use the more modern unit Process that also supports piping, but I suspect that doesn't work for Dos.

In general Posix abstractions are not used by FPC for targets here it is not the default interface (dos,windows,OS/2, AmigaOS etc), so baseunix is mostly *nixy targets only, as the name implies. (Linux,FreeBSD, OS X, but also e.g. BeOS/Haiku)

marcov

17.02.2023, 16:02

@ Laaca

PSP manipulation from DPMI programs

> So we see that ENVP points to internal structure
> 'operatingsystem_parameter_envp'. I don't know when and when is this
> structire created (maybe even in the realmode before the protected mode is
> entered)

Afaik in the asm startup code before the main program executes. That already is protected mode. All realmode stuff is handled by the extender.

Laaca

Homepage

Czech republic,
18.02.2023, 00:52

@ tkchia

PSP manipulation from DPMI programs

Uff, I got it to work.
I had some difficulties with it because I thought that ENVP is just a pointer to buffer where are all the environment (zero-terminated) strings together.
But in the fact ENVP is in the fact not a pointer to one buffer but pointer to array of multiple buffers. (It behaves like a dynamic array)

---
DOS-u-akbar!

Back to the board
Thread view  Mix view  Order
22049 Postings in 2034 Threads, 396 registered users, 76 users online (0 registered, 76 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum