Page 1 of 2

ret does crash!?!

Posted: Thu Jun 07, 2007 2:20 am
by RedEagle
Hi

first, the code:

Code: Select all

   jmp EnablePMode


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GDT                                ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

GDT_START:

  gdt_NULL:
      dd 0
      dd 0

    
  gdt_CODE: 
     dw 0xFFFF 
     dw 0
     db 0
     db 10011010b ; 0x9A
     db 11001111b ; 0xCF
     db 0

  gdt_DATA: 
     dw 0xFFFF
     dw 0
     db 0
     db 10010010b ; 0x92
     db 11001111b ; 0xCF
     db 0

  gdt_VRAM: 
     dw 0x0F9F
     dw 0x8000
     db 0x0B
     db 10010010b ; 0x92
     db 00000000b ; 0x00
     db 0x00

GDT_END:

GDT_DESC:
   limit dw GDT_END - GDT_START - 1
   base  dd GDT_START+0x10000



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Selectoren                         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

nullsel  equ 000000000000000b
codesel  equ 000000000001000b
datasel  equ 000000000010000b
vramsel  equ 000000000011000b

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PMode                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EnablePMode:
   
   cli
   lgdt [GDT_DESC] ; GDT laden
  
    mov eax, cr0 ; Das CR0 Register in eax laden
    or  eax, 1   ; Das 0. Bit (PE Bit) auf 1 setzen
    mov cr0, eax ; Den neuen Wert in CR0 laden

    jmp long 0x08:PM2+0x10000

[Bits 32]
   PM2:
   
    ; Selector
    mov ax, datasel
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x1FFFFF

     sti
     
     call check  ;;;;This is the Function
     chk01:
     jmp chk01


    jmp ende
   
;;;;TEST
check:
  push eax
  pop eax
ret    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CRASH
So:
I switch to PM. This works fine.
Than I want to call a function (check), works fine, too.
I push and pop something, works!
but at the ret, the PC reboots...

why?? I can jump, and I can use the Stack. Why does ret crash?

ps.: this foult happans on a real PC (I tested it with 2 PCs). With bochs, ret works.

Posted: Thu Jun 07, 2007 4:18 am
by XCHG
We can't be specific about the cause of the error unless we see where the RET crashes for you. Give us the code and we will be able to help you better.

In most of the cases I get a General Protection Fault in RETs that are returning to invalid addresses. The only cause for that is that I have not POPped as many values off of the stack as I have PUSHed them in when I created my stack frame. Again, I don't know if you are Assembly/C or any other programming language so try to be more specific.

Posted: Thu Jun 07, 2007 4:40 am
by AJ
Hi,

I am interested about the fact you have set interrupts (STI). If this is the first time your have enetered PMode, you need a valid IDT and exception handlers before you enable interrupts.

I suspect that the CALL and RET are working fine, but you are getting something like a timer IRQ firing. Of course, the handler isn't present, so you get a triple fault as (I think) a null IDT tries to load zero (or garbage) in to the code segment.

HTH
Adam

Posted: Thu Jun 07, 2007 8:08 am
by JAAman
AJ wrote:Hi,

I am interested about the fact you have set interrupts (STI). If this is the first time your have enetered PMode, you need a valid IDT and exception handlers before you enable interrupts.

I suspect that the CALL and RET are working fine, but you are getting something like a timer IRQ firing. Of course, the handler isn't present, so you get a triple fault as (I think) a null IDT tries to load zero (or garbage) in to the code segment.

HTH
Adam
ya, this is probably not the problem, but it is a problem

no, a unloaded IDT will be located at zero address (same as it was in RMode -- the intel manuals make no distinction between RMode IDTR and PMode IDTR), and will:
try to load values from the RMode IDT -- and those values are obviously wrong -- most likely segment > GDT.limit, which results in a GPF (iirc) which results in another segment > GDT.limit, which results in a double-fault, which results in another segment > GDT.limit, which results in a tripple-fault

so this is certainly a problem, you should leave interrupts disabled until you have an IDT and at least dummy handlers for all the hard-ints


mov ax, datasel
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x1FFFFF
i see you are placing 0x1FFFFF into esp -- this is not usually recommended, as it will result in frequent unaligned memory accesses -- and i doubt you have any other plans for address 1FFFFF...

you should set it to esp = 0X200000, which will result in the first value being placed at 0x1FFFFC-0x1FFFFF (but will not use 0x200000), what you are using now, the first value is at 0x1FFFFB-0x1FFFFE, and location 0x1FFFFF is never used

this isnt something that will cause the code not to work (usually), but it is something you should know, but probably didnt

Posted: Thu Jun 07, 2007 1:30 pm
by mathematician

Code: Select all

mov ax, datasel
should probably be:

