Search code examples
clinux

How does each process's private address space gets mapped to physical address?


I'm new to Linux and virtual memory address, just a question on how does each process's private address space gets maped to physical address.

Let's say we have two program A and B, so when both running concurrently, process A and process B have their own private address. and let's say the picture below is the private address of process A:

enter image description here

We can see that process A's code segment starts at 0x400000, my question is:

what about process B's code segment's address? I think the virtual memory plays a role here, so process B's code segment's address will be mapped to somewhere else, and it could be mapped to anywhere in physical memory (between 0x400000 and 248-1), is my understanding correct?


Solution

  • That is the job of the MMU (Memory Management Unit), or one of the jobs. Process A's 0x400000 might be physical address 0x12300000 and Process B's 0x400000 might be physical address 0x32100000 for example. Basically when process A is running there is a mmu table for that core it is running on that replaces 0x004xxxxx with 0x123xxxxx for example in a simplified way. It is a direct address bit replacement, the size of the space can vary both one mmu may have multiple block sizes as well as one architectures mmu chips mmu may vary from another. It could be a case of 0x0040 becomes 0x1230 and 0x0041 becomes 0x1231 and so on.

    It can also be that 0x0040 becomes 0x1111 and 0x0041 becomes 0x2123 and 0x0042 becomes 0x1312. For each block size in the mmu you can have a different address replacement from virtual to physical. Likewise for each block in the mmu you can have different protection and other features. For code the processor may have a read only feature, it should have at least a basic cache enable/disable feature as code you want to cache but some data areas you may not. And then address spaces that you want to trap the process from accessing so marking the rest of the address space as invalid.

    Assume for understanding purposes there is one size of block and some table (this table might live at physical address 0x40010000)

    virtual     physical
    ...
    0x00400000  0x1230000
    0x00410000  0x1231000
    0x00420000  0x1232000
    ...
    

    for process A and this table was created by the operating system at some physical address.

    If/when that core switches to process B, then ideally a single register re-directs the mmu to some other physical address for the table (this physical table might live at 0x40020000)

    ...
    0x00400000 0x32100000
    0x00410000 0x32110000
    0x00420000 0x32120000
    ...
    

    As an example.

    So you can link every program for the same address space, but physically they are in separate memory that doesn't interfere with each other.

    And if process A and process B are in different cores and/or behind different MMUs then they would still have their own mmu table in front of them but could concurrently run.

    Now I don't know the x86 implementation and expect that over the years different chips had different mmus, but, some architecture designs the mmu is per core so one process per core at a time one mmu table for that core at a time. If the mmu is further down and there are multiple cores per mmu then there is going to be some sort of process ID such that the access still lands on a unique set of entries per process.

    MMUs these days make this virtual to physical mapping happen, they cover caching or not, and protection of address spaces to keep the application from wandering about memory. But if you think about it this also greatly helps memory allocation and management. Let's say for example in my made up table above the mmu actually does operate on 64K byte sections. if I want to allocate 256Kbytes of data, the operating system doesn't need to find a linear 256Kbytes, It only needs to find four 64Kbyte chunks, anywhere. It doesn't need to try to move memory around like the way old days or copy it somewhere and put it back before whoever owned that memory before wanted to access it etc.

    0x00500000 0x11210000
    0x00510000 0x31230000
    0x00520000 0x12120000
    0x00530000 0x43210000
    

    To the process that looks like 256K of linear memory, but in reality it is smaller chunks nowhere near each other.