bootloader?

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.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: bootloader?

Post by Brendan »

Hi,
Love4Boobies wrote:As far as BAIDs go, only the first HD and FD are valid IPL devices (that means 00H and 80H). The workaround is having a PnP BIOS; that way any INT 13H drive can be used for booting.
Using something like GRUB, it's easy to boot/chain-load the MBR on any device (note: I don't mean the multi-boot thing here). For example, a GRUB script to boot the second floppy disk would look something like this:

Code: Select all

title Boot Second Floppy
rootnoverify (fd1)
chainloader +1
boot
All decent boot managers can chain-load any MBR (from any device). It's even possible to have several different boot managers (on several different devices) that are all setup to boot each other. That way you can play "hide and seek" with your OS (e.g. see how many boot managers other people go through until they find one that boots an OS ;) ).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: bootloader?

Post by neon »

But I havn't found a good way of debugging this because I have read that the carry could be set even though the floppy disk was read.
What I usually do when writing disk reading or filesystem reading code is dumping a few bytes from the address that it is being read to both before and after reading it to see if it changes and if the changes in the bytes look correct.

If the values remain the same, either it is being loaded at the wrong address or not being loaded at all. If the bytes do change after the read, it is reading to the correct address but the wrong sector from disk.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Love4Boobies
Member
Member
Posts: 2111
Joined: Fri Mar 07, 2008 5:36 pm
Location: Bucharest, Romania

Re: bootloader?

Post by Love4Boobies »

Brendan wrote:Hi,
Love4Boobies wrote:As far as BAIDs go, only the first HD and FD are valid IPL devices (that means 00H and 80H). The workaround is having a PnP BIOS; that way any INT 13H drive can be used for booting.
Using something like GRUB, it's easy to boot/chain-load the MBR on any device (note: I don't mean the multi-boot thing here). For example, a GRUB script to boot the second floppy disk would look something like this:

Code: Select all

title Boot Second Floppy
rootnoverify (fd1)
chainloader +1
boot
All decent boot managers can chain-load any MBR (from any device). It's even possible to have several different boot managers (on several different devices) that are all setup to boot each other. That way you can play "hide and seek" with your OS (e.g. see how many boot managers other people go through until they find one that boots an OS ;) ).


Cheers,

Brendan
I know. However, there's no *standard* for chainloading. People usually pass the drive number in DL, but no one sais you can depend on that, it's more like an unwritten convention.
"Computers in the future may weigh no more than 1.5 tons.", Popular Mechanics (1949)
[ Project UDI ]
User avatar
Sam111
Member
Member
Posts: 385
Joined: Mon Nov 03, 2008 6:06 pm

Re: bootloader?

Post by Sam111 »

I have another question if I use the int 13 the way I am using it previously it has an 8G barrier on it.

So if I change it to use the int 13 extended


sample code

Code: Select all

jmp start
packet: 
sizeofpacket            db 10h         ;size of this packet counting this byte
reserved                db 0h          ;reserved always zero
numofblockstotransfer   dw 0x44        ; number of blocks to transfer to transfer buffer address (  number of sectors to transfer) 
transferbufferaddress   dd 0x11111111  ; the starting memory address to use for read data into
startingLBA             dq 6454564645  ;starting absolute block number (the disk LBA to read )


start:
mov ah , 42h    ;int 13 extension function to get over 8G barrier
mov dl , 80h    ;primary harddisk
mov si , packet ;point si to the disk packet ds:si -> packet
ignore for the moment the values for the packet.

I am wondering when you define a label like packet
and do

Code: Select all

mov si , packet
does that mov the memory location of sizeofpacket into it or one less.

Another words in the sample code
is it

Code: Select all

mov si , packet
or

Code: Select all

mov si , packet
add si , 1 
Does the label actually have a value to it like zero. Or when nasm compiles it just makes the first thing after the label the memory address associated to this label.

I hope I am not confusing you with what I am trying to say.
I know I could just mov si , sizeofpacket but I was wondering if I could use a label (that has a better ring to it like packet)
User avatar
Love4Boobies
Member
Member
Posts: 2111
Joined: Fri Mar 07, 2008 5:36 pm
Location: Bucharest, Romania

