flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Triple fault on far jump after setting pmode bit

Author
Thread Post new topic Reply to topic
Daedalus



Joined: 25 Mar 2007
Posts: 52
Daedalus
Hey, me again.

I had the previous code working and entering pmode, so I decided to clean it up and I came up with this:

Code:
;w00t-OS V0.2
format binary as 'img'
use16
org 0x7C00

loader:
jmp tocode
;FAT16 descriptor:
nop
BytesPerSector          DW 512
SectorsPerCluster       DB 1
ReservedSectors         DW 1
NumberOfFATs            DB 0x02    ;is ALWAYS 0x02
RootEntries             DW 512     ;Should be 512 for FAT16
TotalSectors            DW 2880    ;2880 for 1.44 MB floppy
Media                   DB 0xF0    ;0xF0 is common
SectorsPerFAT           DW 9
SectorsPerTrack         DW 18      ;used by Interupt
HeadsPerCylinder        DW 2       ;should be 2 for 1.44 MB floppy
HiddenSectors           DD 0
TotalSectorsBig         DD 0       ;Used by FAT32

DriveNumber             DB 0x00
Unused                  DB 0
ExtBootSignature        DB 0x00    ;Indicates that the following three fields are present
SerialNumber            DD 12345
VolumeLabel             DB "V01um3L4813"
FileSystem              DB "FAT16   "

tocode:

;Create stack
mov ax, 0x9000
mov ss, ax
mov sp, 0xFFFF

cli
  lgdt [gdt_desc]
  lidt [idt_desc]

  mov eax, cr0
  or eax, 1
  mov cr0, eax
  jmp 0x08:ProtectedMode

ProtectedMode:
use32
mov ax, 8*2 ; item 2 in GDT is the DATA segment . . .
mov ds, ax
mov ax, 8*3 ; item 3 in GDT is the STACK segment . . .
mov ss, ax


mov ecx, 0x08000
mov edi, 0xB8000
.loop1:
mov [ds:edi], byte 'A'
inc edi
dec ecx
mov [ds:edi], byte 0x07
inc edi
dec ecx
jnz .loop1

.end:
jmp .end

;Global Descriptor Table entries
gdt_desc:
  dw gdt_end - gdt_dummy - 1  ;limit (as in, size)
  dw gdt_dummy                ;base low
  dw 0                        ;base high

gdt_dummy:
  dw 0      ;base low   (word)
  dw 0      ;base high  (word)
  dw 0      ;limit low  (word)
  db 0      ;limit high (nibble) + gran (nibble)
  db 0      ;access (byte)

gdt_cs:
  dw 0                       ;base low   (word)
  dw 0                       ;base high  (word)
  dw 0xFFFF                  ;limit low  (word)
  db 0x0F + 16 * 1100b       ;limit high (nibble) + gran (nibble)
  db 0x9A                    ;access (byte)

gdt_ds:
  dw 0                       ;base low   (word)
  dw 0                       ;base high  (word)
  dw 0xFFFF                  ;limit low  (word)
  db 0x0F + 16 * 1100b       ;limit high (nibble) + gran (nibble)
  db 0x92                    ;access (byte)

gdt_ss:
  dw 0                       ;base low
  dw 0                       ;base high
  dw 0xFFFF                  ;limit low
  db 16 * 0100b              ;limit high + granularity
  db 0x92                    ;access
gdt_end:

idt_desc:
  dw 0                       ;limit
  dw idt_end                ;base low
  dw 0                       ;base high
idt_end:


times 510 - ($-$$) db 0
dw 0xAA55    


Compiles to ~200 bytes, yeey. So it may be small, but it doesn't work. Bochs restarts on the jmp to protected mode.

Here are some lines from bochsout.txt:

Code:
[BIOS ] Booting from 0000:7c00
[CPU0 ] check_cs: conforming code seg descriptor dpl > cpl
[CPU0 ] CPU is in protected mode (active)
[CPU0 ] CS.d_b = 16 bit
[CPU0 ] SS.d_b = 16 bit
[CPU0 ] EFER   = 0x00000000
[CPU0 ] | RAX=0000000000000011  RBX=0000000000000000
[CPU0 ] | RCX=0000000000000000  RDX=0000000000000000
[CPU0 ] | RSP=000000000000ffff  RBP=0000000000000000
[CPU0 ] | RSI=00000000ffff88ca  RDI=0000000000080000
[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
[CPU0 ] | R10=0000000000000000  R11=0000000000000000
[CPU0 ] | R12=0000000000000000  R13=0000000000000000
[CPU0 ] | R14=0000000000000000  R15=0000000000000000
[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
[CPU0 ] | SEG selector     base    limit G D
[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
[CPU0 ] |  CS:0000( 0004| 0|  0) 00000000 0000ffff 0 0
[CPU0 ] |  DS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
[CPU0 ] |  SS:9000( 0005| 0|  0) 00090000 0000ffff 0 0
[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
[CPU0 ] |  MSR_FS_BASE:0000000000000000
[CPU0 ] |  MSR_GS_BASE:0000000000000000
[CPU0 ] | RIP=0000000000007c53 (0000000000007c53)
[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000
[CPU0 ] | CR3=0x00000000 CR4=0x00000000
[CPU0 ] >> jmp far 0008:7c58 : EA587C0800
[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
[CPU0 ] cpu software reset    


CS and SS are still 16 bit due to the jump not executing. The CPU switches into pmode only after the jump, according to Intel, so... I'm stuck here. Why does it triple fault? Sad
Post 09 Mar 2008, 20:49
View user's profile Send private message MSN Messenger Reply with quote
Daedalus



Joined: 25 Mar 2007
Posts: 52
Daedalus
Oh, forgot to mention. Previous code works without doing anything to A20 gate. Intel doesn't even mention it in System Engineering 3A for switching to protected mode.

Here's the previous code:

bootloader.asm
Code:
;BOOTLOADER

format binary as 'img'
use16
org 0x7c00

include 'diskHeader.asm'

bootcode:

;Creating stack, disabling interrupts to not be interrupted and triple fault the whole thing.
cli
mov ax, 0x9000
mov ss, ax
mov ax, 0xFFFF
mov sp, ax

;********** Setup a GDT & IDT ************************************

include 'gdtcreate.asm'

pop di
lidt [es:di]    ;Let the CPU know where the IDT (pointer) is

pop di
lgdt [es:di]    ;Let the CPU know where the GDT (pointer) is

;********** Set the first bit of CR0 to 1 **********
mov eax, cr0
or eax, 1
mov cr0, eax

;********** FAR JMP to protected mode **********
jmp 0x08:ProtectedMode ;Far jump to protected mode (0x08 referers to item 8 in the GDT, that's the CODE segment)

include 'gdt.inc.asm'

ProtectedMode:
;****************************** We are now in PMode ******************************
use32
mov ax, 8*2 ; item 2 in GDT is the DATA segment . . .
mov ds, ax
mov ax, 8*3 ; item 3 in GDT is the STACK segment . . .
mov ss, ax

mov ecx, 0x08000
mov edi, 0xB8000
.loop1:
mov [ds:edi], byte 'A'
inc edi
dec ecx
mov [ds:edi], byte 0x07
inc edi
dec ecx
jnz .loop1

.end:
jmp .end

times 510-($-$$) db 0
dw 0xAA55    


gdtcreate.asm
Code:
;Create GDT
mov ax, 0x0000
mov es, ax
mov di, 0x1000

;Making a GDT POINTER:
; bx base low   (word)
; dx base high  (word)
; cx limit      (word)
push di
mov bx, 0x1006        ;base low   (word)
mov dx, 0             ;base high  (word)
mov cx, 5*8-1         ;limit      (word)   = count(entries) * sizeof(entry) - 1
call gdtWritePointer  ;Write GDT POINTER

;Making the GDT itself, first the dummy entry.
mov bx, 0  ;base low
mov dx, 0  ;base high
mov cx, 0  ;limit
mov al, 0  ;access
mov ah, 0  ;gran
call gdtWriteEntry

mov bx, 0               ;base low   (word)
mov dx, 0               ;base high  (word)
mov cx, 0xFfFF          ;limit low  (word)
mov ah, 0x0F + 16*1100b ;limit high (nibble) + gran (nibble)
mov al, 0x9A            ;access (byte)
call gdtWriteEntry      ;Write CODE segment (covers all memory)

mov bx, 0               ;base low   (word)
mov dx, 0               ;base high  (word)
mov cx, 0xFFFF          ;limit low  (word)
mov ah, 0x0F + 16*1100b ;limit high (nibble) + gran (nibble)
mov al, 0x92            ;access (byte)
call gdtWriteEntry      ;Write DATA segment (covers all memory)

mov bx, 0x0000          ;base low   (word)         base = 90000
mov dx, 0x0009          ;base high  (word)
mov cx, 0xFFFF          ;limit low  (word)         limit = A0000
mov ah, 0x00 + 16*0100b ;limit high (nibble) + gran (nibble)
mov al, 0x92            ;access (byte)
call gdtWriteEntry      ;Write STACK segment (0x9000:0 - 0x9000:0xFFFF)

;Making a IDT POINTER:
; bx base low   (word)
; dx base high  (word)
; cx limit      (word)
push di
mov bx, di
add bx, 6            ;BX = DX + 6, put the IDT directly after the IDTpointer
mov dx, 0             ;base high  (word)
mov cx, 0             ;limit      (word)   = count(entries) * sizeof(entry) - 1
call idtWritePointer  ;Write IDT POINTER    


gdt.inc.asm
Code:
; Filename: gdt.inc.asm
; GDT functions

; gdtwriteentry Write GDT entry at es:di
; bx base low   (word)
; dx base high  (word)
; cx limit low  (word)
; ah limit high (nibble) + gran (nibble)   0xLG l=limit g=gran
; al access (byte)
gdtWriteEntry:
 mov [es:di], cx ;limit
 add di, 2
 mov [es:di], bx ;base low
 add di, 2
 mov [es:di], dl ;base middle
 inc di
 mov [es:di], al ;access
 inc di
 mov [es:di], ah ;gran
 inc di
 mov [es:di], dh;base high
 inc di
.return:
 ret
 
; gdt/idtwritepointer Write GDT/IDT POINTER entry at es:di
; bx base low   (word)
; dx base high  (word)
; cx limit      (word)
gdtWritePointer:
idtWritePointer:
 mov [es:di], cx ;limit
 add di, 2
 mov [es:di], bx ;base low
 add di, 2
 mov [es:di], dx ;base middle
 add di, 2
.return:
 ret    


Diskheader.asm
Code:
jmp bootcode  ;Jump to bootcode

;The code below is based on the FAT16 definition.
  times 3-($-$$) db 0
  DB "BosByte"           ;Microsoft wants us to put "MSWIN4.1" in here... fuck them!
  times 11-($-$$) db 0
  DW 512     ;Bytes per sector (do not change!)
  DB 1       ;Sectors per Cluster
  DW 1       ;Reserved sector count
  DB 0x02    ;Num FATs (is ALWAYS 0x02)
  DW 512     ;Root entry's count (Should be 512 for FAT16)
  DW 2880    ;Sector count (2880 for 1.44 MB floppy)
  DB 0xF0    ;Media (0xF0 is common)
  DW 9       ;FatSize
  DW 18      ;Sectors per Track (used by Interupt)
  DW 2       ;Heads count (should be 2 for 1.44 MB floppy)
  DD 0       ;Hidden sectors
  DD 0       ;Used by FAT32
  ;Should be at offset 36 now . . .
  DB 0x00    ;Drivenum (0 = floppy1)
  DB 0       ;Reserved for windows NT, fuck windows!
  DB 0x29    ;Indicates that the following three fields are present
  DD 12345   ;VolumeID (just random shizzle)
  DB "w00t-OS" ;VolumeName (max 11 chars)
  times 54-($-$$) db " " ;Fill Volumename up to 11 chars
  DB "FAT16" ;FileSysType (max 8 chars)
  times 62-($-$$) db " " ;Fill FileSysType up to 8 chars
;End of FAT16 header    


mainOutput.inc.asm
Code:
; Filename: mainOutput.inc.asm
; Main output functions

;initscreen(void)
initscreen:
  mov ah, 0x00
  mov al, 0x12
  int 0x10
.return:
 ret

;putc (AL char)
putc:
  mov bl, 0x07
  call putcc
.return:
 ret

;puts(SI string)
puts:
  mov bl, 0x07
  call putcs
.return:
 ret

;putcc (AL char,BL color)
putcc:
  mov ah, 0x0E
  mov bh, 0x00
  int 0x10
.return:
 ret

;putcs (SI string,BL color)
putcs:
  cld
.nextchar:
  lodsb           ;load char @ DS:SI, SI++
  or al, al       ;check for 0
  jz .return      ;if 0
  call putcc
  jmp .nextchar
.return:
 ret    
Post 09 Mar 2008, 20:50
View user's profile Send private message MSN Messenger Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
it's normal, the IA manuals are not destined (sorry) to PC programming, but to the ┬ÁP programming, then, they don't mention anything about the PC platforms, only windows and MSDOS appears in their documents.

the A20 gate is external, it is a simple and gate, with an input for the A20 line and another for A20 enable.

the problem is that you set the IDTR with a null table, and enable interrupts.
if you set the IDTR, you should set a minimal PM set for IDT, or clear the I flag, CLI.
Post 09 Mar 2008, 20:56
View user's profile Send private message Visit poster's website Reply with quote
Daedalus



Joined: 25 Mar 2007
Posts: 52
Daedalus
I CLI right before LGDT.

EDIT:
And I know it's a pain in the ass, but could you look why the other example does work without ever touching A20? Bochs perhaps?
Post 09 Mar 2008, 20:59
View user's profile Send private message MSN Messenger Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
no boch. but more an addressing problem, it is always a problem in addressing, a bad reference, a biased reference, or a bad pointer. org is not there to simplify the task.

your SP is bad. try SP=0
and set it elsewhere.
Post 09 Mar 2008, 21:33
View user's profile Send private message Visit poster's website Reply with quote
Daedalus



Joined: 25 Mar 2007
Posts: 52
Daedalus
My SP is the same as in the other bootloader, and that works fine. Why would it be wrong now? SP = 0 doesn't work.
Post 09 Mar 2008, 22:24
View user's profile Send private message MSN Messenger Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
please, vid, delete it.


Last edited by edfed on 09 Mar 2008, 23:51; edited 1 time in total
Post 09 Mar 2008, 22:43
View user's profile Send private message Visit poster's website Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
now, it works.
the problem was in the GDT, you didn't build it correctly. you reversed all parameters.
if one day you cross a problem with jmp 0000:7Cxx, it is because you put use32 too soon.

use32 shall be writen just before the first 32 bit instruction, just at the pmode label.


Last edited by edfed on 10 Mar 2008, 08:21; edited 1 time in total
Post 09 Mar 2008, 23:43
View user's profile Send private message Visit poster's website Reply with quote
Daedalus



Joined: 25 Mar 2007
Posts: 52
Daedalus
Yeeeeeeeeeeeeeeeeeeeeey. I saw a bunch of A's and really happy now. Thanks edfed, for pointing out the GDT errors, hahahaha.. Didn't see them. Changed that, worked like a charm. 170 bytes. Very Happy
Post 10 Mar 2008, 08:19
View user's profile Send private message MSN Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.