18

I know that Virtual 8086 mode was added on the 80386 to make it possible to run old applications in a Protected Mode environment.

The 80286 had a lot of shortcomings, such as not being able to switch back to Real Mode from Protected Mode (except by reset), but its PM environment wasn't that bad by itself. What made it unusable was its incompatibility with the old applications, which expected to be able to do segment arithmetic and other tricks that can be used in Real Mode.

But why wasn't this issue addressed in software at the time? People chose to ditch PM completely until the 80386 came along and instead use RM with dirty hacks to access extended memory (Unreal Mode or switching to PM to access memory and then reset).

Here's a way that I think they could have done it (but I'm not sure it would work in practice). The OS (or DOS extender or whatever) sets up a GDT (and possibly LDTs) which contain the descriptors required by each application (on the 286 you cannot have flat descriptors that cover all memory, because registers are 16-bit). However, all of these descriptors are marked as Not Present in the GDT/LDT except for the time slices in which the applications actually run. Of course, there's no need to create all these descriptors in a single-tasking system like MS-DOS. The only descriptors that are marked Present are the Ring 0 ones (kernel stuff, basically).

When an old 8086 application is run, allocate segments for it as required. If the segments are in extended memory, use LOADALL to set the segment registers to them, since there is no entry in the GDT that can be used. If the application starts resetting segment registers (either by using segment register instructions, far calls or whatever), the CPU will trap and generate a fault, since regardless of what value the segment register takes, it won't be a valid GDT entry. The virtual monitor can then use LOADALL to set the descriptor caches to the new segment (possibly in extended memory), while keeping the value in the visible segment register itself as it was set by the 8086 application.

TLDR: If the program ever reads the segment register, it will get what it expects. If it tries to write to the segment register, the virtual monitor will handle the case by using LOADALL to load segments above 1MB in the descriptor caches while keeping the unrelated values set by the software inside the visible part of the segment registers.

Was this too slow to be practical? Did DOS programs perform so much segment reloading that the LOADALLs would slow the system down to a crawl?

If DOS was extended to run in PM when the 80286 came out, while keeping compatibility with 8086 programs, programmers could have started making a lot of 16-bit PM applications instead of RM ones, which would reduce the overhead of accessing extended memory for all applications, not just applications which used DOS extenders.

16
  • 3
    "Premature optimization is the root of all evil (or at least most of it) in programming"
    – Brian H
    Feb 19, 2022 at 20:35
  • 6
    This isn't an optimization attempt. It's a system design change. The reason why someone would want to do this is to stay away from the ugliness of accessing extended memory in Real Mode. As history tells us, staying inside this chaos allowed for more chaos to come, because more RM got written instead of PM applications. Optimization would mean that you have a working system and you make various tweaks to increase performance.
    – DarkAtom
    Feb 19, 2022 at 20:39
  • 4
    Yes. System software. DOS and Real Mode itself were a mess ever since 1MB became a barrier, until the 386 came with V86 mode. I think everybody agrees on that.
    – DarkAtom
    Feb 19, 2022 at 21:11
  • 7
    First off- It's a good question. Second, don't shoot the messenger. Third, millions of Microsoft customers of the time didn't care about this nearly as much as they cared about "perfect" backwards compatibility for their apps.
    – Brian H
    Feb 19, 2022 at 21:15
  • 7
    "People chose to ditch PM completely until the 80386 came along" - No, they didn't. Windows 3.0 / Windows 3.1 in standard mode make good use of the 286 PM features. Actually, Windows 3.0 abstracted from protected mode in a way, that Windows applications could run unchanged in real mode or protected mode. This feature was removed from Windows 3.1, though, as 8088-class computers were obsolete at the time of Windows 3.1 Feb 19, 2022 at 23:38

3 Answers 3

27

I believe what you are describing was in fact done. Concurrent DOS for the 286 could multitask DOS programs in protected mode. See the Wikipedia article on Multiuser DOS as well as DOS VMs.

