simple asm protected mode switch help!
simple asm protected mode switch help!
Hi all,
well I've been fiddling around with some asm code, trying to go into protected mode...I wanted to go into 32bit pm from dos instead of doing a boot disk...just simple stuff.
I've been messing around with this for ages...I mean its not long...kept it very simple...but I know its something to do with where the code is in memory or something stupid.
Its not much code...and when we get into pm it just seems to reboot the computer...tried all sorts of hacks and checks but think it has something to do with where the code is put in memory...or possibly offsets or something.
Thanks for any feedback on this :)
Ben
<div class='indent'>
; Run in dos (not under windows) and it will take us to 32 bit protected mode
[ORG 0x100] ; Reserve 256 bytes for dos
[BITS 16] ; Dos is 16 bits
; assemble using 'nasm' assembler
; C:>nasm asmtest.asm -o test.exe
jmp entry ; Jump to the start of our code
msg1 db 'Where good to go..$';
entry:
; Display a message showing where alive!
mov dx, msg1 ; register dx=msg1
mov ah, 9 ; register ah=9 -- the print string function
int 21h ; dos service interrupt .. looks at register ah to figure out what to do
; Where in dos, and we've done a simple text message to the screen to show
; our program is running... so now where going to break out of this real 16 bit
; world and get into 32 protected mode. So lets set things up and go go go..
cli ; Clear or disable interrupts
lgdt[gdtr] ; Load GDT
mov eax,cr0 ; The lsb of cr0 is the protected mode bit
or al,0x01 ; Set protected mode bit
mov cr0,eax ; Mov modified word to the control register
jmp go_pm
; Once we reach here where in protected mode! 32 Bit! Where not in
; the real world (mode) anymore :)
[BITS 32]
go_pm :
mov ax, 0; ; Just poke something into the graphics memory so that we
mov es, ax; ; know its all okay! *SEEMS TO CRASH HERE!!!*
mov word [es: 0xb8000],0x740
spin : jmp spin ; Loop forever
; We use 16 bit alignment here - as you'll notice we use dw and dd only,
; and out data will be packed together nice and tight.
[BITS 16]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Our GDTR register value
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr :
dw gdt_end-gdt-1 ; Length of the gdt
dd gdt ; physical address of gdt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This is the start of our gdt - its actual value
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdt:
nullsel equ $-gdt
gdt0
dd 0
dd 0
codesel equ $-gdt
code_gdt:
dw 0x0ffff
dw 0x0000
db 0x00
db 0x09a
db 0x0cf
db 0x00
datasel equ $-gdt
data_gdt:
dw 0x0ffff ; Limit 4Gb
dw 0x0000 ; Base 0000:0000h
db 0x00 ; Descriptor format same as above
db 0x092
db 0x0cf
db 0x00
gdt_end:
TIMES 0x500-($-$$) DB 0x90 ; And of course, this will make our file size
; equal to 0x500 a nice round number -
; 0x500 ... so if you assemble the file
; you should find its that size exactly.
</div>
well I've been fiddling around with some asm code, trying to go into protected mode...I wanted to go into 32bit pm from dos instead of doing a boot disk...just simple stuff.
I've been messing around with this for ages...I mean its not long...kept it very simple...but I know its something to do with where the code is in memory or something stupid.
Its not much code...and when we get into pm it just seems to reboot the computer...tried all sorts of hacks and checks but think it has something to do with where the code is put in memory...or possibly offsets or something.
Thanks for any feedback on this :)
Ben
<div class='indent'>
; Run in dos (not under windows) and it will take us to 32 bit protected mode
[ORG 0x100] ; Reserve 256 bytes for dos
[BITS 16] ; Dos is 16 bits
; assemble using 'nasm' assembler
; C:>nasm asmtest.asm -o test.exe
jmp entry ; Jump to the start of our code
msg1 db 'Where good to go..$';
entry:
; Display a message showing where alive!
mov dx, msg1 ; register dx=msg1
mov ah, 9 ; register ah=9 -- the print string function
int 21h ; dos service interrupt .. looks at register ah to figure out what to do
; Where in dos, and we've done a simple text message to the screen to show
; our program is running... so now where going to break out of this real 16 bit
; world and get into 32 protected mode. So lets set things up and go go go..
cli ; Clear or disable interrupts
lgdt[gdtr] ; Load GDT
mov eax,cr0 ; The lsb of cr0 is the protected mode bit
or al,0x01 ; Set protected mode bit
mov cr0,eax ; Mov modified word to the control register
jmp go_pm
; Once we reach here where in protected mode! 32 Bit! Where not in
; the real world (mode) anymore :)
[BITS 32]
go_pm :
mov ax, 0; ; Just poke something into the graphics memory so that we
mov es, ax; ; know its all okay! *SEEMS TO CRASH HERE!!!*
mov word [es: 0xb8000],0x740
spin : jmp spin ; Loop forever
; We use 16 bit alignment here - as you'll notice we use dw and dd only,
; and out data will be packed together nice and tight.
[BITS 16]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Our GDTR register value
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr :
dw gdt_end-gdt-1 ; Length of the gdt
dd gdt ; physical address of gdt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This is the start of our gdt - its actual value
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdt:
nullsel equ $-gdt
gdt0
dd 0
dd 0
codesel equ $-gdt
code_gdt:
dw 0x0ffff
dw 0x0000
db 0x00
db 0x09a
db 0x0cf
db 0x00
datasel equ $-gdt
data_gdt:
dw 0x0ffff ; Limit 4Gb
dw 0x0000 ; Base 0000:0000h
db 0x00 ; Descriptor format same as above
db 0x092
db 0x0cf
db 0x00
gdt_end:
TIMES 0x500-($-$$) DB 0x90 ; And of course, this will make our file size
; equal to 0x500 a nice round number -
; 0x500 ... so if you assemble the file
; you should find its that size exactly.
</div>
Re:simple asm protected mode switch help!
try using a far jump when jumping to 32bit mode(e.g. jmp 08:go_pm). Part from that the rest of the code seems fine.
Re:simple asm protected mode switch help!
The FAR jump is one thing, the other thing I noticed is you need to ensure your GDT offset for ES, DS, isn't 0. Meaning, the GDT is your selector and the 0 selector is usually 0, which will cause your reboot or rather triple fault, which reboots the box. Most people use the second selector 10 as their data selector, so putting ES,DS, etc. to 10h is what you need to do also (that is if it is your intended data selector for reading/writing information).
[edited]
DAH, yes, your selector should be 10h, or datasel, which is your EQUate. Then it will write to video RAM.
Also
works too for continuous loop to self.
[edited]
DAH, yes, your selector should be 10h, or datasel, which is your EQUate. Then it will write to video RAM.
Also
Code: Select all
JMP $
Re:simple asm protected mode switch help!
:(
Thanks guys, I can see the errors that could have caused it... as I was making the silly mistake of assuming es and ds to be offsets in memory when there really offsets into the gdt table.
I modified the jump into protected mode (thanks to B.E):
jmp 0x08:go_pm ; uses codesel selector and jumps into 32 bit pm
Then I modified the code in the 32bit section, so it became (thanks to smiddy):
mov ax, 0x10
mov ds, ax
mov es, ax
mov word[0xb8000], 0x740
jmp $
I mean it looks simple...but it still reboots :(
It couldn't have anything to do with the code being offset to 0x100?...I didn't think it did as where not doing any memory stuff...just simple opcodes.
Hmmmmm
As I boot up a dos floppy, and then launch my binary from the disk....everything seems to work until protected mode comes into action...something inside go_pm just seems to make it reboot the computer :(
Any ideas or hacks to fix this would be great...just been changing lots of things today and have run out of ideas.
Thanks
Ben
Thanks guys, I can see the errors that could have caused it... as I was making the silly mistake of assuming es and ds to be offsets in memory when there really offsets into the gdt table.
I modified the jump into protected mode (thanks to B.E):
jmp 0x08:go_pm ; uses codesel selector and jumps into 32 bit pm
Then I modified the code in the 32bit section, so it became (thanks to smiddy):
mov ax, 0x10
mov ds, ax
mov es, ax
mov word[0xb8000], 0x740
jmp $
I mean it looks simple...but it still reboots :(
It couldn't have anything to do with the code being offset to 0x100?...I didn't think it did as where not doing any memory stuff...just simple opcodes.
Hmmmmm
As I boot up a dos floppy, and then launch my binary from the disk....everything seems to work until protected mode comes into action...something inside go_pm just seems to make it reboot the computer :(
Any ideas or hacks to fix this would be great...just been changing lots of things today and have run out of ideas.
Thanks
Ben
Re:simple asm protected mode switch help!
Thanks guys, I changed the jmp and I changed it so that the ds and es are set to 0x10 (datasel selector)...but it still seems to reboot...hmmmm
I just boot up a dos floppy and lauch the program from the disk...everything seems okay until it goes into protected mode...just seems to reboot...thought it would just display a changed char on the screen ....hmmmm.
Tried changing all sorts of things this morning but can't seem to get it!...bet its something really silly.
Thanks for your feedback guys...I can see where I was going wrong before...and really thought it would have worked, but any other ideas would be great.
Thanks
Ben
I just boot up a dos floppy and lauch the program from the disk...everything seems okay until it goes into protected mode...just seems to reboot...thought it would just display a changed char on the screen ....hmmmm.
Tried changing all sorts of things this morning but can't seem to get it!...bet its something really silly.
Thanks for your feedback guys...I can see where I was going wrong before...and really thought it would have worked, but any other ideas would be great.
Thanks
Ben
Re:simple asm protected mode switch help!
Hi,
This last line should contain the actual address of the GDT, not the offset of the GDT relative to where DOS loaded it...
To fix this you'll need to work out where in memory DOS loaded your binary and adjust accordingly - for example:
I didn't see any other bugs...
I'd also recommend using some alignment, for e.g. "align 4" before the GDT, and perhaps some before "gdtr:". To save a little space you can also recycle the first GDT entry (the NULL descriptor), because the CPU never uses it.
Cheers,
Brendan
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Our GDTR register value
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr:
dw gdt_end-gdt-1 ; Length of the gdt
dd gdt ; physical address of gdt
To fix this you'll need to work out where in memory DOS loaded your binary and adjust accordingly - for example:
Code: Select all
mov eax,0
mov ax,cs
shl eax,4
add [gdtr+2],eax
cli ; Clear or disable interrupts
lgdt[gdtr] ; Load GDT
mov eax,cr0 ; The lsb of cr0 is the protected mode bit
or al,0x01 ; Set protected mode bit
mov cr0,eax ; Mov modified word to the control register
jmp go_pm
I'd also recommend using some alignment, for e.g. "align 4" before the GDT, and perhaps some before "gdtr:". To save a little space you can also recycle the first GDT entry (the NULL descriptor), because the CPU never uses it.
Code: Select all
align 4
gdt:
nullsel equ $-gdt
dw 0
gdtr:
dw gdt_end-gdt-1 ; Length of the gdt
dd gdt ; physical address of gdt
codesel equ $-gdt
code_gdt:
dw 0x0ffff
dw 0x0000
<--more GDT in here-->
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:simple asm protected mode switch help!
Hi Brendon,
thanks for that info...I think thats the problem with the rebooting, it was the physical address of gdt as you said.
I added that code and it doesn't reboot anymore!..yeahh!...but it just seems to hang in pm...wont let me poke anything on the screen at 0xb8000...I mean I thought I could just write a few char's onto the graphics memory to show the code is okay.
I've pasted the code here...just seems to lock up after its gone into pm... I mean its using the dataselector which has a base address of 0000:0000 so if I access memory ds:0xb8000 it should show up on the screen in theory :)
Thanks again for all your help.
Ben
thanks for that info...I think thats the problem with the rebooting, it was the physical address of gdt as you said.
I added that code and it doesn't reboot anymore!..yeahh!...but it just seems to hang in pm...wont let me poke anything on the screen at 0xb8000...I mean I thought I could just write a few char's onto the graphics memory to show the code is okay.
I've pasted the code here...just seems to lock up after its gone into pm... I mean its using the dataselector which has a base address of 0000:0000 so if I access memory ds:0xb8000 it should show up on the screen in theory :)
Thanks again for all your help.
Ben
Code: Select all
mov eax,0
mov ax,cs
shl eax,4
add [gdtr+2],eax
cli ; Clear or disable interrupts
lgdt[gdtr] ; Load GDT
mov eax,cr0 ; The lsb of cr0 is the protected mode bit
or al,0x01 ; Set protected mode bit
mov cr0,eax ; Mov modified word to the control register
jmp go_pm
nop ; ignore - no operation opcodes :)
nop
; Once we reach here where in protected mode! 32 Bit! Where not in
; the real world (mode) anymore :)
[BITS 32]
go_pm :
mov ax, 0x10 ; use our datasel selector ( alternatively mov ax, datasel )
mov ds, ax,
mov es, ax
mov word [es: 0xb8000],0x740
; Write '- 32 bits OK -' at [ds:0B84AAh].
;---------------------------------------
mov byte [ds:0B84CAh], '-' ; char '-'
mov byte [ds:0B84CBh], 02h ; Assign a color code
mov byte [ds:0B84CCh], ' ' ; char ' '
mov byte [ds:0B84CDh], 02h ; Assign a color code
mov byte [ds:0B84CEh], '3' ; char '3'
mov byte [ds:0B84CFh], 02h ; Assign a color code
mov byte [ds:0B84D0h], '2'
mov byte [ds:0B84D1h], 02h ; Assign a color code
mov byte [ds:0B84D2h], ' '
mov byte [ds:0B84D3h], 02h ; Assign a color code
mov byte [ds:0B84D4h], 'b'
mov byte [ds:0B84D5h], 02h ; Assign a color code
mov byte [ds:0B84D6h], 'i'
mov byte [ds:0B84D7h], 02h ; Assign a color code
mov byte [ds:0B84D8h], 't'
mov byte [ds:0B84D9h], 02h ; Assign a color code
mov byte [ds:0B84DAh], 's'
mov byte [ds:0B84DBh], 02h ; Assign a color code
mov byte [ds:0B84DCh], ' '
mov byte [ds:0B84DDh], 02h ; Assign a color code
mov byte [ds:0B84DEh], 'O'
mov byte [ds:0B84DFh], 02h ; Assign a color code
mov byte [ds:0B84E0h], 'K'
mov byte [ds:0B84E1h], 02h ; Assign a color code
mov byte [ds:0B84E2h], ' '
mov byte [ds:0B84E3h], 02h ; Assign a color code
mov byte [ds:0B84E4h], ' '
mov byte [ds:0B84E5h], 02h ; Assign a color code
mov byte [ds:0B84E6h], ' '
mov byte [ds:0B84E7h], 02h ; Assign a color code
mov byte [ds:0B84E8h], '-'
mov byte [ds:0B84E9h], 02h ; Assign a color code
lp: jmp lp ; loops here forever and ever...
Re:simple asm protected mode switch help!
I would change "jmp go_pm" to "jmp 0x08:go_pm", it just feels safer (no idea if it helps)..
/ Christoffer
/ Christoffer
Re:simple asm protected mode switch help!
Try this code:
This should write your message at the top of the screen.
OH, I just noticed something, you'll need to establish a stack too, so you can do CALLs to routines. So set your SS when you set you DS, ES, FS, GS...then set ESP to a place where you can have some room to play, like 0ffffffh (1 byte under 16MB).
Code: Select all
MyMessage db '- 32 bits OK -',0
DisplayMyMessage: ; Messag displaying algo
mov esi,MyMessage
mov eax,0b8000 ; assumes color linear framebuffer
.Loop:
mov al,byte [esi] ; copy byte
cmp al,0
je .Done
mov byte [eax],al ; swap this if I have them reversed (char attribute)
inc eax
mov byte [eax],7 ; or what ever attribute you want
inc eax
inc esi
jmp .Loop
.Done:
ret
OH, I just noticed something, you'll need to establish a stack too, so you can do CALLs to routines. So set your SS when you set you DS, ES, FS, GS...then set ESP to a place where you can have some room to play, like 0ffffffh (1 byte under 16MB).
Re:simple asm protected mode switch help!
Hi,
This jump instruction has the same problem that GDTR had, but it's not so easy to fix. The problem is that "JMP 0x08:go_pm" will jump to "0 + go_pm" rather than "where_DOS_loaded_the_code + go_pm".
You could do something like:
And then:
This would jump to the right address, but you'd need to adjust everything that accesses anything within your code. The main problem is that you're using "ORG 0x100", which is correct in real mode but becomes completely wrong when you change to protected mode.
You could change the code segment base in the GDT so that it works the same as in real mode, and then use "JMP 0x08:go_pm" - that'd work too. Then you'd still have to be careful with accessing data that's within your binary, for example something like:
Wouldn't work - you'd need to use something like:
Another solution would be to create a seperate binary for 32 bit code, which is transferred to a fixed address. In this case you can use a correct ORG and you'd have no problems.
For example, the 32 bit code could be something like:
In this case the 16 bit code would need something like:
You'd also need to copy the protected mode code to the right fixed address, and then jump to it (e.g. "JMP DWORD 0x08:0x10000"). The problem here is that you'd need to avoid overwriting the real mode code when you copy the protected mode code to it's correct address. This can be tricky because you can't predict which address DOS is going to load the real mode code at.
Which method you use is going to depend on how much protected mode code you need. If it's your entire kernel then use the last method (seperate binary at fixed address). Otherwise, if the amount of code is small it'd be easier to use one of the other methods..
Cheers,
Brendan
It'd definately help, but it still won't be correct!bubach wrote:I would change "jmp go_pm" to "jmp 0x08:go_pm", it just feels safer (no idea if it helps)..
This jump instruction has the same problem that GDTR had, but it's not so easy to fix. The problem is that "JMP 0x08:go_pm" will jump to "0 + go_pm" rather than "where_DOS_loaded_the_code + go_pm".
You could do something like:
Code: Select all
section .data
jumpOffset:
dd go_pm
dw 0x08
section .text
Code: Select all
clr eax
mov ax,cs
shl eax,4
mov eax,0
add [gdtr+2],eax
add [jumpOffset],eax
cli ; Clear or disable interrupts
lgdt[gdtr] ; Load GDT
mov eax,cr0 ; The lsb of cr0 is the protected mode bit
or al,0x01 ; Set protected mode bit
mov cr0,eax ; Mov modified word to the control register
jmp far dword [jumpOffset]
You could change the code segment base in the GDT so that it works the same as in real mode, and then use "JMP 0x08:go_pm" - that'd work too. Then you'd still have to be careful with accessing data that's within your binary, for example something like:
Code: Select all
mov esi,address_of_string
call print
Code: Select all
mov esi,address_of_string
add esi,[base_address_of_CS]
call print
For example, the 32 bit code could be something like:
Code: Select all
BITS 32
org 0x10000
jmp start
start:
inc dword [0x000B8000]
jmp start
Code: Select all
section .data
kernelCodeAddress:
%incbin "kernel.bin" ;Include the first binary in this binary
kernelCodeEndAddress:
section .text
Which method you use is going to depend on how much protected mode code you need. If it's your entire kernel then use the last method (seperate binary at fixed address). Otherwise, if the amount of code is small it'd be easier to use one of the other methods..
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:simple asm protected mode switch help!
Hey Brendan,
thanks...as you said it was the offsets for gdtr and the jmp to clear the pipeline and into protected mode.
Now that I know what it is I can work on playing around with the code some more
Thanks again everyone.
Ben
thanks...as you said it was the offsets for gdtr and the jmp to clear the pipeline and into protected mode.
Now that I know what it is I can work on playing around with the code some more
Thanks again everyone.
Ben