Booting

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
Guest

Booting

Post by Guest »

I've been using GRUB but now wish to implement my own FS in a boot sector. Part of my FS is that the kernel is always starting at sector 2. When the boot sector is compiled the kernel length is specified. I have code to load up to 17 sectors of the kernel (18 - bootsector) but I'm not fluent in assembly to implement a system to work out the cylinders and heads for the next sectors. Below is my current code, could someone please explain how I could update it to accept variables in KERNEL_SIZE greater than 17

Code: Select all

mov ax, 0x4000            ;ES:BX = 0x4000:0000
   mov es, ax
   mov bx, 0x0000
   mov ah, 2                            ;Load disk data to ES:BX
   mov ch, 0                            ;First Cylinder
   mov cl, 2                            ;Start at the 2nd Sector, so you don't load the bootsector
   mov dh, 0                            ;Use first floppy head
   mov dl, [drive]                      ;Load boot drive
   mov al, KERNEL_SIZE                  ;Load Length of Kernel in Sectors
read:
   int 13h                              ;Read
   jc read                              ;Error? Try again
Thanks
pskyboy

Re:Booting

Post by pskyboy »

all you need to do is make sure kernel size is the number of sectors you want to load. You should have no problem loading up to 63 sectors its only after this you will need to up the cylinder by 1.

Peter

P.S. That code should work fine as its mine :), i have got mine loading up to 16 sectors at the moment i haven't tried more yet but i will.
pskyboy

Re:Booting

Post by pskyboy »

I just realised what your problem is.

If you are using my bootloader you will find that KERNEL_SIZE is the size of the kernel in bytes ie it will be something like

Code: Select all

%define KERNEL_SIZE 8*1024
what you need to do is but the number of sectors in AL there are 2 ways to do this. Either do another define called KERN_SECTORS and put this code on it

Code: Select all

(KERNEL_SIZE * 2)/1024 
or but this directly in the place of KERNEL_SIZE in your read in from disc function.

Hope this helps
Peter
Guest

Re:Booting

Post by Guest »

No, in my version KERNEL_SIZE is in sectors. And you can't just read more sectors in because you need to switch heads and increase cylinders. I know all the logic I just don't know how to implement it in assembly

logical
sector | head | cylinder
--------+--------+------------
1 - 18 0 1
19-36 1 1
37-54 0 2
55-72 1 2
etc.

I am not knowledgable enough in asm to do the logic. I have tried using a system of counting down the no. of sectors needed and every time the count was reduced, after each read of 18 sectors, it fiddled with the head and cylinder values but it didn't work.

Please could someone explain the asm instructions I can use to do this
Curufir

Re:Booting

Post by Curufir »

LBA -> CHS algorithm

Sector = ((LBA Sector) mod (Sectors per track)) + 1
Head = floor((LBA Sector) / (Sectors per track)) mod (Heads per cylinder)
Cylinder = floor(((LBA Sector) / (Sectors per track)) / (Heads per cylinder))

In assembly language:

Code: Select all

      ;************************************************************************
      ;* Convert the LBA sector address into CHS scheme so int 13h can use it *
      ;* HPC = Number of heads/cylinder                                       *
      ;* SPT = sectors/track                                                  *
      ;* Sector = (LBA mod SPT) + 1                                           *
      ;* Head = (LBA / SPT) mod HPC                                           *
      ;* Cylinder = (lba / SPT) / HPC                                         *
      ;************************************************************************

      XOR DX, DX
      DIV WORD [BPB_SecPerTrk]
      INC DX
      MOV CL, DL
      XOR DX, DX
      DIV WORD [BPB_NumHeads]
      MOV CH, AL
      MOV DH, DL
Assumes AX contains the lba sector you want to convert. Leaves CL=Sector, CH=Cylinder, DH=Head, it's that way to make it easier to use int 13h.

Hope that helps.
pskyboy

Re:Booting

Post by pskyboy »

Are you loading in from a floppy disk?

If your loading in from a hard drive you shouldn't have to switch heads until you have reached 63 sectors.

Peter
guest

Re:Booting

Post by guest »

I'm loading from a floppy and I've tried using Curufir's code like this:

Code: Select all

   mov ax, 0x4000                       ;ES:BX = 0x4000:0000
   mov es, ax
   mov bx, 0x0000
   mov ah, 2                            ;INT 13h Function 2 - Read Sector
   mov dl, [drive]                      ;Load boot drive
   mov ax, 2             
read:
   XOR DX, DX
      DIV WORD [BPB_SecPerTrk]
      INC DX
      MOV CL, DL
      XOR DX, DX
      DIV WORD [BPB_NumHeads]
      MOV CH, AL
      MOV DH, DL
read2:
   int 13h                              ;Read
   jc read2                              ;Error? Try again
   inc ax
   cmp ax, KERNEL_SIZE
   jnz read
but it never stops reading
Curufir

Re:Booting

Post by Curufir »

Perhaps you missed the fact that I trash AX in that code (Ie the value of AX going into it is not the value of AX that comes out of it. So you need a push/pop ax pair around it otherwise you will (As you have discovered) end up with an infinite loop reading the same sector.

You're probably better off doing something like this:

Code: Select all

read_kernel:
 pusha
 call reset

 mov ax, 0x4000   ;Target is 0x4000:0000
 mov es, ax
 xor bx, bx
 mov ax, 0x02  ;Sector to start reading at

.1:
 push ax

;
; Do the translation
;
 xor dx, dx
 div word [BPB_SecPerTrk]
 inc dx
 mov cl, dl
 div word [BPB_NumHeads]
 mov ch, al
 mov dh, dl

;
; Do the actual read
;
.2:
 mov dl, [drive]
 mov ax, 0x0201  ;Setup for disk read, 1 sector at a time
 int 0x13
 jnc .3

;
; Handle a read error by reseting the drive and trying again
;
 call reset  ;On error reset the drive
 jmp .2

;
; Get the stored value of the current sector
; Increment and check to see if all sectors are read
; If not then go around again
;
.3:
 pop ax   ;Pop the stored value of AX off the stack
 inc ax
 cmp ax, KERNEL_SIZE
 jnz .1

;
; End by returning to wherever you called read_kernel from
;
 popa
 ret

;
; Resets the disk drive
;
reset:
 xor ax, ax
 mov dl, [drive]
 int 0x13
 jc reset
 ret
Should be called from somewhere. That looks about right, but I haven't bothered testing it. The downside here is that you're reading in 1 sector at a time. The extension to reading in full tracks at a time is fairly logical so I'll leave you to figure it out on your own. 1 sector at a time will work, it just stresses the floppy disk more and is slower. Also be aware of the trap that is KERNEL_SIZE not being equal to the last sector you read in because you start your count at the 2nd sector ;).

Anyhow, hope that helps a bit, or at least clears up why you had an infinite loop.
Therx

Re:Booting

Post by Therx »

Ok, so I've added the lines to push and pop ax off and on to the stack and I've come up with the following code partly from your code but without the function layout. I'll attach the whole file. Now it stops reading gets to the debug msg '0' in top left but then triple faults
Post Reply