Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Secure Programming for Li...6507 
 Linux Kernel 2.6...5280 
 Trees...1119 
 Максвелл 3...1051 
 William Gropp...990 
 Go Web ...963 
 Ethreal 3...930 
 Ethreal 4...918 
 Gary V.Vaughan-> Libtool...914 
 Ext4 FS...905 
 Clickhouse...902 
 Rodriguez 6...900 
 Ethreal 1...897 
 Steve Pate 1...886 
 C++ Patterns 3...864 
 Assembler...854 
 Ulrich Drepper...844 
 DevFS...788 
 MySQL & PosgreSQL...774 
 Стивенс 9...758 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

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.
 
    
    
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье