Page 1 of 2
boot code needs fix [FIXED]
Posted: Wed Feb 14, 2007 6:18 pm
by GLneo
hi all, ok, basically my boot sector breaks after it reads 53 sectors, i just ignored this then forgot about this and my kernel grew, so my boot sector stopped loading all of my kernel(so i had some hellish bugs) but luckily I've remembered this and now it's time to fix the boot sector.
here is my code:
http://lemonos.cvs.sourceforge.net/lemo ... iew=markup
i dont know much asm, so i hope someone can help!
thx!
Posted: Wed Feb 14, 2007 7:25 pm
by frank
Code: Select all
kernel_load:
mov ax, 0
mov es, ax
mov bx, 0x1000
mov ax, 1
mov cx, 53
call LoadSectors
On the line where it says mov cx, 53 (line 80) you could just change the 53 to the number of sectors that the kernel occupies.
Posted: Wed Feb 14, 2007 7:32 pm
by GLneo
well thats the thing, if i make it more than 53 the thing locks up?!?!
but thanks for the idea
Posted: Wed Feb 14, 2007 7:54 pm
by bubach
Here's John S. Fine's readsector code as it looks in my bootsector, it
works really well for me.
Code: Select all
;-------------------------------------------------------------------;
; read_16 & read_32 ;
; input: dx:ax = sector within partition ;
; si = sector count ;
; di = destination segment / 32 ;
; ;
; The sector number is converted from a partition-relative to a ;
; whole-disk (LBN) value, and then converted to CHS form, and ;
; then the sectors are read into (di*32):0. ;
; ;
; output: dx:ax = updated (sector count added) ;
; di = updated (sector count added) ;
; si = 0 ;
; ;
; bp, ds preserved ;
; bx, cx, es modified ;
;-------------------------------------------------------------------;
read_16:
xor dx, dx
read_32:
.1:
push dx ; (high) relative sector
push ax ; (low) relative sector
add ax, word [bpbHiddenSect] ; Convert to LBN
adc dx, word [bpbHiddenSect+2]
mov bx, [bpbTrackSect] ; Sectors per track
div bx ; ax = track ; dx = sector-1
sub bx, dx ; Sectors remaining, this track
cmp bx, si ; More than we want?
jbe .2 ; No
mov bx, si ; Yes: Transfer just what we want
.2:
inc dx ; Sector number
mov cx, dx ; cl = sector ; ch = 0
cwd ; (This supports up to 32767 tracks
div word [bpbHeads] ; Track number / Number of heads
mov dh, dl ; dh = head
xchg ch, al ; ch = (low) cylinder ; al=0
ror ah, 1 ; rotate (high) cylinder
ror ah, 1
add cl, ah ; cl = combine: sector, (high) cylinder
sub ax, di
and ax, 0x7F ; ax = sectors to next 64Kb boundary
jz .3 ; On a 64Kb boundary already
cmp ax, bx ; More than we want?
jbe .4 ; No
.3:
xchg ax, bx ; Yes: Transfer just what we want
.4:
push ax ; Save length
mov bx, di ; Compute destination seg
push cx
mov cl, 5
shl bx, cl
pop cx
mov es, bx
xor bx, bx ; es:bx = address
mov dl, [bpbDriveNo] ; dl = Drive number
mov ah, 2 ; ah = Read command
int 0x13 ; Do it
jc error
pop bx ; Length
pop ax ; (low) relative sector
pop dx ; (high) relative sector
add ax, bx ; Update relative sector
adc dl, dh
add di, bx ; Update destination
sub si, bx ; Update count
jnz .1 ; Read some more
ret
example usage:
Code: Select all
mov ax, [bpbReservedSec] ; Sector number of FAT
mov si, [bpbFatSize] ; Length of FAT
mov di, 0x40 ; segment / 32 (0x800 / 32)
call read_16 ; Read FAT
Posted: Wed Feb 14, 2007 8:17 pm
by GLneo
thx, but i dont understand what
Code: Select all
[bpbHiddenSect], [bpbTrackSect], ect...
are?
Posted: Thu Feb 15, 2007 1:04 am
by Combuster
The two methods differ significantly:
GLNeo loads everything from a fixed location on disk, while bubach's bootloader seems to parse the filesystem and locate the kernel that way. What you see is the reference to the BPB (the drive structure that tells you the properties of your disk).
However, this is not the problem:
when you try to load >53 sectors (take for example 54) you will overwrite the area from 0x1000 to 0x1000 + 54 * 512. = 0x7C00 (!). If you try loading even more, you'll be overwriting your bootsector with the obvious consequences.
To solve this properly you should choose another location, and then you possibly have to update your kernel and the likes to match the new address.
Posted: Thu Feb 15, 2007 7:20 am
by bubach
The variables is from the BPB, but you'll need some of those values to read sectors even if you don't care about FAT.
The function is to read sectors, so it's the same wheter you use FAT12 or not.
GLneo, you have the BPB in your bootsector so all you have to do is change
the names in the read function like this:
Code: Select all
bpbHiddenSect -> HiddenSectors
bpbTrackSect -> SectorsPerTrack
bpbHeads -> NumberOfHeads
bpbDriveNo -> DriveNumber
Posted: Thu Feb 15, 2007 7:42 am
by Solar
Combuster wrote:when you try to load >53 sectors (take for example 54) you will overwrite the area from 0x1000 to 0x1000 + 54 * 512. = 0x7C00 (!).
The "(!)" did remind me of chess notation. Nice bughunting!
Posted: Thu Feb 15, 2007 11:42 am
by GLneo
@Combuster: thx that would be a problem!
this question has probably been asked a thousand times, but how do you put your kernel at the 1MB spot?
Posted: Thu Feb 15, 2007 12:23 pm
by Otter
That's only possible if your bootloader switches to protected mode. But if you are in pm, you can not use the BIOS interupts to load your kernel any more. The simplest way is to load your kernel to a position after your bootloader ( you could define a label at the end to get the position ), then switch to pm and move it to 1 MB.
There are other ways like long mode but I think if your kernel is not too big this one should be good.
Posted: Thu Feb 15, 2007 12:29 pm
by GLneo
where does my boot loader end( where is it safe to put 100+ sectors )?
Posted: Thu Feb 15, 2007 1:15 pm
by Otter
As I said ... add a label to the end of your boot loader ( bootloader_end ) . You could move it there. I don't know where you put the stack cause I have not readed your code but If you put it at the end of your 640K it should be save ... should
Posted: Thu Feb 15, 2007 1:33 pm
by GLneo
my sp is 0xFFFF, so i told it to put my kernel at 0x8000, then linked my kernel to that spot and tryed to boot: IT WORKS!
so now how do i move 60+ sectors from 0x8000 to 0x10000(or wherever) in protectaed mode ( i dont now much asm and i think there is some easy loop instruction to do it)
thx, everyone!
Posted: Thu Feb 15, 2007 1:38 pm
by xsix
your bootloader ends up on 0x7c00+0x200 and just write a routine which call INT 13h with CX=1 as many times as much sectors you want to read
Posted: Thu Feb 15, 2007 4:19 pm
by Otter
If you want to move it to 0x00100000 ( 1 MB ) you need to switch to protected mode. This is not easy, but there are lots of tutorials for that. If you use 32 bit code ( in protected mode you can ) you can move it using "rep movsd"
Code: Select all
mov esi,0x00008000
mov edi,0x00100000
mov ecx,( kernelSize+3)/4
rep movsd