Page 1 of 1

OS Development. Bootloader question

Posted: Wed Aug 27, 2014 2:56 pm
by Milnadar
Hello everyone. I started to study OS development and got stuck with bootloader.
In an old online course i've found there was a task
Trace through the first few instructions of the boot loader again and identify the first instruction that would "break" or otherwise do the wrong thing if you were to get the boot loader's link address wrong. Then change the link address in Makefile to something wrong, run make clean, recompile the lab with make, and trace into the boot loader again to see what happens. Don't forget to change the link address back and make clean again afterward!
So here is the bootloader code:

Code: Select all

start:
  cli                         # BIOS enabled interrupts; disable

  # Zero data segment registers DS, ES, and SS.
  xorw    %ax,%ax             # Set %ax to zero
  movw    %ax,%ds             # -> Data Segment
  movw    %ax,%es             # -> Extra Segment
  movw    %ax,%ss             # -> Stack Segment

  # Physical address line A20 is tied to zero so that the first PCs 
  # with 2 MB would run software that assumed 1 MB.  Undo that.
seta20.1:
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.1

  movb    $0xd1,%al               # 0xd1 -> port 0x64
  outb    %al,$0x64

seta20.2:
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.2

  movb    $0xdf,%al               # 0xdf -> port 0x60
  outb    %al,$0x60

  # Switch from real to protected mode.  Use a bootstrap GDT that makes
  # virtual addresses map directly to physical addresses so that the
  # effective memory map doesn't change during the transition.
  lgdt    gdtdesc
  movl    %cr0, %eax
  orl     $CR0_PE, %eax
  movl    %eax, %cr0

//PAGEBREAK!
  # Complete transition to 32-bit protected mode by using long jmp
  # to reload %cs and %eip.  The segment descriptors are set up with no
  # translation, so that the mapping is still the identity mapping.
  ljmp    $(SEG_KCODE<<3), $start32
.code32  # Tell assembler to generate 32-bit code now.
start32:
  # Set up the protected-mode data segment registers
  movw    $(SEG_KDATA<<3), %ax    # Our data segment selector
  movw    %ax, %ds                # -> DS: Data Segment
I changed link adress for bootloader to 0x7d00.
Also i did trace though this code, and it fails at the last line
ljmp $(SEG_KCODE<<3), $start32

My question is:
BIOS loads bootloader at phisical adress 0x7c00
All code before line "ljmp $(SEG_KCODE<<3), $start32" is switching from real mode to protected mode.
So why then ljump fails?

Thank you

Re: OS Development. Bootloader question

Posted: Wed Aug 27, 2014 3:14 pm
by alexfru
What is the offset that the assembler chooses/generates for the first instruction of your bootloader code? Is it implicitly set to 0 or is there some kind of an org (origin) directive that you're not showing us?

What are the segment base addresses in your GDT?

What is the address in your GDTR?

What is in the GDT?

When you answer these questions, you'll have more than 50% of the problem solved.

Re: OS Development. Bootloader question

Posted: Thu Aug 28, 2014 10:32 am
by Milnadar
alexfru wrote:What is the offset that the assembler chooses/generates for the first instruction of your bootloader code? Is it implicitly set to 0 or is there some kind of an org (origin) directive that you're not showing us?
It depends on a link adress i assign to a bootloader in a make file. So if for example as it says in a tas after i change adress to 0x7d00
disassembly will lok like this:

Code: Select all

Disassembly of section .text:

00007d00 <start>:
# with %cs=0 %ip=7c00.

.code16                       # Assemble for 16-bit mode
.globl start
start:
  cli                         # BIOS enabled interrupts; disable
    7d00:	fa                   	cli    

  # Zero data segment registers DS, ES, and SS.
  xorw    %ax,%ax             # Set %ax to zero
    7d01:	31 c0                	xor    %eax,%eax
  movw    %ax,%ds             # -> Data Segment
    7d03:	8e d8                	mov    %eax,%ds
  movw    %ax,%es             # -> Extra Segment
    7d05:	8e c0                	mov    %eax,%es
  movw    %ax,%ss             # -> Stack Segment
    7d07:	8e d0                	mov    %eax,%ss
Anf i don't know how to see what are values of GDT and GDTR

Re: OS Development. Bootloader question

Posted: Sat Aug 30, 2014 1:37 am
by hometue
Use bochs(compile with the debugging feature). It will help you a lot and can display your GDT and GDTR (and much more).

Re: OS Development. Bootloader question

Posted: Mon Sep 01, 2014 8:20 pm
by CelestialMechanic
Also, what is the value in SP? I do not see the stack pointer being loaded. It should be loaded right after the load of SS, as in:

Code: Select all

movw %ax, %ss
movw something, %sp
If you are lucky, no harm will be done, but since we live in a universe where Murphy's laws are rigorously enforced your stack could be writing over your GDT, IDT or even the BIOS's IVT.

Re: OS Development. Bootloader question

Posted: Tue Sep 02, 2014 5:29 am
by Icee
@CelestialMechanic
There is nothing in this code fragment that uses the stack, so your point is invalid.

In case the OP had not given up on this problem yet, I suggest having a closer look at the LGDT and LJMP instructions. How are they different from all other instructions in this fragment?

Re: OS Development. Bootloader question

Posted: Wed Sep 03, 2014 3:13 pm
by Milnadar
I've been reading about memory and also read similar questions asked by people.
So i think i started to understand a bit why it fails.

Bios loads bootloader into memory to adress 0x7c00, and also sets CS:IP to 0:0x7c00
After GDT is loaded, ljmp just resets CS:IP to 0x8:(and here IP will be whatewer what was in a makefile. In a normal case 0x7c00, or if you changed a value as i did to 0x7d00)
So adress of a next instruction will be transformed to a real aress, 0x7d00, when code is loaded to adress 0x7c00.
So at the begining, when bootloader is loaded, there is no difference what is a virtual adress, because BIOS sets CS:IP for us, and code will run untill LJMP instruction

Is that coreect?

Re: OS Development. Bootloader question

Posted: Wed Sep 03, 2014 8:27 pm
by CelestialMechanic
Icee wrote:@CelestialMechanic
There is nothing in this code fragment that uses the stack, so your point is invalid.
You have a point in that the code makes no intentional use of the stack (push, call, int, etc.) Yet the SS register has been set. Exceptions are not masked, the NMI is not maskable (by definition), there really needs to be a properly configured stack. The OP would have one if only he had loaded the SP register immediately after loading SS, for which Intel has provided an uninterruptible slot since the 8086. Murphy's laws have a way of being enforced.

I see this omission a lot these days. I suspect it's a case of cutting and pasting and then deleting the lines that are not understood.

Re: OS Development. Bootloader question

Posted: Thu Sep 04, 2014 3:51 am
by Icee
@CelestialMechanic
Strictly speaking, you are right, and I stand corrected. One could argue, though, that NMI is pretty much a one-way ticket and even if there is an installed handler and it returns control correctly, the execution is pretty much screwed anyway. The same Murphy law dictates that the NMI in question might very well have occurred because of memory corruption in the GDT, IDT or even the BIOS's IVT.

Also, the NMI is maskable, though this is by no means a good practice.

Re: OS Development. Bootloader question

Posted: Fri Sep 05, 2014 7:02 pm
by CelestialMechanic
Icee wrote:...

Also, the NMI is maskable, though this is by no means a good practice.
Quite right, I forgot about that. Thank you for the reminder. :D