Higher half memory kernel

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
solarius
Posts: 20
Joined: Mon Sep 27, 2010 4:45 am

Higher half memory kernel

Post by solarius »

Hi everybody,

I'm trying tu put my kernel in higher memory (0xC0000000) with this tutorial: http://wiki.osdev.org/Higher_Half_With_GDT but I get some problems.

As explained in the document, I defined a GDT and a pointer to this GDT. This section is linked to 0x100000.

Code: Select all

	.org	0xe000
gdt_desc:
    .word   bootstrap_gdt_end - bootstrap_gdt - 1
    .long   
    .word   0x0         /* Padding */
bootstrap_gdt:
    .long   0x0         /* Null gate */
    .long   0x0
    .long   0x40CF9A00  
    .long   0x0000FFFF  /* Code selector */
    .long   0x40CF9200
    .long   0x0000FFFF  /* Data selector */
    .long   0x0
    .long   0x0
bootstrap_gdt_end:
Then the following code, linked @ 0xC0100000, starts the kernel setting up a GDT to convert addresses like 0xC0100000 to 0x100000 as explained in the tutorial.

Code: Select all

/* The entry point must be before the multiboot header. */
.global entry
entry:
  	movl	%eax,       multiboot_magic - 0xC0000000	/* It can be verified later. */
	movl	%ebx,       multiboot_info - 0xC0000000
        /*** Load the tricky GDT ***/
        cli
        lgdtl    gdt_desc
        movw    $0x10,      %ax
        movw    %ax,        %ds
        movw    %ax,        %es
        movw    %ax,        %fs
        movw    %ax,        %gs
        jmp     $0x08,      $virtual_kernel

	/* The multiboot header. */
	.p2align 2
0:	.long	0x1BADB002		/* magic number. */
	.long	0x00010002		/* flags. */
	.long	-0x1BADB002-0x00010002	/* checksum. */
	.long	0b
	.long	_start
	.long	_edata
	.long	__bss_end
	.long	entry 

virtual_kernel:
...
I run this code in Bochs, but when the execution reaches

Code: Select all

jmp     $0x08,      $virtual_kernel
it stops and bochs display the following message :

Code: Select all

