Posts: 25
Joined: Mon Jul 23, 2012 6:57 pm

Virtual memory and linking

Tue Jul 31, 2012 2:04 pm


I have some, mostly theoretical issues when setting up my virtual memory system. What I want is a single binary (the kernel) to be loaded into continuous physical memory starting at 0x00008000. Only a very small part of the code that is responsible for setting up an initial page table and activating the MMU should be linked to run in this address space. The rest of the code should live somewhere in the top half of the virtual memory, leaving room for user space processes at the bottom.

Is this possible or do I need to rethink it? Another possibility is of course a two step process where I first set up the virtual memory and then load the main kernel from the SD card, but I would really like to avoid that...

User avatar
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Virtual memory and linking

Tue Jul 31, 2012 3:51 pm

you have to get yourself some infos on OS Design.
is a good place to start.

Linux, Windows, MacOSx, all compile their binaries (programms) to 0x0. so if you put your kernel at 0x0800, you have to write your own compiler/linker tools.
Most 32 bit OS tend to use a 2:2 approach (2gig user, 2gig system, so that all user calls to system will end up at an adress bigger 0x8000 0000. this makes it easier (and faster) for system calls. Negative effect: you program can only use 2gig adress space. OSX tends to use 4:4 allocation, but this brings the look aside buffer into big trouble, cause every user <-> system call you need to refresh the whole virtual adress mapping.

So you should first read the link above and think about your proposal.

in my OS design all is flat. i dont use virtual adress space. thus i have the problem to relocate the binary files when loading them into ram. :-( but every concept has its pros and cons.

Posts: 25
Joined: Mon Jul 23, 2012 6:57 pm

Re: Virtual memory and linking

Tue Jul 31, 2012 5:08 pm

Thanks for the link, I will check it out.

Maybe I was a bit unclear about the placement of the kernel. I don't it placed at virtual address 0x8000 and it doesn't really matter where its placed in physical memory as long as I can boot into it and set up an initial page table (identity mapping). My problem is more related to how I can instruct the linker to make parts of the code to be executed in the upper part of the address space, while still being loaded into the lower part together with the other code.

Sorry for the messy explanation, I will try to summarize my intended program flow:

* The whole binary gets loaded into physical address 0x8000 with MMU turned off. (Just like any other bare metal program)
* A small assembly routine sets up a temporary page table with an identity mapping to itself and a virtual-to-physical mapping for the remaining part of the kernel, e.g. 0xA0000000->[main kernel entry point]
* Turn on MMU and jump to 0xA0000000.

This is where I expect strange things to happen if the program is linked using absoute addresses starting from 0x8000...

I hope this makes at least some sense. Any ideas?

Posts: 7
Joined: Mon Feb 20, 2012 9:50 pm

Re: Virtual memory and linking

Tue Jul 31, 2012 7:52 pm

Well, it makes perfect sense to me.

I've been playing around with similar setup on both x86 and ARM (qemu-system-arm, haven't had time to try it on actual RasPi). All you need is slightly more sophisticated linker script. Something like this (you may notice that I prefer 3:1 userspace/kernel split):

Code: Select all

ENTRY (_start)
load_start = 0x8000;
virt_start = 0xC0000000;
    . = load_start;
    .lowtext :
    . = . + virt_start;
    .text : AT(code_start - virt_start) 
        code_start = .;
    /* other higher half sections goes here */
You write all the code meant to run linked at 0x8000 in separate sections .lowtext, the rest goes into regular .text. When linked together, there will be 2 sections, continuous by physical addresses, but "higher-half" .text will start at 0xC0000000 + 0x8000 + whatever the size of .lowtext is. Having it this way, instead of forcing .text to start at "round" address (0xC0000000 in this case) makes it much, much easier to set up the initial page tables.

As long as you do not do function calls between these 2 sections (except for that one special jump to higher-half), you'll be fine.

And setting up initial page table needs not to be pure assembly. You can use C for it as well, using GCC attributes __section__ to compile functions into .lowtext section.

Posts: 25
Joined: Mon Jul 23, 2012 6:57 pm

Re: Virtual memory and linking

Tue Jul 31, 2012 8:51 pm

Thank you Velko, that was exactly what I was looking for! I will try it out tomorrow. Too many beers for any decent coding now I'm afraid. :)

Posts: 948
Joined: Sat May 26, 2012 5:32 pm

Re: Virtual memory and linking

Wed Aug 01, 2012 1:27 am the extest example starts by coming up bare metal and sets up a minimal mmu table and enables the mmu. I matched real and virtual but just as easy to make the virtual somewhere else. get the ARM ARM and ARM TRM for the processor core.

Posts: 25
Joined: Mon Jul 23, 2012 6:57 pm

Re: Virtual memory and linking

Fri Aug 03, 2012 11:42 pm

It works! :D My kernel is now running in the upper parts of virtual memory. I'm currently using a 3:1 split between user and kernel space, but I will probably change that to 1:1 since there seems to be a nice hardware support for that kind of split (see section 6.12.1 of the ARM TRM).

The linker script provided by Velko sort of worked. I had to remove the "AT()" command to stop the linker from spitting out a 1GB+ binary..

Return to “Bare metal, Assembly language”