Going crazy with my higher half kernel initialization.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Sourcer
Member
Member
Posts: 58
Joined: Fri Jun 17, 2016 11:29 pm
Freenode IRC: WalterPinkman

Going crazy with my higher half kernel initialization.

Post by Sourcer »

I'm trying to map my kernel to virtual higher half memory.

My linker script is:

Code: Select all

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)

KERNEL_VIRTUAL_OFFSET = 0xC0000000;

SECTIONS
{
    . = 1M;
    kernel_start = .;

    start_init = .;
   .init ALIGN(4K) :
                          { *(.multiboot);
                            *(.init);
                            *(.tables);
                          }
    end_init = .;

    init_size = end_init - start_init ;

    . += KERNEL_VIRTUAL_OFFSET;

    kernel_high_half_start = .;
    /****** KERNEL *******/
   .text ALIGN(4K) :  AT(ADDR(.text) - KERNEL_VIRTUAL_OFFSET)
                         {*(.text) }
   .data ALIGN(4K) :  AT(ADDR(.data) - KERNEL_VIRTUAL_OFFSET)
                         { *(.data) }
   .bss  ALIGN(4K) :  AT(ADDR(.bss) - KERNEL_VIRTUAL_OFFSET)
                         { *(.bss)  }
    /****** KERNEL *******/
    kernel_high_half_end = .;

    kernel_end = . - KERNEL_VIRTUAL_OFFSET;
}


As you can see in the linker script, i've tackled the whole virtual/physical linker relocation issues with special sections
for initializations only.

I'm using GRUB as my bootloader, my entry point is in the
.init
section:

Code: Select all

bits 32
section .multiboot
;grub bootloader header
        align 4
        dd 0x1BADB002            ;magic
        dd 0x00                  ;flags
        dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero

global start
extern kmain          
extern paging_init

section .init

start:
  cli          ;block interrupts
  mov esp, init_stack
  call paging_init
  ; Now high half kernel is mapped to the page directory
  mov esp, stack_space   ;set stack pointer
  push ebx ; grub boot info
  call kmain

loop:
  hlt          ;halt the CPU
  jmp loop

resb 4096; 4KB small stack for my init section.
init_stack:

section .bss
resb 8192 ;8KB for stack
stack_space:


Printing a character to the screen using VGA works before calling

Code: Select all

paging_init
, but after

Code: Select all

paging_init
is called, the function never returns, and my kernel goes crazy.

Here are my identitiy maps of the lower 1M memory and my kernel memory:

Code: Select all

typedef int page_table_t;
typedef int page_pointer_t;

page_table_t kernel_page_directory[PAGE_DIR_SIZE]
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables")));

page_pointer_t kernel_page_tables[PAGE_TABLE_SIZE]
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables")));

page_pointer_t identity_page_table[PAGE_TABLE_SIZE]
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables")));

/* Identity map the low 1M
 * In early boot stage.
 */
static void __attribute__((section(".init"))) map_identity()
{
   //memset(0, identity_page_table, PAGE_TABLE_SIZE);

   unsigned int current_page = 0;
   for(int i = 0; i < BIOS_PAGE_TABLE_ENTRIES; i++, current_page += PAGE_SIZE)
      identity_page_table[i] = (current_page) | 0x3;

   current_page = 0x100000;
   for(int i = BIOS_PAGE_TABLE_ENTRIES + 1;
       i < (BIOS_PAGE_TABLE_ENTRIES + 1) + (INIT_SIZE / PAGE_SIZE);
       i++, current_page += PAGE_SIZE)
   {
      identity_page_table[i] = (current_page) | 0x3;
   }

   kernel_page_directory[0] = ((unsigned long)(identity_page_table)) | 0x3;
}

/* Map the kernel memory to its page directory,
 * **in early boot stage.
 * We don't need to map the init section, we don't need it anymore.
 */
__attribute__((section(".init"))) static void map_kernel_memory()
{
   //Identity map the init section
   //Start at 1MB i.e. its page aligned.
   unsigned int start_index = (INIT_SIZE / PAGE_SIZE) - 1;
   unsigned long current_page = KERNEL_VIRTUAL_START - KERNEL_VIRTUAL_OFFSET;

   for(int i = start_index;
       i < (start_index + (KERNEL_VIRTUAL_SIZE / PAGE_SIZE));
       i++, current_page += PAGE_SIZE)
   {
      kernel_page_tables[i] = current_page | 0x3;
   }

   kernel_page_directory[KERNEL_DIRECTORY_ENTRY] = (unsigned long)kernel_page_tables | 0x3;
}

__attribute__((section(".init"))) static inline void enable_paging()
{
   asm("mov eax, kernel_page_directory");

   asm("mov cr3, eax");
   asm("mov eax, cr0");

   //Turn on paging bit
   asm("or eax, 0x80000000");
   asm("mov cr0, eax");
}

__attribute__((section(".init"))) void paging_init()
{
   map_identity();

   map_kernel_memory();

   enable_paging();
}


'map_identitiy' identity maps the lower 1M(bios, bootloader, etc..) and the init and table sections, which are right after the 1M.
'map_kernel_memory' maps the higher half kernel to physical addresses.



I didn't find anything odd in my code, and i'm already in a bloody debugging session for more than 5 hours.

Any ideas, suggestions..? Thank you.

EDIT:

I have found the problematic instruction that makes my kernel reboot, all of the addresses are correct and aligned to 4K, CR3 does contain the address of my page directory, but AFTER these instructions are executed:

Code: Select all

mov eax, cr0
or eax, 0x80000000
mov cr0, eax


the system reboots constantly.

EDIT:
Solved...
The problem was that i didn't load the GDT, although GRUB has loaded one, weird. maybe one of the segments wasn't mapped.
Post Reply