Floppy boot
386-я интеловская архитектура , наряду с поддержкой архитектур 8086 и 286 , имеет много новых фич.
У 386 , как и у 286 , есть возможность работать в 2-х режимах - реальном и защищенном .
Но в 386 защищенный режим более защищенный :-) . Его главная задача - не защищать ваши пользовательские программы .
Его цель - защищитить ядро от этих программ .
Оба этих режима используют сегментацию , прерывания и драйвера для управления железом .
Так в чем же разница между реальным и защищенным режимом ?
В реальном режиме размер сегмента ограничен 64 КБ . Сегментация в реальном режиме управляется
с помощью регистров CS,DS,SS,размерность которых не позволяет выйти за границы 64 КБ.
В защищенном режиме сегментация управляется с помощью специальных дескрипторных таблиц .
А в сегментных регистрах хранятся только адреса этих таблиц . Эти таблицы можно разбить на 3 основных типа :
1 GDT - Global Descriptor Table
2 LDT - Local Descriptor Table
3 IDT - Interrupt Descriptor Table
GDT хранит дескрипторы всех приложений . И каждое такое приложение имеет свою LDT .
Размер сегмента памяти в защищенном размере ограничен только 4 гигами .
Каждый дескриптор имеет длину в 8 байт . IDT хранит дескрипторы стандартных прерываний операционной системы.
У 386 имеется 4 контрольных регистра - CR0, CR1, CR2 , CR3.CR0
управляет переключением защищенного режима.
Бит PE=1 регистра CR0 включает защищенный режим , бит PE=0 включает реальный режим .
Теперь собственно код самого загрузчика :
org 0x07c00 ; Start address 0000:7c00
jmp short begin_boot ; Jump to start of boot routine & skip other data
bootmesg db "Our OS boot sector loading ......"
pm_mesg db "Switching to protected mode ...."
dw 512 ; Bytes per sector
db 1 ; Sectors per cluster
dw 1 ; Number of reserved sectors
db 2 ; Number of FATs
dw 0x00e0 ; Number of dirs in root
dw 0x0b40 ; Number of sectors in volume
db 0x0f0 ; Media descriptor
dw 9 ; Number of sectors per FAT
dw 18 ; Number of sectors per track
dw 2 ; Number of read/write sectors
dw 0 ; Number of hidden sectors
print_mesg :
mov ah,0x13 ; Fn 13h of int 10h writes a whole string on screen
mov al,0x00 ; bit 0 determines cursor pos,0->point to start after
; function call,1->point to last position written
mov bx,0x0007 ; bh -> screen page ie 0,bl = 07 ie white on black
mov cx,0x20 ; Length of string here 32
mov dx,0x0000 ; dh->start cursor row,dl->start cursor column
int 0x10 ; call bios interrupt 10h
ret ; Return to calling routine
get_key :
mov ah,0x00
int 0x16 ; Get_key Fn 00h of 16h,read next character
ret
clrscr :
mov ax,0x0600 ; Fn 06 of int 10h,scroll window up,if al = 0 clrscr
mov cx,0x0000 ; Clear window from 0,0
mov dx,0x174f ; to 23,79
mov bh,0 ; fill with colour 0
int 0x10 ; call bios interrupt 10h
ret
begin_boot :
xor ax, ax ; XOR ax
mov ds, ax ; Mov AX into DS
call clrscr ; Clear the screen first
mov bp,bootmesg ; Set the string ptr to message location
call print_mesg ; Print the message
call get_key ; Wait till a key is pressed
bits 16
call clrscr ; Clear the screen
mov ax,0xb800 ; Load gs to point to video memory
mov gs,ax ; We intend to display a brown A in real mode
mov word [gs:0],0x641 ; display
call get_key ; Get_key again,ie display till key is pressed
mov bp,pm_mesg ; Set string pointer
call print_mesg ; Call print_mesg subroutine
call get_key ; Wait till key is pressed
call clrscr ; Clear the screen
cli ; Clear or disable interrupts
lgdt[gdtr] ; Load GDT
mov eax,cr0 ; The lsb of cr0 is the protected mode bit
or al,0x01 ; Set protected mode bit
mov cr0,eax ; Mov modified word to the control register
jmp codesel:go_pm
bits 32
go_pm :
mov ax,datasel
mov ds,ax ; Initialise ds & es to data segment
mov es,ax
mov ax,videosel ; Initialise gs to video memory
mov gs,ax
mov word [gs:0],0x741 ; Display white A in protected mode
spin : jmp spin ; Loop
bits 16
gdtr :
dw gdt_end-gdt-1 ; Length of the gdt
dd gdt ; physical address of gdt
gdt
nullsel equ $-gdt ; $->current location,so nullsel = 0h
gdt0 ; Null descriptor,as per convention gdt0 is 0
dd 0 ; Each gdt entry is 8 bytes, so at 08h it is CS
dd 0 ; In all the segment descriptor is 64 bits
codesel equ $-gdt ; This is 8h,ie 2nd descriptor in gdt
code_gdt ; Code descriptor 4Gb flat segment at 0000:0000h
dw 0x0ffff ; Limit 4Gb bits 0-15 of segment descriptor
dw 0x0000 ; Base 0h bits 16-31 of segment descriptor (sd)
db 0x00 ; Base addr of seg 16-23 of 32bit addr,32-39 of sd
db 0x09a ; P,DPL(2),S,TYPE(3),A->Present bit 1,Descriptor
; privilege level 0-3,Segment descriptor 1 ie code
; or data seg descriptor,Type of seg,Accessed bit
db 0x0cf ; Upper 4 bits G,D,0,AVL ->1 segment len is page
; granular, 1 default operation size is 32bit seg
; AVL : Available field for user or OS
; Lower nibble bits 16-19 of segment limit
db 0x00 ; Base addr of seg 24-31 of 32bit addr,56-63 of sd
datasel equ $-gdt ; ie 10h, beginning of next 8 bytes for data sd
data_gdt ; Data descriptor 4Gb flat seg at 0000:0000h
dw 0x0ffff ; Limit 4Gb
dw 0x0000 ; Base 0000:0000h
db 0x00 ; Descriptor format same as above
db 0x092
db 0x0cf
db 0x00
videosel equ $-gdt ; ie 18h,next gdt entry
dw 3999 ; Limit 80*25*2-1
dw 0x8000 ; Base 0xb8000
db 0x0b
db 0x92 ; present,ring 0,data,expand-up,writable
db 0x00 ; byte granularity 16 bit
db 0x00
gdt_end
times 510-($-$$) db 0 ; Fill bytes from present loc to 510 with 0s
dw 0x0aa55 ; Write aa55 in bytes 511,512 to indicate that
; it is a bootable sector.
Обзовем этот файл abc.asm и выполним :
nasm abc.asm
Будет сгенерирован файл abc . Далее вставляем в дисковод пустую дискету и выполняем :
dd if=abc of=/dev/fd0
Эта команда запишет файл abc в первый сектор флоппи .
Теперь перезагружаем компьютер с дискеты . Происходит следующее :
1 Выводится сообщение "Our OS boot sector loading ......"
2 Нажимаем на клаву , и выводится символ А коричневого цвета
3 Нажимаем на клаву ,выводится надпись "Switching to protected mode ...."
4 Нажимаем на клаву , и выводится символ А белого цвета
Вот такой незамысловатый загрузчик .
При загрузке биос копирует содержимое первого сектора дискеты по адресу 0x7c00,после чего этот код в памяти запускается.
Функция printg_mesg выводит строку на экран.
Функция get_key обрабатывает клаву.
Функция clrscr очищает экран.
Загрузчик начинает работать в реальном режиме .
После переключения в защищенный режим все прерывания будут запрещены - это делает инструкция cli .
Позже мы опять включим прерывания.
Мы инициализируем GDT и несколько сегментов - кодовый , данные , стек , видео .
Адрес GDT храним в регистре GDTR.
После того как бит PE устанавливается в 1 , в соответствии с мануалами , необходимо немедленно
выполнить инструкцию JMP .
После перехода в защищенный режим мы печатаем белый символ А . Для этого инициализируется новый сегмент .
Кстати ,для того чтобы обозначить сектор как загрузочный , нужно в 511 и 512-й байты записать AA55.
Аналогичный пример загрузчика :
; -----------------------------------------------------------
; PolyOS boot loader code (c)1997 Jeff Weeks of Code X Software
; ------------------------------------------------------------
; This little bit of assembly is the boot loader
; -----------------------------------------------------------
[BITS 16] ; the bios starts out in 16-bit real mode
[ORG 0]
; --------------------------------------------------------------
; SECTOR ONE: THE BOOT LOADER
; ---------------------------------------------------------------
; This sector detects your processor.
; If a 386 is found, it loads the
; kernel from the disk and executes it
; (atleast it will in the future :).
; -------------------------------------------------------
jmp start ; skip over our data and functions
; -------------------------------------
; Data used in the boot-loading process
; ------------------------------------------------------------
bootdrv db 0
bootmsg db 'Booting PolyOS (c)1997 Cipher of Code X',13,10,0
loadmsg db 'Loading kernel',13,10,0
jumpmsg db 'Jumping to kernel',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 'Excellent!',13,10,0
; these are used when entering protected mode
a20msg db 'Setting A20 address line',13,10,0
pmodemsg db 'Setting CR0 -> Entering PMode',13,10,0
; Here's the locations of my IDT and GDT. Remember, Intel's are
; little endian processors, therefore, these are in reversed order.
; Also note that lidt and lgdt accept a 32-bit address and 16-bit
; limit, therefore, these are 48-bit variables.
pIDT dw 7FFh ; limit of 256 IDT slots
dd 0000h ; starting at 0000
pGDT dw 17FFh ; limit of 768 GDT slots
dd 0800h ; starting at 0800h (after IDT)
; ------------------------------------------
; Functions used in the boot-loading process
; -------------------------------------------------
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,loadmsg ; tell the user we're loading the kernel
call message
call getkey
read_me:
; first, reset the disk controller
xor ax, ax
int 0x13
jc reboot ; reboot on error
; then load in the PolyFS superblock
mov ax,0x09000 ; superblock goes to 9000:0000 (above stack)
mov es,ax
xor bx,bx
; I could condense a few of these high/low 8-bit movs into one 16-bit
; mov, but, for simplicity, I'll leave it as is, unless necessary.
mov ax,0x0202 ; load one block (two sectors)
mov ch,0 ; cylinder = 0
mov cl,3 ; sector = 2 (starts at sector 1 not 0)
mov dh,0 ; head = 0 = side one
mov dl,[bootdrv] ; disk = what we booted from
int 0x13 ; read it
jc read_me ; if there's an error then we'll try again.
; Often there is not error but requires a few
; tries. Ofcourse, this may end up as an
; infinite loop... but only on a bad disk...
; Check if we have a valid super block (BTW: ES still equals 0x9000)
mov di, 0 ; offset of PolyFS magic signature
mov si, polymagic ; offset of PolyFS magic to check for (in ds)
cmpsw ; compare ES:[DI] with DS:[SI]
jnz reboot ; reboot on error (otherwise, we've got a PolyFS)
; Ideally, we'd load the kernel right here
mov si, a20msg ; tell the user we're setting the A20 line
call message
; set A20 line
cli ; no more interuptions! :)
xor cx, cx
clear_buf:
in al, 64h ; get input from keyboard status port
test al, 02h ; test the buffer full flag
loopnz clear_buf ; loop until buffer is empty
mov al, 0D1h ; keyboard: write to output port
out 64h, al ; output command to keyboard
clear_buf2:
in al, 64h ; wait 'till buffer is empty again
test al, 02h
loopnz clear_buf2
mov al, 0dfh ; keyboard: set A20
out 60h, al ; send it to the keyboard controller
mov cx, 14h
wait_kbc: ; this is approx. a 25uS delay to wait
out 0edh, ax ; for the kb controler to execute our
loop wait_kbc ; command.
; the A20 line is on now. Let's load in our ITD and GDT tables...
; Ideally, there will actually be data in their locations (by loading
; the kernel)
lidt [pIDT]
lgdt [pGDT]
; now let's enter pmode...
mov si, pmodemsg
call message
call getkey
mov eax, cr0 ; load the control register in
or al, 1 ; set bit 1: pmode bit
mov cr0, eax ; copy it back to the control register
jmp $+2 ; and clear the prefetch queue
nop
nop
; jump to the kernel that we've loaded in...
; For now, we'll actually just reboot (this really doesn't
; work in protected mode, but it does reboot :)
db 0xEA
dw 0x0000
dw 0xFFFF
; The boot sector is supposed to have to have 0xAA55 at the end of
; the sector (the word at 510 bytes) to be loaded by the BIOS...
times 510-($-$$) db 0
dw 0xAA55
Еще один вариант :
; NYAOS Boot Sector (C) Copyright Sean Tash 1998
; assemble with:
; nasm -f bin -o bootsect.bin bootsect.asm
bits 16
org 0x7C00
start: jmp short begin
nop
bsOEM db "NYAOS1.0" ; OEM String
bsSectSize dw 512 ; Bytes per sector
bsClustSize db 1 ; Sectors per cluster
bsRessect dw 1 ; # of reserved sectors
bsFatCnt db 2 ; # of fat copies
bsRootSize dw 224 ; size of root directory
bsTotalSect dw 2880 ; total # of sectors if < 32 meg
bsMedia db 0xF0 ; Media Descriptor
bsFatSize dw 9 ; Size of each FAT
bsTrackSect dw 18 ; Sectors per track
bsHeadCnt dw 2 ; number of read-write heads
bsHidenSect dd 0 ; number of hidden sectors
bsHugeSect dd 0 ; if bsTotalSect is 0 this value is
; the number of sectors
bsBootDrv db 0 ; holds drive that the bs came from
bsReserv db 0 ; not used for anything
bsBootSign db 29h ; boot signature 29h
bsVolID dd 0 ; Disk volume ID also used for temp
; sector # / # sectors to load
bsVoLabel db "NO NAME " ; Volume Label
bsFSType db "FAT12 " ; File System type
begin: cli ; disable interrupts
mov [bsBootDrv],dl ; save drive number
mov ax,0x9000 ; put stack at 0x98000
mov ss,ax
mov sp,0x8000
mov cx,[bsTrackSect] update int 1E FDC param table
mov bx,0x0078
lds si,[ds:bx]
mov byte [si+4], cl
mov byte [si+9], 0x0F
sti ; enable interrupts
push ds
mov dl,[bsBootDrv] ; reset controller
xor ax,ax
int 0x13
pop ds
jc bootfail2 ; display error message
jmp _l1
bootfail2: jmp bootfail
_l1:
mov ax,0x0000
mov es,ax
mov ds,ax
mov si,MsgLoad ; display load message
call putstr
; find the root directory
xor ax,ax
mov al,[bsFatCnt]
mov bx,[bsFatSize]
mul bx
add ax,word [bsHidenSect]
adc ax,word [bsHidenSect+2]
add ax,word [bsRessect] ; ax holds root directory location
mov word [BootSig],ax
call checkroot
xor ax,ax
add ax,word [start]
add ax,word [bsVolID] ; sector number
add ax,word [BootSig]
sub ax,2 ; correction for a mis-calc
mov cx,word [bsVolID+2] ; number of sectors
mov bx,0x8000
mov es,bx
nextsector: push ax ; save registers
push cx
push dx
push es
xor bx,bx ; set zero offset
call readsect ; read a sector
mov si,MsgDot ; display a dot
call putstr
pop es ; restore registers
pop dx
pop cx
pop ax
mov bx,es
add bx,20h ; increment address 512 bytes
mov es,bx
inc ax ; read next sector
loopnz nextsector
mov ax,0x8000 set segment registers and jump
mov es,ax
mov ds,ax
push ax
mov ax,0
push ax
retf
checkroot:
push ax ; save registers
push bx
push cx
push dx
push si
push di
mov ax,0x8000 ; put root directory at 0x80000
mov es,ax
mov ax,32 ; AX = ((32*RootSize)/512) + 2
mul word [bsRootSize]
div word [bsSectSize]
mov cx,ax ; cx holds # of sectors in root
mov word [start],ax
mov ax,word [BootSig] ; get prev. saved loc. for root dir
r1: xor bx,bx
push cx ; save count
push ax ; save sector number
push es
push dx
call readsect
xor bx,bx
l_1: mov di,bx ; set address to check from
mov cx,11 ; check 11 bytes
mov si,FileName ; address of string to check with
repz cmpsb
je foundit
add bx,32 ; check next entry
cmp bx,[bsSectSize] ; end of sector?
je l_2
jmp l_1
l_2: pop dx ; restore registers
pop es
pop ax
pop cx
inc ax ; read next sector
loopnz r1
jmp bootfail
foundit: pop dx ; get these off the stack
pop es
pop ax
pop cx
mov di,0x1A ; get clustor #
add di,bx
push bx ; save bx for finding # of sectors
mov ax,[es:di]
xor bx,bx ; calculate sector #
mov bl,[bsClustSize]
mul bx ; ax holds sector #
mov word [bsVolID],ax
pop bx ; get location of directory entry
mov di,0x1C
add di,bx
mov ax,[es:di] ; put number of bytes in ax
xor dx,dx
mov bx,[bsClustSize] ; # of bytes / 512
div bx
inc ax
mov word [bsVolID+2],ax ; save number of sectors to load
pop di ; restore registers
pop si
pop dx
pop cx
pop bx
pop ax
ret ; return to caller
putstr: ; SI = address of string to display
lodsb
or al,al
jz short putstrd
mov ah,0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd: retn ; return to caller
bootfail: ; display failure message
mov si,MsgBad ; display error message
call putstr
xor ax,ax ; wait for keypress
int 0x16
int 0x19 ; reboot
readsect: ; ES:BX = Location ; AX = Sector
mov si,[bsTrackSect]
div si ; divide logical sect by track size
inc dl ; sector # begins at 1
mov [bsReserv],dl ; sector to read
xor dx,dx ; logical track left in ax
div word [bsHeadCnt] ; leaves head in dl, cyl in ax
mov dh, [bsBootDrv] ;
xchg dl,dh ; head to dh, drive to dl
mov cx,ax ; cyl to cx
xchg cl,ch ; low 8 bits of cyl to ch, hi 2 bits
shl cl,6 ; shifted to bits 6 and 7
or cl, byte [bsReserv] ; or with sector number
mov al,1 ; number of sectors
mov ah,2 ; use read function of int 0x13
int 0x13 ; read sector
jc bootfail ; display error message
ret ; return to caller
padding times 45 db 0
FileName db "OSLOADERBIN"
MsgBad db "Disk Error...",13,10,0
MsgDot db ".",0
MsgLoad db "NYAOS Loading",0
BootSig db 0x55, 0xAA
========================================
Daniels NASM bootstraps tutorial
========================================
author: Daniel Marjamдki (daniel.marjamaki@home.se)
Preface
-------
This tutorial is a guide for those who want to create
their own bootstraps.
The basics
----------
These are the rules that you must follow:
- The BIOS will load your bootstrap to address 07C00h.
Sadly, the segment and offset varies.
- Bootstraps must be compiled as plain binary files.
- The filesize for the plain binary file must be 512
bytes.
- The file must end with AA55h.
A minimal bootstrap
-------------------
This bootstrap just hangs:
; HANG.ASM
; A minimal bootstrap
hang: ; Hang!
jmp hang
times 510-($-$$) db 0 ; Fill the file with 0's
dw 0AA55h ; End the file with AA55
The line starting with "times" is a command that only
NASM understands. The line will insert 0's until the
filesize is 510 bytes. The whole file will therefore be
512 bytes.
The last instruction puts AA55 at the end of the file.
To compile the bootstrap, use this command:
nasm hang.asm -o hang.bin
If you want to test the bootstrap, you must first put it
on the first sector on a floppy disk. You can for example
use 'dd' or 'rawrite'.
When the bootstrap is on the floppy, test it by
restarting your computer with the floppy inserted. The
computer should hang then.
The memory problem
------------------
There is a memory problem.
As I've written bootstraps are always loaded to address
07C00. We don't know what segment and offset the BIOS has
put us in. The segment can be anything between 0000 and
07C0. This is a problem when we want to use variables.
The solution is simple. Begin your bootstrap by jumping
to your bootstrap, but jump to a known segment.
Here is an example:
; JUMP.ASM
; Make a jump and then hang
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
hang: ; Hang!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
If you compile and test this bootstrap, there will be no
visible difference to the minimal bootstrap presented
earlier. The computer will just hang.
Some exercises
--------------
1. Create a bootstrap that outputs "====" on the screen,
and then hangs. Tip: modify the jump.asm program.
2. Create a bootstrap that outputs "Hello Cyberspace!"
and hangs.
3. Create a bootstrap that loads a program off the floppy
disk and jumps to it.
Solutions to the exercises
--------------------------
1.
; 1.ASM
; Print "====" on the screen and hang
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
mov ah, 9 ; Print "===="
mov al, '=' ;
mov bx, 7 ;
mov cx, 4 ;
int 10h ;
hang: ; Hang!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
2.
; 2.ASM
; Print "Hello Cyberspace!" on the screen and hang
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
; Declare the string that will be printed
msg db 'Hello Cyberspace!'
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
mov si, msg ; Print msg
print:
lodsb ; AL=memory contents at DS:SI
cmp al, 0 ; If AL=0 then hang
je hang
mov ah, 0Eh ; Print AL
mov bx, 7
int 10h
jmp print ; Print next character
hang: ; Hang!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
3.
; 3.ASM
; Load a program off the disk and jump to it
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
reset: ; Reset the floppy drive
mov ax, 0 ;
mov dl, 0 ; Drive=0 (=A)
int 13h ;
jc reset ; ERROR => reset again
read:
mov ax, 1000h ; ES:BX = 1000:0000
mov es, ax ;
mov bx, 0 ;
mov ah, 2 ; Load disk data to ES:BX
mov al, 5 ; Load 5 sectors
mov ch, 0 ; Cylinder=0
mov cl, 2 ; Sector=2
mov dh, 0 ; Head=0
mov dl, 0 ; Drive=0
int 13h ; Read!
jc read ; ERROR => Try again
jmp 1000h:0000 ; Jump to the program
times 510-($-$$) db 0
dw 0AA55h
This is a small loadable program.
; PROG.ASM
mov ah, 9
mov al, '='
mov bx, 7
mov cx, 10
int 10h
hang:
jmp hang
This program creates a disk image file that contains both
the bootstrap and the small loadable program.
; IMAGE.ASM
; Disk image
%include '3.asm'
%include 'prog.asm'
Finally
-------
Thanks for reading.
Email me any suggestions, comments, questions, ...
If you don't use NASM and are having problems with the
code, you should contact me. Together we can solve it.
|