In DPMI, interrupt 0x31 services 0x0000 and 0x0100 are capable of simultaneously allocating multiple protected-mode selectors in a single call. When that happens, both services return only the first allocated selector; the others are obtained by adding a fixed increment (repeatedly if necessary), whose value is obtainable from service 0x0003.

All the DPMI hosts I (somewhat superficially) tried this under — Borland’s, Windows 3.11, DOS/4GW and CWSDPMI — return the value 8 from this service, which means that descriptors are allocated in contiguous blocks (as the three least-significant bits do not index selectors, but determine the privilege level and choose between the GDT and the LDT). In principle though, nothing stops a DPMI host from using a larger multiple of 8.

The section of the DPMI specification describing the 0x0003 call (§8.4) does not explain at all why the DPMI host is allowed to do this or how it might be useful for the host to allocate descriptors non-contiguously. What purpose could this freedom serve? What does it afford implementations? Was there a DPMI host implementation that took advantage of it?

(I would prefer an official document or a statement from someone who worked on or was familiar with the development of the DPMI specification, but failing that, speculation may be enough.)

  • 2
    just speculating: A single-tasking DPMI implementation could unify LDT and GDT into one virtual descriptor table and return 4 as "selector increment". Furthermore, it was a common pattern in mode-agnostic code to leave the selector increment variable, and to use 1000h as increment in real mode. As mode-agnostic code wouldn't directly call DPMI services, this doesn't explain why DPMI itself has this funtion, though. Aug 5 at 12:49
  • 3
    Perhaps it was a transposition of __AHINCR... Aug 5 at 13:03
  • @StephenKitt Chen’s description of __AHINCR seems to imply the value in protected mode is always 8 anyway, so it doesn’t really provide any justification for this call’s existence. Sure, you need to invoke it if you want to implement your own __AHINCR portable to different DPMI hosts. But it might as well have not existed, with the DPMI contract specifying the increment as always 8. And yet it is there. What is it there for? Aug 5 at 19:14
  • 1
    @user3840170 put another way, perhaps adding this to the DPMI spec was hedging bets for the future, with no certainty that it would be useful but with the knowledge that not having something like that would have been a blocker, or at least a significant hurdle, for Windows 3. YAGNI is all very well until you’re stuck because you don’t have it. Aug 5 at 20:59
  • 1
    @Michael yes, I just found it interesting initially to catalog the other places where similar APIs were found. It turns out that DosGetHugeShift did have varying results depending on the version of OS/2, so the API was useful even for protected-mode-only code. Aug 6 at 9:38

I don’t have any insider knowledge on this topic, so this is purely speculation.

I suspect the call exists because there was potential variation in similar mechanisms available at the time, which turned out to be useful at around the same time as the DPMI specification was written (and before the first drafts were published). There’s a decent chance that Ralph Lipe, the original author of the DPMI specification, was aware of memory allocation rules in at least two contemporaneous operating environments, OS/2 and Windows 2.

OS/2 1.x ran in protected mode on 286s and supported allocations larger than 64KiB, in a similar fashion to what ended up in the DPMI specification. This can be seen in the Family API functions DosAllocHuge and DosGetHugeShift; native OS/2 applications also had access to corresponding variables (whose values were constant during any given boot of OS/2), DOSHUGEINCR and DOSHUGESHIFT (see Inside OS/2, section 9.2.2, for details).

Windows 2 didn’t run applications in protected mode, but it did provide a similar “API”, through the __AHINCR and __AHSHIFT variables in the kernel, and compiler writers used that to implement far pointer arithmetic. This famously helped the switch to running applications in protected mode in Windows 3, since correctly-written applications could run as-is in either real or protected mode even if they needed segment arithmetic. (This wasn’t new to Windows 3; OS/2 already allowed writing mode-agnostic programs, using the aforementioned Family API.) See also Why the DOS extender and DPMI were unavailable to DOS programs on 286 standard mode of Windows 3.0.

Significantly in the context of this question, OS/2 1.0 used a shift of 4, not 3 (it interleaved private and shared LDT entries), and OS/2 1.1 used a shift of 5 (it interleaved one private LDT entry for every three shared LDT entries). The Design of OS/2 section explains this in more detail. This would have provided two reasons for allowing a non-constant selector gap in the DPMI specification: anyone familiar with 286 protected mode would have been aware that the minimum gap there is 8, not 16, so a DPMI host could conceivably want to use 8; and varying the gap had already been used, between OS/2 1.0 and 1.1.

(I haven’t checked the value returned by OS/2’s DPMI host in later versions of OS/2. OS/2 2.x and later used a flat memory model, so this might not be significant anyway.)

  • If I recall correctly, Windows 2 did run in protected mode (the /386 version did at least), that’s why the __AHINCR symbol was there (an it’s also the motivation Chen gives for it). Aug 6 at 9:46
  • Windows/386 had a protected-mode kernel, but Windows applications ran in V86 mode on top of it. Aug 6 at 9:50
  • By the way, though: if you’re including references to things like technical manuals for similar APIs of the time, I don’t think it’s pure speculation anymore. This is the kind of informed speculation I’d rather see, if any. Aug 6 at 10:48
  • 1
    Windows/286 ran in real mode. It just added support for the HMA (so 64K extra memory) Aug 6 at 21:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.