Wrote a tutorial covering long mode
-
- Member
- Posts: 127
- Joined: Sat Sep 29, 2007 5:43 pm
- Location: Amsterdam, The Netherlands
Wrote a tutorial covering long mode
Hi,
I wrote a new article on the wiki today which covers setting up long mode. Any suggestions are welcome as well as making it more conform to the wiki itself (If somebody likes to). You can find the article here. I hope it will be of any use.
Regards,
Stephan J.R. van Schaik.
I wrote a new article on the wiki today which covers setting up long mode. Any suggestions are welcome as well as making it more conform to the wiki itself (If somebody likes to). You can find the article here. I hope it will be of any use.
Regards,
Stephan J.R. van Schaik.
- xenos
- Member
- Posts: 1121
- Joined: Thu Aug 11, 2005 11:00 pm
- Libera.chat IRC: xenos1984
- Location: Tartu, Estonia
- Contact:
Re: Wrote a tutorial covering long mode
First of all, this is absolutely great work I guess it will help many people fiddling around with the transition to long mode.
Second, I have some small hints. At the very end of the article, you clear the screen using "rep movsq". I guess you should set RDI to the start of video ram before doing so. In the same piece of code, instead of the power-consuming endless loop at the end, I would recommend to halt the CPU, so beginners who just copy and paste the article into some assembler won't heat up their CPUs too much. Finally, the binary numbers in your code are really nice as one can simply count which bit is set / cleared, but I would add some comment like "set bit 23", just to make things clear.
Second, I have some small hints. At the very end of the article, you clear the screen using "rep movsq". I guess you should set RDI to the start of video ram before doing so. In the same piece of code, instead of the power-consuming endless loop at the end, I would recommend to halt the CPU, so beginners who just copy and paste the article into some assembler won't heat up their CPUs too much. Finally, the binary numbers in your code are really nice as one can simply count which bit is set / cleared, but I would add some comment like "set bit 23", just to make things clear.
Re: Wrote a tutorial covering long mode
I have an idea on the CPUID part. You don't have to worry weather the CPU is from AMD or Intel. An piece of code below with detect 64-bit capability. And 64-bit supported means PAE supported, so you don't have to check for PAE if the CPU is 64-ready
Just in case you want to know, this code is taken from AMD manual, Chapter 14 section 8
Code: Select all
mov eax, 80000000h ; Extended-function 8000000h.
cpuid ; Is largest extended function
cmp eax, 80000000h ; any function > 80000000h?
jbe no_long_mode ; If not, no long mode.
mov eax, 80000001h ; Extended-function 8000001h.
cpuid ; Now EDX = extended-features flags.
bt edx, 29 ; Test if long mode is supported.
jnc no_long_mode ; Exit if not supported.
"Programmers are tools for converting caffeine into code."
-
- Member
- Posts: 127
- Joined: Sat Sep 29, 2007 5:43 pm
- Location: Amsterdam, The Netherlands
Re: Wrote a tutorial covering long mode
Thanks a lot. Yes, I should have set rdi to 0xB8000 , I forgot about that. Will update the article.XenOS wrote:First of all, this is absolutely great work I guess it will help many people fiddling around with the transition to long mode.
Second, I have some small hints. At the very end of the article, you clear the screen using "rep movsq". I guess you should set RDI to the start of video ram before doing so. In the same piece of code, instead of the power-consuming endless loop at the end, I would recommend to halt the CPU, so beginners who just copy and paste the article into some assembler won't heat up their CPUs too much. Finally, the binary numbers in your code are really nice as one can simply count which bit is set / cleared, but I would add some comment like "set bit 23", just to make things clear.
I was expecting other x86-like processors to have some other flags, if they even actually support those functions, but I guess not.quanganht wrote:I have an idea on the CPUID part. You don't have to worry weather the CPU is from AMD or Intel.
I saw the code in the manual once, but generally derived it myself based on the ideas I had about enabling long mode. Thanks for the information.quanganht wrote:An piece of code below with detect 64-bit capability.And 64-bit supported means PAE supported, so you don't have to check for PAE if the CPU is 64-readyJust in case you want to know, this code is taken from AMD manual, Chapter 14 section 8Code: Select all
mov eax, 80000000h ; Extended-function 8000000h. cpuid ; Is largest extended function cmp eax, 80000000h ; any function > 80000000h? jbe no_long_mode ; If not, no long mode. mov eax, 80000001h ; Extended-function 8000001h. cpuid ; Now EDX = extended-features flags. bt edx, 29 ; Test if long mode is supported. jnc no_long_mode ; Exit if not supported.
Edit: updated it.
Regards,
Stephan J.R. van Schaik.
Re: Wrote a tutorial covering long mode
What a great tutorial! Can you please continue with the IDT and interrupts ? (I won't be helpful as I found it a little confusing )
"Programmers are tools for converting caffeine into code."
-
- Member
- Posts: 127
- Joined: Sat Sep 29, 2007 5:43 pm
- Location: Amsterdam, The Netherlands
Re: Wrote a tutorial covering long mode
Sure, basically the IDT used for 64-bit is the same as the one used for 32-bit though with generally two exceptions: the entries have been extended with an additional eight bytes (where the first four bytes serve as part of the offset) and the pointer has been extended to 80-bit as well (16-bit size, 64-bit base).quanganht wrote:What a great tutorial! Can you please continue with the IDT and interrupts ? (I won't be helpful as I found it a little confusing )
Regards,
Stephan J.R. van Schaik.
Re: Wrote a tutorial covering long mode
Thank for your work.
After entering long mode, U don't reload SS (mov ss,ax). It means that CPU continue using prot mode stack.
But when I try to set new LM stack, bochs fires SS exception, saying that bit P is not set.
I using GRUB2 -> 32bit stub in ELF64.
Should I setup 32bit gdt first, prior entering long mode?
Or this is some kind of bug in Bochs?
Any ideas?
After entering long mode, U don't reload SS (mov ss,ax). It means that CPU continue using prot mode stack.
But when I try to set new LM stack, bochs fires SS exception, saying that bit P is not set.
I using GRUB2 -> 32bit stub in ELF64.
Should I setup 32bit gdt first, prior entering long mode?
Or this is some kind of bug in Bochs?
Any ideas?
-
- Member
- Posts: 127
- Joined: Sat Sep 29, 2007 5:43 pm
- Location: Amsterdam, The Netherlands
Re: Wrote a tutorial covering long mode
Hi,
The GDT used for entering long mode is actually temporary. You ought to set up another GDT afterwards. In my kernel the new GDT to be loaded looks like this:
And the way I load the GDT and set up the segment registers looks like this:
You might want to look at the AMD64 Architecture Programmer's Manual, Volume 2 to be more specific, as this manual contains more information about how the GDT should be laid out, but also about the EFLAGS I modified before using the IRETQ-instruction to reload the segment registers, more specifically the CS and SS registers.
Regards,
Stephan J.R. van Schaik.
The GDT used for entering long mode is actually temporary. You ought to set up another GDT afterwards. In my kernel the new GDT to be loaded looks like this:
Code: Select all
GDT:
.Null: equ $ - GDT
dq 0
.KCode: equ $ - GDT
dw 0
dw 0
db 0
db 0x98
db 0x20
db 0
.KData: equ $ - GDT
dw 0
dw 0
db 0
db 0x92
db 0x20
db 0
.UCode: equ $ - GDT
dw 0
dw 0
db 0
db 0xF8
db 0x20
db 0
.UData: equ $ - GDT
dw 0
dw 0
db 0
db 0xF2
db 0x20
db 0
.Pointer: dw $ - GDT - 1
dq GDT
Code: Select all
mov rsp, 0x90000
lgdt [GDT.Pointer]
push QWORD GDT.KData
push QWORD 0x90000
pushfq
pushfq
pop rax
and rax, 1111111111111111111111111111111111111111111111101011111011111111b
push rax
popfq
push QWORD GDT.KCode
push QWORD .Flush
iretq
.Flush:
mov ax, GDT.KData
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
Regards,
Stephan J.R. van Schaik.
Re: Wrote a tutorial covering long mode
Stephan,
Gotta congratulate you on your Long Mode tutorial. It is excellent. I have one possible correction, though I must admit I haven't actually tried your code.
Shouldn't the 'or' be a 'mov' ?
- gerryg400
Gotta congratulate you on your Long Mode tutorial. It is excellent. I have one possible correction, though I must admit I haven't actually tried your code.
Code: Select all
; Set the A-register to 0x00004000.
or eax, 0x00004000
; Set control register 3 to the A-register.
mov cr3, eax
- gerryg400
If a trainstation is where trains stop, what is a workstation ?
- Firestryke31
- Member
- Posts: 550
- Joined: Sat Nov 29, 2008 1:07 pm
- Location: Throw a dart at central Texas
- Contact:
Re: Wrote a tutorial covering long mode
Not if he only wants to set that one bit. OR will leave all of the other bits alone, and so will preserve the other flags (such as paging enabled and whatnot).
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
Re: Wrote a tutorial covering long mode
CR3 holds an address (of pml4). Well it holds some bits in the lower 12 bits, but Stephan is not setting those. Fairly sure it sure be a 'mov'
- gerryg400
- gerryg400
If a trainstation is where trains stop, what is a workstation ?
- Firestryke31
- Member
- Posts: 550
- Joined: Sat Nov 29, 2008 1:07 pm
- Location: Throw a dart at central Texas
- Contact:
Re: Wrote a tutorial covering long mode
I was thinking CR4. My bad.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
Re: Wrote a tutorial covering long mode
GDTR,After entering long mode, U don't reload SS (mov ss,ax). It means that CPU continue using prot mode stack.
But when I try to set new LM stack, bochs fires SS exception, saying that bit P is not set.
These are my findings (mainly from trial and error because the manuals aren't always very descriptive.)
You don't need to load SS. It's difficult to understand (for me anyway) but in long mode there are no data/stack segments. It's just one big memory area.
If you want to load SS, load the NULL selector. Other values crash my machine. Not sure about yours.
Also you don't need to load DS or ES. If you do load them make sure the P bit in the selector is set. P not set crashes my machine. But the processor ignores every other part of a data descriptor. Even the DPL is ignored. You don't need to have separate RINGn data segments. You use the paging mechanism for protection.
As I said this information was gathered by trial and error. I would like to hear from anyone who has a different experience.
- gerryg400
If a trainstation is where trains stop, what is a workstation ?
-
- Member
- Posts: 127
- Joined: Sat Sep 29, 2007 5:43 pm
- Location: Amsterdam, The Netherlands
Re: Wrote a tutorial covering long mode
Yes, most likely. I don't have that revision of my source code any more so I'm not sure whether this is just me being confused with the OR and MOV instructions all around, or if it was something I got directly out of my source. In a newer version of my source I handle it like this (when creating the 32-bit page table):gerryg400 wrote:Stephan,
Gotta congratulate you on your Long Mode tutorial. It is excellent. I have one possible correction, though I must admit I haven't actually tried your code.
Shouldn't the 'or' be a 'mov' ?Code: Select all
; Set the A-register to 0x00004000. or eax, 0x00004000 ; Set control register 3 to the A-register. mov cr3, eax
- gerryg400
Code: Select all
mov edi, DWORD [FreeMemory]
add edi, 0xFFF
and edi, 11111111111111111111000000000000b
mov cr3, edi
Code: Select all
mov edi, cr3
Regards,
Stephan J.R. van Schaik.
Re: Wrote a tutorial covering long mode
Hi there, few question about tutorial here
After this part di points to 4096+16384, so we need to set it one more time: mov di, 0x1000
...and we dont need last add di, 0x1000
Next, we need to set di to 0x4000, not add 0x4000 to current value: mov di,0x4000
Last note. We assume that ecx and edi (their high part) is zero, but it not always true.
mb use edi, ecx insted? (or zero them at begining)
UPD
AMD64 APM vol. 2, page 357
"- Data-segment descriptors for software running in compatibility mode. The DS, ES, and SS
segments are ignored in 64-bit mode. See “Data-Segment Descriptors” on page 87 for more
information."
Best wishes,
Igor
Code: Select all
mov di, 0x1000
xor ax, ax
mov cx, 16384
rep stosb ; Clear the memory.
Code: Select all
; Set the word at the destination index to 0x2003.
mov WORD [di], 0x2003
; Add 0x1000 to the destination index.
add di, 0x1000
; Set the word at the destination index to 0x3003.
mov WORD [di], 0x3003
; Add 0x1000 to the destination index.
add di, 0x1000
; Set the word at the destination index to 0x4003.
mov WORD [di], 0x4003
; Add 0x1000 to the destination index.
add di, 0x1000
Next, we need to set di to 0x4000, not add 0x4000 to current value: mov di,0x4000
Code: Select all
; Set the destination index to 0x4000.
add di, 0x4000
; Set the B-register to 0x00000003.
mov ebx, 0x00000003
; Set the C-register to 512.
mov cx, 512
mb use edi, ecx insted? (or zero them at begining)
UPD
AMD64 APM vol. 2, page 357
"- Data-segment descriptors for software running in compatibility mode. The DS, ES, and SS
segments are ignored in 64-bit mode. See “Data-Segment Descriptors” on page 87 for more
information."
Best wishes,
Igor