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
