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

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