My x86_64 kernel is loaded into the higher half, at 0xFFFFFFFF80000000. Before paging is set up and the jump to the higher half and long mode is made, I'm subtracting 0xFFFFFFFF80000000 from my addresses to get the lower half physical address. So far so good.
I would, however, like to call some 32-bit C code from assembly while we're still in the lower half (kernel starts at 1MB) to initialize paging, load the gdt. This is presents a problem because said code is linked into the higher half of the kernel which results in an error. I tried to solve this by using GCC's section attribute to relocate the static variables and functions to a section in the lower half (1). Linking now succeeds, but the machine just triple faults and Bochs reports this error:
Code:
bx_dbg_read_linear: physical memory read error (phy=0x000080101170, lin=0x0000000080101170)
This happens if I just:
Code:
call paging_init
Which makes sense. So I tried this:
Code:
lea paging_init, %eax
call *%eax
Check the contents of eax again and now they correspond to the address of the function and the machine doesn't triple fault... But the function is simply not called! What?
My ld script looks like this:
Code:
VM_ADDR = 0xFFFFFFFF80000000;
SECTIONS
{
. = 0x100000;
.mboot ALIGN(4096) : {
*(.mboot)
. = ALIGN(4096);
}
.init ALIGN(4096) : {
*(.init)
*(.gdt)
}
. += VM_ADDR;
.text ALIGN(4096) : AT(ADDR(.text) - VM_ADDR) {
*(.text)
}
.data ALIGN(4096) : AT(ADDR(.data) - VM_ADDR) {
*(.data)
*(.rodata)
}
.bss ALIGN(4096) : AT(ADDR(.bss) - VM_ADDR) {
*(COMMON)
*(.bss)
}
/DISCARD/ : {
*(.eh_frame)
*(.comment)
}
}
The .init section contains .text compiled for i386 and .gdt is for 32-bit .bss data.
Moving the section is done by prefixing this to functions:
Code:
__attribute__ ((section(".init")))
Maybe what I'm trying to do is just impossible (it shouldn't be) and I should just separate the binaries into a 32-bit loader and the 64-bit kernel. I would love to hear your thoughts on this and perhaps even a solution.
(1) I can move the functions and variables to another section but I haven't found a way to give debugging information a new section, for now I'm just omitting 32-bit debug info using -g0. If you have a solution for this issue as well, that'd be awesome!
P.S. I don't like how my tabs (and tabs are 8 columns, mind you) are displayed as a mere 3 spaces on this forum.
EDIT: I've decided to get rid of the C code and just implement it in assembly. This works for me, though it'd still be nice to know how to tackle this problem in the future if (read when) it comes up again...