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.
bits 16
org 0x7c00
start:
jmp loader
gdt_data:
dd 0 ; null descriptor
dd 0
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)10:56 AM 7/8/2007
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
toc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
dd gdt_data ; base of GDT
loader:
xor ax, ax
mov ds, ax
mov es, ax
cli
lgdt [toc]
hlt
times 510 - ($-$$) db 0
dw 0xAA55
Does this actually put the computer in to 32bit pmode?
Yes i know a20 hasnt been enabled and all that, but from what ive read this is really all there is to it, when only considering entering 32bit pmode, and i find that very hard to believe.
As you say, you need to enable A20 and once you have done the jump to pmode you will need an IDT and TSS if you plan to handle interrupts / multitask, but all that is done once you are in PMode - run it in Bochs and you will notice that the final register dump will say 'Protected Mode'.
Cheers,
Adam
[EDIT]Damn - you aren't in PMode - you havent set the PE bit in CR0![/EDIT]
While the code is correct, it does not touch pmode at all. You need to set the PMode bit in cr0 to enter protected mode. From here, CS will still contain the segment value (Probably still 0x7c0), which is bad. Because of this, you need to reset CS to your code descriptor offset (0x8) by far jumping:
; make sure to disable interrupts before entering pmode, and do not
; re-enable them until you have a valid IDT.
cli
mov eax, cr0
or eax, 1
mov cr0, eax
; we are now in pmode. Far jump to reset CS
jmp 0x8:Stage3
bits 32
Stage3:
; Welcome to 32bit world
Also, you dont *need* a20 to enter protected mode, however it is recommended.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
And, of course, once you are in PMODE, the BIOS no longer works. So you can't read anything else into memory with an INT command. So, unless you have all your data, or a disk driver in memory, you're stuck at that point.
And, of course, you really want to gather all the BIOS info that you can, before that point ... especially regarding memory and VBE info (and maybe PCI, and floppy, and etc. too).
for now im just interested in getting into long mode (while understanding the process). I dont intent to make anything that should be able to run on other than my own machine (and qemu) which shouldnt be a problem.
Thus, i dont need to get the size of the memory as i always know it. Nor do i need any info about pci or anything else. Well, i need to read/write the disk (usb or hdd or maybe even lan, but i dont believe ill be able to do the usb/lan stuff) but ill take that up later when i understand the process better.
And kudos to brokenthorn.com, its really an amazing os tut.
There is a difference between enabling A20 before or after you enter PMode. Because of the way the address lines are wired up, I believe that some systems prevent you accessing every other MiB if you don't enable it before you go to PMode (you can't access 2-3Mib, 4-5Mib etc...). Someone else may be able to furnish you with the details of this, but it's safer to enable A20 first.
I'm not sure about qemu, but bochs always has the A20 line enabled. You do not have to do it yourself in bochs. Your PC may be the same. Just for fun, here is my A20 code.
(Written for NASM. Public domain. Interrupts need to be off, I think. It compiles, and should run fine. It needs timeouts in all the wait loops, of course.)
lukem_95 wrote:if you enter it before i believe you are entering unreal mode briefly, although i dont think this matters.
also i've seen code that does both, i dont think there is a difference.
AFAIK, unreal mode is when you enter pm, set your segments' bases to 0 and their limits to maximum and then return to real mode, so that you can address you full memory in real mode (which makes it so "UN"real)