C:\1990S\WINDOWSN.TXT
1993
Windows NT: An Address Needed an Owner
Windows NT 3.1 put a familiar Windows environment over a protected operating system whose memory boundaries were part of the design.
An application has made a mistake. Somewhere in its calculations, a pointer now identifies the wrong place in memory. The useful question is how much damage that mistake can do.
Perhaps it corrupts its own invoice. Perhaps it overwrites another program’s work. Perhaps it reaches data the operating system needs to keep everything running. These are substantially different outcomes for the person waiting to print the invoice.
Windows NT’s interesting promise was an operating system with boundaries that applications couldn’t simply wish away. A familiar window on the screen concealed a different arrangement of responsibility underneath it. The system would decide which memory a program could access, which resources it could open, and when its threads would run.
The screen wasn’t the most revealing place to look. An address was.
A new system with an established interface
Microsoft announced Windows NT and Windows NT Advanced Server 3.1 at Windows World on May 24, 1993. NT 3.1 shipped on July 27. Those are different milestones; a product announcement doesn’t install an operating system on anyone’s computer.12
Dave Cutler joined Microsoft in October 1988, with colleagues from Digital Equipment Corporation following him. The team’s substantial design effort preceded coding in April 1989. Microsoft’s later account describes a project that changed hardware targets and moved its principal application interface from an expanded OS/2 API to Win32. Cutler was central, and the shipping product was a team achievement.2
The engineering problem extended beyond making a clean new kernel. Programs already existed, customers had bought them, and their expectations didn’t disappear because the designers had a better idea. Compatibility was part of the job. So was keeping the new system’s internal rules coherent.
That combination makes NT more interesting than a story about replacing old code with new code. An application interface describes what a program can ask for. The implementation beneath that interface determines how the request happens and which protections survive it. Preserving recognizable requests can coexist with changing the machinery that answers them.
Helen Custer’s contemporary Inside Windows NT describes a kernel-mode executive beneath protected user-mode subsystems. The Win32 subsystem provided the graphical interface in this 1993 architecture; it belongs above the privilege boundary, unlike diagrams of later NT versions. Other environments included POSIX, OS/2, DOS and 16-bit Windows support, with compatibility limits rather than universal interchangeability.3
Original explanatory diagram, 2026. Selected roles in the 1993 architecture, not a complete component chart or historical screenshot. The Win32 graphical subsystem is shown in user mode.
The distinction matters when evaluating a claim about reliability. A boundary can contain some mistakes without making the entire computer incapable of failure. Kernel code and drivers remain powerful participants. Protection is an arrangement of privileges, not a warranty that every instruction was written correctly.
The same number, two different places
Here is an invented teaching model. It illustrates address translation and access checks, rather than reproducing NT’s page-table format or claiming to execute an NT binary.
Two processes are running: an invoice editor, A, and an image viewer, B. A process is the environment containing a running program’s resources; its threads perform the execution. Both programs happen to use the virtual address 0x1234.
A virtual address is a number interpreted through the current process’s mapping. A physical address identifies a location in the memory hardware. Confusing those roles would be like treating a room number as sufficient directions without knowing which building you’re in.
Our model divides memory into pages of 4,096 bytes. This chosen teaching size is 0x1000 in hexadecimal. Hexadecimal uses sixteen digits, so its notation makes the division particularly visible:
virtual address 0x1234
page number 0x1
offset 0x234
The offset is 564 bytes into the page. It tells us where inside a mapped block to look, without telling us which physical block holds it.
We give A a mapping from virtual page 1 to the physical block starting at 0x9000. B’s virtual page 1 instead maps to the block starting at 0xD000.
| Process | Virtual address | Physical block base | Offset | Resulting physical address |
|---|---|---|---|---|
| Invoice editor A | 0x1234 | 0x9000 | 0x234 | 0x9234 |
| Image viewer B | 0x1234 | 0xD000 | 0x234 | 0xD234 |
The arithmetic is just addition after the mapping lookup. The significant operation is choosing the lookup table.
If A writes the value 17 to its address, the model stores it at 0x9234. If B writes 29 to the same numerical virtual address, the model stores it at 0xD234. Reading those addresses back gives A 17 and B 29. Neither program needs to negotiate a unique numerical pointer with the other.
Original teaching diagram, 2026. Invented page mappings and values from the worked example; not an NT diagnostic trace.
This is a useful freedom for application developers. A program can reason about its own addresses while the operating system manages placement. Moving another program’s physical storage needn’t force a developer to redesign the invoice editor’s data structures.
It is also a useful restriction. Suppose A decides to write directly to 0xD234, hoping to reach B’s image. That number is still interpreted in A’s virtual address space. In our model A has no mapping for virtual page 0xD, so the request fails. Knowing the physical address printed in this article doesn’t grant a process access to it.
The failure isn’t evidence that the computer couldn’t find its memory. It means the requested access wasn’t permitted by the process’s current arrangement.
Protection needs more than a lookup
A mapping can also carry permissions. Give A a second page, virtual page 2, backed by a block at 0xB000, and mark it readable but not writable. A read at 0x2234 succeeds. A write at that address is rejected even though a physical destination exists.
There are two separate questions: does the address have a valid mapping, and does that mapping allow this operation? Our small checker asks both. It doesn’t attempt to implement hardware exceptions, the NT memory manager or recovery after a fault.
This helps explain the distinction between a controlled failure and silent corruption. If the program reaches an unavailable address, rejecting the operation preserves the boundary. The application may still lose work or terminate. A protection mechanism doesn’t repair the calculation that produced the bad pointer.
There is an equally important limitation within a process. Suppose A’s incorrect pointer lands in another writable page belonging to A. The mapping and permissions may both be valid. The computer has no general knowledge that the programmer intended to update an invoice total instead of some unrelated object.
Memory protection divides authority between processes and privilege levels. It doesn’t supply the missing meaning of every write. Application correctness remains a separate obligation, inconveniently resistant to being delegated entirely to the operating system.
Custer describes NT’s 32-bit virtual space as 4 GB per process, divided into 2 GB for program storage and 2 GB for system storage. That address range isn’t a promise of installed RAM. Hardware-assisted translation and paging let the system manage the relationship between virtual addresses, resident memory and disk-backed contents.3
Our deliberately tiny model keeps all of its physical bytes resident. It illustrates ownership and permissions without pretending that a four-entry dictionary captures allocation, page faults, backing stores or performance.
Sharing is an explicit arrangement
Isolation would be awkward if programs could never cooperate. An editor might pass an image to a printing component, or several programs might need access to a common data region. The useful principle is controlled sharing.
Extend our example with a physical block beginning at 0xF000. Map it into A at virtual page 3 and into B at virtual page 5. Both mappings allow reading and writing.
Now A’s address 0x3234 and B’s address 0x5234 identify the same physical byte, 0xF234. A writes 41; B reads 41. Different virtual addresses can deliberately refer to the same storage, just as identical virtual addresses can deliberately refer to different storage.
This second case is worth keeping beside the first. Otherwise, isolation sounds like a rule that prohibits cooperation. The mapping defines the relationship. Sharing is something the system establishes, with permissions, rather than an accidental consequence of two programs choosing similar numbers.
Sharing also introduces a new problem: coordination. If A changes several related values while B reads them, B might see an intermediate state. Permission to access a region doesn’t establish the order in which cooperating threads use it. Locks, messages or other synchronization arrangements have another job to do.
The result is a more precise vocabulary for reliability. Address translation chooses the storage. Permissions regulate access. Synchronization regulates cooperation. None of these automatically proves that an invoice total is correct.
Portability has a boundary too
NT’s hardware abstraction layer separated platform details such as interrupt controllers and I/O interfaces from much of the executive. Processor-dependent code also remained in the kernel and memory manager.3
That arrangement makes portability a tractable engineering task. If a hypothetical machine delivers device interrupts differently, the operating system can concentrate that difference behind a defined interface instead of distributing special cases throughout unrelated services.
It doesn’t turn an x86 application’s instructions into another processor’s native instructions. Separating operating-system code from hardware details and executing an existing application binary are different problems. A portability diagram should never quietly promise a universal translator at the bottom.
I find that distinction characteristic of NT’s broader achievement. The system made several relationships explicit: application requests and implementation, virtual addresses and physical storage, ordinary execution and privileged work. Each boundary gave the engineers a place to state what was allowed and a place to concentrate necessary exceptions.
The invoice editor could still calculate the wrong number. The more useful achievement was giving its mistake an address space of its own.
Footnotes
-
Microsoft, The History of Microsoft — 1993, May 24 entry: announcement of Windows NT and Windows NT Advanced Server 3.1. ↩
-
Microsoft, The engineer’s engineer, retrospective with NT team interviews. Used for Cutler’s arrival, development chronology, changing targets and July 27, 1993 shipping date; later hardware and promotional firsts aren’t projected into the launch. ↩ ↩2
-
Helen Custer, Inside Windows NT, Microsoft Press, 1993, printed pp. 20–30 and 35–36; chapter 6’s virtual-address discussion also inspected. The original worked model is explanatory, not a transcription of NT internals. ↩ ↩2 ↩3