234 lines
8.3 KiB
Plaintext
234 lines
8.3 KiB
Plaintext
Bootsector authoring by Gareth Owen
|
|
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
-=- gaz@athene.co.uk -=-
|
|
|
|
Requirements
|
|
============
|
|
During this article I assume that you have good knowledge of the
|
|
assembly language and intel architecture.
|
|
If not, read an assembly tutorial, they aren't hard to find...
|
|
|
|
Start
|
|
=====
|
|
|
|
Creating your own bootsector is simpler than you may think,
|
|
the only requirement is that the bootsector is 512 bytes long, and at
|
|
offset 0x1FE (decimal=510), the word 0xAA55 is placed. This is the first
|
|
thing the BIOS does when the PC boots up, it first looks on the first
|
|
floppy drive at the first sector for 0xAA55 at the end, and if it finds it
|
|
then it loads it into memory, and starts executing it, otherwise it trys the
|
|
primary harddisk, and if that isn't found it just bombs out with an error.
|
|
|
|
You should place your boot sector at:
|
|
Sector 1
|
|
Cylinder 0
|
|
Head 0
|
|
|
|
I recommend you start playing about with floppys first instead of your hard disk
|
|
because the hard disk bootsector stores information about the file system if you
|
|
are running DOS/Windows, if you overrite that, then you have just lost your
|
|
hard disk contents :-)
|
|
|
|
The BIOS loads the bootsector at linear offset 0x7C00, the state of
|
|
the registers are:
|
|
|
|
DL = Boot drive, 1h = floppy1, 80h = primary harddisk, etc
|
|
CS = 0
|
|
IP = 0x7c00
|
|
|
|
So instead of adding [ORG 7C00h] to the top of your file, you can add:
|
|
|
|
mov ax, 0x7C0
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov fs, ax
|
|
mov gs, ax
|
|
|
|
And that will set-up the segment registers so they point to the start of
|
|
your bootsector..
|
|
|
|
Most boot sectors usually just store the boot drive, load the kernel
|
|
from disk, and jump to it.. Some will also load protected mode.
|
|
|
|
Since most people find it easier looking at source code and figuring
|
|
it out than reading documentation i have included sources for a boot
|
|
sector and a boot sector writter.
|
|
|
|
Here is the bootsector...
|
|
|
|
;******************* START ************************
|
|
|
|
; Boot sector authoring example by Gareth Owen (gaz@athene.co.uk)
|
|
; This should be accompanied with an article explaining bootsectors
|
|
|
|
[BITS 16] ; the bios starts out in 16-bit real mode
|
|
[ORG 0] ; Data offset = 0
|
|
|
|
jmp start ; skip over our data and functions, we cannot execute data :-),
|
|
; well, you can, but i am not held responsible for the results :)
|
|
|
|
; Boot sector authoring example by Gareth Owen (gaz@athene.co.uk)
|
|
; This should be accompanied with an article explaining bootsectors
|
|
|
|
[BITS 16] ; the bios starts out in 16-bit real mode
|
|
[ORG 0] ; Data offset = 0
|
|
|
|
jmp start ; skip over our data and functions, we cannot execute data :-),
|
|
; well, you can, but i am not held responsible for the results :)
|
|
|
|
; -------------------------------------
|
|
; Data used in the boot-loading process
|
|
; ------------------------------------------------------------------------
|
|
bootdrv db 0
|
|
bootmsg db 'Gareth Owen',39,'s Boot Sector Example',13,10,0
|
|
|
|
rebootmsg db 'Press any key to reboot',13,10,0
|
|
|
|
; these are used in the processor identification
|
|
processormsg db 'Checking for 386+ processor: ',0
|
|
need386 db 'Sorry... 386+ required!',13,10,0
|
|
found386 db 'Found!',13,10,0
|
|
|
|
whatever db 'Insert your code to do something here',13,10,0
|
|
|
|
;*******************************************
|
|
; Functions we are going to use ...
|
|
;*******************************************
|
|
detect_cpu:
|
|
mov si, processormsg ; tell the user what we're doing
|
|
call message
|
|
|
|
; test if 8088/8086 is present (flag bits 12-15 will be set)
|
|
pushf ; save the flags original value
|
|
|
|
xor ah,ah ; ah = 0
|
|
push ax ; copy ax into the flags
|
|
popf ; with bits 12-15 clear
|
|
|
|
pushf ; Read flags back into ax
|
|
pop ax
|
|
and ah,0f0h ; check if bits 12-15 are set
|
|
cmp ah,0f0h
|
|
je no386 ; no 386 detected (8088/8086 present)
|
|
|
|
; check for a 286 (bits 12-15 are clear)
|
|
mov ah,0f0h ; set bits 12-15
|
|
push ax ; copy ax onto the flags
|
|
popf
|
|
|
|
pushf ; copy the flags into ax
|
|
pop ax
|
|
and ah,0f0h ; check if bits 12-15 are clear
|
|
jz no386 ; no 386 detected (80286 present)
|
|
popf ; pop the original flags back
|
|
|
|
mov si, found386
|
|
call message
|
|
|
|
ret ; no 8088/8086 or 286, so ateast 386
|
|
no386:
|
|
mov si,need386 ; tell the user the problem
|
|
call message
|
|
jmp reboot ; and reboot when key pressed
|
|
|
|
; ********************************************************************
|
|
message: ; Dump ds:si to screen.
|
|
lodsb ; load byte at ds:si into al
|
|
or al,al ; test if character is 0 (end)
|
|
jz done
|
|
mov ah,0eh ; put character
|
|
mov bx,0007 ; attribute
|
|
int 0x10 ; call BIOS
|
|
jmp message
|
|
done:
|
|
ret
|
|
; ********************************************************************
|
|
getkey:
|
|
mov ah, 0 ; wait for key
|
|
int 016h
|
|
ret
|
|
|
|
; ********************************************************************
|
|
reboot:
|
|
mov si, rebootmsg ; be polite, and say we're rebooting
|
|
call message
|
|
call getkey ; and even wait for a key :)
|
|
|
|
db 0EAh ; machine language to jump to FFFF:0000 (reboot)
|
|
|
|
dw 0000h
|
|
dw 0FFFFh
|
|
; no ret required; we're rebooting! (Hey, I just saved a byte :)
|
|
|
|
; *******************************************
|
|
; The actual code of our boot loading process
|
|
; *******************************************
|
|
start:
|
|
mov ax,0x7c0 ; BIOS puts us at 0:07C00h, so set DS accordinly
|
|
mov ds,ax ; Therefore, we don't have to add 07C00h to all our
|
|
data
|
|
|
|
mov [bootdrv], dl ; quickly save what drive we booted from
|
|
|
|
cli ; clear interrupts while we setup a stack
|
|
mov ax,0x9000 ; this seems to be the typical place for a stack
|
|
mov ss,ax
|
|
mov sp,0xffff ; let's use the whole segment. Why not? We can :)
|
|
sti ; put our interrupts back on
|
|
|
|
; Interestingly enough, apparently the processor will disable
|
|
; interupts itself when you directly access the stack segment!
|
|
; Atleast it does in protected mode, I'm not sure about real mode.
|
|
|
|
mov si,bootmsg ; display our startup message
|
|
call message
|
|
|
|
call detect_cpu ; check if we've got a 386
|
|
|
|
.386 ; use 386 instructions from now on (I don't want to manually include
|
|
; operand-size(66h) or address-size(67h) prefixes... it's annoying :)
|
|
|
|
mov si,whatever ; tell the user we're not doing anything interesting here
|
|
call message
|
|
call getkey
|
|
|
|
call reboot
|
|
|
|
times 510-($-$$) db 0
|
|
dw 0xAA55
|
|
|
|
;******************** GBOOTSECT END *************************
|
|
|
|
Here is the code for writting the bootsector to a floppy disk.
|
|
It has been compiled with DJGPP for DOS.
|
|
It writes the file 'bootsect', onto Sector 1, Cylinder 0, Head 0 of
|
|
the floppy drive.
|
|
|
|
//***************START****************
|
|
#include <bios.h>
|
|
#include <stdio.h>
|
|
|
|
void main()
|
|
{
|
|
FILE *in;
|
|
unsigned char buffer[520];
|
|
|
|
if((in = fopen("bootsect", "rb"))==NULL)
|
|
{
|
|
printf("Error loading file\n");
|
|
exit(0);
|
|
}
|
|
|
|
fread(&buffer, 512, 1, in);
|
|
|
|
while(biosdisk(3, 0, 0, 0, 1, 1, buffer));
|
|
|
|
fclose(in);
|
|
}
|
|
//*************END****************************
|
|
|
|
Well, if you still don't understand something, then mail me
|
|
at gaz@athene.co.uk and i'll help you out
|
|
|
|
- Gareth Owen
|