P-Mode code fails on jmp

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
Eric Avery

P-Mode code fails on jmp

Post by Eric Avery »

The p-mode code im working with dies in bochs when the first jmp (jmp SYS_CODE_SEL:do_pm )is called after i get into p-mode. Bochs returns with an error
s=1 descriptor not executable. From what I can figure everything is
ok and the descriptor im trying to work with (SYS_CODE_SEL) is
executable and should work fine. Here’s a copy of the code
if anyone has any ideas on what could be going wrong
I would really appreciate the help.



[BITS 16]
[ORG 0]
jmp short Start
nop

Start:
cli ; disable interrupts
xor ebx,ebx ; now in real mode (16-bit)
mov bx,cs
shl ebx,4
mov eax,ebx ; EAX=EBX=CS<<4
lea eax,[ebx]
mov [gdt2 + 2],ax ; set descriptor base address=EAX
mov [gdt3 + 2],ax
shr eax,16
mov [gdt2 + 4],al
mov [gdt3 + 4],al
mov [gdt2 + 7],ah
mov [gdt3 + 7],ah
lea eax,[ebx + gdt] ; point gdt_ptr to the gdt
mov [gdt_ptr + 2],eax ; EAX=linear address of gdt
push dword 0 ; zero EFLAGS (interrupts off,
popfd ; IOPL=0, NT bit=0)
lgdt [gdt_ptr]
mov eax,cr0
or al,1
mov cr0,eax

jmp SYS_CODE_SEL:do_pm

do_pm:
mov ax,SYS_DATA_SEL ; now in 32-bit pmode
mov ds,eax ; EAX works, one byte smaller :)
mov ss,eax
nop
mov es,eax
mov fs,eax
mov gs,eax
xor eax,eax ; zero top 16 bits of ESP
mov ax,sp
mov esp,eax
jmp $ ; loop

;*******
; Data *******************************************************
;*******

; null descriptor
gdt: dw 0 ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0 ; type
db 0 ; limit 19:16, flags
db 0 ; base 31:24
; linear data segment descriptor
LINEAR_SEL equ $-gdt
dw 0xFFFF ; limit 0xFFFFF (1 meg? 4 gig?)
dw 0 ; base for this one is always 0
db 0
db 0x92 ; present,ring 0,data,expand-up,writable
db 0xCF ; page-granular (4 gig limit), 32-bit
db 0
; code segment descriptor
SYS_CODE_SEL equ $-gdt
gdt2: dw 0xFFFF
dw 0 ; (base gets set above)
db 0
db 0x9A ; present,ring 0,code,non-conforming,readable
db 0xCF
db 0
; data segment descriptor
SYS_DATA_SEL equ $-gdt
gdt3: dw 0xFFFF
dw 0 ; (base gets set above)
db 0
db 0x92 ; present,ring 0,data,expand-up,writable
db 0xCF
db 0
gdt_end:

gdt_ptr:
dw gdt_end - gdt - 1 ; GDT limit
dd gdt ; linear, physical address of GDT

times 510-($-$$) db 0 ; pad the file with the needed 0 bytes to
; make it 510 bytes at this point
dw 0xAA55 ; boot sector signature needed to have
; bios read it as a bootsector
chatamballi

RE:P-Mode code fails on jmp

Post by chatamballi »

From your code, it appears that you are expect
this to be loaded at boot time from the first
sector!!! Right??? If so...the only problem is
that you have to change [ORG 0] to [ORG 0x7c00]
because, that is where the boot sector is loaded!


