Can't jump into 0x10000 from protected mode

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
sebastian93921
Posts: 15
Joined: Thu Jan 12, 2012 7:44 pm

Can't jump into 0x10000 from protected mode

Post by sebastian93921 »

Here is the code of my program

Code: Select all

/* boot.asm */
[bits 16]				;asign  to 16bit CPU
[org 0x7c00]			;origin start point
[section .text]

jmp start

;Data
BootTitle db 'OS BootLoader x16 07122012 - Loading in Real Mode ...',13,10,0

start: 
	mov ax, 0x0000		;asignning a 0 address to ax for data segment address
	mov ds, ax			;move the address 0x0000 to data segment register
	
	mov si, BootTitle	;moving the String data to String interrupts register preper to print out
	call printString	;call print out method
	
	call reset_drive	;load kernel
	
	;;Read GDT
	cli
	pusha				;Save registers
	lgdt [gdt_desc]		;Load GDT Descriptor
	sti					;enable interrupts
	popa				;Pop/restore registers
	
	;;Setup a stack
	cli
	mov ax, 0x0000
	mov ss, ax
	mov sp, 0x7C00
	sti
	
	jmp 0:0xEFFF		;code selector is 8 , goto loader position EFFFh
	
	hlt					;Stop CPU moving

;-----------------------------------------------------------------------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Set GDT
;If you write wrong any word
;means you will die for debugging
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	GDT:
;00000000 00000000 00000000 00000000 00000000 00000000	;GDT_Null
;11111111 00000000 00000000 10011010 11001111 00000000	;GDT_Code
;11111111 00000000 00000000 10010010 11001111 00000000	;GDT_Data

gdt: 		;making Global Description Table
			;first is null segment description
			;then is code segment
			;and the last is data segment

gdt_null: 			;Null Segment
	dd 0			;all 64bits 0
	dd 0			;
   
gdt_code: 			;Code Segment description
	dw 0FFFFh 		;16 bits
	dw 0 			;16 bits
	db 0 			;8 bits
	db 10011010b	;8 bits
	db 11001111b	;8 bits
	db 0 ;8 bits

gdt_data: 			;Data Segment description
	dw 0FFFFh
	dw 0
	db 0
	db 10010010b	;number 4 bit will change to 0 mean data segment description
	db 11001111b
	db 0

gdt_end:

gdt_desc:
	dw gdt_end - gdt - 1
	dd gdt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Startup Drive
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
reset_drive:			;reset floppy drive
	mov ah, 0x00		;
	int 0x13			;floppy drive interrupt
	or ah, ah			;if it's 0(return code)
	jnz reset_drive		;jump back
	
	mov ax, 0			;
	mov es,	ax			;reset extended segment
	mov bx,	0xEFFF		;set kernel location to 0000:EFFF(ES:BX)
	
	mov ah, 0x02		;commend - "read sector from disk"			
	mov al, 0x02		;Number of sectors need to read				
	mov ch, 0			;disk cylinder
	mov cl, 0x02		;set sector (0x01 is bootloader)			
	mov dh, 0			;disk head
	int 0x13			;call floppy drive interrupt
	or ah, ah			;check error
	jnz reset_drive
	
	ret


	
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;String printing
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
printString:			;method (printString)
	pusha
	mov ah, 0x0E		;asignning 0x0E(video display) instruction to ah(accumulator register)
	mov bh, 0x00		;asignning page no (default is 0x00)
	mov bl, 0x07		;asignning text color (07 = White)
	
	;
	;FULL string display in 16bits
	;AX(AH+AL) 0x0E??	<-- adding to register, not yet execute (int)
	;			 | |-Means ACSII code (XY) X = bg color Y = Text Color (16bit)
	;			 |---Means Display  
	;
	;BX(BH+BL) 0x00??   <-- adding to register, means display usage
	;			 | |-Means front color (Can't display without no color
	;			 |---Means Page no (Default is page 0)
	;
	;int 0x10 <------------ interrupt address (execute)
	;				|------ 0x10 is display port address services
	;
		
	.getChar:
		;lodsb			;load a string block 'x''y''z' = "xyz" (LOaD String Block)
						;load a put it into AL register
		mov al,[si]		;get data from pointer of source index		;This method same as using lodsb
		inc si			;si check location + 1						;
		or al,al		;or gate (if-or)
		jz .return		;jump if the or gate returns 0
		
		int 0x10		;interrupt the Video Display instruction
		jmp .getChar	;loop if bytes not equals to 0
	
	.return:
	popa
	ret					;return method back to main


	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
times 510-($-$$) db 0	;for boot loader size MUST be 512bytes
						;adding bytes with 0 to increase the size of file
	dw 0xAA55			;BOOT sign

Code: Select all

/* loader.asm */
[bits 16]
[org 0xEFFF]

jmp start

start:	
	mov al, 'J'			;Jump to kernel
	call printChar
	mov al, 'u'
	call printChar
	mov al, 'm'
	call printChar
	mov al, 'p'
	call printChar
	mov al, ' '
	call printChar
	mov al, 't'
	call printChar
	mov al, 'o'
	call printChar
	mov al, ' '
	call printChar
	mov al, 'k'
	call printChar
	mov al, 'e'
	call printChar
	mov al, 'r'
	call printChar
	mov al, 'n'
	call printChar
	mov al, 'e'
	call printChar
	mov al, 'l'
	call printChar
	mov al, 13
	call printChar
	mov al, 10
	call printChar
	
	
	;;;;;;;;;;;;;;;;;;;;;;;
	;Switch PMode
	;;;;;;;;;;;;;;;;;;;;;;;
	mov eax, cr0		;move cr0(including protected mode instruction) to eax for checking
	or eax, 1			;checking al(2bits) 0001b
	mov cr0, eax		;giving back
	
	jmp 08:loadBit	;jump to 32bit kernel loader
	

	
;;;;;;;;;;;;;;;;;;;;;;
;Print Char
;;;;;;;;;;;;;;;;;;;;;;
printChar:
	mov ah, 0x0E		;instruction of 0x10 (display char)
	mov bx, 0x0007		;00 = page  07 = black color bg and white text
	int 0x10			;interrupt display code
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;String printing
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
printString:			;method (printString)
	pusha
	mov ah, 0x0E		;asignning 0x0E(video display) instruction to ah(accumulator register)
	mov bh, 0x00		;asignning page no (default is 0x00)
	mov bl, 0x07		;asignning text color (07 = White)
	
	;
	;FULL string display in 16bits
	;AX(AH+AL) 0x0E??	<-- adding to register, not yet execute (int)
	;			 | |-Means ACSII code (XY) X = bg color Y = Text Color (16bit)
	;			 |---Means Display  
	;
	;BX(BH+BL) 0x00??   <-- adding to register, means display usage
	;			 | |-Means front color (Can't display without no color
	;			 |---Means Page no (Default is page 0)
	;
	;int 0x10 <------------ interrupt address (execute)
	;				|------ 0x10 is display port address services
	;
		
	.getChar:
		;lodsb			;load a string block 'x''y''z' = "xyz" (LOaD String Block)
						;load a put it into AL register
		mov al,[si]		;get data from pointer of source index		;This method same as using lodsb
		inc si			;si check location + 1						;
		or al,al		;or gate (if-or)
		jz .return		;jump if the or gate returns 0
		
		int 0x10		;interrupt the Video Display instruction
		jmp .getChar	;loop if bytes not equals to 0
	
	.return:
	popa
	ret					;return method back to main
	
	
;================================================================================
;================================================================================

[bits 32]
loadBit:
	mov ax, 10h					;reset segment to 10h (data selector)
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	
	call enable_A20
	
	mov word [es: 0xb8000],'P'	;Protected Mode
	mov word [es: 0xb8001],02h	
	mov word [es: 0xb8002],'M'
	mov word [es: 0xb8003],02h
	mov word [es: 0xb8004],'o'
	mov word [es: 0xb8005],02h
	mov word [es: 0xb8006],'d'
	mov word [es: 0xb8007],02h
	mov word [es: 0xb8008],'e'
	mov word [es: 0xb8009],02h
	
	jmp 8:10000h				;long jump to 1M offset
	
	hlt
	
enable_A20:
        cli
 
        call    a20wait
        mov     al,0xAD
        out     0x64,al
 
        call    a20wait
        mov     al,0xD0
        out     0x64,al
 
        call    a20wait2
        in      al,0x60
        push    eax
 
        call    a20wait
        mov     al,0xD1
        out     0x64,al
 
        call    a20wait
        pop     eax
        or      al,2
        out     0x60,al
 
        call    a20wait
        mov     al,0xAE
        out     0x64,al
 
        call    a20wait
        sti
        ret
 
a20wait:
        in      al,0x64
        test    al,2
        jnz     a20wait
        ret
 
 
a20wait2:
        in      al,0x64
        test    al,1
        jz      a20wait2
        ret
	
	

Code: Select all

/* kernel */
[bits 32]
[org 0x100000]
[global start]

[section .text]
;[extern k_main]

jmp start

start:
	mov word [es: 0xb8000],'K'	;Kernel Mode
	mov word [es: 0xb8001],02h	
	mov word [es: 0xb8002],'M'
	mov word [es: 0xb8003],02h
	mov word [es: 0xb8004],'o'
	mov word [es: 0xb8005],02h
	mov word [es: 0xb8006],'d'
	mov word [es: 0xb8007],02h
	mov word [es: 0xb8008],'e'
	mov word [es: 0xb8009],02h
	mov word [es: 0xb800A],'-'
	mov word [es: 0xb800B],02h
	mov word [es: 0xb800C],'x'
	mov word [es: 0xb800D],02h
	
	
	;call k_main
	
	hlt
Since that I compile these as a binary eg(nasm loader.asm -f bin -o loader.bin)
and mix it up (cat boot.bin loader.bin kernel.bin >> System.img )

the result is the program goes to the second file (loader.asm) but can't access the kernel through 0x100000
The file of boot.asm is in real mode which read the gdt table, and the loader.asm is activate the protected mode and enable A20 gate
finally the bottom of the file which is start the far jump into the kernel

Did I miss something? :(
Capture.JPG
I have copied the log file from Bochs but I'm not so understand :(

Code: Select all

00105666114i[BIOS ] Booting from 0000:7c00
00105705543i[FDD  ] partial read() on floppy image returns 328/512
00105749989i[FDD  ] read() on floppy image returns 0
00105871500e[CPU0 ] load_seg_reg(ES, 0xffff): invalid segment
00105871500e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00105871500e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00105871500i[CPU0 ] CPU is in protected mode (active)
00105871500i[CPU0 ] CS.mode = 32 bit
00105871500i[CPU0 ] SS.mode = 32 bit
00105871500i[CPU0 ] EFER   = 0x00000000
00105871500i[CPU0 ] | EAX=60000018  EBX=00000007  ECX=ffffffff  EDX=00000000
00105871500i[CPU0 ] | ESP=00007bec  EBP=00007bfc  ESI=000e7c02  EDI=0000ffac
00105871500i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf zf AF PF CF
00105871500i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00105871500i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00105871500i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00105871500i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00105871500i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00105871500i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00105871500i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00105871500i[CPU0 ] | EIP=0003000c (0003000c)
00105871500i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00105871500i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00105871500i[CPU0 ] 0x000000000003000c>> les edi, ds:[esi+6] : C47E06
00105871500e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00105871500i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00105871500i[CPU0 ] cpu hardware reset
doxrobot
Member
Member
Posts: 30
Joined: Wed May 15, 2013 10:14 am

Re: Can't jump into 0x10000 from protected mode

Post by doxrobot »

Your LES is generating a GP because either the effective address for your in memory operands exceeds the ds seg limit or the selector you are trying to load for ES is invalid.
sebastian93921
Posts: 15
Joined: Thu Jan 12, 2012 7:44 pm

Re: Can't jump into 0x10000 from protected mode

Post by sebastian93921 »

doxrobot wrote:Your LES is generating a GP because either the effective address for your in memory operands exceeds the ds seg limit or the selector you are trying to load for ES is invalid.
how can I fix this :( ?
doxrobot
Member
Member
Posts: 30
Joined: Wed May 15, 2013 10:14 am

Re: Can't jump into 0x10000 from protected mode

Post by doxrobot »

Well I don't see the les fault anywhere in your source (plus, who does les rg32, esi+6? :P). So I'm thinking you must be branching to garbage code at some point.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump into 0x10000 from protected mode

Post by iansjack »

You tell the assembler, via an org directive, that you are going to load your kernel at 10000h. What do you do to ensure that it is loaded there rather than at some other address?
sebastian93921
Posts: 15
Joined: Thu Jan 12, 2012 7:44 pm

Re: Can't jump into 0x10000 from protected mode

Post by sebastian93921 »

iansjack wrote:You tell the assembler, via an org directive, that you are going to load your kernel at 10000h. What do you do to ensure that it is loaded there rather than at some other address?
I just think that jmp 0x10000 which would be load there from the last file

because when my first file "boot.asm" loaded to "loader.asm" is also using jmp 0:0xEFFF to access there :(
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump into 0x10000 from protected mode

Post by iansjack »

Well, you load loader.bin to EF00, don't you. But, unless I'm missing something, I don't see you loading kernel.bin to 10000. In fact you concatenate the two files and load them to EF00; are you saying that the kernel.bin part of that concatenation file just happens to load to 10000?

And you only load two sectors, I think, which loads from EFFF to F3FF (I think floppy sectors are 512 bytes), so what is at 10000 is totally random. You need to move the kernel.bin part of the file to that address before jumping to it.

Or am I missing something?
sebastian93921
Posts: 15
Joined: Thu Jan 12, 2012 7:44 pm

Re: Can't jump into 0x10000 from protected mode

Post by sebastian93921 »

iansjack wrote:Well, you load loader.bin to EF00, don't you. But, unless I'm missing something, I don't see you loading kernel.bin to 10000. In fact you concatenate the two files and load them to EF00; are you saying that the kernel.bin part of that concatenation file just happens to load to 10000?

And you only load two sectors, I think, which loads from EFFF to F3FF (I think floppy sectors are 512 bytes), so what is at 10000 is totally random. You need to move the kernel.bin part of the file to that address before jumping to it.

Or am I missing something?
thx for reply, I think I'm haven't move the kernel.bin to that address 0x10000 (I can't found on the tutorial :( )
I found some solution to solve this problem, thx :)

EDIT: I found that I loaded the sector from 0xEFFF (the second loader), but now on the second stage I have to load the kernel, how can I load the kernel to 0x10000? :( thx
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can't jump into 0x10000 from protected mode

Post by iansjack »

This is now getting too close to spoon-feeding, so this will be my last post in this thread.

Think about what you are doing rather than trying to blindly follow a tutorial (which you are clearly not following anyway). You want to load some particular code from disk to a specific memory address. There are at least two ways you can do this:

1. Determine what sectors on your disk hold the code. Load them in the same way that you loaded loader.bin.

2. Do what you have done and create one file that contains loader.bin and kernel.bin. Load that to the address where loader.bin should reside then move the kernel.bin part to where you want it to reside.

Make your own choice and then implement it. Try to understand what you are doing and why you are doing it. If something isn't working than gather as much information as you can as to what is going wrong. Rather than making wild guesses, use a debugger to inspect memory and registers as the code executes. Think what should be happening and compare it with what is actually happening.

There is a limit to how useful it is to ask others to solve your problems. If you're not up to doing this yourself then consider whether OS development is the right hobby for you or whether it is just too difficult.
sebastian93921
Posts: 15
Joined: Thu Jan 12, 2012 7:44 pm

Re: Can't jump into 0x10000 from protected mode

Post by sebastian93921 »

iansjack wrote:This is now getting too close to spoon-feeding, so this will be my last post in this thread.

Think about what you are doing rather than trying to blindly follow a tutorial (which you are clearly not following anyway). You want to load some particular code from disk to a specific memory address. There are at least two ways you can do this:

1. Determine what sectors on your disk hold the code. Load them in the same way that you loaded loader.bin.

2. Do what you have done and create one file that contains loader.bin and kernel.bin. Load that to the address where loader.bin should reside then move the kernel.bin part to where you want it to reside.

Make your own choice and then implement it. Try to understand what you are doing and why you are doing it. If something isn't working than gather as much information as you can as to what is going wrong. Rather than making wild guesses, use a debugger to inspect memory and registers as the code executes. Think what should be happening and compare it with what is actually happening.

There is a limit to how useful it is to ask others to solve your problems. If you're not up to doing this yourself then consider whether OS development is the right hobby for you or whether it is just too difficult.
Thx for help, now I'm know how to load the kernel (within 0xFFFF) and loaded completely
but I found some article said it have to be reposition the address in protected mode if I want to move the kernel to 1M
how can I do this?

Now my progress is combine 2 stage of bootloader (boot.bin and preload.bin as 1 file), and move the kernel to 0xEFFF by the followings code

Code: Select all

load_kernel:			;reset floppy drive
	mov ah, 0x00		;
	int 0x13			;floppy drive interrupt
	or ah, ah			;if it's 0(return code)
	jnz load_kernel		;jump back
	
	mov ax, 0			;
	mov es,	ax			;reset extended segment
	mov bx,	0xEFFF		;load the kernel and move to 0x8:0xEFFF (08 as from GDT)
	
	mov ah, 0x02		;commend - "read sector from disk"			
	mov al, 0x04		;Number of sectors need to read	(512B x 4 = 2KB)			
	mov ch, 0			;disk cylinder
	mov cl, 0x02		;set sector (0x01 is bootloader)			
	mov dh, 0			;read from head 0
	int 0x13			;call floppy drive interrupt
	
	or ah, ah			;check error
	jnz load_kernel
As I knew that, 16bit program is just only accept up to 0xFFFF data. But in protected mode I can't use the interrupt :(
Last edited by sebastian93921 on Wed Feb 05, 2014 2:55 am, edited 1 time in total.
sebastian93921
Posts: 15
Joined: Thu Jan 12, 2012 7:44 pm

Re: Can't jump into 0x10000 from protected mode

Post by sebastian93921 »

All done, thx for help :)
Post Reply