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

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