Mail Archives: djgpp/2024/04/12/09:37:56
> Date: Thu, 21 Mar 2024 18:49:23 +0100
> From: Pali <pali AT pali DOT im>
> Cc: Charles Sandmann <cwsdpmi AT earthlink DOT net>, dj AT delorie DOT com,
> sezeroz AT gmail DOT com, djgpp AT delorie DOT com
>
> On Thursday 21 March 2024 08:31:16 Eli Zaretskii wrote:
> > > Hello, I observed strange issue that __djgpp_nearptr_enable() function
> > > when running in NTVDM on Windows XP, on failure let segment limit in
> > > some undefined/intermediate state.
> > >
> > > Test case:
> > >
> > > #include <stdio.h>
> > > #include <dpmi.h>
> > > #include <go32.h>
> > > #include <sys/nearptr.h>
> > > #include <sys/exceptn.h>
> > >
> > > int main() {
> > > unsigned long addr;
> > > if (__dpmi_get_segment_base_address(_my_ds(), &addr) == 0)
> > > printf("OLD BASE: 0x%lx\n", addr);
> > > printf("OLD LIMIT: 0x%lx\n", __dpmi_get_segment_limit(_my_ds()));
> > > printf("CALLING __djgpp_nearptr_enable()\n");
> > > if (__djgpp_nearptr_enable())
> > > printf("SUCCESS\n");
> > > else
> > > printf("FAILED\n");
> > > if (__dpmi_get_segment_base_address(_my_ds(), &addr) == 0)
> > > printf("NEW BASE: 0x%lx\n", addr);
> > > printf("NEW LIMIT: 0x%lx\n", __dpmi_get_segment_limit(_my_ds()));
> > > return 0;
> > > }
> > >
> > > It prints:
> > >
> > > OLD BASE: 0x29e0000
> > > OLD LIMIT: 0x9ffff
> > > CALLING __djgpp_nearptr_enable()
> > > FAILED
> > > NEW BASE: 0x29e0000
> > > NEW LIMIT: 0x7d60ffff
> > >
> > > I know that Windows NT kernel does not allow userspace to create a
> > > segment with access to kernel memory space (above 0x7fff0000 limit).
> > > So failure from the __djgpp_nearptr_enable() call in NTVDM is expected.
> > > But I was not expecting that DJGPP in some cases may let segment limit
> > > in some intermediate state.
> > >
> > > What about following DJGPP change? I think it can improve failure
> > > behavior of __djgpp_nearptr_enable() when 4 GB DS limit is not allowed.
> > >
> > > --- src/libc/pc_hw/nearptr/nearptr.c
> > > +++ src/libc/pc_hw/nearptr/nearptr.c
> > > @@ -14,7 +14,10 @@ int __djgpp_nearptr_enable(void)
> > > {
> > > if(!__dpmi_set_segment_limit(_my_ds(), 0xffffffffU)) {
> > > if(__dpmi_get_segment_limit(_my_ds()) != 0xffffffffU)
> > > + {
> > > + __dpmi_set_segment_limit(_my_ds(), __djgpp_selector_limit | 0xfff);
> > > return 0; /* We set it but DPMI ignored/truncated it */
> > > + }
> > > __dpmi_set_segment_limit(__djgpp_ds_alias, 0xffffffffU);
> > > __dpmi_set_segment_limit(_my_cs(), 0xffffffffU);
> > > _crt0_startup_flags |= _CRT0_FLAG_NEARPTR;
> >
> > What are the implications of this change, in plain English, in
> > particular for DPMI hosts other than NTVDM?
>
> __djgpp_nearptr_enable() first tries to change DS limit to 4GB. If it
> fails then function returns error back to the client. If it success then
> it checks if DS limit is really set to 4GB. If the DS limit is not 4GB
> then function returns error back to the client (return 0; in above
> snipped).
>
> My change above does following: If DS limit is not 4GB then it is reset
> back to the previous value (used before trying to change it to 4GB) and
> after that returns error back to the client (return 0;).
>
> > (It would be best to
> > actually test this with at least the popular hosts, including CWSDPMI
> > and perhaps also versions of Windows newer than XP that still support
> > DPMI in a reasonable enough manner that allows running |DJGPP
> > programs.)
>
> This change does not affect CWSDPMI, because CWSDPMI supports setting DS
> limit to 4GB and hence this code path is not executed.
>
> Also it does not affect any other DPMI host which return failure "on
> failure" and success "on success".
>
> Normally DPMI host should return error if it reject request for changing
> DS limit. But NTVDM is somehow special there, it neither reject request,
> nor accept it. Instead it changes DS limit to the value which is below
> the linear address 0x7fff0000; and returns success to the client. This
> is a reason why DJGPP here has that check if DS limit was really set to
> 4GB.
>
> My change improve the situation here, independently of the failure
> reason (either __dpmi_set_segment_limit() failed or DPMI host returned
> success but not set limit to 4GB), the previous DS limit is not
> modified when function fails.
>
> So if application calls __djgpp_nearptr_enable(), it can ensure that on
> success the limit is 4GB and on failure the limit is not changed at all.
>
> > I'm CC'ing Charles, in the hope that he is available and can comment
> > on this.
> >
> > Btw, the DJGPP FAQ explicitly says that __djgpp_nearptr_enable fails
> > on Windows NT family (i.e. with NTVDM). So strictly speaking, a
> > program that calls __djgpp_nearptr_enable in that case is shooting
> > itself in the foot...
>
> The NTVDM behavior is well documented and it is known that it does not
> allow to access linear memory above 0x7fff0000. And application does
> not know if is running under NTVDM or other DPMI host.
OK, I've now installed this.
- Raw text -