• setup.s (读核笔记系列)


    在前面的一篇文章中已谈到过setup.s,这个文件主要是用于读取机器的硬件配置参数,并把内核模块system 移动到适当的内存位置处。

    下面把setup.s贴出来。

    linux0.11版本的:
      1 !
      2 !    setup.s        (C) 1991 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 
     15 ! NOTE! These had better be the same as in bootsect.s!
     16 
     17 INITSEG  = 0x9000    ! we move boot here - out of the way
     18 SYSSEG   = 0x1000    ! system loaded at 0x10000 (65536).
     19 SETUPSEG = 0x9020    ! this is the current segment
     20 
     21 .globl begtext, begdata, begbss, endtext, enddata, endbss
     22 .text
     23 begtext:
     24 .data
     25 begdata:
     26 .bss
     27 begbss:
     28 .text
     29 
     30 entry start
     31 start:
     32 
     33 ! ok, the read went well so we get current cursor position and save it for
     34 ! posterity.
     35 
     36     mov    ax,#INITSEG    ! this is done in bootsect already, but
     37     mov    ds,ax
     38     mov    ah,#0x03    ! read cursor pos
     39     xor    bh,bh
     40     int    0x10        ! save it in known place, con_init fetches
     41     mov    [0],dx        ! it from 0x90000.
     42 
     43 ! Get memory size (extended mem, kB)
     44 
     45     mov    ah,#0x88
     46     int    0x15
     47     mov    [2],ax
     48 
     49 ! Get video-card data:
     50 
     51     mov    ah,#0x0f
     52     int    0x10
     53     mov    [4],bx        ! bh = display page
     54     mov    [6],ax        ! al = video mode, ah = window width
     55 
     56 ! check for EGA/VGA and some config parameters
     57 
     58     mov    ah,#0x12
     59     mov    bl,#0x10
     60     int    0x10
     61     mov    [8],ax
     62     mov    [10],bx
     63     mov    [12],cx
     64 
     65 ! Get hd0 data
     66 
     67     mov    ax,#0x0000
     68     mov    ds,ax
     69     lds    si,[4*0x41]
     70     mov    ax,#INITSEG
     71     mov    es,ax
     72     mov    di,#0x0080
     73     mov    cx,#0x10
     74     rep
     75     movsb
     76 
     77 ! Get hd1 data
     78 
     79     mov    ax,#0x0000
     80     mov    ds,ax
     81     lds    si,[4*0x46]
     82     mov    ax,#INITSEG
     83     mov    es,ax
     84     mov    di,#0x0090
     85     mov    cx,#0x10
     86     rep
     87     movsb
     88 
     89 ! Check that there IS a hd1 :-)
     90 
     91     mov    ax,#0x01500
     92     mov    dl,#0x81
     93     int    0x13
     94     jc    no_disk1
     95     cmp    ah,#3
     96     je    is_disk1
     97 no_disk1:
     98     mov    ax,#INITSEG
     99     mov    es,ax
    100     mov    di,#0x0090
    101     mov    cx,#0x10
    102     mov    ax,#0x00
    103     rep
    104     stosb
    105 is_disk1:
    106 
    107 ! now we want to move to protected mode 
    108 
    109     cli            ! no interrupts allowed !
    110 
    111 ! first we move the system to it's rightful place
    112 
    113     mov    ax,#0x0000
    114     cld            ! 'direction'=0, movs moves forward
    115 do_move:
    116     mov    es,ax        ! destination segment
    117     add    ax,#0x1000
    118     cmp    ax,#0x9000
    119     jz    end_move
    120     mov    ds,ax        ! source segment
    121     sub    di,di
    122     sub    si,si
    123     mov     cx,#0x8000
    124     rep
    125     movsw
    126     jmp    do_move
    127 
    128 ! then we load the segment descriptors
    129 
    130 end_move:
    131     mov    ax,#SETUPSEG    ! right, forgot this at first. didn't work :-)
    132     mov    ds,ax
    133     lidt    idt_48        ! load idt with 0,0
    134     lgdt    gdt_48        ! load gdt with whatever appropriate
    135 
    136 ! that was painless, now we enable A20
    137 
    138     call    empty_8042
    139     mov    al,#0xD1        ! command write
    140     out    #0x64,al
    141     call    empty_8042
    142     mov    al,#0xDF        ! A20 on
    143     out    #0x60,al
    144     call    empty_8042
    145 
    146 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
    147 ! we put them right after the intel-reserved hardware interrupts, at
    148 ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
    149 ! messed this up with the original PC, and they haven't been able to
    150 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
    151 ! which is used for the internal hardware interrupts as well. We just
    152 ! have to reprogram the 8259's, and it isn't fun.
    153 
    154     mov    al,#0x11        ! initialization sequence
    155     out    #0x20,al        ! send it to 8259A-1
    156     .word    0x00eb,0x00eb        ! jmp $+2, jmp $+2
    157     out    #0xA0,al        ! and to 8259A-2
    158     .word    0x00eb,0x00eb
    159     mov    al,#0x20        ! start of hardware int's (0x20)
    160     out    #0x21,al
    161     .word    0x00eb,0x00eb
    162     mov    al,#0x28        ! start of hardware int's 2 (0x28)
    163     out    #0xA1,al
    164     .word    0x00eb,0x00eb
    165     mov    al,#0x04        ! 8259-1 is master
    166     out    #0x21,al
    167     .word    0x00eb,0x00eb
    168     mov    al,#0x02        ! 8259-2 is slave
    169     out    #0xA1,al
    170     .word    0x00eb,0x00eb
    171     mov    al,#0x01        ! 8086 mode for both
    172     out    #0x21,al
    173     .word    0x00eb,0x00eb
    174     out    #0xA1,al
    175     .word    0x00eb,0x00eb
    176     mov    al,#0xFF        ! mask off all interrupts for now
    177     out    #0x21,al
    178     .word    0x00eb,0x00eb
    179     out    #0xA1,al
    180 
    181 ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
    182 ! need no steenking BIOS anyway (except for the initial loading :-).
    183 ! The BIOS-routine wants lots of unnecessary data, and it's less
    184 "interesting" anyway. This is how REAL programmers do it.
    185 !
    186 ! Well, now's the time to actually move into protected mode. To make
    187 ! things as simple as possible, we do no register set-up or anything,
    188 ! we let the gnu-compiled 32-bit programs do that. We just jump to
    189 ! absolute address 0x00000, in 32-bit protected mode.
    190 
    191     mov    ax,#0x0001    ! protected mode (PE) bit
    192     lmsw    ax        ! This is it!
    193     jmpi    0,8        ! jmp offset 0 of segment 8 (cs)
    194 
    195 ! This routine checks that the keyboard command queue is empty
    196 ! No timeout is used - if this hangs there is something wrong with
    197 ! the machine, and we probably couldn't proceed anyway.
    198 empty_8042:
    199     .word    0x00eb,0x00eb
    200     in    al,#0x64    ! 8042 status port
    201     test    al,#2        ! is input buffer full?
    202     jnz    empty_8042    ! yes - loop
    203     ret
    204 
    205 gdt:
    206     .word    0,0,0,0        ! dummy
    207 
    208     .word    0x07FF        ! 8Mb - limit=2047 (2048*4096=8Mb)
    209     .word    0x0000        ! base address=0
    210     .word    0x9A00        ! code read/exec
    211     .word    0x00C0        ! granularity=4096, 386
    212 
    213     .word    0x07FF        ! 8Mb - limit=2047 (2048*4096=8Mb)
    214     .word    0x0000        ! base address=0
    215     .word    0x9200        ! data read/write
    216     .word    0x00C0        ! granularity=4096, 386
    217 
    218 idt_48:
    219     .word    0            ! idt limit=0
    220     .word    0,0            ! idt base=0L
    221 
    222 gdt_48:
    223     .word    0x800        ! gdt limit=2048, 256 GDT entries
    224     .word    512+gdt,0x9    ! gdt base = 0X9xxxx
    225     
    226 .text
    227 endtext:
    228 .data
    229 enddata:
    230 .bss
    231 endbss:
    232 

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

  • 相关阅读:
    LeetCode. 476. Number Complement
    LeetCode 172.Factorial Trailing Zeroes
    原码,反码,补码笔记
    python3笔记
    django笔记(python web框架)
    mysql 8.0 主从复制配置
    centos 7系统安装mysql 8.0
    MobaXterm无法退格删除
    Oracle数据泵常用命令
    oracle查年度周末日期
  • 原文地址:https://www.cnblogs.com/BoyeeStudio/p/250959.html
Copyright © 2020-2023  润新知