Problems With Entering Long Mode

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.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Problems With Entering Long Mode

Post by neon »

Sorry, I edited my response after looking at your code. Please see above. The part that you just posted (for GDTR) is fine. And actually this code is different then your last code -- your last code installs a zero length idt. This one does not install any. Wouldn't worry about the idt just yet though until after you get into protected/long mode.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Tony201300
Posts: 12
Joined: Wed May 27, 2015 9:19 pm

Re: Problems With Entering Long Mode

Post by Tony201300 »

Ok used the code and the logs are...

Booting from 0000:7c00
01346912610e[CPU0 ] jump_protected: gate type 3 unsupported
01346912610e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
01346912610e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
01346912610i[CPU0 ] CPU is in protected mode (active)
01346912610i[CPU0 ] CS.mode = 16 bit
01346912610i[CPU0 ] SS.mode = 16 bit
01346912610i[CPU0 ] EFER = 0x00000000
01346912610i[CPU0 ] | EAX=60000011 EBX=00008000 ECX=0000000c EDX=0000000c
01346912610i[CPU0 ] | ESP=00000000 EBP=00000000 ESI=000effde EDI=00000000
01346912610i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
01346912610i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
01346912610i[CPU0 ] | CS:07e0( 0004| 0| 0) 00007e00 0000ffff 0 0
01346912610i[CPU0 ] | DS:07e0( 0005| 0| 0) 00007e00 0000ffff 0 0
01346912610i[CPU0 ] | SS:07c0( 0005| 0| 0) 00007c00 0000ffff 0 0
01346912610i[CPU0 ] | ES:07e0( 0005| 0| 0) 00007e00 0000ffff 0 0
01346912610i[CPU0 ] | FS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
01346912610i[CPU0 ] | GS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
01346912610i[CPU0 ] | EIP=0000001e (0000001e)
01346912610i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
01346912610i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
01346912610i[CPU0 ] 0x000000000000001e>> jmpf 0x0008:0060 : EA60000800
01346912610e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
01346912610i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
01346912610i[CPU0 ] cpu hardware reset

The only difference I see is highlighted
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Problems With Entering Long Mode

Post by neon »

Hello,

This appears to be a similar problem as the one that you had before due to the org 0 directive. Try this instead --

Code: Select all

bits 16
org 0x7e00

entry:
  cli
  push 0
  push .fix_cs
  retf
.fix_cs: ; cs:ip = 0:7e00
  xor ax, ax
  mov	es, ax
  mov	ds, ax
  lgdt [gdtr] ; load gdtr
  cli
  mov eax, cr0
  or al, 1 ; enable pmode
  mov cr0, eax
  jmp 8:.pmode_start ; flush cs

align 16
gdt_start:
  dw 0x0000, 0x0000, 0x0000, 0x0000
  dw 0xFFFF, 0x0000, 0x9A00, 0x00CF
  dw 0xFFFF, 0x0000, 0x9200, 0x00CF
gdt_end:  

align 16
gdtr:
  dw gdt_end - gdt_start - 1
  dd gdt_start

bits 32
align 16
.pmode_start:
  cli
  hlt
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Tony201300
Posts: 12
Joined: Wed May 27, 2015 9:19 pm

Re: Problems With Entering Long Mode

Post by Tony201300 »

Hello again Neon,

Your modified code showed some improvement. I didn't get any errors. However when I entered the code below after the cli instruction I was back to the same problem.

jmp 0x8:Start32 ;Descriptor:Offset syntax. Each desciptor is 8 bytes

;------------------------------------------------
;Start of 32-bit Protected Mode
;------------------------------------------------

;use32

Start32:

mov si, msg_stage2
call print

print:
lodsb
or al, al
jz .done
mov ah, 0eh
int 10h
jmp print
.done:
ret

msg_stage2 db "The boot loader has been loaded successfully.", 0

Bochs logs...