Re: bootloader?

Post by Love4Boobies »

Code: Select all

label1:
.var: db 00h

label2:
.var: dw 00h
here, label1.var is the same as label1. label2.var is the offset of the least significant byte, that is label2+1. label2 is the most significant byte. this happens because x86 is little-endian.
"Computers in the future may weigh no more than 1.5 tons.", Popular Mechanics (1949)
[ Project UDI ]
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: bootloader?

Post by Brendan »

Hi,
Love4Boobies wrote:I know. However, there's no *standard* for chainloading. People usually pass the drive number in DL, but no one sais you can depend on that, it's more like an unwritten convention.
Sure, but if a boot manager doesn't pass the drive number in DL, then the boot manager is broken (not the OS developer's problem)...


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Sam111
Member
Member
Posts: 385
Joined: Mon Nov 03, 2008 6:06 pm

Re: bootloader?

Post by Sam111 »

I am still wondering
about

Code: Select all

jmp start
packet: 
sizeofpacket            db 10h         ;size of this packet counting this byte
reserved                db 0h          ;reserved always zero
numofblockstotransfer   dw 0x44        ; number of blocks to transfer to transfer buffer address (  number of sectors to transfer) 
transferbufferaddress   dd 0x11111111  ; the starting memory address to use for read data into
startingLBA             dq 6454564645  ;starting absolute block number (the disk LBA to read )


start:
mov ah , 42h    ;int 13 extension function to get over 8G barrier
mov dl , 80h    ;primary harddisk
mov si , packet ;point si to the disk packet ds:si -> packet

does doing mov si , packet
move the memory location of sizeofpacket into si?

what is the difference between

Code: Select all

mov si , packet  
and

Code: Select all

mov si , sizeofpacket 
I don't understand when you move a label into a register that isn't a varable. What address does it move into the register. Because a label isn't really a machine code instruction and it isn't a varable either so what is it convert to location wise?

similarly

Code: Select all

label:
jmp label

Is the address of the jmp command so it just jumps nowhere back to itself every time.
or does it jump one address up from the jump command. Because if this is the case then

Code: Select all

packet:
is like an uninitialized variable. And mov si , packet would be off by one? #-o #-o #-o

To put it in your terms

Code: Select all

label1:
var1: db 00h

label2:
var2: dw 00h
mov si , label1
mov si , label2
;are the next to lines the same as the previous 2
mov si , var1
mov si , var2
removing the dots from var
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: bootloader?

Post by Brendan »

Hi,
Sam111 wrote:what is the difference between

Code: Select all

mov si , packet  
and

Code: Select all

