Page 1 of 1

Kernel Boots but no GRUB Information (higher-half)

Posted: Sun Sep 29, 2013 12:27 pm
by RageD
Hi Everyone,

So I have begun implementing a higher-half kernel and can successfully boot into it. I boot into a routine which first enables paging and directly maps the first 4MB of code and stack into memory so then I can proceed with with my "kernel_init()" C method which will in turn initialize a proper memory manager and setup more robust paging.

That said, I am having issues actually getting to the point legitimately. When I boot into my kernel, grub starts at the correct place, but my eax register == 0 (before I execute anything). I am not exactly sure why. So everything works until my kernel_init() method checks for the correct magic number and then, obviously, it breaks down.

I should note that it seems directly related to the fact that my .text section begins above 0xc0010000. When I map this directly into the lower 1MB, I find no problems with the eax register. Let me know if you need more information, but I have shown the relevant sections of my kernel dump as well as the linker script.

Code: Select all

SECTIONS
{
  . =  0x00100000;

  .lowermem :
  {
    *(.lowermem)
  }

  . += 0xc0000000; /* +3GB -- higher-half skipping mbh */

  .text : AT(ADDR(.text) - 0xC0000000)
  {
    *(.text)
  }

Code: Select all

00100000 <.lowermem>:
  100000: 02 b0 ad 1b 03 00     add    0x31bad(%eax),%dh
  100006: 00 00                 add    %al,(%eax)
  100008: fb                    sti    
  100009: 4f                    dec    %edi 
  10000a: 52                    push   %edx 
  10000b: e4                    .byte 0xe4 

Disassembly of section .text:

c010000c <_boot>:
c010000c: bc 00 b0 90 c0        mov    $0xc090b000,%esp
c0100011: 81 ec 00 00 00 c0     sub    $0xc0000000,%esp
c0100017: 89 e5                 mov    %esp,%ebp
c0100019: 50                    push   %eax 
c010001a: 8d 0d 78 01 10 c0     lea    0xc0100178,%ecx
c0100020: 81 e9 00 00 00 c0     sub    $0xc0000000,%ecx
c0100026: ff d1                 call   *%ecx
c0100028: 58                    pop    %eax 
c0100029: 8d 0d 31 00 10 c0     lea    0xc0100031,%ecx
c010002f: ff e1                 jmp    *%ecx
.lowermem should be my header for grub and _boot is the working entry point. Notice that I do need to trick the entry point into loading at phys memory. My actual entry point is "boot" (no underscore) defined as follows:

Code: Select all

.globl boot
.set boot, (_boot - 0xc0000000)
Anyone have any ideas about this? Thanks.

-RageD

EDIT: I should be clearer: I can execute code and access relevant portions of the stack at address 0xc0000000. I have manually setup the relevant page directory and page table entries to do this and it works properly. The problem is that the state of the machine is not what I expect when grub hands off execution to my code.

Re: Kernel Boots but no GRUB Information (higher-half)

Posted: Sun Sep 29, 2013 12:34 pm
by Combuster
The error you make is that you link all of your code to run at 3GB, which is not where it is actually located until you enable paging with the right settings because you explicitly tell the linker to load it at 1M.

So you will need to add some dedicated code that sets up the page tables for the higherhalf, which is to be linked to be at 1M with the same load and execution address (like the multiboot header). Working examples for this are on the wiki.

Re: Kernel Boots but no GRUB Information (higher-half)

Posted: Sun Sep 29, 2013 1:09 pm
by RageD
Sorry, but the page tables are working properly, I believe; I can execute code and access my stack at 0xc000000.

My problem is that at the start of execution eax = 0. But according to the multiboot spec, the state of the machine after grub has finished loading is eax = magicno and ebx = multiboot_header.

Why would where my code executes interfere with grub modifying registers since these are not in memory (and grub bootloader should always be <1M anyway, right?)?

-RageD

Re: Kernel Boots but no GRUB Information (higher-half)

Posted: Mon Sep 30, 2013 12:21 am
by Combuster
Well, obviously your setup is not doing what it should, otherwise the value passed at _boot (prove it, so you know grub isn't doing anything wrong!) would end up at kernel_init, and the same goes for the stack being where you said it is (prove it - especially because the disassembly disagrees!), and that kernel_init being executed at the location you say it is (prove it!).

OSDev is not a place for guesswork.

Re: Kernel Boots but no GRUB Information (higher-half)

Posted: Mon Sep 30, 2013 2:50 pm
by RageD
I am not guessing-- I have a breakpoint set at _boot and the status of eax = 0. Notice that _boot and boot point to the same code. I simply link the whole kernel >3GB to keep my debugging symbols for when I jump into the higher half; I used my linker script to keep this in lower memory unless I didn't do what I think I did-- which is entirely possible, but then would confuse me as to how my code ran at all. That said, my exact code (with the exception of fixing 0xc0000000 offsets) works fine (i.e. status of eax = 0x2bad002 at boot) when linking everything lower. Here is an example (with a little more disassembly) of a working version:

Code: Select all

00100000 <boot-0xc>:
  100000: 02 b0 ad 1b 03 00     add    0x31bad(%eax),%dh
  100006: 00 00                 add    %al,(%eax)
  100008: fb                    sti    
  100009: 4f                    dec    %edi 
  10000a: 52                    push   %edx 
  10000b: e4 bc                 in     $0xbc,%al

0010000c <boot>:
  10000c: bc 00 b0 90 00        mov    $0x90b000,%esp
  100011: 89 e5                 mov    %esp,%ebp
  100013: 50                    push   %eax 
  100014: 8d 0d 6c 01 10 00     lea    0x10016c,%ecx
  10001a: ff d1                 call   *%ecx
  10001c: 58                    pop    %eax 
  10001d: 8d 0d 25 00 10 c0     lea    0xc0100025,%ecx
  100023: ff e1                 jmp    *%ecx

00100025 <boot_higherhalf>:
  100025: bc 00 b0 90 00        mov    $0xc090b000,%esp
  10002a: 89 e5                 mov    %esp,%ebp
  10002c: fa                    cli    
  10002d: 53                    push   %ebx 
  10002e: 50                    push   %eax 
  10002f: e8 a4 01 00 00        call   1001d8 <kernel_init>
  100034: 83 c4 08              add    $0x8,%esp
  100037: 85 c0                 test   %eax,%eax
  100039: 75 06                 jne    100041 <end>
  10003b: fb                    sti    
  10003c: e8 f8 01 00 00        call   100239 <kernel_main>
The only difference is the address. Do you have any insight into what may be causing this issue that eax would be wrong? In my other example (everything linked high) according to gdb I began my execution at 0x10000c (remember that I began executing at _boot - 0xc0000000) and it would step through the code properly and bring me into the higher half with my debug symbols.

If you know of another way to keep my debug symbols in the higher half, I have no other reason to link the whole kernel >3GB, but would still appreciate any advice on the original error if you have any ideas simply out of curiosity.

-RageD

EDIT: Here is what I mean by the linker script (sorry, should have included this earlier)

Code: Select all

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
...
  1 .text         00001127  c010000c  0010000c  0000100c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
...
As you can see, the real memory address is VMA - 0xc0000000

Re: Kernel Boots but no GRUB Information (higher-half)

Posted: Mon Sep 30, 2013 9:15 pm
by RageD
Thank you for the help, but I have solved the problem by linking the kernel directly to the first 1MB (0x00100000). I don't know exactly what I was thinking, but I forgot about gdb's "add-symbol-file" capability (as I noted in my original post, this is what I tried at first and changed it). To keep the debug symbols in the higher half, I simply add the following line to my .gdbinit file:

Code: Select all

add-symbol-file bin/kernel.bin 0xc0000000
All works as expected now.

-RageD