Memory space on modern PCs

PsychoZA

Newcomer
I was wondering how the memory space is defined in modern computers. I'm studying Electronic Engineering and I understand how a microcontroller or simple CPU works, but I don't know how more complex CPU's read/write to RAM. The reason I ask this is that I was wondering if its possible for a CPU to jump to a location outside of the system memory (DRAM) to get the next instruction. I.e. could a program make the CPU fetch the next instruction from DRAM on a PCI-e card? Or do the memory controllers allow the system memory to be expanded beyond the DRAM slots?

Thanks.
(I've been hovering around here for years and I know there are some really well informed people about so, hello.)
 
The simple answer to your question is yes. The complex answer is yes it can, but normally it can't due to the PCI address space not being mapped into virtual address space by the OS kernel. In modern PCs the physical address space is split as follows

0 - 3GB is the first 3 GB of actual memory
3GB - 4GB is address space used by PCI devices
4GB and above is the rest of the physical memory

If the 3GB to 4GB range is mapped into virtual address space then it will be possible to execute from PCI provided the pages have execute enabled on them (if the CPU supports NX). It will be very very very slow, but none the less possible.
 
Ok. I'll expand my answer. ;)

Electronically, you need some way to map your adress bus to the bus of the right chip (chip select, generally). You can do that in two ways: use a separate bus to select the required device, or use the upper part of the adress to select it.

The first seems like the simplest, from an electrotechnical point of view. But not from a programming POV. Especially, because it would be very hard to select added devices, or devices that increase in size.

What all programmers really want, is a flat adress space. Which means: you can map devices wherever you feel like.

Say, you have some RAM. You have to map that somewhere. But, if you think it will never be more than 32KB on a controller, and you map something else right behind, it becomes quite hard to expand that memory size. Bankswitching and all that. Which requires you to use a general I/O port to select it, and all the additional circuitry that goes with that.

So, you really want a memory map, that consists of a list of pointers and sizes. If you want to read or write the ram, you look up the right pointer, which is simply a memory location that tells you where it starts. And you look at the next memory location to see how big it is.

If you want to access any device, you first have to map it by making an entry in your memory map index. Which is a table. And when you have done that, you can access it.


Of course, that requires something like a microcontroller that translates the memory accesses into the right chip select. That's what is called a memory controller or manager.

But, if you have such a memory controller, why stop there? Because, if you use multitasking and scheduling, there is a lot of adress space claimed by programs that is hardly used. Like a program that only activates when it receives an interrupt, for example. We call all active programs processes.

And when you make a memory map, you might want to shuffle things around a bit, when it becomes cluttered. Otherwise it breaks down after some time, with all those devices and processes demanding memory space.

The easiest way to solve that, is by using virtual memory. That is simply paging (bankswitching), but it is performed by the memory controller. The running processes don't have a clue.

You simply define the total adress space as something rediculously large, and you have the memory controller try and keep only the active parts in memory all the time. That is virtual memory.

Some parts of memory (read only, input devices as well as programs) can simply be discarded when they're not used anymore. As long as you can map and load them on demand. And other inactive parts of the memory can be swapped to disk.

To be able to do that efficiently, most processors use pages, ranging from 512 bytes to 64KB. The most commonly used page size is 4KB.

That gives a memory map that is divided into 4KB pages. And there is a very important table, the page table, that records which page goes where, and where it resides at the moment. All this is managed by the memory controller.



So, if you want to do something with a PCI device, you first have to map it into the memory space. You need to find a space that is large enough, consisting of 4KB pages. After that, you might need a driver to access it. That's like an extension to the memory manager. Like a program it can run to actually access the device. Because there is no need for a physical 1-on-1 mapping of the device through a chip select and an adress bus when you have virtual memory.

And then you can read and write to that device like it occupies a set region of memory.


To make it a bit more complicated ( :) ), if you want multitasking, you want each process to think it has such a flat memory space. That requires another layer of page tables, one for each process.



So, why is this actually an improvement?

First, because the processes don't need to know all the details. You can write them without knowing exactly how the system it's going to run on looks like.

Second, because it makes it easy to swap, add and remove stuff. Which you need if you don't want to reboot after each change.


The most important rule to remember is, that you should always look up the start of the device you want to access immediately before you do so. And add the offset to that.

Because that's cumbersome, error prone and takes a lot of extra cycles, most operating systems map devices only once for each process at startup, unless the process asks for a change. So all the translation is done by the memory controller. Although you still have to ask where it starts and how big it is, before the first access.


To go back to the start:

You want a separate microcontroller as memory manager, that keeps track of all those tables and does the translation. Start with only one. And when you want to activate a device, you ask the memory manager and supply him with the program he needs to run to access the device. In return, you get a pointer to the entry in the page table, that tells you where it starts and how big it is.


For the most important caveat: page tables can grow very big, and you need to be able to unload them to disk as well. So, you need a table that keeps track of the virtual memory used by all the page tables as well!

That's why a double page table miss (the page table, as well as the index aren't in memory) are reboot errors.


Feel free to ask any more questions, or go into discussion with us, any way you like.

;)
 
Excellent. I'll slowly digest your posts and check out those wiki entries when I get back from varsity. I'm sure I'll be back with questions.
 
Back
Top