>On 2002-02-03 23:47:05, Eric Avery wrote:
>The p-mode code im working with dies in bochs when the first jmp (jmp SYS_CODE_SEL:do_pm )is called after i get into p-mode. Bochs returns with an error
>s=1 descriptor not executable. From what I can figure everything is
>ok and the descriptor im trying to work with (SYS_CODE_SEL) is
>executable and should work fine. Here’s a copy of the code
>if anyone has any ideas on what could be going wrong
>I would really appreciate the help.
>
>
>
>[BITS 16]
>[ORG 0]
> jmp short Start
> nop
>
>Start:
> cli ; disable interrupts
> xor ebx,ebx ; now in real mode (16-bit)
> mov bx,cs
> shl ebx,4
> mov eax,ebx ; EAX=EBX=CS<<4
> lea eax,[ebx]
> mov [gdt2 + 2],ax ; set descriptor base address=EAX
> mov [gdt3 + 2],ax
> shr eax,16
> mov [gdt2 + 4],al
> mov [gdt3 + 4],al
> mov [gdt2 + 7],ah
> mov [gdt3 + 7],ah
> lea eax,[ebx + gdt] ; point gdt_ptr to the gdt
> mov [gdt_ptr + 2],eax ; EAX=linear address of gdt
> push dword 0 ; zero EFLAGS (interrupts off,
> popfd ; IOPL=0, NT bit=0)
> lgdt [gdt_ptr]
> mov eax,cr0
> or al,1
> mov cr0,eax
>
> jmp SYS_CODE_SEL:do_pm
>
>do_pm:
> mov ax,SYS_DATA_SEL ; now in 32-bit pmode
> mov ds,eax ; EAX works, one byte smaller :)
> mov ss,eax
> nop
> mov es,eax
> mov fs,eax
> mov gs,eax
> xor eax,eax ; zero top 16 bits of ESP
> mov ax,sp
> mov esp,eax
> jmp $ ; loop
>
>;*******
>; Data *******************************************************
>;*******
>
>; null descriptor
>gdt: dw 0 ; limit 15:0
> dw 0 ; base 15:0
> db 0 ; base 23:16
> db 0 ; type
> db 0 ; limit 19:16, flags
> db 0 ; base 31:24
>; linear data segment descriptor
>LINEAR_SEL equ $-gdt
> dw 0xFFFF ; limit 0xFFFFF (1 meg? 4 gig?)
> dw 0 ; base for this one is always 0
> db 0
> db 0x92 ; present,ring 0,data,expand-up,writable
> db 0xCF ; page-granular (4 gig limit), 32-bit
> db 0
>; code segment descriptor
>SYS_CODE_SEL equ $-gdt
>gdt2: dw 0xFFFF
> dw 0 ; (base gets set above)
> db 0
> db 0x9A ; present,ring 0,code,non-conforming,readable
> db 0xCF
> db 0
>; data segment descriptor
>SYS_DATA_SEL equ $-gdt
>gdt3: dw 0xFFFF
> dw 0 ; (base gets set above)
> db 0
> db 0x92 ; present,ring 0,data,expand-up,writable
> db 0xCF
> db 0
>gdt_end:
>
>gdt_ptr:
> dw gdt_end - gdt - 1 ; GDT limit
> dd gdt ; linear, physical address of GDT
>
>times 510-($-$$) db 0 ; pad the file with the needed 0 bytes to
> ; make it 510 bytes at this point
>dw 0xAA55 ; boot sector signature needed to have
> ; bios read it as a bootsector
Guest

RE:P-Mode

Post by Guest »

>On 2002-02-04 01:03:12, chatamballi wrote:
>From your code, it appears that you are expect
>this to be loaded at boot time from the first
>sector!!! Right??? If so...the only problem is
>that you have to change [ORG 0] to [ORG 0x7c00]
>because, that is where the boot sector is loaded!

While this is correct, it is not the only reason the code fails (if you look at the code, you'll find that, up to the point of the changeover, all of the memory references are relative; this is why it worked to the extent it did). The other problem is that the code being generated is 16-bit, even after switching to protected mode. To correct this, you'll need to add a [bits 32] statement after the jump, like this:

...
jmp SYS_CODE_SEL:do_pm

[BITS 32]
do_pm:

...

I have take the liberty of testing this, and its does in fact work after both of these changes are made; the bochsout.txt file does indeed show that it switches to p-mode correctly.
Schol-R-LEA

RE:P-Mode

Post by Schol-R-LEA »

Oh, if it helps any, here's the modified version
I tested. It also has a rather trivial example of
text I/O code, which I hacked up so that it
would actually show that it had switched to
p-mode (OK, so it wasn't so trivial; it took me
a few hours to get it right, actually, mostly due
to bad math on my part). HTH.


*******************************************

[BITS 16]
[ORG 0x7C00]

cols equ 80 * 2
currcol equ 0
strtrow equ 0x0C ; arbitrarily chosen to appear two lines below
; Bochs 1.3 default text
vidpage equ 0
pgsize equ 0x00001000
vidseg equ 0xB800
vidlinr equ 0x000B8000
textatt equ 0x0F

jmp short Start
nop

Start:
; According to IPHB, the formula for the cursor address
; cursor(k,i,j)=video_segment+(k * page_size)+(2 * row_size *i)+(2 * j)
; where k is the current video page, i is vertical row and j is
; horizontal column. Since most PCs boot into text mode 2, the
; video segment is at 0xB800 (0x00B8000 linear), the page size is 0x1000,
; and the number of columns per row is 0xA0. Since the default page is
; 0, you technically can ignore that part at this stage, but I included
; it for completeness' sake..

MOV AX, vidseg
MOV ES, AX

MOV CX, pgsize
MOV AX, vidpage
MUL CX
MOV CX, AX ; CX = current_page * pagesize

MOV AX, strtrow
MOV BX, cols
MUL BX
MOV BX, AX ; BX = columns_per_row * 2 * current_row
MOV AX, currcol
SHL AX, 1 ; AX = current_column * 2
ADD AX, BX
ADD AX, CX

MOV DI, AX
MOV SI, msg1
MOV AH, textatt

prloop1:
MOV AL, [SI]
CMP AL, 0
JE prend
MOV [ES:DI], AX
INC SI
ADD DI, 2
JMP short prloop1

prend: MOV [cursor], DI

cli ; disable interrupts
xor ebx,ebx ; now in real mode (16-bit)
mov bx,cs
shl ebx,4
mov eax,ebx ; EAX=EBX=CS<<4
lea eax,[ebx]
mov [gdt2 + 2],ax ; set descriptor base address=EAX
mov [gdt3 + 2],ax
shr eax,16
mov [gdt2 + 4],al
mov [gdt3 + 4],al
mov [gdt2 + 7],ah
mov [gdt3 + 7],ah
lea eax,[ebx + gdt] ; point gdt_ptr to the gdt
mov [gdt_ptr + 2],eax ; EAX=linear address of gdt
push dword 0 ; zero EFLAGS (interrupts off,
popfd ; IOPL=0, NT bit=0)
lgdt [gdt_ptr]
mov eax,cr0
or al,1
mov cr0,eax

jmp SYS_CODE_SEL:do_pm

[BITS 32]
do_pm:
mov ax,SYS_DATA_SEL ; now in 32-bit pmode
mov ds,eax ; EAX works, one byte smaller :)
mov ss,eax
nop
mov es,eax
mov fs,eax
mov gs,eax
xor eax,eax ; zero top 16 bits of ESP
mov ax,sp
mov esp,eax

printOK:
XOR EDI, EDI
MOV DI, [cursor]
ADD EDI, vidlinr

MOV SI, msg2
MOV AH, textatt
MOV AL, [SI]

prloop: ADD EDI, 2
MOV [EDI], AX
INC SI
MOV AL, [SI]
CMP AL, 0
JNZ prloop

exit:
JMP short $

;*******
; Data *******************************************************
;*******

;temp variables
k dw 0
i dw 0
j dw 0
cursor dw 0

; OK message
msg1 db "Entering Protected Mode..."
db 0

msg2 db "OK."
db 0

; null descriptor
gdt: dw 0 ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0 ; type
db 0 ; limit 19:16, flags
db 0 ; base 31:24

; linear data segment descriptor
LINEAR_SEL equ $-gdt
dw 0xFFFF ; limit 0xFFFFF (1 meg? 4 gig?)
dw 0 ; base for this one is always 0
db 0
db 0x92 ; present,ring 0,data,expand-up,writable
db 0xCF ; page-granular (4 gig limit), 32-bit
db 0

; code segment descriptor
SYS_CODE_SEL equ $-gdt
gdt2: dw 0xFFFF
dw 0 ; (base gets set above)
db 0
db 0x9A ; present,ring 0,code,non-conforming,readable
db 0xCF
db 0

; data segment descriptor
SYS_DATA_SEL equ $-gdt
gdt3: dw 0xFFFF
dw 0 ; (base gets set above)
db 0
db 0x92 ; present,ring 0,data,expand-up,writable
db 0xCF
db 0
gdt_end:

gdt_ptr:
dw gdt_end - gdt - 1 ; GDT limit
dd gdt ; linear, physical address of GDT