Code: Select all

mov ax, cs:datasel
At the moment you are implicitly referencing datasel through the ds register, but the ds register is the very thing you are in the process of initialising. (Similarly the ss register, which is involved in all of the push, pop and ret instructions.)

Posted: Fri Jun 08, 2007 5:32 am
by Aali
mathematician wrote:

Code: Select all

mov ax, datasel
should probably be:

Code: Select all

mov ax, cs:datasel
At the moment you are implicitly referencing datasel through the ds register, but the ds register is the very thing you are in the process of initialising. (Similarly the ss register, which is involved in all of the push, pop and ret instructions.)
an immediate value referenced through a segment? yeah.. that makes sense :wink:

Posted: Fri Jun 08, 2007 5:42 am
by mathematician
Aali wrote:an immediate value referenced through a segment? yeah.. that makes sense :wink:
You think so too?

Posted: Fri Jun 08, 2007 6:11 am
by urxae
mathematician wrote:
Aali wrote:an immediate value referenced through a segment? yeah.. that makes sense :wink:
You think so too?
Hint: datasel is declared as

Code: Select all

datasel  equ 000000000010000b
That means it's not stored in some memory location, but encoded as an immediate value[1] directly in whatever instructions use it. The only segment involved is therefore cs, which is used to load the instruction including immediate value.


[1]: Or an address if enclosed in []s, but that doesn't make much sense in this case.

Posted: Fri Jun 08, 2007 7:03 am
by mathematician
urxae wrote:
mathematician wrote:
Aali wrote:an immediate value referenced through a segment? yeah.. that makes sense :wink:
You think so too?
Hint: datasel is declared as

Code: Select all

datasel  equ 000000000010000b
That means it's not stored in some memory location, but encoded as an immediate value[1] directly in whatever instructions use it. The only segment involved is therefore cs, which is used to load the instruction including immediate value.


[1]: Or an address if enclosed in []s, but that doesn't make much sense in this case.
You shouldn't try irony on this site it would seem.

Posted: Sat Jun 09, 2007 4:10 am
by urxae
mathematician wrote:You shouldn't try irony on this site it would seem.
Sorry, didn't catch that.
My only excuses are that I didn't sleep well the night before and the fact that your post contained no smilies. Pick whichever you prefer :).

Posted: Mon Jun 11, 2007 5:11 am
by RedEagle
I'm sorry, that I can't test your tips...
but i have much Problems with winXP, so I not time to test it.

ps.:
sti was only a test, cause first I called a debugfunction, which uses the rs232, so i thought, that it was a couse, but later I recognized, that the ret-opcode couses it.

well
jmp and pop works perfectly, what does ret other do??
If winXP works, I'll test a far-jmp...

Posted: Mon Jun 11, 2007 7:11 am
by os64dev
did you enable the a20 address line because you have your stack pointer above 1MiB. Bochs always turns on a20, real computers generally don't.

Posted: Sat Jul 21, 2007 3:19 am
by RedEagle
Yes, A20 should be enabled.

After a long time, I continued searching the mistake.

First, my stack:

Code: Select all

    mov ax, datasel
    mov ss, ax
    mov esp, 0x200000
And this is the test-code:
push&pop after the pop, I have an other charecter

Code: Select all

    mov esi, 0xB8000
    mov al, '#'
      push ax
      pop ax
    mov [esi], al
    inc esi
    mov al, 0xAC
    mov [esi], al
read&write but here I get my '#' back

Code: Select all

    mov esi, 0xB8002
    mov al, '#'
      mov edi, 0x200000 
      mov [edi], al
      mov al, [edi]
    mov [esi], al
    inc esi
    mov al, 0xAC
    mov [esi], al
I can read and write to 0x200000 but not with push and pop. But why??

Posted: Sat Jul 21, 2007 3:39 am
by AJ
Not certain why the push and pop don't work if your stack is set up correctly, but the 2 pieces of code are not the same. I believe that your first frame of the stack will actually be 0x1FFFFC, not 0x200000 as esp will decrement before the push, IIRC.

Cheers,
Adam

Posted: Sat Jul 21, 2007 9:09 am
by RedEagle
Here, the '#' gets lost

Code: Select all

   mov esi, 0xB8002
    mov al, '#'
      mov edi, 0x1ffffc 
      mov [edi], al
      mov al, [edi]
    mov [esi], al
    inc esi
    mov al, 0xAC
    mov [esi], al
And here, I get it back.

Code: Select all

    mov esi, 0xB8004
    mov al, '#'
      mov edi, 0x200000 
      mov [edi], al
      mov al, [edi]
    mov [esi], al
    inc esi
    mov al, 0xAC
    mov [esi], al
Is the address below 0x200000 reserved??