00066806313e[CPU0 ] check_cs(0x0008): attempt to jump to long mode without enabling EFER.LMA !
00066806313e[CPU0 ] check_cs(0x0008): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00066806313e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00066806313e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00066806313i[CPU0 ] CPU is in protected mode (active)
00066806313i[CPU0 ] CS.d_b = 32 bit
00066806313i[CPU0 ] SS.d_b = 32 bit
00066806313i[CPU0 ] EFER   = 0x00000000
00066806313i[CPU0 ] | RAX=0000000000000010  RBX=000000000000e004
00066806313i[CPU0 ] | RCX=000000000000e104  RDX=0000000000000000
00066806313i[CPU0 ] | RSP=0000000000067e3c  RBP=0000000000067e5c
00066806313i[CPU0 ] | RSI=000000000002f600  RDI=000000000002f5f8
00066806313i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00066806313i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00066806313i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00066806313i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00066806313i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00066806313i[CPU0 ] | SEG selector     base    limit G D
00066806313i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00066806313i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00066806313i[CPU0 ] |  DS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00066806313i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00066806313i[CPU0 ] |  ES:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00066806313i[CPU0 ] |  FS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00066806313i[CPU0 ] |  GS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00066806313i[CPU0 ] |  MSR_FS_BASE:00000000ffffffff
00066806313i[CPU0 ] |  MSR_GS_BASE:00000000ffffffff
00066806313i[CPU0 ] | RIP=0000000000100038 (0000000000100038)
00066806313i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00066806313i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
(0).[66806313] [0x0000000000100038] 0008:0000000000100038 (unk. ctxt): [b]jmp far 0008:c0100060[/b]     ; ea600010c00800
00066806313e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00066806313i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00066806313i[CPU0 ] cpu hardware reset
00066806313i[APIC0] allocate APIC id=0 (MMIO enabled) to 0x00000000fee00000
00066806313i[CPU0 ] CPU[0] is the bootstrap processor
00066806313i[     ] reset of 'unmapped' plugin device by virtual method
00066806313i[     ] reset of 'biosdev' plugin device by virtual method
00066806313i[     ] reset of 'speaker' plugin device by virtual method
00066806313i[     ] reset of 'extfpuirq' plugin device by virtual method
00066806313i[     ] reset of 'gameport' plugin device by virtual method
00066806313i[     ] reset of 'pci_ide' plugin device by virtual method
00066806313i[     ] reset of 'acpi' plugin device by virtual method
00066806313i[     ] reset of 'ioapic' plugin device by virtual method
00066806313i[     ] reset of 'keyboard' plugin device by virtual method
00066806313i[     ] reset of 'harddrv' plugin device by virtual method
00066806313i[     ] reset of 'serial' plugin device by virtual method
00066806313i[     ] reset of 'parallel' plugin device by virtual method
Next at t=66806314
(0) [0x00000000fffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0
<bochs:4> 
I probably missed something, but I didn't find it, if someone see something totally crazy ... help me !
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Higher half memory kernel

Post by gerryg400 »

Your GDT entries are wrong.

Code: Select all

    .long   0x40CF9A00  
    .long   0x0000FFFF  /* Code selector */
Should be more like this

Code: Select all

		.long 0x0000ffff
		.long 0x40cf9a00
If a trainstation is where trains stop, what is a workstation ?
solarius
Posts: 20
Joined: Mon Sep 27, 2010 4:45 am

Re: Higher half memory kernel

Post by solarius »

I suspect it was from here, because I'm not very at ease with little endian ^^". Nevertheless it doesn't work with your solution. I try it in bochs again and I got this (step by step result):

Code: Select all

(0) Breakpoint 1, 0x0000000000100000 in ?? ()
Next at t=60827173
(0) [0x0000000000100000] 0008:0000000000100000 (unk. ctxt): mov dword ptr ds:0x52b5a0, eax ; a3a0b55200
<bochs:3> n
Next at t=60827174
(0) [0x0000000000100005] 0008:0000000000100005 (unk. ctxt): mov dword ptr ds:0x52b5a4, ebx ; 891da4b55200
<bochs:4> 
Next at t=60827175
(0) [0x000000000010000b] 0008:000000000010000b (unk. ctxt): cli                       ; fa
<bochs:5> 
Next at t=60827176
(0) [0x000000000010000c] 0008:000000000010000c (unk. ctxt): lgdt ds:0xe000            ; 0f011500e00000
<bochs:6> 
Next at t=60827177
(0) [0x0000000000100013] 0008:0000000000100013 (unk. ctxt): mov ax, 0x0010            ; 66b81000
<bochs:7> 
Next at t=60827178
(0) [0x0000000000100017] 0008:0000000000100017 (unk. ctxt): mov ds, ax                ; 8ed8
<bochs:8> 
Next at t=60827179
(0) [0x0000000000100019] 0008:0000000000100019 (unk. ctxt): mov es, ax                ; 8ec0
<bochs:9> 
Next at t=60827180
(0) [0x000000000010001b] 0008:000000000010001b (unk. ctxt): mov fs, ax                ; 8ee0
<bochs:10> 
Next at t=60827181
(0) [0x000000000010001d] 0008:000000000010001d (unk. ctxt): mov gs, ax                ; 8ee8
<bochs:11> 
Next at t=60827182
(0) [0x000000000010001f] 0008:000000000010001f (unk. ctxt): jmp far 0008:c0100048     ; ea480010c00800
<bochs:12> 
00060827182e[CPU0 ] check_cs(0x0008): attempt to jump to long mode without enabling EFER.LMA !
00060827182e[CPU0 ] check_cs(0x0008): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00060827182e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00060827182e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00060827182i[CPU0 ] CPU is in protected mode (active)
00060827182i[CPU0 ] CS.d_b = 32 bit
00060827182i[CPU0 ] SS.d_b = 32 bit
00060827182i[CPU0 ] EFER   = 0x00000000
00060827182i[CPU0 ] | RAX=000000002bad0010  RBX=000000000002f468
00060827182i[CPU0 ] | RCX=0000000000000001  RDX=0000000000000000
00060827182i[CPU0 ] | RSP=0000000000067e3c  RBP=0000000000067e5c
00060827182i[CPU0 ] | RSI=000000000002f600  RDI=000000000002f5f8
00060827182i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00060827182i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00060827182i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00060827182i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00060827182i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00060827182i[CPU0 ] | SEG selector     base    limit G D
00060827182i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00060827182i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00060827182i[CPU0 ] |  DS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00060827182i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00060827182i[CPU0 ] |  ES:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00060827182i[CPU0 ] |  FS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00060827182i[CPU0 ] |  GS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00060827182i[CPU0 ] |  MSR_FS_BASE:00000000ffffffff
00060827182i[CPU0 ] |  MSR_GS_BASE:00000000ffffffff
00060827182i[CPU0 ] | RIP=000000000010001f (000000000010001f)
00060827182i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00060827182i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
(0).[60827182] [0x000000000010001f] 0008:000000000010001f (unk. ctxt): jmp far 0008:c0100048     ; ea480010c00800
00060827182e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00060827182i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00060827182i[CPU0 ] cpu hardware reset
00060827182i[APIC0] allocate APIC id=0 (MMIO enabled) to 0x00000000fee00000
00060827182i[CPU0 ] CPU[0] is the bootstrap processor
00060827182i[     ] reset of 'unmapped' plugin device by virtual method
00060827182i[     ] reset of 'biosdev' plugin device by virtual method
00060827182i[     ] reset of 'speaker' plugin device by virtual method
00060827182i[     ] reset of 'extfpuirq' plugin device by virtual method
00060827182i[     ] reset of 'gameport' plugin device by virtual method
00060827182i[     ] reset of 'pci_ide' plugin device by virtual method
00060827182i[     ] reset of 'acpi' plugin device by virtual method
00060827182i[     ] reset of 'ioapic' plugin device by virtual method
00060827182i[     ] reset of 'keyboard' plugin device by virtual method
00060827182i[     ] reset of 'harddrv' plugin device by virtual method
00060827182i[     ] reset of 'serial' plugin device by virtual method
00060827182i[     ] reset of 'parallel' plugin device by virtual method
Next at t=60827183
(0) [0x00000000fffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b         ; ea5be000f0
<bochs:13> 
...
I put here my link script just in case:

Code: Select all

/*
 * ld directives the for kernel
 */

FORCE_COMMON_ALLOCATION

SECTIONS {
        /* The kernel starts at 1M */
        . = 0x100000;

        _start = .;
    entry = .;

    .bootstrap : {
        *(.bootstrap)
    }
    
    . += 0xC0000000;

        .text : AT(ADDR(.text) - 0xC0000000) {
                *(.text)
                _etext = . - 0xC0000000;    /* We don't want a linear address */
        }

        .data : AT(ADDR(.data) - 0xC0000000) {
                __CTOR_LIST__ = .;
                LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
                *(.ctors)
                LONG(0)
                __CTOR_END__ = .;
                __DTOR_LIST__ = .;
                LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
                *(.dtors)
                LONG(0)
                __DTOR_END__ = .;

                *(.fini)
                *(.anno)
                *(.rodata)
                *(.rodata.str1.1)
                *(.rodata.str1.4)
                *(.rodata.str1.32)
                *(__ex_table)
                *(.rodata.cst8)
                *(.data)

                /* The user program is wrapped in as data */
                usercode_start = .;
                *(.user)
                usercode_end = .;

                /* The real mode code too */
                rmcode_start = .;
                *(.rmcode)
                rmcode_end = .;

                task_dump_screen = .;
                *(.task_dump_screen)

                _edata  =  . - 0xC0000000;    /* We don't want a linear address */
        }

        .bss : AT(ADDR(.bss) - 0xC0000000) {
                __bss_start = .;
                *(.bss)
                *(COMMON)
                __bss_end = . - 0xC0000000;   /* We don't want a linear address */
        }

        _end = .;

        /DISCARD/ : {
                *(.comment)
        }

        /* The memory map */
        idt = 0x1000;
        gdt = 0x10000;
        tss = 0x20000;

        /* Beginning of kernel memory heap */
        mem_heap = _end;

        /* End of kernel memory heap */
        mem_heap_end = 0xC1000000;

        /* Beginning of user space. User program is loaded here by the kernel */
        user_start = mem_heap_end;

    /* Wrapper function for running user processes */
    user_run = 0xC1000005;

        /* Heap for the kernel to allocate user stacks */
        user_stack_heap = 0xC2800000;

        /* End of user space */
        user_end = 0xC3000000;
}
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Higher half memory kernel

Post by Combuster »

With bochs, you have that nice "info gdt" at your disposal.

Also, why is your GDTR (not your GDT) stored hardcoded at 0x0000e000 physical, even though grub will never load anything there?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
b.zaar
Member
Member
Posts: 294
Joined: Wed May 21, 2008 4:33 am
Location: Mars MTC +6:00
Contact:

Re: Higher half memory kernel

Post by b.zaar »

solarius wrote:
I run this code in Bochs, but when the execution reaches

Code: Select all

jmp     $0x08,      $virtual_kernel
it stops and bochs display the following message :

Code: Select all

00066806313e[CPU0 ] check_cs(0x0008): attempt to jump to long mode without enabling EFER.LMA !
Are you trying to enter protected mode or long mode? I haven't looked at long mode properly myself so Im not sure about the exact error Bochs is having with efer.lma.
"God! Not Unix" - Richard Stallman

Website: venom Dev
OS project: venom OS
Hexadecimal Editor: hexed
solarius
Posts: 20
Joined: Mon Sep 27, 2010 4:45 am

Re: Higher half memory kernel

Post by solarius »

Also, why is your GDTR (not your GDT) stored hardcoded at 0x0000e000 physical, even though grub will never load anything there?
Because I need to know its physical address (I believe, if it's not the case, here is my fault ^^") as done in the tutorial. It is stored at 0x0000e000 because it just follows my page/directory table, and symbols in this section have physical addresses.
Are you trying to enter protected mode or long mode? I haven't looked at long mode properly myself so Im not sure about the exact error Bochs is having with efer.lma.
No, I'm already in protected mode, and I don't try to enter in long mode. I just didn't understand this message.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Higher half memory kernel

Post by gerryg400 »

Because I need to know its physical address
No you don't.
If a trainstation is where trains stop, what is a workstation ?
solarius
Posts: 20
Joined: Mon Sep 27, 2010 4:45 am

Re: Higher half memory kernel

Post by solarius »

No you don't.
Oo ? Can I use its virtual adress, I mean 0xCsomething ? Because in the tutorial, the author is putting the gdt in a section ".setup" specially linked with the physical addresses !
With bochs, you have that nice "info gdt" at your disposal.
Thank you, I just type it and my GDT adress seems to be invalid :

Code: Select all

<bochs:10> info gdt 0
Global Descriptor Table (base=0x00000000590002f4, limit=52253):
bx_dbg_read_linear: physical memory read error (phy=0x00000000590002f4, lin=0x00000000590002f4)
error: GDTR+8*0 points to invalid linear address 0x00000000590002f4
But I really don't derstand why ...
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Higher half memory kernel

Post by gerryg400 »

You've deviated a loooong way from the tutorial and broken it. I recommend you work with Grub (which is what that tutorial does) rather than trying to force it to do odd things. Grub wants to load an ELF file at 0x100000 so you should create an ELF file that loads at 0x100000. Let it choose where the sections go and do all your calcs at run time. All those hardcoded addresses in the LD script is messy and trying to explicitly say where you want your GDT, TSS etc to be will only end in frustration and/or tears.

Also, and this is just my opinion, the 'GDT trick' (which sets up the GDT, enables paging, sets up the GDT again) is the difficult way to load a higher half kernel. The easy way is to enable paging fiirst then setup your GDT.
If a trainstation is where trains stop, what is a workstation ?
solarius
Posts: 20
Joined: Mon Sep 27, 2010 4:45 am

Re: Higher half memory kernel

Post by solarius »

You're right, I had a problem with my sections in the linker script, I was putting my GDT before 0x100000 and grub doesn't load it here, now it works. Then I immediatly setup the paging but I'm blocked by the paging activation/segment translation deactivation. Indeed if I enable paging, the adresses converted by the processor using the GDT are not valid anymore, so I try to find the right moment to change segments.

If not use the GDT trick implies that my page tables and directory must be statically, or I will have to compute adresses to jump in the loops ...
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Higher half memory kernel

Post by Combuster »

solarius wrote:If not use the GDT trick implies that my page tables and directory must be statically, or I will have to compute adresses to jump in the loops ...
Wrong, wrong. Jumps are relative by default and can be run at an address they were not initially linked to. You can dynamically allocate page tables and system structures in the kernel without statically defining them.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
solarius
Posts: 20
Joined: Mon Sep 27, 2010 4:45 am

Re: Higher half memory kernel

Post by solarius »

Ok now it works, I had a mistake in my page tables. I finally keep the GDT method, it works well. Thank you for your advices.
Post Reply