mov si , sizeofpacket 
The only difference is code readability - "mov si,packet" loads the address of a structure into SI, while "mov si,sizeofpacket" loads the address of the first field in the structure into SI. In practice it's exactly the same address.
Sam111 wrote:I don't understand when you move a label into a register that isn't a varable. What address does it move into the register. Because a label isn't really a machine code instruction and it isn't a varable either so what is it convert to location wise?
A label is something that assigns a name to an address. From the assembler's point of view, there's no such thing as a variable (there's just the contents of memory at an address, where that address may have been assigned a name with a label).

For example, consider this:

Code: Select all

   org 0x1234
foo:                ;Assembler assigns the name "foo" to the address 0x1234

    mov eax,[foo]   ;Assembler replaces the name "foo" with the address 0x1234
    lgdt [foo]      ;Assembler replaces the name "foo" with the address 0x1234
    mov esi,foo     ;Assembler replaces the name "foo" with the address 0x1234
Sam111 wrote:

Code: Select all

label:
jmp label

Is the address of the jmp command so it just jumps nowhere back to itself every time.
or does it jump one address up from the jump command. Because if this is the case then

Code: Select all

packet:
is like an uninitialized variable. And mov si , packet would be off by one? #-o #-o #-o

There's no bytes of code or data between "label:" and "jmp label", so the "label" is the address of the jump instruction.

Now consider this:

Code: Select all

    org 0x1234

myLabel:

%ifdef FOO
 %define Woot BAR
%endif

%macro DING_DING_DING 0
    section .bss
%%yip:
    resb 123
%%yap:
    resd %%yip - %%yap
    section .text
%endmacro

%macro DING_DING_DONG 1
    section .bss
%%yip:
    resb %1
%%yap:
    resd %%yip - %%yap
    section .text
%endmacro

   DING_DING_DING
   DING_DING_DONG 777
   DING_DING_DING
   DING_DING_DONG 777

   jmp myLabel
In this case, there's *still* no code or data between "myLabel:" and "jmp myLabel", because everything else is either preprocessor directives or in a completely different section (in the ".bss" section instead of the ".text" section), therefore the "myLabel" label is the address of the jump instruction.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Sam111
Member
Member
Posts: 385
Joined: Mon Nov 03, 2008 6:06 pm

Re: bootloader?

Post by Sam111 »

Thank you very much.

But I just have a few little things to clear up
The only difference is code readability - "mov si,packet" loads the address of a structure into SI, while "mov si,sizeofpacket" loads the address of the first field in the structure into SI. In practice it's exactly the same address.
Correct me if I am wrong but isn't the address of a structure the address of the first element in that structure. Kind of like an array is a pointer to the first element.

Also in your last example
what happens if you had something that wasn't just preprossor directive ...etc etc stuff

like

Code: Select all

label:
mov ax , ax ; 
xor dx , dx
jmp label

So this is like a jmp a few bytes back (I forget how many bytes those 2 instructions would be but something like jmp (address of jmp - 4)

So when you have code between a label declaration the lable is the address of mov ax , ax.
Yes/No ? And if you did jmp label + 4 it would jump back to the jmp command.

So what I am getting down to is when you declare a label that get's compiled to the address of the next instruction after it.
And a varable is nothing more then a label. So it would stand to reason if I did

Code: Select all

jmp start
myvar db '1'

start:
jmp myvar
Which would jump to myvar and if it was bits 16 would try to execute an instruction
that was 00000001 , first 8 bits of my jump command. And probably crash because it is not a valid instruction.

But the point is you can jmp to varables just as you can jump to labels. yes/no ?
And the scheme for the address of a label is the same as the scheme for the address of a variable. So what is the difference between varables as opposed to label's? I would say you can still have

var db EF , 90
jmp var

which var in this case is an address of a vaild instruction so the cpu would process the instruction after the jump to that instruction EF 90.

So if their is anything I am misunderstanding let me know.
But

Code: Select all

var1 db 0
;same as
var2: db 0

mov ax , [var1]
;same as
mov ax , [var2]
So we have to things that are the same.
correct me if I am wrong but
[var1]
[var2] ;are the values at the memory address of var1 , and var2

var1
var2 ; are the memory addresses of var1 and var2

And the segment data key line
is the same type of thing like a label
because

Code: Select all

mov ax , data ;moves the address of the data segment which I think is the address of the first varable in the data segment?
User avatar
Love4Boobies
Member
Member
Posts: 2111
Joined: Fri Mar 07, 2008 5:36 pm
Location: Bucharest, Romania

Re: bootloader?

Post by Love4Boobies »

In physical RAM, there's no difference between code and data. It is not uncommon for viruses to exploit this, especially in OSes like DOS. Self-modifying code is an example... an easy way of doing it is to write data that makes sense when executing it. You're right about the addresses (although you might want to just call them offsets, as addresses can be more complicated than just offsets). What I tried to explain in my previous post was that

Code: Select all

label:
var db 0
here var is the same as label. The reason for that is that var is only 1 byte long. If var were to be a word (dw), then var would mean label+1. So if you do

Code: Select all

mov word [label],0ffffh ; move the value FFFFh into the memory location of label
you would have bytes [label] and [label-1] equal to FFh. The least significant byte is the right-most. So you either have to do

Code: Select all

mov word [label+1],0ffffh
OR

Code: Select all

mov word var,0ffffh
as var points to its right-most byte.

Also, note that in NASM, $$ is a pointer to the origin.

Code: Select all

; start of code
xor ax,ax
...
jmp $$
this is an infinite loop.

$ is a pointer to the instruction currently being executed. So

Code: Select all

jmp $
and

Code: Select all

spin: jmp spin
are the same.
"Computers in the future may weigh no more than 1.5 tons.", Popular Mechanics (1949)
[ Project UDI ]
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: bootloader?

Post by Brendan »

Hi,
Love4Boobies wrote:

Code: Select all

label:
var db 0
here var is the same as label. The reason for that is that var is only 1 byte long. If var were to be a word (dw), then var would mean label+1. So if you do
No. It doesn't matter how much space is used after "var" is defined, there's still no space used between "label" and "var" and therefore they refer to the same offset/address.
Love4Boobies wrote:

Code: Select all

mov word [label],0ffffh ; move the value FFFFh into the memory location of label
you would have bytes [label] and [label-1] equal to FFh. The least significant byte is the right-most. So you either have to do

Code: Select all

mov word [label+1],0ffffh
OR

Code: Select all

mov word var,0ffffh
as var points to its right-most byte.
No. If you do "mov word [label],0xFFFF" then you'd end up with the low byte at "label" and the high byte at "label+1".
Love4Boobies wrote:Also, note that in NASM, $$ is a pointer to the origin.
No. In NASM $$ refers to the beginning of the current section, which isn't the same as the origin (unless the current section happens to begin at the origin, which is common for the ".text" section).
Love4Boobies wrote:$ is a pointer to the instruction currently being executed. So
You mean $ refers to the current position in the current section...


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Sam111
Member
Member
Posts: 385
Joined: Mon Nov 03, 2008 6:06 pm

Re: bootloader?

Post by Sam111 »

Ok I get everything you are saying but I want to make sure of a few things

Code: Select all

label:
var dw 0xFFAA

mov ax , word [label]
mov ax , [label]
mov ax , label
mov ax , word label

mov word [label] , 0xFFAA
so going in order of the mov instructions
1) would move 0xFFAA into register ax as little endian AA FF ?
2) this would be the same as 1 but what happens if you said byte [label] would it move the AA or FF? (I am assuming AA)
3) this would move ax with the starting memory location of label this would point to AA or FF ? I would think it would point to the starting byte of data which in little endian is AA first then FF.
So AA is one memory location less then FF.
4) I just did this to know what the reason is to specify word , byte , dword keywords.
Other then the fact to tell a mov instruction to move a word byte or dword into the register or memory location. What would it do if you did

