Linux/boot/bootsect.S

本文详细介绍了Linux启动扇区(bootsect.s)的工作原理和技术细节。包括加载过程、内存分配、错误处理等内容,并解释了如何通过BIOS中断读取磁盘上的系统文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Linux/boot/bootsect.S

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值