root/arch/i386/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 1
  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 ! ax and es already contain INITSEG
  72 
  73 go:     mov     di,#0x4000-12   ! 0x4000 is arbitrary value >= length of
  74                                 ! bootsect + length of setup + room for stack
  75                                 ! 12 is disk parm size
  76 
  77 ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
  78 ! wouldn't have to worry about this if we checked the top of memory.  Also
  79 ! my BIOS can be configured to put the wini drive tables in high memory
  80 ! instead of in the vector table.  The old stack might have clobbered the
  81 ! drive table.
  82 
  83         mov     ds,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 ! cx contains 0 from rep movsw above
 104 
 105         mov     fs,cx
 106         mov     bx,#0x78                ! fs:bx is parameter table address
 107         push    ds
 108         seg fs
 109         lds     si,(bx)                 ! ds:si is source
 110 
 111         mov     cl,#6                   ! copy 12 bytes
 112         cld
 113         push    di
 114 
 115         rep
 116         movsw
 117 
 118         pop     di
 119         pop     ds
 120 
 121         movb    4(di),*36               ! patch sector count
 122 
 123         seg fs
 124         mov     (bx),di
 125         seg fs
 126         mov     2(bx),es
 127 
 128 ! load the setup-sectors directly after the bootblock.
 129 ! Note that 'es' is already set up.
 130 ! Also cx is 0 from rep movsw above.
 131 
 132 load_setup:
 133         xor     ah,ah                   ! reset FDC 
 134         xor     dl,dl
 135         int     0x13    
 136 
 137         xor     dx, dx                  ! drive 0, head 0
 138         mov     cl,#0x02                ! sector 2, track 0
 139         mov     bx,#0x0200              ! address = 512, in INITSEG
 140         mov     ah,#0x02                ! service 2, nr of sectors
 141         mov     al,setup_sects          ! (assume all on head 0, track 0)
 142         int     0x13                    ! read it
 143         jnc     ok_load_setup           ! ok - continue
 144 
 145         push    ax                      ! dump error code
 146         call    print_nl
 147         mov     bp, sp
 148         call    print_hex
 149         pop     ax      
 150         
 151         jmp     load_setup
 152 
 153 ok_load_setup:
 154 
 155 ! Get disk drive parameters, specifically nr of sectors/track
 156 
 157 #if 0
 158 
 159 ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
 160 ! disks.  It doesn't work for one of my BIOS's (1987 Award).  It was
 161 ! fatal not to check the error code.
 162 
 163         xor     dl,dl
 164         mov     ah,#0x08                ! AH=8 is get drive parameters
 165         int     0x13
 166         xor     ch,ch
 167 #else
 168 
 169 ! It seems that there is no BIOS call to get the number of sectors.  Guess
 170 ! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
 171 ! 15 if sector 15 can be read.  Otherwise guess 9.
 172 
 173         mov     si,#disksizes           ! table of sizes to try
 174 
 175 probe_loop:
 176         lodsb
 177         cbw                             ! extend to word
 178         mov     sectors, ax
 179         cmp     si,#disksizes+4
 180         jae     got_sectors             ! if all else fails, try 9
 181         xchg    ax, cx                  ! cx = track and sector
 182         xor     dx, dx                  ! drive 0, head 0
 183         xor     bl, bl
 184         mov     bh,setup_sects
 185         inc     bh
 186         shl     bh,#1                   ! address after setup (es = cs)
 187         mov     ax,#0x0201              ! service 2, 1 sector
 188         int     0x13
 189         jc      probe_loop              ! try next value
 190 
 191 #endif
 192 
 193 got_sectors:
 194 
 195 ! Restore es
 196 
 197         mov     ax,#INITSEG
 198         mov     es,ax
 199 
 200 ! Print some inane message
 201 
 202         mov     ah,#0x03                ! read cursor pos
 203         xor     bh,bh
 204         int     0x10
 205         
 206         mov     cx,#9
 207         mov     bx,#0x0007              ! page 0, attribute 7 (normal)
 208         mov     bp,#msg1
 209         mov     ax,#0x1301              ! write string, move cursor
 210         int     0x10
 211 
 212 ! ok, we've written the message, now
 213 ! we want to load the system (at 0x10000)
 214 
 215         mov     ax,#SYSSEG
 216         mov     es,ax           ! segment of 0x010000
 217         call    read_it
 218         call    kill_motor
 219         call    print_nl
 220 
 221 ! After that we check which root-device to use. If the device is
 222 ! defined (!= 0), nothing is done and the given device is used.
 223 ! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
 224 ! depending on the number of sectors we pretend to know we have.
 225 
 226         seg cs
 227         mov     ax,root_dev
 228         or      ax,ax
 229         jne     root_defined
 230         seg cs
 231         mov     bx,sectors
 232         mov     ax,#0x0208              ! /dev/ps0 - 1.2Mb
 233         cmp     bx,#15
 234         je      root_defined
 235         mov     al,#0x1c                ! /dev/PS0 - 1.44Mb
 236         cmp     bx,#18
 237         je      root_defined
 238         mov     al,#0x20                ! /dev/fd0H2880 - 2.88Mb
 239         cmp     bx,#36
 240         je      root_defined
 241         mov     al,#0                   ! /dev/fd0 - autodetect
 242 root_defined:
 243         seg cs
 244         mov     root_dev,ax
 245 
 246 ! after that (everything loaded), we jump to
 247 ! the setup-routine loaded directly after
 248 ! the bootblock:
 249 
 250         jmpi    0,SETUPSEG
 251 
 252 ! This routine loads the system at address 0x10000, making sure
 253 ! no 64kB boundaries are crossed. We try to load it as fast as
 254 ! possible, loading whole tracks whenever we can.
 255 !
 256 ! in:   es - starting address segment (normally 0x1000)
 257 !
 258 sread:  .word 0                 ! sectors read of current track
 259 head:   .word 0                 ! current head
 260 track:  .word 0                 ! current track
 261 
 262 read_it:
 263         mov     al,setup_sects
 264         inc     al
 265         mov     sread,al
 266         mov ax,es
 267         test ax,#0x0fff
 268 die:    jne die                 ! es must be at 64kB boundary
 269         xor bx,bx               ! bx is starting address within segment
 270 rp_read:
 271 #ifdef __BIG_KERNEL__
 272 #define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
 273                                 ! NOTE: as86 can't assemble this
 274         CALL_HIGHLOAD_KLUDGE    ! this is within setup.S
 275 #else
 276         mov ax,es
 277         sub ax,#SYSSEG
 278 #endif
 279         cmp ax,syssize          ! have we loaded all yet?
 280         jbe ok1_read
 281         ret
 282 ok1_read:
 283         mov ax,sectors
 284         sub ax,sread
 285         mov cx,ax
 286         shl cx,#9
 287         add cx,bx
 288         jnc ok2_read
 289         je ok2_read
 290         xor ax,ax
 291         sub ax,bx
 292         shr ax,#9
 293 ok2_read:
 294         call read_track
 295         mov cx,ax
 296         add ax,sread
 297         cmp ax,sectors
 298         jne ok3_read
 299         mov ax,#1
 300         sub ax,head
 301         jne ok4_read
 302         inc track
 303 ok4_read:
 304         mov head,ax
 305         xor ax,ax
 306 ok3_read:
 307         mov sread,ax
 308         shl cx,#9
 309         add bx,cx
 310         jnc rp_read
 311         mov ax,es
 312         add ah,#0x10
 313         mov es,ax
 314         xor bx,bx
 315         jmp rp_read
 316 
 317 read_track:
 318         pusha
 319         pusha   
 320         mov     ax, #0xe2e      ! loading... message 2e = .
 321         mov     bx, #7
 322         int     0x10
 323         popa            
 324 
 325         mov     dx,track
 326         mov     cx,sread
 327         inc     cx
 328         mov     ch,dl
 329         mov     dx,head
 330         mov     dh,dl
 331         and     dx,#0x0100
 332         mov     ah,#2
 333         
 334         push    dx                              ! save for error dump
 335         push    cx
 336         push    bx
 337         push    ax
 338 
 339         int     0x13
 340         jc      bad_rt
 341         add     sp, #8
 342         popa
 343         ret
 344 
 345 bad_rt: push    ax                              ! save error code
 346         call    print_all                       ! ah = error, al = read
 347         
 348         
 349         xor ah,ah
 350         xor dl,dl
 351         int 0x13
 352         
 353 
 354         add     sp, #10
 355         popa    
 356         jmp read_track
 357 
 358 /*
 359  *      print_all is for debugging purposes.  
 360  *      It will print out all of the registers.  The assumption is that this is
 361  *      called from a routine, with a stack frame like
 362  *      dx 
 363  *      cx
 364  *      bx
 365  *      ax
 366  *      error
 367  *      ret <- sp
 368  *
 369 */
 370  
 371 print_all:
 372         mov     cx, #5          ! error code + 4 registers
 373         mov     bp, sp  
 374 
 375 print_loop:
 376         push    cx              ! save count left
 377         call    print_nl        ! nl for readability
 378 
 379         cmp     cl, #5
 380         jae     no_reg          ! see if register name is needed
 381         
 382         mov     ax, #0xe05 + 'A - 1
 383         sub     al, cl
 384         int     0x10
 385 
 386         mov     al, #'X
 387         int     0x10
 388 
 389         mov     al, #':
 390         int     0x10
 391 
 392 no_reg:
 393         add     bp, #2          ! next register
 394         call    print_hex       ! print it
 395         pop     cx
 396         loop    print_loop
 397         ret
 398 
 399 print_nl:
 400         mov     ax, #0xe0d      ! CR
 401         int     0x10
 402         mov     al, #0xa        ! LF
 403         int     0x10
 404         ret
 405 
 406 /*
 407  *      print_hex is for debugging purposes, and prints the word
 408  *      pointed to by ss:bp in hexadecimal.
 409 */
 410 
 411 print_hex:
 412         mov     cx, #4          ! 4 hex digits
 413         mov     dx, (bp)        ! load word into dx
 414 print_digit:
 415         rol     dx, #4          ! rotate so that lowest 4 bits are used
 416         mov     ax, #0xe0f      ! ah = request, al = mask for nybble
 417         and     al, dl
 418         add     al, #0x90       ! convert al to ascii hex (four instructions)
 419         daa
 420         adc     al, #0x40
 421         daa
 422         int     0x10
 423         loop    print_digit
 424         ret
 425 
 426 
 427 /*
 428  * This procedure turns off the floppy drive motor, so
 429  * that we enter the kernel in a known state, and
 430  * don't have to worry about it later.
 431  */
 432 kill_motor:
 433         push dx
 434         mov dx,#0x3f2
 435         xor al, al
 436         outb
 437         pop dx
 438         ret
 439 
 440 sectors:
 441         .word 0
 442 
 443 disksizes:
 444         .byte 36,18,15,9
 445 
 446 msg1:
 447         .byte 13,10
 448         .ascii "Loading"
 449 
 450 .org 497
 451 setup_sects:
 452         .byte SETUPSECS
 453 root_flags:
 454         .word CONFIG_ROOT_RDONLY
 455 syssize:
 456         .word SYSSIZE
 457 swap_dev:
 458         .word SWAP_DEV
 459 ram_size:
 460         .word RAMDISK
 461 vid_mode:
 462         .word SVGA_MODE
 463 root_dev:
 464         .word ROOT_DEV
 465 boot_flag:
 466         .word 0xAA55

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