Code: Select all

mov ax , word [abyte]
would it just move the byte into ax along with the next byte higher in memory?

And if I get rid of label and replaced it with var in all my moves I am assuming the 4 questions above would be exactly the same answers nothing changes. So their is no difference in using labels for varablies or visa versa. So really varables and labels are 2 names for the samething. At least from the assembilers point of few.

Code: Select all

var  db "hello"

does hello get stored as olleh in memory so mov ax, byte [var]
moves the o into the ax register. (i.e ah = 0 al = o)

I think I am understanding this just let me know if I am missing something.
And from the point of view of the assembler
segment data , ...etc etc
mov ax , data
just moves the starting address of the data segment i.e the memory location of the data.

Either way I am a little confused on one last thing when you move a memory location is memory locations 16 bits or 32 bits
like
mov eax , data
mov ax , data ?????????????????????????
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: bootloader?

Post by Troy Martin »

Being a db, "hello" is stored in memory just as it's defined: "hello". If you had this:

Code: Select all

var dw 0x55AA, 0xAA55
it would be stored in memory like this:

Code: Select all

AA 55 55 AA
because the endian-ness is dependant on the size.

Hope that makes sense!
Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: bootloader?

Post by Omega »

tons of errors in this. You should never load stage2 the way you did. You are probably loading your stage 1 to that address and starting it that way and just looping. You should find your stage2 on disk and load it that way. Then in stage2 it should be org 0x0 and you should setup stack to be the way you want it. Then load off disk or incbin your kernel. With incbin you could tack a ram disk to the end of the kernel and have a easy and cheap ram disk. Just know your kernel size * 1024 = bytes, convert to hex add it to your start address and there you have the start of your ram disk. anyway the example you are basing this loader from is broken.
Free energy is indeed evil for it absorbs the light.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: bootloader?

Post by Brendan »

Hi,
Sam111 wrote:

Code: Select all

label:
var dw 0xFFAA

mov ax , word [label]
mov ax , [label]
mov ax , label
mov ax , word label

mov word [label] , 0xFFAA
so going in order of the mov instructions
1) would move 0xFFAA into register ax as little endian AA FF ?
It'd move 0xFFAA into AX (where 0xAA goes into AL and 0xFF goes into AH).
Sam111 wrote:2) this would be the same as 1 but what happens if you said byte [label] would it move the AA or FF? (I am assuming AA)
For "mov ax, byte [label]" the assembler should complain about mixed sizes. For something like "movzx eax, byte [label]" or "mov al, [label]" you'd end up with 0xAA in AL.
Sam111 wrote:3) this would move ax with the starting memory location of label this would point to AA or FF ? I would think it would point to the starting byte of data which in little endian is AA first then FF.
So AA is one memory location less then FF.
Yes - AX is the address of "label", so that you could then do "mov bx,[ax]" and end up with 0xFFAA in BX.
Sam111 wrote:4) I just did this to know what the reason is to specify word , byte , dword keywords.
Other then the fact to tell a mov instruction to move a word byte or dword into the register or memory location. What would it do if you did

Code: Select all

mov ax , word [abyte]
would it just move the byte into ax along with the next byte higher in memory?
Yes. There isn't any type checking in assembler (mostly just addresses and register contents), so something you think is a byte variable can be read as a word or a dword, and the assembler won't complain because it only sees the address of the label and doesn't know what type of data that label is intended to be used for.
Sam111 wrote:And if I get rid of label and replaced it with var in all my moves I am assuming the 4 questions above would be exactly the same answers nothing changes. So their is no difference in using labels for varablies or visa versa. So really varables and labels are 2 names for the samething. At least from the assembilers point of few.
Correct.
Sam111 wrote:

Code: Select all

var  db "hello"

does hello get stored as olleh in memory so mov ax, byte [var]
moves the o into the ax register. (i.e ah = 0 al = o)
All assemblers would store this as "hello" (with 'h' at the lowest address and 'o' at the highest address), so if you do "mov eax, [var]" you end up 'h' in AL and 'e' in AH.

However, for something like this:

Code: Select all

     section .data
var: dd "hello"
     section .text

    mov eax,"hello"
    mov ebx,[var]
Different assemblers will behave differently - some assemblers will put the 'o' at the lowest address. For NASM you end up with 'h' at the lowest address (just like before when it was a string of bytes instead of a dword), which IMHO is more consistent and more correct. Despite this, occasionally you'll see the reverse in some documentation - for example, I remember seeing a document about BIOS function "Int 0x15, eax = 0xE820" recently that said "mov edx,'SMAP'" instead of "mov edx,'PAMS'".
Sam111 wrote:Either way I am a little confused on one last thing when you move a memory location is memory locations 16 bits or 32 bits
like
mov eax , data
mov ax , data ?????????????????????????
Addresses are numbers (integers), and can be treated as 16-bit numbers or as 32-bit numbers. For example:

Code: Select all

foo:
    mov si,foo      ;SI = 16-bit address of "foo"
    mov esi,foo     ;EDI = 32-bit address of "foo"
Most of the time, for 16-bit code you'd use 16-bit addresses and for 32-bit code you'd use 32-bit addresses. Sometimes you need to mix sizes. For example, in 16-bit code you might need to jump to a 32-bit address, so you could do "jmp dword 0x08:START" (which is fairly common if you've just enabled protected mode).

Also note that NASM will silently truncate addresses. For example:

Code: Select all

    org 0x12345000
    bits 32

foo:
    mov si,foo     ;si = 0x5000 because 0x12345000 won't fit

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply