When I learned programming, the programmer of the CPU had direct memory access. That is, the Z80, the 8086/8088, 6502, and so on. I don't know of any real use of the 186, but at least the 286 introduced "protected mode", which in reality had no impact on the MS/DOS world, besides some extra memory.

Somewhere down the road, O/S like Windows NT, Linux, and so on, used protected mode, and memory became virtual for the (assembly) programmer.

But where was this step really done? Where became protected mode the norm and real mode something for old people with fond memories?

  • 8
    You seem to be mixing two concepts - virtual addressing, in which the memory addresses seen by a program differ from physical memory addresses (which just requires a MMU), and virtual memory, in which the memory space as seen by a program is not always resident in physical memory (generally, a paged or segmented system). I would not characterize either of these as not 'having direct memory access'. Can you clarify what you're really asking? Is it simply when did systems start using protected mode? Surely as soon as it was available - the benefits are obvious.
    – dave
    Commented Jan 10 at 12:57
  • 5
    Step to whom? To average home users with IBM compatible PCs running home OSes such as MS-DOS/Windows, or to some other users that do not use IBM compatible PCs, but servers or workstations running Unix-alike or other OSes?
    – Justme
    Commented Jan 10 at 13:00
  • 5
    @lvd Don't tell that to hundreds of thousands of 286 running some Unix/Xenix variation. Protected mode was the main reason to use the 286, as real mode performance was achieved at lower cost by using 8086 or 186 CPUs.
    – Raffzahn
    Commented Jan 10 at 14:21
  • 2
    I do not believe this question can produce any serious answer. It neither defines what that 'step' asked for should be nor gives any source for the vague assumptions made. Any answer will be of speculation founded on interpretation of its unlclear defined content.
    – Raffzahn
    Commented Jan 10 at 14:26
  • 4
    And yet, very interesting and serious answers. Let’s say I am grateful for those who are willing to approach a question with positive intentions
    – ABM K
    Commented Jan 10 at 23:52

4 Answers 4


Where became protected mode the norm and real mode something for old people with fond memories?

I think the answer to that question is with the 80386. Protected mode on the 286 had some issues in that segment loads were very slow due to the protection mechanism. You can't just change a segment register to provide greater than 64kb address spaces which is a technique used by a lot of real mode programs because a segment register is no longer an address offset but a pointer into a global or local descriptor table.

Also, famously, you couldn't easily get back to real mode from protected mode which meant you couldn't make BIOS calls, since most BIOS's at the time were only compatible with real mode.

The 286 also didn't support virtual memory or paging. Protected mode is different from virtual memory. Protected mode just says (effectively) "you cannot change your segment registers easily" and hence "you are limited to addresses from the 256kb accessible through your segment registers"*.

Virtual memory is almost orthogonal to protected mode. It provides a means of mapping virtual addresses to real addresses through a page table. But it does also have a form of protection since unprivileged processes couldn't change their own page tables and couldn't access memory except through the page table. This proved a much more popular method of providing memory protection as evidenced by the fact that virtually all modern operating systems start by setting all the segments to cover the entire 32 bit address space and then ignoring them and using paging to provide memory protection.

So, actually protected mode has never been the norm. It's only used because enabling it is a prerequisite to enabling virtual paged memory. If you could do the latter on a 386 without doing the former, protected mode would just be a forgotten footnote to history.

*actually it is a bit more complicated as there were privilege levels which set rules about what segments you could load and what memory you could access.

  • Note that virtual memory doesn't require page tables. Either way you get the "access violation" / "segmentation fault" trap which provides an opportunity to perform the paging. In one case it's "no mapping for this address and/or access denied by flags in page table entry" and in the other it's "offset outside segment extents". In the case of fixed 64k segment sizes it can be even easier, because the application has to explicitly request a segment swap, at which time the OS can perform paging.
    – Ben Voigt
    Commented Jan 10 at 21:45
  • Additionally, it's possible to have multitasking--even preemptive multitasking--between non-hostile applications even without any memory-protection mechanisms whatsoever, if a tolerably fast mass storage device is available, and if enough RAM or remote I/O processing is available to smoothly handle I/O buffering.
    – supercat
    Commented Jan 11 at 17:56
  • @supercat Kind of. In reality, there is no such thing as a non hostile application. All it needs is a bug and an application can start scribbling on memory it doesn't own. This is why multitasking operating systems without memory protection are inherently more fragile than those with.
    – JeremyP
    Commented Jan 14 at 17:16
  • 2
    @JeremyP: Some early time sharing systems had no memory protection. A retired CS professor told me of a student who, back in the days of card-batch processing system, had--without asking permission from anyone--written a program that persistently patched the OS to IIRC adjust task priorities in a way which better fit the actual job loads than the defaults. The student wasn't punished, but was asked to put things "back to normal".
    – supercat
    Commented Jan 14 at 19:51

A major weakness of the 80286 was the fact that most programs were limited to having two general-purpose segment registers loaded at a time. This was adequate if one wanted to copy a range of data from one location to another, but if one wanted to do even something so basic as:

for (int i=0; i<100; i++)
  dest[i] = src1[i] + src2[i];

the only way to perform such an operation efficiently would be to rewrite it as something like:

for (int i=0; i<100; i++) // Only far pointers src1 and dest used in this loop
  dest[i] = src1[i];
for (int i=0; i<100; i++) // Only far pointers src2 and dest used in this loop
  dest[i] += src2[i];

The 80386 changed two things:

  1. It added two additional segment registers, vastly increasing the range of situations where programs that kept different data in different segments could avoid having to switch segments when processing each and every item.

  2. It allowed segments to be 65,536 times as big, meaning that many programs applications could simply use one segment for everything. This ability meant that the extra segment registers end up not really being needed.

If #1 had occurred while going from the 8086 to the 80286, it could have made 80286 protected mode much more useful. As it was, though, using 80286 protected mode efficiently generally required writing code around a pattern which separates memory into a "near" data area which is 64K or less and a "far" data area which may be any size, but is much slower to access except when doing "bulk" transfers to/from the "near" storage, and using real mode with a memory manager would be about the same except (1) there was an intermediate level of data storage for things within the 640K DOS area but outside the "near" segment, which could be accessed much more efficiently than "far" storage, (2) bulk transfers to/from far storage had more overhead (per transaction, not per byte) than in protected mode. For many tasks, using real mode with a memory manager was more efficient than using protected mode for everything would have been.


But where was this step really done? Where became protected mode the norm and real mode something for old people with fond memories?

My understanding is it was a gradual transition, spanning a decade. I would consider the start of the transition for typical PC users to be the release of Windows 3.0 in 1990 and the culmination of the transition to be the release of windows XP in 2001.

Windows 3.0 made use of protected mode to expand the memory available for windows applications. The win16 programming environment had originally been designed to run in real mode, but the way it handled memory management meant that windows programs were generally amenable to running in protected mode without being recompiled.

Specifically windows 3.0 had three modes. "real mode" as the name suggests ran the CPU in real mode, the same as previous versions of windows. "standard mode" used the protected mode features of the 286 to provide access to more memory. "enhanced mode" further used the features of the 386 to support virtual memory and to allow running multiple DOS applications at the same time.

For DOS applications, AFAIK 16 bit protected mode was little used, however 32-bit protected mode was used through "DOS extenders". Most famously DOS/4GW bundled with Watcom C++. Most of the later DOS games used DOS/4GW.

As well as supporting native windows applications in protected mode, windows 3.0 and later offered an interface called DPMI. This interface allowed DOS extenders to cooperate with windows and thus allowed protected mode DOS applications to run under windows.

However, while windows 3.0 used protected mode it did not use it exclusively. The system still had to switch back to real mode to call into DOS and the BIOS. Windows 3.1, released in introduced "32-bit disk access" and "32-bit file access" to reduce the number of times windows would have to switch back to real mode. The ability to switch back down to DOS was kept around for backwards compatibility. In 1993, "win32s" was released, allowing windows 3.1 and windows 3.11 to support 32-bit applications.

Windows 95 moved even more stuff to 32-bit mode, but it's heritage as a DOS based single user operating system was still clearly visible. Windows 95 would try to use 32-bit drivers where possible, but was still able to switch to 16 bit where needed.

Windows NT on the other hand was designed from the ground up as a multiuser operating system and on x86 it always ran in 32-bit protected mode. You had to have 32-bit drivers for your hardware, calling out to DOS was not an option. Linux too was designed from the start as a protected mode operating system running on the 386.

So in the late 1990s, MS had two linages of operating system for the PC. 9x was what most home users and smaller businesses got, NT had proper multi-user support and was more robust, but lacked support for "plug and play" and had relatively poor support for legacy software.

Windows 2000 had been intended to be a unifying release, abandoning the windows 9x series. However in the end only "professional" and "server" editions of windows 2000 were released. Home users were instead treated to a final upgrade to the windows 9x series in the form of windows ME.

Windows XP finally unified the lineup, and deprecated the old DOS-based versions of windows.

  • There was an intermediate step with Windows 3.1, winmem32, which was a 32 bit flat address space, but without the NT like API. Watcom C++ fully supported winmem32 as a memory model, making it popular at the time.
    – rcgldr
    Commented Jan 10 at 23:03

Early versions of OS/2 and SCO Xenix (Unix like system for PC) supported 286. Sometime after the 386 was released, Microsoft switched to Windows NT while IBM continued with later versions of OS/2.

Windows 3.1 dropped support for real mode and only supported 286 or 386 protected modes.

One of the hassles with Windows 286 protected mode was the limit of 64KB non-overlapping chunks. I wrote a program to sort a text file, reading 63KB at at time into 64KB chunks at offset 4 to make room for a byte count prefix (assuming max record size was 1KB-4), and if a record spanned a boundary, I would append the trailing part of the record to the end of the prior chunk. The CR|LF in the remaining records were replaced with byte counts. While doing this, I was creating an array of far pointers to the records in 32KB of local memory, so it was limited to text files with 4095 records or less. Once the array of far pointers was created, the array could be used without segment spanning issues.

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