root/boot/bootsect.S

/* [previous][next][first][last][top][bottom][index][help] */
   1 !
   2 ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
   3 ! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
   4 ! versions of linux
   5 !
   6 #include <linux/config.h>
   7 SYSSIZE = DEF_SYSSIZE
   8 !
   9 !       bootsect.s              (C) 1991 Linus Torvalds
  10 !       modified by Drew Eckhardt
  11 !       modified by Bruce Evans (bde)
  12 !
  13 ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
  14 ! itself out of the way to address 0x90000, and jumps there.
  15 !
  16 ! bde - should not jump blindly, there may be systems with only 512K low
  17 ! memory.  Use int 0x12 to get the top of memory, etc.
  18 !
  19 ! It then loads 'setup' directly after itself (0x90200), and the system
  20 ! at 0x10000, using BIOS interrupts. 
  21 !
  22 ! NOTE! currently system is at most 8*65536 bytes long. This should be no
  23 ! problem, even in the future. I want to keep it simple. This 512 kB
  24 ! kernel size should be enough, especially as this doesn't contain the
  25 ! buffer cache as in minix
  26 !
  27 ! The loader has been made as simple as possible, and continuos
  28 ! read errors will result in a unbreakable loop. Reboot by hand. It
  29 ! loads pretty fast by getting whole tracks at a time whenever possible.
  30 
  31 .text
  32 
  33 SETUPSECS = 4                           ! nr of setup-sectors
  34 BOOTSEG   = 0x07C0                      ! original address of boot-sector
  35 INITSEG   = DEF_INITSEG                 ! we move boot here - out of the way
  36 SETUPSEG  = DEF_SETUPSEG                ! setup starts here
  37 SYSSEG    = DEF_SYSSEG                  ! system loaded at 0x10000 (65536).
  38 ENDSEG    = SYSSEG + SYSSIZE            ! where to stop loading
  39 
  40 ! ROOT_DEV & SWAP_DEV are now written by "build".
  41 ROOT_DEV = 0
  42 SWAP_DEV = 0
  43 
  44 ! ld86 requires an entry symbol. This may as well be the usual one.
  45 .globl  _main
  46 _main:
  47 #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
  48         int     3
  49 #endif
  50         mov     ax,#BOOTSEG
  51         mov     ds,ax
  52         mov     ax,#INITSEG
  53         mov     es,ax
  54         mov     cx,#256
  55         sub     si,si
  56         sub     di,di
  57         cld
  58         rep
  59         movsw
  60         jmpi    go,INITSEG
  61 
  62 go:     mov     ax,cs           
  63         mov     dx,#0x4000-12   ! 0x4000 is arbitrary value >= length of
  64                                 ! bootsect + length of setup + room for stack
  65                                 ! 12 is disk parm size
  66 
  67 ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
  68 ! wouldn't have to worry about this if we checked the top of memory.  Also
  69 ! my BIOS can be configured to put the wini drive tables in high memory
  70 ! instead of in the vector table.  The old stack might have clobbered the
  71 ! drive table.
  72 
  73         mov     ds,ax
  74         mov     es,ax
  75         push    ax
  76 
  77         mov     ss,ax           ! put stack at INITSEG:0x4000-12.
  78         mov     sp,dx
  79 /*
  80  *      Many BIOS's default disk parameter tables will not 
  81  *      recognize multi-sector reads beyond the maximum sector number
  82  *      specified in the default diskette parameter tables - this may
  83  *      mean 7 sectors in some cases.
  84  *
  85  *      Since single sector reads are slow and out of the question,
  86  *      we must take care of this by creating new parameter tables
  87  *      (for the first disk) in RAM.  We will set the maximum sector
  88  *      count to 18 - the most we will encounter on an HD 1.44.  
  89  *
  90  *      High doesn't hurt.  Low does.
  91  *
  92  *      Segments are as follows: ds=es=ss=cs - INITSEG,
  93  *              fs = 0, gs = parameter table segment
  94  */
  95 
  96         push    #0
  97         pop     fs
  98         mov     bx,#0x78                ! fs:bx is parameter table address
  99         seg fs
 100         lgs     si,(bx)                 ! gs:si is source
 101 
 102         mov     di,dx                   ! es:di is destination
 103         mov     cx,#6                   ! copy 12 bytes
 104         cld
 105 
 106         rep
 107         seg gs
 108         movsw
 109 
 110         mov     di,dx
 111         movb    4(di),*18               ! patch sector count
 112 
 113         seg fs
 114         mov     (bx),di
 115         seg fs
 116         mov     2(bx),es
 117 
 118         pop     ax
 119         mov     fs,ax
 120         mov     gs,ax
 121         
 122         xor     ah,ah                   ! reset FDC 
 123         xor     dl,dl
 124         int     0x13    
 125 
 126 ! load the setup-sectors directly after the bootblock.
 127 ! Note that 'es' is already set up.
 128 
 129 load_setup:
 130         xor     dx, dx                  ! drive 0, head 0
 131         mov     cx,#0x0002              ! sector 2, track 0
 132         mov     bx,#0x0200              ! address = 512, in INITSEG
 133         mov     ax,#0x0200+SETUPSECS    ! service 2, nr of sectors
 134                                         ! (assume all on head 0, track 0)
 135         int     0x13                    ! read it
 136         jnc     ok_load_setup           ! ok - continue
 137 
 138         push    ax                      ! dump error code
 139         call    print_nl
 140         mov     bp, sp
 141         call    print_hex
 142         pop     ax      
 143         
 144         xor     dl, dl                  ! reset FDC
 145         xor     ah, ah
 146         int     0x13
 147         jmp     load_setup
 148 
 149 ok_load_setup:
 150 
 151 ! Get disk drive parameters, specifically nr of sectors/track
 152 
 153 #if 0
 154 
 155 ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
 156 ! disks.  It doesn't work for one of my BIOS's (1987 Award).  It was
 157 ! fatal not to check the error code.
 158 
 159         xor     dl,dl
 160         mov     ah,#0x08                ! AH=8 is get drive parameters
 161         int     0x13
 162         xor     ch,ch
 163 #else
 164 
 165 ! It seems that there is no BIOS call to get the number of sectors.  Guess
 166 ! 18 sectors if sector 18 can be read, 15 if sector 15 can be read.
 167 ! Otherwise guess 9.
 168 
 169         xor     dx, dx                  ! drive 0, head 0
 170         mov     cx,#0x0012              ! sector 18, track 0
 171         mov     bx,#0x0200+SETUPSECS*0x200  ! address after setup (es = cs)
 172         mov     ax,#0x0201              ! service 2, 1 sector
 173         int     0x13
 174         jnc     got_sectors
 175         mov     cl,#0x0f                ! sector 15
 176         mov     ax,#0x0201              ! service 2, 1 sector
 177         int     0x13
 178         jnc     got_sectors
 179         mov     cl,#0x09
 180 
 181 #endif
 182 
 183 got_sectors:
 184         seg cs
 185         mov     sectors,cx
 186         mov     ax,#INITSEG
 187         mov     es,ax
 188 
 189 ! Print some inane message
 190 
 191         mov     ah,#0x03                ! read cursor pos
 192         xor     bh,bh
 193         int     0x10
 194         
 195         mov     cx,#9
 196         mov     bx,#0x0007              ! page 0, attribute 7 (normal)
 197         mov     bp,#msg1
 198         mov     ax,#0x1301              ! write string, move cursor
 199         int     0x10
 200 
 201 ! ok, we've written the message, now
 202 ! we want to load the system (at 0x10000)
 203 
 204         mov     ax,#SYSSEG
 205         mov     es,ax           ! segment of 0x010000
 206         call    read_it
 207         call    kill_motor
 208         call    print_nl
 209 
 210 ! After that we check which root-device to use. If the device is
 211 ! defined (!= 0), nothing is done and the given device is used.
 212 ! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
 213 ! on the number of sectors that the BIOS reports currently.
 214 
 215         seg cs
 216         mov     ax,root_dev
 217         or      ax,ax
 218         jne     root_defined
 219         seg cs
 220         mov     bx,sectors
 221         mov     ax,#0x0208              ! /dev/ps0 - 1.2Mb
 222         cmp     bx,#15
 223         je      root_defined
 224         mov     ax,#0x021c              ! /dev/PS0 - 1.44Mb
 225         cmp     bx,#18
 226         je      root_defined
 227 undef_root:
 228         jmp undef_root
 229 root_defined:
 230         seg cs
 231         mov     root_dev,ax
 232 
 233 ! after that (everyting loaded), we jump to
 234 ! the setup-routine loaded directly after
 235 ! the bootblock:
 236 
 237         jmpi    0,SETUPSEG
 238 
 239 ! This routine loads the system at address 0x10000, making sure
 240 ! no 64kB boundaries are crossed. We try to load it as fast as
 241 ! possible, loading whole tracks whenever we can.
 242 !
 243 ! in:   es - starting address segment (normally 0x1000)
 244 !
 245 sread:  .word 1+SETUPSECS       ! sectors read of current track
 246 head:   .word 0                 ! current head
 247 track:  .word 0                 ! current track
 248 
 249 read_it:
 250         mov ax,es
 251         test ax,#0x0fff
 252 die:    jne die                 ! es must be at 64kB boundary
 253         xor bx,bx               ! bx is starting address within segment
 254 rp_read:
 255         mov ax,es
 256         cmp ax,#ENDSEG          ! have we loaded all yet?
 257         jb ok1_read
 258         ret
 259 ok1_read:
 260         seg cs
 261         mov ax,sectors
 262         sub ax,sread
 263         mov cx,ax
 264         shl cx,#9
 265         add cx,bx
 266         jnc ok2_read
 267         je ok2_read
 268         xor ax,ax
 269         sub ax,bx
 270         shr ax,#9
 271 ok2_read:
 272         call read_track
 273         mov cx,ax
 274         add ax,sread
 275         seg cs
 276         cmp ax,sectors
 277         jne ok3_read
 278         mov ax,#1
 279         sub ax,head
 280         jne ok4_read
 281         inc track
 282 ok4_read:
 283         mov head,ax
 284         xor ax,ax
 285 ok3_read:
 286         mov sread,ax
 287         shl cx,#9
 288         add bx,cx
 289         jnc rp_read
 290         mov ax,es
 291         add ah,#0x10
 292         mov es,ax
 293         xor bx,bx
 294         jmp rp_read
 295 
 296 read_track:
 297         pusha
 298         pusha   
 299         mov     ax, #0xe2e      ! loading... message 2e = .
 300         mov     bx, #7
 301         int     0x10
 302         popa            
 303 
 304         mov     dx,track
 305         mov     cx,sread
 306         inc     cx
 307         mov     ch,dl
 308         mov     dx,head
 309         mov     dh,dl
 310         and     dx,#0x0100
 311         mov     ah,#2
 312         
 313         push    dx                              ! save for error dump
 314         push    cx
 315         push    bx
 316         push    ax
 317 
 318         int     0x13
 319         jc      bad_rt
 320         add     sp, #8
 321         popa
 322         ret
 323 
 324 bad_rt: push    ax                              ! save error code
 325         call    print_all                       ! ah = error, al = read
 326         
 327         
 328         xor ah,ah
 329         xor dl,dl
 330         int 0x13
 331         
 332 
 333         add     sp, #10
 334         popa    
 335         jmp read_track
 336 
 337 /*
 338  *      print_all is for debugging purposes.  
 339  *      It will print out all of the registers.  The assumption is that this is
 340  *      called from a routine, with a stack frame like
 341  *      dx 
 342  *      cx
 343  *      bx
 344  *      ax
 345  *      error
 346  *      ret <- sp
 347  *
 348 */
 349  
 350 print_all:
 351         mov     cx, #5          ! error code + 4 registers
 352         mov     bp, sp  
 353 
 354 print_loop:
 355         push    cx              ! save count left
 356         call    print_nl        ! nl for readability
 357 
 358         cmp     cl, 5
 359         jae     no_reg          ! see if register name is needed
 360         
 361         mov     ax, #0xe05 + 'A - 1
 362         sub     al, cl
 363         int     0x10
 364 
 365         mov     al, #'X
 366         int     0x10
 367 
 368         mov     al, #':
 369         int     0x10
 370 
 371 no_reg:
 372         add     bp, #2          ! next register
 373         call    print_hex       ! print it
 374         pop     cx
 375         loop    print_loop
 376         ret
 377 
 378 print_nl:
 379         mov     ax, #0xe0d      ! CR
 380         int     0x10
 381         mov     al, #0xa        ! LF
 382         int     0x10
 383         ret
 384 
 385 /*
 386  *      print_hex is for debugging purposes, and prints the word
 387  *      pointed to by ss:bp in hexadecmial.
 388 */
 389 
 390 print_hex:
 391         mov     cx, #4          ! 4 hex digits
 392         mov     dx, (bp)        ! load word into dx
 393 print_digit:
 394         rol     dx, #4          ! rotate so that lowest 4 bits are used
 395         mov     ah, #0xe        
 396         mov     al, dl          ! mask off so we have only next nibble
 397         and     al, #0xf
 398         add     al, #'0         ! convert to 0-based digit
 399         cmp     al, #'9         ! check for overflow
 400         jbe     good_digit
 401         add     al, #'A - '0 - 10
 402 
 403 good_digit:
 404         int     0x10
 405         loop    print_digit
 406         ret
 407 
 408 
 409 /*
 410  * This procedure turns off the floppy drive motor, so
 411  * that we enter the kernel in a known state, and
 412  * don't have to worry about it later.
 413  */
 414 kill_motor:
 415         push dx
 416         mov dx,#0x3f2
 417         xor al, al
 418         outb
 419         pop dx
 420         ret
 421 
 422 sectors:
 423         .word 0
 424 
 425 msg1:
 426         .byte 13,10
 427         .ascii "Loading"
 428 
 429 .org 506
 430 swap_dev:
 431         .word SWAP_DEV
 432 root_dev:
 433         .word ROOT_DEV
 434 boot_flag:
 435         .word 0xAA55

/* [previous][next][first][last][top][bottom][index][help] */