Page 1 of 1

kernel loading

Posted: Fri Jun 27, 2003 9:57 am
by dazed
Hi,

I`ve currently got a hello world kernel linked with 0x1000 and loaded in memory at the same address.
Now, for a user process to see the kernel address space at 0xC0000000, all that is required would be to map the kernel in the page directory and page table of the process.

The problem now is that since the kernel has been linked with 0x1000 the problem is that there is no way that the process can access of the kernel space through a system call.

The solution to this was given at

http://my.execpc.com/~geezer/osd/mem/index.htm

The other way that this could be done would be to leave everything at 0x1000 set the interrupt handler at
(address +0xC0000000), then on interrupt load ds with a base segment of 0xC0000000.
This I think sould work.

Is there any other way that this could be done without using segmentation at all?

Thanks.

Re:kernel loading

Posted: Fri Jun 27, 2003 2:29 pm
by Tim
The simplest way of handling this would be to link the kernel at C000_0000. Write the startup portion of your kernel in assembly and make it position independent, since it will be running at 0000_1000 yet linked at C000_0000. Enable paging as early as possible.

An alternative is to fiddle with the GDT base address, to make physical 0000_1000 look like virtual C000_0000 even with paging disabled.

Re:kernel loading

Posted: Mon Jun 30, 2003 3:16 pm
by dazed
Hi Tim.

What I`ve done is to
I) boot sector loads first program
II) first program loads kernel at 0x10000,set-up pm paging and maps address 0XC0000000 to 0x10000
then jmp to 0x10000.


Since, I compiler the kernel with 0xC000000 and the first program already sets up the mapping, it seems to work.

Is this what you meant?

Otherwise, I couldn`t work out what you meant by
"Write the startup portion of your kernel in assembly and make it position independent"

Thanks for your help.

Re:kernel loading

Posted: Mon Jun 30, 2003 4:31 pm
by Tim
dazed wrote: II) first program loads kernel at 0x10000,set-up pm paging and maps address 0XC0000000 to 0x10000
then jmp to 0x10000.
Yes, this is what I meant. Although surely if you've got paging set you, you should jump to C000_0000?
Otherwise, I couldn`t work out what you meant by "Write the startup portion of your kernel in assembly and make it position independent"
Well, I'd recommend writing the first part of kernel code in assembly anyway, because you need to set up the stack and zero the .bss as a minimum.

But also, if EIP is not set to the address there the kernel is linked (e.g. you jumped to 0010_0000 but the image was linked to run at C000_0000), you won't be able to access any global variables properly. This is what I mean by position-independent code: code which doesn't access any global data, or jump or call any absolute addresses. (On the x86, it's OK to do normal CALLs and JMPs, because these use the address relative to EIP.)

Re:kernel loading

Posted: Tue Jul 01, 2003 5:11 am
by dazed
Hi Tim.

For the time being, the kernel uses the same page directory and page table as the header program(linked at 0x10000). This includes mapping for the 0x10000 (I`ve mapped 4 mb in the header program).

does the size of the bss always give you the end of the kernel?(ie the bss section is the last section of the binary image).

hum..... I see what you mean with position independent.(I think I do). So if I create a new pg/pt for the kernel that does not include the mapping for 0x10000, referencing an address location hard coded at eg 0x11000 does not work.

Thank you.

Re:kernel loading

Posted: Tue Jul 01, 2003 9:39 am
by Tim
dazed wrote:does the size of the bss always give you the end of the kernel?(ie the bss section is the last section of the binary image).
This depends on where the linker has put everything. To be on the safe side, use a linker script, with a symbol defined at the end of the last section. The address of this symbol will give you the address of the end of the kernel.
hum..... I see what you mean with position independent.(I think I do). So if I create a new pg/pt for the kernel that does not include the mapping for 0x10000, referencing an address location hard coded at eg 0x11000 does not work.
If you've got mappings for 0010_0000 and C000_0000, mapped to the same address, then you can get away without position-independent code. Once the kernel is running you can remove the mapping for 0010_0000 and just use the mappings above C000_0000.

Re:kernel loading

Posted: Mon Jul 07, 2003 8:23 am
by Carnac
The best way is to simply link your app (kernel) at virtual address 0xc0000000, then get the bootstrapper to load it at say 1mb (0x100000), that way, it'll be above the RAM hole, and the BIOS data area (if you want to find information from that for some reason). Then either page map your kernel from virtual address 0xc0000000 during bootstrap, or leave paging disabled, until the kernel itself can initialise it. This allows you to touch all of RAM (without needing to first map it all), in order to do RAM counting, for example, ie, seeing how much memory is available to be put on the heap.

I personally find it more sensible to basically not map all of physically memory up front by the core kernel, and basically allow the VM subsystem to allocate those pages, as well as the page table entries, itself. The core kernel doesn't even really need to know about those mappings, unless a driver instructs it to allocate a piece of physical memory on its behalf, in order to perform DMA, etc. The kernel in this case woulds till refer to the memory manager to handle all the details though.

Re:kernel loading

Posted: Mon Jul 07, 2003 11:08 am
by dazed
Hi Carnac,

If the bootstrap code does not enable paging
I really cannot see how you would jump to the kernel which has been linked with(0xc0000000) and loaded at 0x100000. (without using segmentation in the bootstrap). unless linking with 0xc0000000 or 0x100000 does not have any particular meaning.( in fact how does it change the code?).

Thanks.

Re:kernel loading

Posted: Mon Jul 07, 2003 11:27 am
by bkilgore
Changing the linking address changes certain offsets in the code. For instance, global variables are referenced by absolute addresses, so references to them consist of their offset in the binary plus the linking address.

The trick is to enable paging soon after jumping to your kernel, and making all code until you enable paging position-independent. In other words, only stuff like calls, but no reference to global varialbles unless you're careful.

For example, it is possible to place this at the very beginning of your kernel:

Code: Select all

;Calculate the virtual-to-physical conversion
  call calc_virt_to_phys

calc_virt_to_phys:
  pop esi?????????; ESI=current physical adr (pushed when calling)
  sub esi,calc_virt_to_phys???; subtract virtual adr (for identity mapping)
????????????; now ESI=virt-to-phys (must be used as a reference to data until paging enabled)
Then, you can reference variables using esi as a base, and the variable as an offset (thereby converting from virtual to physical address) like the following:

Code: Select all

mov word [esi + var_name], value
Now you can reference globals if you need to, and then just quickly call the code to enable paging.

Re:kernel loading

Posted: Mon Jul 07, 2003 12:49 pm
by dazed
Thank you.

Re:kernel loading

Posted: Mon Jul 07, 2003 8:28 pm
by Carnac
You need to understand that just because the program has been 'linked' to 0xc0000000 doesn't mean that it can't run elsewhere in memory, for example, 0x100000. It's quite possible to link to 0xc0000000 and run at 0x100000, so long as you don't use fixed addresses.

Doing something like:

startup:
movl $1, %eax
pushl %eax

is quite fine...

startup:
call thatcode

generally isn't, because the address is generally fixed, ie, linked. You would need to convert that address to your load address by doing something like

thatcode - KERNELLOGADDR + KERNELPHYSADDR

That'll 'reloc' your code for you...

Re:kernel loading

Posted: Tue Jul 08, 2003 1:40 am
by Tim
...but on x86, most CALLs and JMPs are also fine, because they use relative addressing.