• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
King.c.Tan's Column

-------I'm a bat,a bat with my sense

flying in the dark!

博客园    首页    新随笔    联系   管理    订阅  订阅
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 

posted on 2005-10-09 15:22  BoyeeStudio  阅读(2672)  评论(1)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3