times 510-($-$$) db 0 ; pad the file with the needed 0 bytes to
; make it 510 bytes at this point
dw 0xAA55 ; boot sector signature needed to have
; bios read it as a
blito

RE:P-Mode code fails on jmp

Post by blito »

One problem is [BITS 16]
when you chang to pm the default bits are 32.
so you´ll have to code the pm code with [BITS 32]
í work around this coding the pm code in another
file.
after assemble i concatenate the 2 files.
Ex:
File1 :
[BITS 16]
..
....
...
...
jmp selector:endFile

endFile:

File2:
[BITS 32]
pm code
...
...
..


concatenate 2 files:
copy /b file1.bin /b + file2.bin /b bootsector.bin




>On 2002-02-03 23:47:05, Eric Avery wrote:
>The p-mode code im working with dies in bochs when the first jmp (jmp SYS_CODE_SEL:do_pm )is called after i get into p-mode. Bochs returns with an error
>s=1 descriptor not executable. From what I can figure everything is
>ok and the descriptor im trying to work with (SYS_CODE_SEL) is
>executable and should work fine. Here’s a copy of the code
>if anyone has any ideas on what could be going wrong
>I would really appreciate the help.
>
>
>
>[BITS 16]
>[ORG 0]
> jmp short Start
> nop
>
>Start:
> cli ; disable interrupts
> xor ebx,ebx ; now in real mode (16-bit)
> mov bx,cs
> shl ebx,4
> mov eax,ebx ; EAX=EBX=CS<<4
> lea eax,[ebx]
> mov [gdt2 + 2],ax ; set descriptor base address=EAX
> mov [gdt3 + 2],ax
> shr eax,16
> mov [gdt2 + 4],al
> mov [gdt3 + 4],al
> mov [gdt2 + 7],ah
> mov [gdt3 + 7],ah
> lea eax,[ebx + gdt] ; point gdt_ptr to the gdt
> mov [gdt_ptr + 2],eax ; EAX=linear address of gdt
> push dword 0 ; zero EFLAGS (interrupts off,
> popfd ; IOPL=0, NT bit=0)
> lgdt [gdt_ptr]
> mov eax,cr0
> or al,1
> mov cr0,eax
>
> jmp SYS_CODE_SEL:do_pm
>
>do_pm:
> mov ax,SYS_DATA_SEL ; now in 32-bit pmode
> mov ds,eax ; EAX works, one byte smaller :)
> mov ss,eax
> nop
> mov es,eax
> mov fs,eax
> mov gs,eax
> xor eax,eax ; zero top 16 bits of ESP
> mov ax,sp
> mov esp,eax
> jmp $ ; loop
>
>;*******
>; Data *******************************************************
>;*******
>
>; null descriptor
>gdt: dw 0 ; limit 15:0
> dw 0 ; base 15:0
> db 0 ; base 23:16
> db 0 ; type
> db 0 ; limit 19:16, flags
> db 0 ; base 31:24
>; linear data segment descriptor
>LINEAR_SEL equ $-gdt
> dw 0xFFFF ; limit 0xFFFFF (1 meg? 4 gig?)
> dw 0 ; base for this one is always 0
> db 0
> db 0x92 ; present,ring 0,data,expand-up,writable
> db 0xCF ; page-granular (4 gig limit), 32-bit
> db 0
>; code segment descriptor
>SYS_CODE_SEL equ $-gdt
>gdt2: dw 0xFFFF
> dw 0 ; (base gets set above)
> db 0
> db 0x9A ; present,ring 0,code,non-conforming,readable
> db 0xCF
> db 0
>; data segment descriptor
>SYS_DATA_SEL equ $-gdt
>gdt3: dw 0xFFFF
> dw 0 ; (base gets set above)
> db 0
> db 0x92 ; present,ring 0,data,expand-up,writable
> db 0xCF
> db 0
>gdt_end:
>
>gdt_ptr:
> dw gdt_end - gdt - 1 ; GDT limit
> dd gdt ; linear, physical address of GDT
>
>times 510-($-$$) db 0 ; pad the file with the needed 0 bytes to
> ; make it 510 bytes at this point
>dw 0xAA55 ; boot sector signature needed to have
> ; bios read it as a bootsector
Post Reply