linux/arch/i386/boot/setup.S
<<
>>
Prefs
   1/*
   2 *      setup.S         Copyright (C) 1991, 1992 Linus Torvalds
   3 *
   4 * setup.s is responsible for getting the system data from the BIOS,
   5 * and putting them into the appropriate places in system memory.
   6 * both setup.s and system has been loaded by the bootblock.
   7 *
   8 * This code asks the bios for memory/disk/other parameters, and
   9 * puts them in a "safe" place: 0x90000-0x901FF, ie where the
  10 * boot-block used to be. It is then up to the protected mode
  11 * system to read them from there before the area is overwritten
  12 * for buffer-blocks.
  13 *
  14 * Move PS/2 aux init code to psaux.c
  15 * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
  16 *
  17 * some changes and additional features by Christoph Niemann,
  18 * March 1993/June 1994 (Christoph.Niemann@linux.org)
  19 *
  20 * add APM BIOS checking by Stephen Rothwell, May 1994
  21 * (sfr@canb.auug.org.au)
  22 *
  23 * High load stuff, initrd support and position independency
  24 * by Hans Lermen & Werner Almesberger, February 1996
  25 * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
  26 *
  27 * Video handling moved to video.S by Martin Mares, March 1996
  28 * <mj@k332.feld.cvut.cz>
  29 *
  30 * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
  31 * parsons) to avoid loadlin confusion, July 1997
  32 *
  33 * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
  34 * <stiker@northlink.com>
  35 *
  36 * Fix to work around buggy BIOSes which don't use carry bit correctly
  37 * and/or report extended memory in CX/DX for e801h memory size detection 
  38 * call.  As a result the kernel got wrong figures.  The int15/e801h docs
  39 * from Ralf Brown interrupt list seem to indicate AX/BX should be used
  40 * anyway.  So to avoid breaking many machines (presumably there was a reason
  41 * to orginally use CX/DX instead of AX/BX), we do a kludge to see
  42 * if CX/DX have been changed in the e801 call and if so use AX/BX .
  43 * Michael Miller, April 2001 <michaelm@mjmm.org>
  44 *
  45 * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
  46 * by Robert Schwebel, December 2001 <robert@schwebel.de>
  47 */
  48
  49#include <asm/segment.h>
  50#include <linux/utsrelease.h>
  51#include <linux/compile.h>
  52#include <asm/boot.h>
  53#include <asm/e820.h>
  54#include <asm/page.h>
  55#include <asm/setup.h>
  56        
  57/* Signature words to ensure LILO loaded us right */
  58#define SIG1    0xAA55
  59#define SIG2    0x5A5A
  60
  61INITSEG  = DEF_INITSEG          # 0x9000, we move boot here, out of the way
  62SYSSEG   = DEF_SYSSEG           # 0x1000, system loaded at 0x10000 (65536).
  63SETUPSEG = DEF_SETUPSEG         # 0x9020, this is the current segment
  64                                # ... and the former contents of CS
  65
  66DELTA_INITSEG = SETUPSEG - INITSEG      # 0x0020
  67
  68.code16
  69.globl begtext, begdata, begbss, endtext, enddata, endbss
  70
  71.text
  72begtext:
  73.data
  74begdata:
  75.bss
  76begbss:
  77.text
  78
  79start:
  80        jmp     trampoline
  81
  82# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
  83
  84                .ascii  "HdrS"          # header signature
  85                .word   0x0206          # header version number (>= 0x0105)
  86                                        # or else old loadlin-1.5 will fail)
  87realmode_swtch: .word   0, 0            # default_switch, SETUPSEG
  88start_sys_seg:  .word   SYSSEG
  89                .word   kernel_version  # pointing to kernel version string
  90                                        # above section of header is compatible
  91                                        # with loadlin-1.5 (header v1.5). Don't
  92                                        # change it.
  93
  94type_of_loader: .byte   0               # = 0, old one (LILO, Loadlin,
  95                                        #      Bootlin, SYSLX, bootsect...)
  96                                        # See Documentation/i386/boot.txt for
  97                                        # assigned ids
  98        
  99# flags, unused bits must be zero (RFU) bit within loadflags
 100loadflags:
 101LOADED_HIGH     = 1                     # If set, the kernel is loaded high
 102CAN_USE_HEAP    = 0x80                  # If set, the loader also has set
 103                                        # heap_end_ptr to tell how much
 104                                        # space behind setup.S can be used for
 105                                        # heap purposes.
 106                                        # Only the loader knows what is free
 107#ifndef __BIG_KERNEL__
 108                .byte   0
 109#else
 110                .byte   LOADED_HIGH
 111#endif
 112
 113setup_move_size: .word  0x8000          # size to move, when setup is not
 114                                        # loaded at 0x90000. We will move setup 
 115                                        # to 0x90000 then just before jumping
 116                                        # into the kernel. However, only the
 117                                        # loader knows how much data behind
 118                                        # us also needs to be loaded.
 119
 120code32_start:                           # here loaders can put a different
 121                                        # start address for 32-bit code.
 122#ifndef __BIG_KERNEL__
 123                .long   0x1000          #   0x1000 = default for zImage
 124#else
 125                .long   0x100000        # 0x100000 = default for big kernel
 126#endif
 127
 128ramdisk_image:  .long   0               # address of loaded ramdisk image
 129                                        # Here the loader puts the 32-bit
 130                                        # address where it loaded the image.
 131                                        # This only will be read by the kernel.
 132
 133ramdisk_size:   .long   0               # its size in bytes
 134
 135bootsect_kludge:
 136                .long   0               # obsolete
 137
 138heap_end_ptr:   .word   modelist+1024   # (Header version 0x0201 or later)
 139                                        # space from here (exclusive) down to
 140                                        # end of setup code can be used by setup
 141                                        # for local heap purposes.
 142
 143pad1:           .word   0
 144cmd_line_ptr:   .long 0                 # (Header version 0x0202 or later)
 145                                        # If nonzero, a 32-bit pointer
 146                                        # to the kernel command line.
 147                                        # The command line should be
 148                                        # located between the start of
 149                                        # setup and the end of low
 150                                        # memory (0xa0000), or it may
 151                                        # get overwritten before it
 152                                        # gets read.  If this field is
 153                                        # used, there is no longer
 154                                        # anything magical about the
 155                                        # 0x90000 segment; the setup
 156                                        # can be located anywhere in
 157                                        # low memory 0x10000 or higher.
 158
 159ramdisk_max:    .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
 160                                        # (Header version 0x0203 or later)
 161                                        # The highest safe address for
 162                                        # the contents of an initrd
 163
 164kernel_alignment:  .long CONFIG_PHYSICAL_ALIGN  #physical addr alignment
 165                                                #required for protected mode
 166                                                #kernel
 167#ifdef CONFIG_RELOCATABLE
 168relocatable_kernel:    .byte 1
 169#else
 170relocatable_kernel:    .byte 0
 171#endif
 172pad2:                   .byte 0
 173pad3:                   .word 0
 174
 175cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
 176                                                #added with boot protocol
 177                                                #version 2.06
 178
 179trampoline:     call    start_of_setup
 180                .align 16
 181                                        # The offset at this point is 0x240
 182                .space  (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff)
 183# End of setup header #####################################################
 184
 185start_of_setup:
 186# Bootlin depends on this being done early
 187        movw    $0x01500, %ax
 188        movb    $0x81, %dl
 189        int     $0x13
 190
 191#ifdef SAFE_RESET_DISK_CONTROLLER
 192# Reset the disk controller.
 193        movw    $0x0000, %ax
 194        movb    $0x80, %dl
 195        int     $0x13
 196#endif
 197
 198# Set %ds = %cs, we know that SETUPSEG = %cs at this point
 199        movw    %cs, %ax                # aka SETUPSEG
 200        movw    %ax, %ds
 201# Check signature at end of setup
 202        cmpw    $SIG1, setup_sig1
 203        jne     bad_sig
 204
 205        cmpw    $SIG2, setup_sig2
 206        jne     bad_sig
 207
 208        jmp     good_sig1
 209
 210# Routine to print asciiz string at ds:si
 211prtstr:
 212        lodsb
 213        andb    %al, %al
 214        jz      fin
 215
 216        call    prtchr
 217        jmp     prtstr
 218
 219fin:    ret
 220
 221# Space printing
 222prtsp2: call    prtspc          # Print double space
 223prtspc: movb    $0x20, %al      # Print single space (note: fall-thru)
 224
 225# Part of above routine, this one just prints ascii al
 226prtchr: pushw   %ax
 227        pushw   %cx
 228        movw    $7,%bx
 229        movw    $0x01, %cx
 230        movb    $0x0e, %ah
 231        int     $0x10
 232        popw    %cx
 233        popw    %ax
 234        ret
 235
 236beep:   movb    $0x07, %al
 237        jmp     prtchr
 238        
 239no_sig_mess: .string    "No setup signature found ..."
 240
 241good_sig1:
 242        jmp     good_sig
 243
 244# We now have to find the rest of the setup code/data
 245bad_sig:
 246        movw    %cs, %ax                        # SETUPSEG
 247        subw    $DELTA_INITSEG, %ax             # INITSEG
 248        movw    %ax, %ds
 249        xorb    %bh, %bh
 250        movb    (497), %bl                      # get setup sect from bootsect
 251        subw    $4, %bx                         # LILO loads 4 sectors of setup
 252        shlw    $8, %bx                         # convert to words (1sect=2^8 words)
 253        movw    %bx, %cx
 254        shrw    $3, %bx                         # convert to segment
 255        addw    $SYSSEG, %bx
 256        movw    %bx, %cs:start_sys_seg
 257# Move rest of setup code/data to here
 258        movw    $2048, %di                      # four sectors loaded by LILO
 259        subw    %si, %si
 260        pushw   %cs
 261        popw    %es
 262        movw    $SYSSEG, %ax
 263        movw    %ax, %ds
 264        rep
 265        movsw
 266        movw    %cs, %ax                        # aka SETUPSEG
 267        movw    %ax, %ds
 268        cmpw    $SIG1, setup_sig1
 269        jne     no_sig
 270
 271        cmpw    $SIG2, setup_sig2
 272        jne     no_sig
 273
 274        jmp     good_sig
 275
 276no_sig:
 277        lea     no_sig_mess, %si
 278        call    prtstr
 279
 280no_sig_loop:
 281        hlt
 282        jmp     no_sig_loop
 283
 284good_sig:
 285        movw    %cs, %ax                        # aka SETUPSEG
 286        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 287        movw    %ax, %ds
 288# Check if an old loader tries to load a big-kernel
 289        testb   $LOADED_HIGH, %cs:loadflags     # Do we have a big kernel?
 290        jz      loader_ok                       # No, no danger for old loaders.
 291
 292        cmpb    $0, %cs:type_of_loader          # Do we have a loader that
 293                                                # can deal with us?
 294        jnz     loader_ok                       # Yes, continue.
 295
 296        pushw   %cs                             # No, we have an old loader,
 297        popw    %ds                             # die. 
 298        lea     loader_panic_mess, %si
 299        call    prtstr
 300
 301        jmp     no_sig_loop
 302
 303loader_panic_mess: .string "Wrong loader, giving up..."
 304
 305# check minimum cpuid
 306# we do this here because it is the last place we can actually
 307# show a user visible error message. Later the video modus
 308# might be already messed up.
 309loader_ok:
 310        call verify_cpu
 311        testl  %eax,%eax
 312        jz      cpu_ok
 313        movw    %cs,%ax         # aka SETUPSEG
 314        movw    %ax,%ds
 315        lea     cpu_panic_mess,%si
 316        call    prtstr
 3171:      jmp     1b
 318
 319cpu_panic_mess:
 320        .asciz  "PANIC: CPU too old for this kernel."
 321
 322#include "../kernel/verify_cpu.S"
 323
 324cpu_ok:
 325# Get memory size (extended mem, kB)
 326
 327        xorl    %eax, %eax
 328        movl    %eax, (0x1e0)
 329#ifndef STANDARD_MEMORY_BIOS_CALL
 330        movb    %al, (E820NR)
 331# Try three different memory detection schemes.  First, try
 332# e820h, which lets us assemble a memory map, then try e801h,
 333# which returns a 32-bit memory size, and finally 88h, which
 334# returns 0-64m
 335
 336# method E820H:
 337# the memory map from hell.  e820h returns memory classified into
 338# a whole bunch of different types, and allows memory holes and
 339# everything.  We scan through this memory map and build a list
 340# of the first 32 memory areas, which we return at [E820MAP].
 341# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
 342
 343#define SMAP  0x534d4150
 344
 345meme820:
 346        xorl    %ebx, %ebx                      # continuation counter
 347        movw    $E820MAP, %di                   # point into the whitelist
 348                                                # so we can have the bios
 349                                                # directly write into it.
 350
 351jmpe820:
 352        movl    $0x0000e820, %eax               # e820, upper word zeroed
 353        movl    $SMAP, %edx                     # ascii 'SMAP'
 354        movl    $20, %ecx                       # size of the e820rec
 355        pushw   %ds                             # data record.
 356        popw    %es
 357        int     $0x15                           # make the call
 358        jc      bail820                         # fall to e801 if it fails
 359
 360        cmpl    $SMAP, %eax                     # check the return is `SMAP'
 361        jne     bail820                         # fall to e801 if it fails
 362
 363#       cmpl    $1, 16(%di)                     # is this usable memory?
 364#       jne     again820
 365
 366        # If this is usable memory, we save it by simply advancing %di by
 367        # sizeof(e820rec).
 368        #
 369good820:
 370        movb    (E820NR), %al                   # up to 128 entries
 371        cmpb    $E820MAX, %al
 372        jae     bail820
 373
 374        incb    (E820NR)
 375        movw    %di, %ax
 376        addw    $20, %ax
 377        movw    %ax, %di
 378again820:
 379        cmpl    $0, %ebx                        # check to see if
 380        jne     jmpe820                         # %ebx is set to EOF
 381bail820:
 382
 383
 384# method E801H:
 385# memory size is in 1k chunksizes, to avoid confusing loadlin.
 386# we store the 0xe801 memory size in a completely different place,
 387# because it will most likely be longer than 16 bits.
 388# (use 1e0 because that's what Larry Augustine uses in his
 389# alternative new memory detection scheme, and it's sensible
 390# to write everything into the same place.)
 391
 392meme801:
 393        stc                                     # fix to work around buggy
 394        xorw    %cx,%cx                         # BIOSes which don't clear/set
 395        xorw    %dx,%dx                         # carry on pass/error of
 396                                                # e801h memory size call
 397                                                # or merely pass cx,dx though
 398                                                # without changing them.
 399        movw    $0xe801, %ax
 400        int     $0x15
 401        jc      mem88
 402
 403        cmpw    $0x0, %cx                       # Kludge to handle BIOSes
 404        jne     e801usecxdx                     # which report their extended
 405        cmpw    $0x0, %dx                       # memory in AX/BX rather than
 406        jne     e801usecxdx                     # CX/DX.  The spec I have read
 407        movw    %ax, %cx                        # seems to indicate AX/BX 
 408        movw    %bx, %dx                        # are more reasonable anyway...
 409
 410e801usecxdx:
 411        andl    $0xffff, %edx                   # clear sign extend
 412        shll    $6, %edx                        # and go from 64k to 1k chunks
 413        movl    %edx, (0x1e0)                   # store extended memory size
 414        andl    $0xffff, %ecx                   # clear sign extend
 415        addl    %ecx, (0x1e0)                   # and add lower memory into
 416                                                # total size.
 417
 418# Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
 419# 64mb, depending on the bios) in ax.
 420mem88:
 421
 422#endif
 423        movb    $0x88, %ah
 424        int     $0x15
 425        movw    %ax, (2)
 426
 427# Set the keyboard repeat rate to the max
 428        movw    $0x0305, %ax
 429        xorw    %bx, %bx
 430        int     $0x16
 431
 432# Check for video adapter and its parameters and allow the
 433# user to browse video modes.
 434        call    video                           # NOTE: we need %ds pointing
 435                                                # to bootsector
 436
 437# Get hd0 data...
 438        xorw    %ax, %ax
 439        movw    %ax, %ds
 440        ldsw    (4 * 0x41), %si
 441        movw    %cs, %ax                        # aka SETUPSEG
 442        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 443        pushw   %ax
 444        movw    %ax, %es
 445        movw    $0x0080, %di
 446        movw    $0x10, %cx
 447        pushw   %cx
 448        cld
 449        rep
 450        movsb
 451# Get hd1 data...
 452        xorw    %ax, %ax
 453        movw    %ax, %ds
 454        ldsw    (4 * 0x46), %si
 455        popw    %cx
 456        popw    %es
 457        movw    $0x0090, %di
 458        rep
 459        movsb
 460# Check that there IS a hd1 :-)
 461        movw    $0x01500, %ax
 462        movb    $0x81, %dl
 463        int     $0x13
 464        jc      no_disk1
 465        
 466        cmpb    $3, %ah
 467        je      is_disk1
 468
 469no_disk1:
 470        movw    %cs, %ax                        # aka SETUPSEG
 471        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 472        movw    %ax, %es
 473        movw    $0x0090, %di
 474        movw    $0x10, %cx
 475        xorw    %ax, %ax
 476        cld
 477        rep
 478        stosb
 479is_disk1:
 480# check for Micro Channel (MCA) bus
 481        movw    %cs, %ax                        # aka SETUPSEG
 482        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 483        movw    %ax, %ds
 484        xorw    %ax, %ax
 485        movw    %ax, (0xa0)                     # set table length to 0
 486        movb    $0xc0, %ah
 487        stc
 488        int     $0x15                           # moves feature table to es:bx
 489        jc      no_mca
 490
 491        pushw   %ds
 492        movw    %es, %ax
 493        movw    %ax, %ds
 494        movw    %cs, %ax                        # aka SETUPSEG
 495        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 496        movw    %ax, %es
 497        movw    %bx, %si
 498        movw    $0xa0, %di
 499        movw    (%si), %cx
 500        addw    $2, %cx                         # table length is a short
 501        cmpw    $0x10, %cx
 502        jc      sysdesc_ok
 503
 504        movw    $0x10, %cx                      # we keep only first 16 bytes
 505sysdesc_ok:
 506        rep
 507        movsb
 508        popw    %ds
 509no_mca:
 510#ifdef CONFIG_X86_VOYAGER
 511        movb    $0xff, 0x40     # flag on config found
 512        movb    $0xc0, %al
 513        mov     $0xff, %ah
 514        int     $0x15           # put voyager config info at es:di
 515        jc      no_voyager
 516        movw    $0x40, %si      # place voyager info in apm table
 517        cld
 518        movw    $7, %cx
 519voyager_rep:
 520        movb    %es:(%di), %al
 521        movb    %al,(%si)
 522        incw    %di
 523        incw    %si
 524        decw    %cx
 525        jnz     voyager_rep
 526no_voyager:     
 527#endif
 528# Check for PS/2 pointing device
 529        movw    %cs, %ax                        # aka SETUPSEG
 530        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 531        movw    %ax, %ds
 532        movb    $0, (0x1ff)                     # default is no pointing device
 533        int     $0x11                           # int 0x11: equipment list
 534        testb   $0x04, %al                      # check if mouse installed
 535        jz      no_psmouse
 536
 537        movb    $0xAA, (0x1ff)                  # device present
 538no_psmouse:
 539
 540#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
 541        movl    $0x0000E980, %eax               # IST Support 
 542        movl    $0x47534943, %edx               # Request value
 543        int     $0x15
 544
 545        movl    %eax, (96)
 546        movl    %ebx, (100)
 547        movl    %ecx, (104)
 548        movl    %edx, (108)
 549#endif
 550
 551#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 552# Then check for an APM BIOS...
 553                                                # %ds points to the bootsector
 554        movw    $0, 0x40                        # version = 0 means no APM BIOS
 555        movw    $0x05300, %ax                   # APM BIOS installation check
 556        xorw    %bx, %bx
 557        int     $0x15
 558        jc      done_apm_bios                   # Nope, no APM BIOS
 559        
 560        cmpw    $0x0504d, %bx                   # Check for "PM" signature
 561        jne     done_apm_bios                   # No signature, no APM BIOS
 562
 563        andw    $0x02, %cx                      # Is 32 bit supported?
 564        je      done_apm_bios                   # No 32-bit, no (good) APM BIOS
 565
 566        movw    $0x05304, %ax                   # Disconnect first just in case
 567        xorw    %bx, %bx
 568        int     $0x15                           # ignore return code
 569        movw    $0x05303, %ax                   # 32 bit connect
 570        xorl    %ebx, %ebx
 571        xorw    %cx, %cx                        # paranoia :-)
 572        xorw    %dx, %dx                        #   ...
 573        xorl    %esi, %esi                      #   ...
 574        xorw    %di, %di                        #   ...
 575        int     $0x15
 576        jc      no_32_apm_bios                  # Ack, error. 
 577
 578        movw    %ax,  (66)                      # BIOS code segment
 579        movl    %ebx, (68)                      # BIOS entry point offset
 580        movw    %cx,  (72)                      # BIOS 16 bit code segment
 581        movw    %dx,  (74)                      # BIOS data segment
 582        movl    %esi, (78)                      # BIOS code segment lengths
 583        movw    %di,  (82)                      # BIOS data segment length
 584# Redo the installation check as the 32 bit connect
 585# modifies the flags returned on some BIOSs
 586        movw    $0x05300, %ax                   # APM BIOS installation check
 587        xorw    %bx, %bx
 588        xorw    %cx, %cx                        # paranoia
 589        int     $0x15
 590        jc      apm_disconnect                  # error -> shouldn't happen
 591
 592        cmpw    $0x0504d, %bx                   # check for "PM" signature
 593        jne     apm_disconnect                  # no sig -> shouldn't happen
 594
 595        movw    %ax, (64)                       # record the APM BIOS version
 596        movw    %cx, (76)                       # and flags
 597        jmp     done_apm_bios
 598
 599apm_disconnect:                                 # Tidy up
 600        movw    $0x05304, %ax                   # Disconnect
 601        xorw    %bx, %bx
 602        int     $0x15                           # ignore return code
 603
 604        jmp     done_apm_bios
 605
 606no_32_apm_bios:
 607        andw    $0xfffd, (76)                   # remove 32 bit support bit
 608done_apm_bios:
 609#endif
 610
 611#include "edd.S"
 612
 613# Now we want to move to protected mode ...
 614        cmpw    $0, %cs:realmode_swtch
 615        jz      rmodeswtch_normal
 616
 617        lcall   *%cs:realmode_swtch
 618
 619        jmp     rmodeswtch_end
 620
 621rmodeswtch_normal:
 622        pushw   %cs
 623        call    default_switch
 624
 625rmodeswtch_end:
 626# Now we move the system to its rightful place ... but we check if we have a
 627# big-kernel. In that case we *must* not move it ...
 628        testb   $LOADED_HIGH, %cs:loadflags
 629        jz      do_move0                        # .. then we have a normal low
 630                                                # loaded zImage
 631                                                # .. or else we have a high
 632                                                # loaded bzImage
 633        jmp     end_move                        # ... and we skip moving
 634
 635do_move0:
 636        movw    $0x100, %ax                     # start of destination segment
 637        movw    %cs, %bp                        # aka SETUPSEG
 638        subw    $DELTA_INITSEG, %bp             # aka INITSEG
 639        movw    %cs:start_sys_seg, %bx          # start of source segment
 640        cld
 641do_move:
 642        movw    %ax, %es                        # destination segment
 643        incb    %ah                             # instead of add ax,#0x100
 644        movw    %bx, %ds                        # source segment
 645        addw    $0x100, %bx
 646        subw    %di, %di
 647        subw    %si, %si
 648        movw    $0x800, %cx
 649        rep
 650        movsw
 651        cmpw    %bp, %bx                        # assume start_sys_seg > 0x200,
 652                                                # so we will perhaps read one
 653                                                # page more than needed, but
 654                                                # never overwrite INITSEG
 655                                                # because destination is a
 656                                                # minimum one page below source
 657        jb      do_move
 658
 659end_move:
 660# then we load the segment descriptors
 661        movw    %cs, %ax                        # aka SETUPSEG
 662        movw    %ax, %ds
 663                
 664# Check whether we need to be downward compatible with version <=201
 665        cmpl    $0, cmd_line_ptr
 666        jne     end_move_self           # loader uses version >=202 features
 667        cmpb    $0x20, type_of_loader
 668        je      end_move_self           # bootsect loader, we know of it
 669
 670# Boot loader doesnt support boot protocol version 2.02.
 671# If we have our code not at 0x90000, we need to move it there now.
 672# We also then need to move the params behind it (commandline)
 673# Because we would overwrite the code on the current IP, we move
 674# it in two steps, jumping high after the first one.
 675        movw    %cs, %ax
 676        cmpw    $SETUPSEG, %ax
 677        je      end_move_self
 678
 679        cli                                     # make sure we really have
 680                                                # interrupts disabled !
 681                                                # because after this the stack
 682                                                # should not be used
 683        subw    $DELTA_INITSEG, %ax             # aka INITSEG
 684        movw    %ss, %dx
 685        cmpw    %ax, %dx
 686        jb      move_self_1
 687
 688        addw    $INITSEG, %dx
 689        subw    %ax, %dx                        # this will go into %ss after
 690                                                # the move
 691move_self_1:
 692        movw    %ax, %ds
 693        movw    $INITSEG, %ax                   # real INITSEG
 694        movw    %ax, %es
 695        movw    %cs:setup_move_size, %cx
 696        std                                     # we have to move up, so we use
 697                                                # direction down because the
 698                                                # areas may overlap
 699        movw    %cx, %di
 700        decw    %di
 701        movw    %di, %si
 702        subw    $move_self_here+0x200, %cx
 703        rep
 704        movsb
 705        ljmp    $SETUPSEG, $move_self_here
 706
 707move_self_here:
 708        movw    $move_self_here+0x200, %cx
 709        rep
 710        movsb
 711        movw    $SETUPSEG, %ax
 712        movw    %ax, %ds
 713        movw    %dx, %ss
 714end_move_self:                                  # now we are at the right place
 715
 716#
 717# Enable A20.  This is at the very best an annoying procedure.
 718# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
 719# AMD Elan bug fix by Robert Schwebel.
 720#
 721
 722#if defined(CONFIG_X86_ELAN)
 723        movb $0x02, %al                 # alternate A20 gate
 724        outb %al, $0x92                 # this works on SC410/SC520
 725a20_elan_wait:
 726        call a20_test
 727        jz a20_elan_wait
 728        jmp a20_done
 729#endif
 730
 731
 732A20_TEST_LOOPS          =  32           # Iterations per wait
 733A20_ENABLE_LOOPS        = 255           # Total loops to try            
 734
 735
 736#ifndef CONFIG_X86_VOYAGER
 737a20_try_loop:
 738
 739        # First, see if we are on a system with no A20 gate.
 740a20_none:
 741        call    a20_test
 742        jnz     a20_done
 743
 744        # Next, try the BIOS (INT 0x15, AX=0x2401)
 745a20_bios:
 746        movw    $0x2401, %ax
 747        pushfl                                  # Be paranoid about flags
 748        int     $0x15
 749        popfl
 750
 751        call    a20_test
 752        jnz     a20_done
 753
 754        # Try enabling A20 through the keyboard controller
 755#endif /* CONFIG_X86_VOYAGER */
 756a20_kbc:
 757        call    empty_8042
 758
 759#ifndef CONFIG_X86_VOYAGER
 760        call    a20_test                        # Just in case the BIOS worked
 761        jnz     a20_done                        # but had a delayed reaction.
 762#endif
 763
 764        movb    $0xD1, %al                      # command write
 765        outb    %al, $0x64
 766        call    empty_8042
 767
 768        movb    $0xDF, %al                      # A20 on
 769        outb    %al, $0x60
 770        call    empty_8042
 771
 772#ifndef CONFIG_X86_VOYAGER
 773        # Wait until a20 really *is* enabled; it can take a fair amount of
 774        # time on certain systems; Toshiba Tecras are known to have this
 775        # problem.
 776a20_kbc_wait:
 777        xorw    %cx, %cx
 778a20_kbc_wait_loop:
 779        call    a20_test
 780        jnz     a20_done
 781        loop    a20_kbc_wait_loop
 782
 783        # Final attempt: use "configuration port A"
 784a20_fast:
 785        inb     $0x92, %al                      # Configuration Port A
 786        orb     $0x02, %al                      # "fast A20" version
 787        andb    $0xFE, %al                      # don't accidentally reset
 788        outb    %al, $0x92
 789
 790        # Wait for configuration port A to take effect
 791a20_fast_wait:
 792        xorw    %cx, %cx
 793a20_fast_wait_loop:
 794        call    a20_test
 795        jnz     a20_done
 796        loop    a20_fast_wait_loop
 797
 798        # A20 is still not responding.  Try frobbing it again.
 799        # 
 800        decb    (a20_tries)
 801        jnz     a20_try_loop
 802        
 803        movw    $a20_err_msg, %si
 804        call    prtstr
 805
 806a20_die:
 807        hlt
 808        jmp     a20_die
 809
 810a20_tries:
 811        .byte   A20_ENABLE_LOOPS
 812
 813a20_err_msg:
 814        .ascii  "linux: fatal error: A20 gate not responding!"
 815        .byte   13, 10, 0
 816
 817        # If we get here, all is good
 818a20_done:
 819
 820#endif /* CONFIG_X86_VOYAGER */
 821# set up gdt and idt and 32bit start address
 822        lidt    idt_48                          # load idt with 0,0
 823        xorl    %eax, %eax                      # Compute gdt_base
 824        movw    %ds, %ax                        # (Convert %ds:gdt to a linear ptr)
 825        shll    $4, %eax
 826        addl    %eax, code32
 827        addl    $gdt, %eax
 828        movl    %eax, (gdt_48+2)
 829        lgdt    gdt_48                          # load gdt with whatever is
 830                                                # appropriate
 831
 832# make sure any possible coprocessor is properly reset..
 833        xorw    %ax, %ax
 834        outb    %al, $0xf0
 835        call    delay
 836
 837        outb    %al, $0xf1
 838        call    delay
 839
 840# well, that went ok, I hope. Now we mask all interrupts - the rest
 841# is done in init_IRQ().
 842        movb    $0xFF, %al                      # mask all interrupts for now
 843        outb    %al, $0xA1
 844        call    delay
 845        
 846        movb    $0xFB, %al                      # mask all irq's but irq2 which
 847        outb    %al, $0x21                      # is cascaded
 848
 849# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
 850# need no steenking BIOS anyway (except for the initial loading :-).
 851# The BIOS-routine wants lots of unnecessary data, and it's less
 852# "interesting" anyway. This is how REAL programmers do it.
 853#
 854# Well, now's the time to actually move into protected mode. To make
 855# things as simple as possible, we do no register set-up or anything,
 856# we let the gnu-compiled 32-bit programs do that. We just jump to
 857# absolute address 0x1000 (or the loader supplied one),
 858# in 32-bit protected mode.
 859#
 860# Note that the short jump isn't strictly needed, although there are
 861# reasons why it might be a good idea. It won't hurt in any case.
 862        movw    $1, %ax                         # protected mode (PE) bit
 863        lmsw    %ax                             # This is it!
 864        jmp     flush_instr
 865
 866flush_instr:
 867        xorw    %bx, %bx                        # Flag to indicate a boot
 868        xorl    %esi, %esi                      # Pointer to real-mode code
 869        movw    %cs, %si
 870        subw    $DELTA_INITSEG, %si
 871        shll    $4, %esi                        # Convert to 32-bit pointer
 872
 873# jump to startup_32 in arch/i386/boot/compressed/head.S
 874#       
 875# NOTE: For high loaded big kernels we need a
 876#       jmpi    0x100000,__BOOT_CS
 877#
 878#       but we yet haven't reloaded the CS register, so the default size 
 879#       of the target offset still is 16 bit.
 880#       However, using an operand prefix (0x66), the CPU will properly
 881#       take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
 882#       Manual, Mixing 16-bit and 32-bit code, page 16-6)
 883
 884        .byte 0x66, 0xea                        # prefix + jmpi-opcode
 885code32: .long   startup_32                      # will be set to %cs+startup_32
 886        .word   __BOOT_CS
 887.code32
 888startup_32:
 889        movl $(__BOOT_DS), %eax
 890        movl %eax, %ds
 891        movl %eax, %es
 892        movl %eax, %fs
 893        movl %eax, %gs
 894        movl %eax, %ss
 895
 896        xorl %eax, %eax
 8971:      incl %eax                               # check that A20 really IS enabled
 898        movl %eax, 0x00000000                   # loop forever if it isn't
 899        cmpl %eax, 0x00100000
 900        je 1b
 901
 902        # Jump to the 32bit entry point
 903        jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi)
 904.code16
 905
 906# Here's a bunch of information about your current kernel..
 907kernel_version: .ascii  UTS_RELEASE
 908                .ascii  " ("
 909                .ascii  LINUX_COMPILE_BY
 910                .ascii  "@"
 911                .ascii  LINUX_COMPILE_HOST
 912                .ascii  ") "
 913                .ascii  UTS_VERSION
 914                .byte   0
 915
 916# This is the default real mode switch routine.
 917# to be called just before protected mode transition
 918default_switch:
 919        cli                                     # no interrupts allowed !
 920        movb    $0x80, %al                      # disable NMI for bootup
 921                                                # sequence
 922        outb    %al, $0x70
 923        lret
 924
 925
 926#ifndef CONFIG_X86_VOYAGER
 927# This routine tests whether or not A20 is enabled.  If so, it
 928# exits with zf = 0.
 929#
 930# The memory address used, 0x200, is the int $0x80 vector, which
 931# should be safe.
 932
 933A20_TEST_ADDR = 4*0x80
 934
 935a20_test:
 936        pushw   %cx
 937        pushw   %ax
 938        xorw    %cx, %cx
 939        movw    %cx, %fs                        # Low memory
 940        decw    %cx
 941        movw    %cx, %gs                        # High memory area
 942        movw    $A20_TEST_LOOPS, %cx
 943        movw    %fs:(A20_TEST_ADDR), %ax
 944        pushw   %ax
 945a20_test_wait:
 946        incw    %ax
 947        movw    %ax, %fs:(A20_TEST_ADDR)
 948        call    delay                           # Serialize and make delay constant
 949        cmpw    %gs:(A20_TEST_ADDR+0x10), %ax
 950        loope   a20_test_wait
 951
 952        popw    %fs:(A20_TEST_ADDR)
 953        popw    %ax
 954        popw    %cx
 955        ret     
 956
 957#endif /* CONFIG_X86_VOYAGER */
 958
 959# This routine checks that the keyboard command queue is empty
 960# (after emptying the output buffers)
 961#
 962# Some machines have delusions that the keyboard buffer is always full
 963# with no keyboard attached...
 964#
 965# If there is no keyboard controller, we will usually get 0xff
 966# to all the reads.  With each IO taking a microsecond and
 967# a timeout of 100,000 iterations, this can take about half a
 968# second ("delay" == outb to port 0x80). That should be ok,
 969# and should also be plenty of time for a real keyboard controller
 970# to empty.
 971#
 972
 973empty_8042:
 974        pushl   %ecx
 975        movl    $100000, %ecx
 976
 977empty_8042_loop:
 978        decl    %ecx
 979        jz      empty_8042_end_loop
 980
 981        call    delay
 982
 983        inb     $0x64, %al                      # 8042 status port
 984        testb   $1, %al                         # output buffer?
 985        jz      no_output
 986
 987        call    delay
 988        inb     $0x60, %al                      # read it
 989        jmp     empty_8042_loop
 990
 991no_output:
 992        testb   $2, %al                         # is input buffer full?
 993        jnz     empty_8042_loop                 # yes - loop
 994empty_8042_end_loop:
 995        popl    %ecx
 996        ret
 997
 998# Read the cmos clock. Return the seconds in al
 999gettime:
1000        pushw   %cx
1001        movb    $0x02, %ah
1002        int     $0x1a
1003        movb    %dh, %al                        # %dh contains the seconds
1004        andb    $0x0f, %al
1005        movb    %dh, %ah
1006        movb    $0x04, %cl
1007        shrb    %cl, %ah
1008        aad
1009        popw    %cx
1010        ret
1011
1012# Delay is needed after doing I/O
1013delay:
1014        outb    %al,$0x80
1015        ret
1016
1017# Descriptor tables
1018#
1019# NOTE: The intel manual says gdt should be sixteen bytes aligned for
1020# efficiency reasons.  However, there are machines which are known not
1021# to boot with misaligned GDTs, so alter this at your peril!  If you alter
1022# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
1023# empty GDT entries (one for NULL and one reserved).
1024#
1025# NOTE: On some CPUs, the GDT must be 8 byte aligned.  This is
1026# true for the Voyager Quad CPU card which will not boot without
1027# This directive.  16 byte aligment is recommended by intel.
1028#
1029        .align 16
1030gdt:
1031        .fill GDT_ENTRY_BOOT_CS,8,0
1032
1033        .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
1034        .word   0                               # base address = 0
1035        .word   0x9A00                          # code read/exec
1036        .word   0x00CF                          # granularity = 4096, 386
1037                                                #  (+5th nibble of limit)
1038
1039        .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
1040        .word   0                               # base address = 0
1041        .word   0x9200                          # data read/write
1042        .word   0x00CF                          # granularity = 4096, 386
1043                                                #  (+5th nibble of limit)
1044gdt_end:
1045        .align  4
1046        
1047        .word   0                               # alignment byte
1048idt_48:
1049        .word   0                               # idt limit = 0
1050        .word   0, 0                            # idt base = 0L
1051
1052        .word   0                               # alignment byte
1053gdt_48:
1054        .word   gdt_end - gdt - 1               # gdt limit
1055        .word   0, 0                            # gdt base (filled in later)
1056
1057# Include video setup & detection code
1058
1059#include "video.S"
1060
1061# Setup signature -- must be last
1062setup_sig1:     .word   SIG1
1063setup_sig2:     .word   SIG2
1064
1065# After this point, there is some free space which is used by the video mode
1066# handling code to store the temporary mode table (not used by the kernel).
1067
1068modelist:
1069
1070.text
1071endtext:
1072.data
1073enddata:
1074.bss
1075endbss:
1076
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.