Booting from 0000:7c00
00018729406e[CPU0 ] read_virtual_checks(): read beyond limit
00018729406e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00018729406e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00018729406i[CPU0 ] CPU is in protected mode (active)
00018729406i[CPU0 ] CS.mode = 32 bit
00018729406i[CPU0 ] SS.mode = 16 bit
00018729406i[CPU0 ] EFER = 0x00000000
00018729406i[CPU0 ] | EAX=60000011 EBX=00008000 ECX=0000000c EDX=0000000c
00018729406i[CPU0 ] | ESP=0000fffc EBP=00000000 ESI=000e7e6d EDI=00000000
00018729406i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00018729406i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00018729406i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 ffffffff 1 1
00018729406i[CPU0 ] | DS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00018729406i[CPU0 ] | SS:07c0( 0005| 0| 0) 00007c00 0000ffff 0 0
00018729406i[CPU0 ] | ES:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00018729406i[CPU0 ] | FS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00018729406i[CPU0 ] | GS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00018729406i[CPU0 ] | EIP=00007e61 (00007e61)
00018729406i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00018729406i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00018729406i[CPU0 ] 0x0000000000007e61>> lodsb al, byte ptr ds:[esi] : AC
00018729406e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00018729406i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
00018729406i[CPU0 ] cpu hardware reset
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Problems With Entering Long Mode

Post by neon »

Hello,

Please note that you can not call BIOS services from protected mode. In other words, your print method is a guaranteed crash. (Farther note that you must keep interrupts disabled (CLI instruction) until you set up a proper interrupt dispatcher.)

To print a string in protected or long mode, you have to write directly to video memory. Please reference the Puts32 algorithm in Chapter 10 of the series for a sample implementation in assembly language. We also encourage looking at the C sample code in the Wiki here. Text mode memory typically begins at 0xb8000 and consists of tuples of (character, attribute) so all you have to do is write to this location.

In addition, .pmode_start should begin like this:

Code: Select all

.pmode_start:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0x7c00 ; up to you here. This sets stack to 0x7c00 linear.

; your code here

cli
jmp $ ; trap nmi's
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Tony201300
Posts: 12
Joined: Wed May 27, 2015 9:19 pm

Re: Problems With Entering Long Mode

Post by Tony201300 »

Thanks, Neon.

Yes I was aware of not using interrupts in bios. I just didn't know that I was in PM mode when I tried to call the print function :).

Now that I want to write text to confirm that I am in PM mode how do I do I start it in c. Do I jump to a location and start to code in C? Should this new location be another 4Kib boundary.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Problems With Entering Long Mode

Post by neon »

It does appear that you are in 32 bit protected mode according the Bochs log that you provided. So it should run without triple faulting if you used the code we provided above. To confirm that you are in protected mode, just check the logs.

You have to somehow load the c code into memory before you can jump to it. The c code is compiled into a separate executable image, such as an elf or pe (.exe) file whereas your current stage 2 is a flat binary. So you will either need to load or preload it from disk into memory. Once it is in memory, you can call its entry point.

So you have two options - loading or preloading.

Option 1 - Preloading (C boot loaders)
For our boot loader, we preloaded the c portion of the loader into memory. This is really easy to do, but involves a bit of code in your startup program. By preloading, what we mean is that the c code gets indirectly loaded with your startup program. This magic is performed by merging both programs in a single binary image. For example, copy nstart+nboot.exe nboot prepends stage 2 to the c code. With this example, the volume boot records would load nboot - which loads both nstart and nboot.exe at the same time. nstart can then relocate and call nboot.exe.

Option 2 - Loading (C boot loaders)
In theory, you can use a modified compiler or 16 bit real mode c compiler which can certainly be used. A compiler that supports multiple code generation modes (such as GCC) can also be used. The idea is simple -- just have the boot record parse and call the boot loader file. As of current, I am only aware of certain builds of GCC that can be used in this way (and those builds tend to be custom.)

Please keep in mind that our design is around option 1 so we can not go into details of option 2 nor can we address additional options that might work. In short however, your next step is to load the c code into memory. Then, and only then, can you execute it.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Problems With Entering Long Mode

Post by Octocontrabass »

neon wrote:mov sp, 0x7c00
mov esp, 0x7c00
neon wrote: push 0
push .fix_cs
retf
jmp 0:.fix_cs
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Problems With Entering Long Mode

Post by neon »

Good catch - that should indeed be mov esp, 0x7c00 -- nonetheless it was only to be taken as an example since the initial stack location is up to the original poster. We tend to prefer using the stack with a retf however it really does not matter if you use a jmpf here since they both achieve the same operation.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Post Reply