The 80286 had a lot of shortcomings, such as not being able to switch back to Real Mode from Protected Mode (except by reset), but its PM environment wasn't that bad by itself. What made it unusable was its incompatibility with the old applications

They weren't old applications. That's the perspective of hindsight. When Intel started to design the 80286, the IBM PC didn't exist yet! The 286 was brought to market in February 1982, only ~6 months after the IBM PC. Intel seems to have intended the 286 to be designed into new systems, using new operating systems, that would run exclusively in protected mode.

Speaking of new operating systems, I'd note that DOS was always a stop-gap measure, quick and ugly. It was to be replaced with something better, and soon. By 1985, IBM and Microsoft had signed the contract to develop OS/2 and DOS went through a long period of stagnation in the mid-late 80s. This is speculation, but it seems the thinking at the time was that everyone was going to switch to OS/2 or UNIX shortly, so why invest a great deal of effort retrofitting multitasking into a dead-end OS ill-suited to it? (Of course, OS/2 got terribly delayed, and Microsoft ended up doing just that anyway, with Windows in 386 mode.)

1
  • 3
    This is exactly how Concurrent DOS worked, and I believe it's also how Xenix 286 ran DOS apps. It only worked on later 286s as the early 286 proceessors were a bugfest.
    – Alan Cox
    Feb 22, 2022 at 21:17
12

As RETRAC writes, this was indeed done.

Companies other than Digital Research also considered similar approaches, but ultimately discarded them. One documented case is IBM with OS/2’s DOS support before version 2.0; this is briefly described in The Design of OS/2. One approach considered to run DOS applications in protected mode was to allocate segment descriptors as needed, using documented interfaces; however, even assuming bug-free silicon, this doesn’t leave room for segments descriptors required by the protected-mode operating system itself. The second approach was similar to yours, using LOADALL, but IBM didn’t pursue this because of the 80286 implementation bugs they ran into. Presumably these were the same as those that delayed the release of Concurrent DOS; the bug described in The Design of OS/2 is that CX is destroyed on general protection faults, meaning that faulting code can’t be restarted correctly.

1

I don't think the engineers at Intel really understood what made real-mode 8086 segmentation so useful: it allowed memory to be allocated in 16-byte chunks, and allowed any group of up to 4096 such chunks to be consolidated and treated as a 64K segment, without needing to have separate descriptors for each one. The fact that the segment register was scaled by a constant factor of 16 wasn't nearly as important as the fact that there was no need to manage memory in a size chunk between an application's individual allocations and the 64K maximum for a segment.

4
  • 3
    "without needing to have separate descriptors for each one". You need to reload segment registers whenever you want to get out of a 64KB segment. That doesn't change in 16-bit PM. Nothing stopped an OS to implement an API such as "allocate X KB of memory, without regards to segment bounds" and then "give me a descriptor at offset Y in this memory chunk". In real mode you would do the same, but reload the segment registers yourself instead of asking the OS to do it.
    – DarkAtom
    Feb 20, 2022 at 11:14
  • 2
    Any contiguous group of 4096 such chunks. Unlike with paging later.
    – ilkkachu
    Feb 20, 2022 at 14:16
  • @ilkkachu well, to be fair, you can't divide memory into chunks of less than 4KB using paging =))
    – DarkAtom
    Feb 20, 2022 at 16:33
  • 4
    @DarkAtom: In real mode, MOV ES,CX would take the same amount of time to execute as MOV BX,AX. In protected mode, it would require fetching a segment descriptor, which took IIRC four times as long. As for what changes, if code requests multiple small allocations and gets given allocations which get divided amount two different segments, and then releases most of the small allocations those and wants to allocate bigger chunks, there won't be any way for it to consolidate space at the end of one segment and the start of the next.
    – supercat
    Feb 20, 2022 at 19:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .