Bug jumping from bootsect to kernel [SOLVED]

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.
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Bug jumping from bootsect to kernel [SOLVED]

Post by antoniovazquezblanco »

I'm starting with my own OS in an educational purpose. I just want to learn from this experience. The problem is that after researching and documenting myself I can't complete my boot sector as it can't jump to my kernel. I don't know where I failed but what I know is that I can reach protected mode and print some chars so I think that the error resider in the long jump to kernel. My source code is in github https://github.com/antoniovazquezblanco/FirebirdOS and the bug should be in bootsector/bootsector.s. Can it be a bug in GDT?
Thanks for your help and time.
I'm sorry if this is to noob to be posted here but I'm stuck.

Code: Select all

/********************************************************************************/
/*                                                                              */
/* FIREBIRD OS                                                                  */
/*                                                                              */
/* This is a simple asm bootloader for Firebird OS                              */
/*                                                                              */
/********************************************************************************/

#################################
# Main code...                  #
#################################

.code16
.text
.globl _start
.include "kernel/kernel.inc"
_start:

	/* BIOS will copy kernel to es:bx ... */
	pushw $KERNEL_POS_ES	#  KERNEL_POS_ES:KERNEL_POS_BX...
	popw %es
	movw $KERNEL_POS_BX, %bx

	/* Copy function settings... */
	movb $0x2, %ah		# Copy function...
	movb $KERNEL_SECT, %al	# Sectors to read...
	movb $0x0, %ch		# Cylinder 0...
	movb $0x2, %cl		# Sector 2...
	movb $0x0, %dh		# Head 0...
	movb $0x0, %dl		# Device 0...

	/* Read... */
	int $0x13
	jnc read_done

	/* Error reading... */
	call reset_floppy
	jnc _start		# Read again...

	/* Error reseting floppy... */
	jmp error		# Die...

read_done:

	/* Enable A20 gate... */
	cli             	# Clear interrupts...
	inb $0x92, %al  	# Open al to port 0x92...
	or $0x2, %al    	# Send value 0x2 to al...
	outb %al, $0x92 	# Close al port 0x92...
	sti             	# Re-enable interrupts...

	/* Move the GDT and load it... */
	movw $GDT_ADDR>>4, %ax
	movw %ax, %es
	movw $gdt, %si
	xorw %di, %di
	movw $GDT_SIZE>>2, %cx
	rep movsl
	lgdt gdtr

	/* Go protected mode... */
	cli
	movl %cr0, %eax
	or $1, %eax
	movl %eax, %cr0
	ljmp $CODE_SEL, $protected_mode

.code32
protected_mode:

	/* Jump to kernel... */
	ljmp $CODE_SEL, $((KERNEL_POS_ES<<4)+KERNEL_POS_BX)

.code16

	/* If we reach here something went wrong... */
error:
	movw $error_str, %si
	call print_string

	/* Halt execution if we reach here... */
halt:
	hlt
	jmp halt


#################################
# Functions...                  #
#################################

reset_floppy:
	push %ax	# We use ax and dx so save the values...
	push %dx
	movw $0x0, %ax
	movb $0x0, %dl	# Drive to reset...
	stc		# Activate cartage flag...
	int $0x13
	pop %dx		# Restore ax and dx...
	pop %ax
	ret

print_string:
	pusha
	movb $0xe, %ah	# Teletype function...
	.repeat:
	lodsb		# Get char from str...
	cmpb $0, %al	# End of string?
	je .done
	int $0x10	# Exec function...
	jmp .repeat	# Next char...
	.done:
	popa
	ret


#################################
# Data...                       #
#################################

error_str:
	.ascii "[!] Error booting Firebird OS...\0"


#################################
# GDT descriptor...             #
#################################

gdtr:
	gdtsize: .word gdt_end-gdt-1
	gdtbase: .long GDT_ADDR
gdt:
	/* Null descriptor... */
	.quad 0x0000000000000000

	/* Code segment with 4GB flat memory model... */
	.quad 0x00cf9a000000ffff

	/* Data segment with 4GB flat memory model... */
	.quad 0x00cf92000000ffff

	/* For future use... */
	.quad 0x0000000000000000
	.quad 0x0000000000000000
gdt_end:


#################################
# Boot signature...             #
#################################

.org 0x1fe
.word 0xaa55
Last edited by antoniovazquezblanco on Thu Apr 28, 2011 7:41 am, edited 2 times in total.
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bug jumping from bootsect to kernel

Post by DavidCooper »

If you post your bootsector code here, more people will look at it.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Re: Bug jumping from bootsect to kernel

Post by antoniovazquezblanco »

DavidCooper wrote:If you post your bootsector code here, more people will look at it.
Thanks!
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bug jumping from bootsect to kernel

Post by DavidCooper »

That's better - my antivirus isn't working properly at the moment so I'm avoiding downloading things.
antoniovazquezblanco wrote:

Code: Select all

	/* Enable A20 gate... */
	cli             	# Clear interrupts...
	inb $0x92, %al  	# Open al to port 0x92...
	or $0x2, %al    	# Send value 0x2 to al...
	outb %al, $0x92 	# Close al port 0x92...
	sti             	# Re-enable interrupts...
I don't recognise either this port or this method of enabling the A20. Can anyone confirm whether it's valid. I thought the only way of doing it was to send 209 (D1h) to port 100 (64h) followed by 223 (DFh) to port 96 (60h). Whatever the case though, it shouldn't be causing the problem here.

Code: Select all

	/* Move the GDT and load it... */
	movw $GDT_ADDR>>4, %ax
	movw %ax, %es
	movw $gdt, %si
	xorw %di, %di
	movw $GDT_SIZE>>2, %cx
	rep movsl
	lgdt gdtr
I'm not into assembler (I only do direct machine code programming), so I don't understand the >> part. Can someone who does understand it check to see if it's going to generate a sensible value to put in es given that di is set to 0. If it's dividing by 2 four times, it should be right, so long as the kernel's in the bottom 64KB of memory. [Edit: that should have said "so long as the GDT's to be placed in the bottom 64KB of memory"]

I'm not sure how assembler handles the lgdt instruction. Don't you have to tell it which register to use? The instruction translates into three actual instruction bytes, the third of which is an oo010mmm byte where the value of mmm relates to the register holding the address of the thing you've called gdtr. I suppose it must be working if you're getting into protected mode and prinnting char.s to the screen, but I'm really surprised that you don't have to put the address of gdtr into a register first and then line up the lgdt instruction on it. When you say that you can get into protected mode and print char.s, I presume you don't mean by using your print_string routine, because it shouldn't work from protected mode. Can you confirm that you have successfully sent values directly to the screen at B8000 while in protected mode?

Code: Select all

gdt:
	/* Null descriptor... */
	.quad 0x0000000000000000

	/* Code segment with 4GB flat memory model... */
	.quad 0x00cf9a000000ffff

	/* Data segment with 4GB flat memory model... */
	.quad 0x00cf92000000ffff

	/* For future use... */
	.quad 0x0000000000000000
	.quad 0x0000000000000000
gdt_end:
That looks fine, assuming that each entry ends up in memory with the ffff end first.

Assuming that you are getting into protected mode, have you tried reading memory in the place where your kernel is supposed to be loaded to check that it is actually there? Of course, you'll need to have some way of recognising it, so you may need to put some ASKII into it at some specific location so that you can just read from the appropriate address and print them straight to the screen. (Remember too that every second screen byte is a colour value.)

By the way, it's a good idea to send something to the screen from time to time as you load and set up your OS - that lets you see where it's breaking if it goes wrong, and it may go wrong in some way at any point if you run it on different hardware or within a PC simulator like Bochs. Leaving in these progress markers saves you from having to keep putting them back in every time something stops working.

Code: Select all

	ljmp $CODE_SEL, $protected_mode

.code32
protected_mode:

	/* Jump to kernel... */
	ljmp $CODE_SEL, $((KERNEL_POS_ES<<4)+KERNEL_POS_BX)
Again I'm at a disadvantage here as I don't use assembler, but I can't see any sign that you're using the segment register value relating to your first proper GDT entry, which should be 8. In each case you should be generating a far jump instruction (234 in decimal) followed by a four-byte address followed by two bytes for the segment which are an 8 and a 0. That should show up in a disassembler if your jump code is correct.
Last edited by DavidCooper on Mon Apr 25, 2011 7:45 pm, edited 1 time in total.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
DLBuunk
Member
Member
Posts: 39
Joined: Sun May 18, 2008 9:36 am
Location: The Netherlands

Re: Bug jumping from bootsect to kernel

Post by DLBuunk »

Are you sure your kernel loads properly? Have you tried replacing the kernel with a few chars and tried to print those? The loading code seems buggy.

Oh, and you don't initialize the segment registers. Are you sure ds is 0 when you do the "rep movsl" ?
DavidCooper wrote:I'm not into assembler (I only do direct machine code programming), so I don't understand the >> part. Can someone who does understand it check to see if it's going to generate a sensible value to put in es given that di is set to 0. If it's dividing by 2 four times, it should be right, so long as the kernel's in the bottom 64KB of memory.
It is shifting the value to the right 4 times, so it is okay.
DavidCooper wrote:I'm not sure how assembler handles the lgdt instruction. Don't you have to tell it which register to use? The instruction translates into three actual instruction bytes, the third of which is an oo010mmm byte where the value of mmm relates to the register holding the address of the thing you've called gdtr.
In my bootloader it isn't using a register either and my kernel starts okay, so lgdt seemingly accepts non-register values as well.
DavidCooper wrote:Again I'm at a disadvantage here as I don't use assembler, but I can't see any sign that you're using the segment register value relating to your first proper GDT entry, which should be 8. In each case you should be generating a far jump instruction (234 in decimal) followed by a four-byte address followed by two bytes for the segment which are an 8 and a 0. That should show up in a disassembler if your jump code is correct.
This code is correct.
(Although the first jump has some problem, as you cannot be sure cs:ip starts as 0x0000:0x7C00, you might want to do a ljmp 0x0000,0x7C05 as first instruction)
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Re: Bug jumping from bootsect to kernel

Post by antoniovazquezblanco »

DavidCooper wrote:That's better - my antivirus isn't working properly at the moment so I'm avoiding downloading things.
No need to download things. GitHub lets you see the code online ;).
DavidCooper wrote:
antoniovazquezblanco wrote:

Code: Select all

	/* Enable A20 gate... */
	cli             	# Clear interrupts...
	inb $0x92, %al  	# Open al to port 0x92...
	or $0x2, %al    	# Send value 0x2 to al...
	outb %al, $0x92 	# Close al port 0x92...
	sti             	# Re-enable interrupts...
I don't recognise either this port or this method of enabling the A20. Can anyone confirm whether it's valid. I thought the only way of doing it was to send 209 (D1h) to port 100 (64h) followed by 223 (DFh) to port 96 (60h). Whatever the case though, it shouldn't be causing the problem here.
I'll have a look to this in other moment. Thanks for your advice :).

Code: Select all

	/* Move the GDT and load it... */
	movw $GDT_ADDR>>4, %ax
	movw %ax, %es
	movw $gdt, %si
	xorw %di, %di
	movw $GDT_SIZE>>2, %cx
	rep movsl
	lgdt gdtr
I'm not into assembler (I only do direct machine code programming), so I don't understand the >> part. Can someone who does understand it check to see if it's going to generate a sensible value to put in es given that di is set to 0. If it's dividing by 2 four times, it should be right, so long as the kernel's in the bottom 64KB of memory.

I'm not sure how assembler handles the lgdt instruction. Don't you have to tell it which register to use? The instruction translates into three actual instruction bytes, the third of which is an oo010mmm byte where the value of mmm relates to the register holding the address of the thing you've called gdtr. I suppose it must be working if you're getting into protected mode and prinnting char.s to the screen, but I'm really surprised that you don't have to put the address of gdtr into a register first and then line up the lgdt instruction on it. When you say that you can get into protected mode and print char.s, I presume you don't mean by using your print_string routine, because it shouldn't work from protected mode. Can you confirm that you have successfully sent values directly to the screen at B8000 while in protected mode?
I'm not sure whether this is ok or not. As I mentioned I'm quite n00b and just don't really know if this is ok. I think I must have programmed this taking only the values in my gdtr descriptor instead of taking any constants of the include file. That should reduce the complex of the code. I can confirm I could print some chars to screen using this code situated after the protected_mode: addr

Code: Select all

movw $0x2046, 0xb8000
movw $0x2069, 0xb8002
movw $0x2072, 0xb8004
movw $0x2065, 0xb8006
movw $0x2062, 0xb8008
movw $0x2069, 0xb800a
movw $0x2072, 0xb800c
movw $0x2064, 0xb800e
movw $0x2020, 0xb8010
movw $0x204f, 0xb8012
movw $0x2053, 0xb8014
jmp .


Code: Select all

gdt:
	/* Null descriptor... */
	.quad 0x0000000000000000

	/* Code segment with 4GB flat memory model... */
	.quad 0x00cf9a000000ffff

	/* Data segment with 4GB flat memory model... */
	.quad 0x00cf92000000ffff

	/* For future use... */
	.quad 0x0000000000000000
	.quad 0x0000000000000000
gdt_end:
That looks fine, assuming that each entry ends up in memory with the ffff end first.
This is ok :).
Assuming that you are getting into protected mode, have you tried reading memory in the place where your kernel is supposed to be loaded to check that it is actually there? Of course, you'll need to have some way of recognising it, so you may need to put some ASKII into it at some specific location so that you can just read from the appropriate address and print them straight to the screen. (Remember too that every second screen byte is a colour value.)
I didn't try this but I'll maybe do when I have some more time. It is just I cant spend a lot of time with this...
By the way, it's a good idea to send something to the screen from time to time as you load and set up your OS - that lets you see where it's breaking if it goes wrong, and it may go wrong in some way at any point if you run it on different hardware or within a PC simulator like Bochs. Leaving in these progress markers saves you from having to keep putting them back in every time something stops working.
Thanks for the hint. I agree with you ;)

Code: Select all

	ljmp $CODE_SEL, $protected_mode

.code32
protected_mode:

	/* Jump to kernel... */
	ljmp $CODE_SEL, $((KERNEL_POS_ES<<4)+KERNEL_POS_BX)
Again I'm at a disadvantage here as I don't use assembler, but I can't see any sign that you're using the segment register value relating to your first proper GDT entry, which should be 8. In each case you should be generating a far jump instruction (234 in decimal) followed by a four-byte address followed by two bytes for the segment which are an 8 and a 0. That should show up in a disassembler if your jump code is correct.
[/quote]

I think this is ok but I can't tell you with total security. In hex what this produces is: EA (234) 00 00 01 00 08 00

Finally I've got one more question. I didn't set the stack at the begining of my codde but I'm using pushw and popw, can this crash? Thanks!

Code: Select all

.code16
.text
.globl _start
.include "kernel/kernel.inc"
_start:

   /* BIOS will copy kernel to es:bx ... */
   pushw $KERNEL_POS_ES   #  KERNEL_POS_ES:KERNEL_POS_BX...
   popw %es
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Re: Bug jumping from bootsect to kernel

Post by antoniovazquezblanco »

The current code is:

Code: Select all

/********************************************************************************/
/*                                                                              */
/* FIREBIRD OS                                                                  */
/*                                                                              */
/* This is a simple asm bootloader for Firebird OS                              */
/*                                                                              */
/********************************************************************************/

#################################
# Main code...                  #
#################################

.code16
.text
.globl _start
.include "kernel/kernel.inc"
_start:
	/* Initialize segment registers... */
	ljmp $0x0000, $0x7C05
	xorw %ax, %ax
	movw %ax, %ds
	movw %ax, %ss
	movw $0x7c00, %sp


	/* BIOS will copy kernel to es:bx ... */
	pushw $KERNEL_POS_ES	#  KERNEL_POS_ES:KERNEL_POS_BX...
	popw %es
	movw $KERNEL_POS_BX, %bx

	/* Copy function settings... */
	movb $0x2, %ah		# Copy function...
	movb $KERNEL_SECT, %al	# Sectors to read...
	movb $0x0, %ch		# Cylinder 0...
	movb $0x2, %cl		# Sector 2...
	movb $0x0, %dh		# Head 0...
	movb $0x0, %dl		# Device 0...

	/* Read... */
	int $0x13
	jnc read_done

	/* Error reading... */
	call reset_floppy
	jnc _start		# Read again...

	/* Error reseting floppy... */
	jmp error		# Die...

read_done:

	/* Enable A20 gate... */
	cli             	# Clear interrupts...
	inb $0x92, %al  	# Open al to port 0x92...
	or $0x2, %al    	# Send value 0x2 to al...
	outb %al, $0x92 	# Close al port 0x92...
	sti             	# Re-enable interrupts...

	/* Move the GDT and load it... */
	movw $GDT_ADDR>>4, %ax
	movw %ax, %es
	movw $gdt, %si
	xorw %di, %di
	movw $GDT_SIZE>>2, %cx
	rep movsl
	lgdt gdtr

	/* Go protected mode... */
	cli
	movl %cr0, %eax
	or $1, %eax
	movl %eax, %cr0
	ljmp $CODE_SEL, $protected_mode

.code32
protected_mode:

	/* Jump to kernel... */
	ljmp $CODE_SEL, $((KERNEL_POS_ES<<4)+KERNEL_POS_BX)

.code16

	/* If we reach here something went wrong... */
error:
	movw $error_str, %si
	call print_string

	/* Halt execution if we reach here... */
halt:
	hlt
	jmp halt


#################################
# Functions...                  #
#################################

reset_floppy:
	push %ax	# We use ax and dx so save the values...
	push %dx
	movw $0x0, %ax
	movb $0x0, %dl	# Drive to reset...
	stc		# Activate cartage flag...
	int $0x13
	pop %dx		# Restore ax and dx...
	pop %ax
	ret

print_string:
	pusha
	movb $0xe, %ah	# Teletype function...
	.repeat:
	lodsb		# Get char from str...
	cmpb $0, %al	# End of string?
	je .done
	int $0x10	# Exec function...
	jmp .repeat	# Next char...
	.done:
	popa
	ret


#################################
# Data...                       #
#################################

error_str:
	.ascii "[!] Error booting Firebird OS...\0"


#################################
# GDT descriptor...             #
#################################

gdtr:
	gdtsize: .word gdt_end-gdt-1
	gdtbase: .long GDT_ADDR
gdt:
	/* Null descriptor... */
	.quad 0x0000000000000000

	/* Code segment with 4GB flat memory model... */
	.quad 0x00cf9a000000ffff

	/* Data segment with 4GB flat memory model... */
	.quad 0x00cf92000000ffff

	/* For future use... */
	.quad 0x0000000000000000
	.quad 0x0000000000000000
gdt_end:


#################################
# Boot signature...             #
#################################

.org 0x1fe
.word 0xaa55
About whether the reading part is ok I just can't be sure, but I would say yes.
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Re: Bug jumping from bootsect to kernel

Post by antoniovazquezblanco »

DavidCooper wrote:
antoniovazquezblanco wrote:

Code: Select all

	/* Enable A20 gate... */
	cli             	# Clear interrupts...
	inb $0x92, %al  	# Open al to port 0x92...
	or $0x2, %al    	# Send value 0x2 to al...
	outb %al, $0x92 	# Close al port 0x92...
	sti             	# Re-enable interrupts...
I don't recognise either this port or this method of enabling the A20. Can anyone confirm whether it's valid. I thought the only way of doing it was to send 209 (D1h) to port 100 (64h) followed by 223 (DFh) to port 96 (60h). Whatever the case though, it shouldn't be causing the problem here.
Have a look at this http://wiki.osdev.org/A20_Line#Fast_A20_Gate
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bug jumping from bootsect to kernel

Post by DavidCooper »

DLBuunk wrote:Oh, and you don't initialize the segment registers. Are you sure ds is 0 when you do the "rep movsl" ?
That's a good point - I was thinking he hadn't used any instructions that needed them set, but he did.
In my bootloader it isn't using a register either and my kernel starts okay, so lgdt seemingly accepts non-register values as well.
Ah, it must be able to take an immediate address if a certain value's put into the oo010mmm byte.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bug jumping from bootsect to kernel

Post by DavidCooper »

antoniovazquezblanco wrote:I'm not sure whether this is ok or not. As I mentioned I'm quite n00b and just don't really know if this is ok. I think I must have programmed this taking only the values in my gdtr descriptor instead of taking any constants of the include file. That should reduce the complex of the code.
Leave that bit as is - your lgdt code works, and clearly you are getting into protected mode successfully as your print code shows.
I think this is ok but I can't tell you with total security. In hex what this produces is: EA (234) 00 00 01 00 08 00
That's going to jump to the start of the second block of 64KB of memory (10000h).
Finally I've got one more question. I didn't set the stack at the begining of my code but I'm using pushw and popw, can this crash? Thanks!
It's unlikely to cause a problem unless the BIOS has put the stack somewhere ridiculous, but you might as well set up your own stack right at the start, then do a jump to make CS=0 and load the other segment registers with 0 - if you do this it'll make it easier for you if you put extra bits of test code in the boot sector for some reason later on, even if it's unnecessary at the moment.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bug jumping from bootsect to kernel

Post by DavidCooper »

antoniovazquezblanco wrote:Have a look at this http://wiki.osdev.org/A20_Line#Fast_A20_Gate
That's fine then, so long as you don't use it on an older machine.

So, it looks as if your bootsector should work, but we need to know if it actually does, so have you tried printing to the screen from the start of your kernel?

By the way, I've tried downloading the source and don't have a suitable program to read it with. I can't find any way to read it at the site you linked to without downloading it either, so I haven't seen the kernel. Perhaps it would be worth posting the start of it here too after you've added some code to the start of it to print to the screen. It may be that you've tried this already and done something as simple as forgetting to set ds and es to 10h.

I don't know if you've tried running your code within Bochs (a PC simulator), but it might help identify the problem: http://bochs.sourceforge.net/getcurrent.html - clicking on "see all releases" is the actual link to the download.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Re: Bug jumping from bootsect to kernel

Post by antoniovazquezblanco »

DavidCooper wrote:
DLBuunk wrote:Oh, and you don't initialize the segment registers. Are you sure ds is 0 when you do the "rep movsl" ?
That's a good point - I was thinking he hadn't used any instructions that needed them set, but he did.
Solved, look at the first lines in the last code :).
In my bootloader it isn't using a register either and my kernel starts okay, so lgdt seemingly accepts non-register values as well.
Ah, it must be able to take an immediate address if a certain value's put into the oo010mmm byte.
DavidCooper wrote:
antoniovazquezblanco wrote:I'm not sure whether this is ok or not. As I mentioned I'm quite n00b and just don't really know if this is ok. I think I must have programmed this taking only the values in my gdtr descriptor instead of taking any constants of the include file. That should reduce the complex of the code.
Leave that bit as is - your lgdt code works, and clearly you are getting into protected mode successfully as your print code shows.
So GDT is ok. Thanks!
I think this is ok but I can't tell you with total security. In hex what this produces is: EA (234) 00 00 01 00 08 00
That's going to jump to the start of the second block of 64KB of memory (10000h).
Fine!
Finally I've got one more question. I didn't set the stack at the begining of my code but I'm using pushw and popw, can this crash? Thanks!
It's unlikely to cause a problem unless the BIOS has put the stack somewhere ridiculous, but you might as well set up your own stack right at the start, then do a jump to make CS=0 and load the other segment registers with 0 - if you do this it'll make it easier for you if you put extra bits of test code in the boot sector for some reason later on, even if it's unnecessary at the moment.
Done!

This code produces the next screenshot:

Code: Select all

/********************************************************************************/
/*                                                                              */
/* FIREBIRD OS                                                                  */
/*                                                                              */
/* This is a simple asm bootloader for Firebird OS                              */
/*                                                                              */
/********************************************************************************/

#################################
# Main code...                  #
#################################

.code16
.text
.globl _start
.include "kernel/kernel.inc"
_start:
	/* Initialize segment registers... */
	ljmp $0x0000, $0x7C05
	xorw %ax, %ax
	movw %ax, %ds
	movw %ax, %ss
	movw $0x7c00, %sp


	/* BIOS will copy kernel to es:bx ... */
	pushw $KERNEL_POS_ES	#  KERNEL_POS_ES:KERNEL_POS_BX...
	popw %es
	movw $KERNEL_POS_BX, %bx

	/* Copy function settings... */
	movb $0x2, %ah		# Copy function...
	movb $KERNEL_SECT, %al	# Sectors to read...
	movb $0x0, %ch		# Cylinder 0...
	movb $0x2, %cl		# Sector 2...
	movb $0x0, %dh		# Head 0...
	movb $0x0, %dl		# Device 0...

	/* Read... */
	int $0x13
	jnc read_done

	/* Error reading... */
	call reset_floppy
	jnc _start		# Read again...

	/* Error reseting floppy... */
	jmp error		# Die...

read_done:

	/* Enable A20 gate... */
	cli             	# Clear interrupts...
	inb $0x92, %al  	# Open al to port 0x92...
	or $0x2, %al    	# Send value 0x2 to al...
	outb %al, $0x92 	# Close al port 0x92...
	sti             	# Re-enable interrupts...

	/* Move the GDT and load it... */
	movw $GDT_ADDR>>4, %ax
	movw %ax, %es
	movw $gdt, %si
	xorw %di, %di
	movw $GDT_SIZE>>2, %cx
	rep movsl
	lgdt gdtr

	/* Go protected mode... */
	cli
	movl %cr0, %eax
	or $1, %eax
	movl %eax, %cr0
	ljmp $CODE_SEL, $protected_mode

.code32
protected_mode:

	/* Debug... */
	movw $0x2046, 0xb8000

	/* Jump to kernel... */
	ljmp $CODE_SEL, $((KERNEL_POS_ES<<4)+KERNEL_POS_BX)

.code16

	/* If we reach here something went wrong... */
error:
	movw $error_str, %si
	call print_string

	/* Halt execution if we reach here... */
halt:
	hlt
	jmp halt


#################################
# Functions...                  #
#################################

reset_floppy:
	push %ax	# We use ax and dx so save the values...
	push %dx
	movw $0x0, %ax
	movb $0x0, %dl	# Drive to reset...
	stc		# Activate cartage flag...
	int $0x13
	pop %dx		# Restore ax and dx...
	pop %ax
	ret

print_string:
	pusha
	movb $0xe, %ah	# Teletype function...
	.repeat:
	lodsb		# Get char from str...
	cmpb $0, %al	# End of string?
	je .done
	int $0x10	# Exec function...
	jmp .repeat	# Next char...
	.done:
	popa
	ret


#################################
# Data...                       #
#################################

error_str:
	.ascii "[!] Error booting Firebird OS...\0"


#################################
# GDT descriptor...             #
#################################

gdtr:
	gdtsize: .word gdt_end-gdt-1
	gdtbase: .long GDT_ADDR
gdt:
	/* Null descriptor... */
	.quad 0x0000000000000000

	/* Code segment with 4GB flat memory model... */
	.quad 0x00cf9a000000ffff

	/* Data segment with 4GB flat memory model... */
	.quad 0x00cf92000000ffff

	/* For future use... */
	.quad 0x0000000000000000
	.quad 0x0000000000000000
gdt_end:


#################################
# Boot signature...             #
#################################

.org 0x1fe
.word 0xaa55
Pantallazo-QEMU - Press Ctrl-Alt to exit mouse grab.png
Pantallazo-QEMU - Press Ctrl-Alt to exit mouse grab.png (11.4 KiB) Viewed 3695 times
About the kernel:

Code: Select all

/********************************************************************************/
/*                                                                              */
/* FIREBIRD OS                                                                  */
/*                                                                              */
/* This is a simple asm testing kernel for Firebird OS                          */
/*                                                                              */
/********************************************************************************/

.text
.globl _start
.include "kernel/kernel.inc"
.org 0

_start:
	movw DATA_SEL, %ax
        movw %ax, %ds
        movw %ax, %es
        movw %ax, %fs
        movw %ax, %gs
        movw %ax, %ss
        movl $STACK_BOT, %esp

        movw $0x2046, 0xb8000
        movw $0x2069, 0xb8002
        movw $0x2072, 0xb8004
        movw $0x2065, 0xb8006
        movw $0x2062, 0xb8008
        movw $0x2069, 0xb800a
        movw $0x2072, 0xb800c
        movw $0x2064, 0xb800e
        movw $0x2020, 0xb8010
        movw $0x204f, 0xb8012
        movw $0x2053, 0xb8014
halt:
	hlt
	jmp halt
About watching the code online just click the folders or files and it will appear. You can also use git as it is a git repo and about opening files, they are just plain text, you can open them with any editor and compile them with make. Check the makefile for seeing the requeriments (gcc, as, ld, cat and for testing qemu). Thanks!
DLBuunk
Member
Member
Posts: 39
Joined: Sun May 18, 2008 9:36 am
Location: The Netherlands

Re: Bug jumping from bootsect to kernel

Post by DLBuunk »

Well, you DO end up in pmode. And the jump seems okay, but the dummy kernel isn't executing.
I suggest you replace the kernel with some chars and than do something like (before the jump to the kernel):

Code: Select all

        movw    $0x0700,%ax
        movb    0x10000,%al
        movw    %ax,$0xB8000
If this works, your code is loaded and the problem is with the jump.
If this does not work you should figure out where the kernel ends up in memory, if anywhere. (use bochs build-in debugger!, (I am not sure if qemu has one))
antoniovazquezblanco
Member
Member
Posts: 25
Joined: Sun Apr 24, 2011 1:37 pm

Re: Bug jumping from bootsect to kernel

Post by antoniovazquezblanco »

DLBuunk wrote:Well, you DO end up in pmode. And the jump seems okay, but the dummy kernel isn't executing.
I suggest you replace the kernel with some chars and than do something like (before the jump to the kernel):

Code: Select all

        movw    $0x0700,%ax
        movb    0x10000,%al
        movw    %ax,$0xB8000
If this works, your code is loaded and the problem is with the jump.
If this does not work you should figure out where the kernel ends up in memory, if anywhere. (use bochs build-in debugger!, (I am not sure if qemu has one))
I've used:

Code: Select all

movw    $0x0700,%ax
movb    0x10000,%al
movw    %ax, 0xB8000
and put some 44 44 44 (D D D) in my kernel but it printed a white and strange dot...

About the debugger I've found this! :)
http://wiki.osdev.org/QEMU

I will have a look! :D
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Bug jumping from bootsect to kernel

Post by DavidCooper »

antoniovazquezblanco wrote:

Code: Select all

	/* Debug... */
	movw $0x2046, 0xb8000
Capital F in top left corner with green background - so it's worked up to here, even though ds and es haven't been given protected mode values. I don't know how this instruction has worked out what segment to use with b8000, but maybe it just uses absolute addresses until proper segments are loaded. Then again, you're using Qemu, so it might cause a crash on real hardware.

Code: Select all

	/* Jump to kernel... */
	ljmp $CODE_SEL, $((KERNEL_POS_ES<<4)+KERNEL_POS_BX)
And we already know that this is producing the right code to jump to the kernel, so it looks as if your kernel code must be running, if it's there.
.text
.globl _start
.include "kernel/kernel.inc"
.org 0
Why .org 0? Wouldn't that be setting up the kernel code to run at the bottom of memory rather than at 10000h? I don't think that will affect the actual code that follows.

Code: Select all

_start:
	movw DATA_SEL, %ax
        movw %ax, %ds
        movw %ax, %es
        movw %ax, %fs
        movw %ax, %gs
        movw %ax, %ss
        movl $STACK_BOT, %esp
That looks fine, except that I've found this:-
.set STACK_BOT, 0xa0000 # Stack starts at 640K and grows downside...
That will make your stack trash the EBDA (extended BIOS data area) - you might want to avoid doing this so that you can return to real mode to use the BIOS again, and you will want to do this at some point to collect a whole lot of information from the BIOS about the way the machine has been set up.

Code: Select all

        movw $0x2046, 0xb8000
        movw $0x2069, 0xb8002
        movw $0x2072, 0xb8004
        movw $0x2065, 0xb8006
        movw $0x2062, 0xb8008
        movw $0x2069, 0xb800a
        movw $0x2072, 0xb800c
        movw $0x2064, 0xb800e
        movw $0x2020, 0xb8010
        movw $0x204f, 0xb8012
        movw $0x2053, 0xb8014
halt:
	hlt
	jmp halt
That looks as if it should work. I was going to suggest putting a delay loop after it in case it was being overwritten before you have a chance to see it, but I imagine a halt loop would do the same job (though I've never used the halt instruction myself).
About watching the code online just click the folders or files and it will appear. You can also use git as it is a git repo and about opening files, they are just plain text, you can open them with any editor and compile them with make. Check the makefile for seeing the requeriments (gcc, as, ld, cat and for testing qemu). Thanks!
I've found out how it works now - I clicked on things before and just got a blank screen, but it's working now. As for the downloaded version, I tried looking at it with notepad and wordpad and just got gibberish, but I can just explore the code online instead.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
Post Reply