Unix V6 kernel memory layout
For the PDP-11/40-type 'limited subset' memory management (the /40 is the only model supported by the stock V6, but it is relatively easy to get it running on the PDP-11/34 and the PDP-11/23, which also only support the same limited subset), the memory management hardware provides only a single 16-bit address space.
The organization of the address space in kernel mode is very similar to that of a Unix process: the object code is in the low part of the kernel's address space, with initialized data above it, and the so-called BSS (un-initialized data) above that.
This exactly matches the layout of all this in actual physical main memory; the operating system is in the lowest physical memory, with the code at the bottom, and kernel data above that. Any physical memory above the OS is available for use by user processes.
There are 8 segments available with memory management enabled; the first 6 are used to hold the kernel's instructions and data, as described above. There are two other specialized areas of memory as well; the 7th segment is used to gain access to the swappable per-process data of each process (including its kernel stack); the 8th is set up to allow access to the UNIBUS's so-called 'I/O Page', which holds peripheral and CPU registers.
Note that the allocation of 6 segments to the kernel's code and data provides a hard limit on the size of the kernel, including the number of disk buffers, etc. The stock V6 does not check to make sure that a system build respects this limit; it is perfectly possible to build images that take more than 6 segments (48KB) to hold them, which will fail in bizarre and un-predictable ways.
Split I-D layout
The more powerful models of the PDP-11 (the PDP-11/45 and PDP-11/70) provide two independent 16-bit address spaces for code and data, for both the kernel, and for user processes. The way these are allocated to actual physical main memory for the OS are non-obvious.
All the kernel data (both initialized and un-initialized), along with a small amount of code, is placed in low physical memory. The advantage of doing this is that the physical address of any kernel data is the same as its virtual address, so when setting up a peripheral to do DMA, no address translation is necessary.
(The small amount of code in low memory includes code which runs while booting, before memory management is enabled, and also interrupt vectors, which the PDP-11 hardware requires to be in low kernel data memory.)
This has implications for the layout of the code and data in the system image (in the file which contains it), in the kernel address space, and for the loading and initialization of the system.
First, the Unix linker is not prepared to produce output files in which the data is below the code (in file terms), which is what would be needed to simply load the file produced by the linker into main memory, and have things wind up at the correct physical locations.
Rather than complicate the bootstrap (which, in V6, is a single-stage which has to fit into a single disk block) to perform this transformation, a separate program, 'sysfix', post-processes the linker's output to produce a file where the initialized data is below the code; it also moves the code's absolute address up, so that it starts at the start of the second page of the instruction space.
This is because of that small amount of code in low memory; instruction address space segment 0 is used to contain this (once memory management is enabled), so that it will appear in the address space at the same place after memory management is enabled as before (so that this code, which is what is running when memory management is turned on, will appear in the same place during that); this means that the system's actual code must start in segment 1.
The file does not contain the BSS, though, so after the system image is loaded into main memory by the bootstrap, as part of the OS's initialization the code must be moved up in real memory, to make room for the BSS.