Adding upstream version 3.86+dfsg.
[syslinux-debian/hramrach.git] / core / extlinux.asm
blobac5fb6f036de266e654e0134bc4de2b65a5182ca
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
4 ; extlinux.asm
6 ; A program to boot Linux kernels off an ext2/ext3 filesystem.
8 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
9 ; Copyright 2009 Intel Corporation; author: H. Peter Anvin
11 ; This program is free software; you can redistribute it and/or modify
12 ; it under the terms of the GNU General Public License as published by
13 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
14 ; Boston MA 02111-1307, USA; either version 2 of the License, or
15 ; (at your option) any later version; incorporated herein by reference.
17 ; ****************************************************************************
19 %define IS_EXTLINUX 1
20 %include "head.inc"
21 %include "ext2_fs.inc"
24 ; Some semi-configurable constants... change on your own risk.
26 my_id equ extlinux_id
27 ; NASM 0.98.38 croaks if these are equ's rather than macros...
28 FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
29 FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size
30 NULLFILE equ 0 ; Null character == empty filename
31 NULLOFFSET equ 0 ; Position in which to look
32 retry_count equ 16 ; How patient are we with the disk?
33 %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
34 LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
36 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
37 MAX_OPEN equ (1 << MAX_OPEN_LG2)
39 SECTOR_SHIFT equ 9
40 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
42 MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup
43 SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink
44 ; (should be >= FILENAME_MAX)
46 ROOT_DIR_WORD equ 0x002F
47 CUR_DIR_DWORD equ 0x00002F2E
50 ; The following structure is used for "virtual kernels"; i.e. LILO-style
51 ; option labels. The options we permit here are `kernel' and `append
52 ; Since there is no room in the bottom 64K for all of these, we
53 ; stick them in high memory and copy them down before we need them.
55 struc vkernel
56 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
57 vk_rname: resb FILENAME_MAX ; Real name
58 vk_appendlen: resw 1
59 vk_type: resb 1 ; Type of file
60 alignb 4
61 vk_append: resb max_cmd_len+1 ; Command line
62 alignb 4
63 vk_end: equ $ ; Should be <= vk_size
64 endstruc
67 ; File structure. This holds the information for each currently open file.
69 struc open_file_t
70 file_bytesleft resd 1 ; Number of bytes left (0 = free)
71 file_sector resd 1 ; Next linear sector to read
72 file_in_sec resd 1 ; Sector where inode lives
73 file_in_off resw 1
74 file_mode resw 1
75 endstruc
77 %ifndef DEPEND
78 %if (open_file_t_size & (open_file_t_size-1))
79 %error "open_file_t is not a power of 2"
80 %endif
81 %endif
83 ; ---------------------------------------------------------------------------
84 ; BEGIN CODE
85 ; ---------------------------------------------------------------------------
88 ; Memory below this point is reserved for the BIOS and the MBR
90 section .earlybss
91 trackbufsize equ 8192
92 trackbuf resb trackbufsize ; Track buffer goes here
93 ; ends at 2800h
95 section .bss
96 SuperBlock resb 1024 ; ext2 superblock
97 ClustSize resd 1 ; Bytes/cluster ("block")
98 ClustMask resd 1 ; Sectors/cluster - 1
99 PtrsPerBlock1 resd 1 ; Pointers/cluster
100 PtrsPerBlock2 resd 1 ; (Pointers/cluster)^2
101 DriveNumber resb 1 ; BIOS drive number
102 ClustShift resb 1 ; Shift count for sectors/cluster
103 ClustByteShift resb 1 ; Shift count for bytes/cluster
105 alignb open_file_t_size
106 Files resb MAX_OPEN*open_file_t_size
109 ; Common bootstrap code for disk-based derivatives
111 %include "diskstart.inc"
114 ; Load the real (ext2) superblock; 1024 bytes long at offset 1024
116 mov bx,SuperBlock
117 mov eax,1024 >> SECTOR_SHIFT
118 mov bp,ax
119 call getlinsecsr
122 ; Compute some values...
124 xor edx,edx
125 inc edx
127 ; s_log_block_size = log2(blocksize) - 10
128 mov cl,[SuperBlock+s_log_block_size]
129 add cl,10
130 mov [ClustByteShift],cl
131 mov eax,edx
132 shl eax,cl
133 mov [ClustSize],eax
135 sub cl,SECTOR_SHIFT
136 mov [ClustShift],cl
137 shr eax,SECTOR_SHIFT
138 mov [SecPerClust],eax
139 dec eax
140 mov [ClustMask],eax
142 add cl,SECTOR_SHIFT-2 ; 4 bytes/pointer
143 shl edx,cl
144 mov [PtrsPerBlock1],edx
145 shl edx,cl
146 mov [PtrsPerBlock2],edx
149 ; Common initialization code
151 %include "init.inc"
152 %include "cpuinit.inc"
155 ; Initialize the metadata cache
157 call initcache
160 ; Now, everything is "up and running"... patch kaboom for more
161 ; verbosity and using the full screen system
163 ; E9 = JMP NEAR
164 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
167 ; Now we're all set to start with our *real* business. First load the
168 ; configuration file (if any) and parse it.
170 ; In previous versions I avoided using 32-bit registers because of a
171 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
172 ; random. I figure, though, that if there are any of those still left
173 ; they probably won't be trying to install Linux on them...
175 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
176 ; to take'm out. In fact, we may want to put them back if we're going
177 ; to boot ELKS at some point.
181 ; Load configuration file
183 load_config:
184 mov si,config_name ; Save config file name
185 mov di,ConfigName
186 call strcpy
187 mov dword [CurrentDirName],CUR_DIR_DWORD ; Write './',0,0 to the CurrentDirName
188 call build_curdir_str
190 mov di,ConfigName
191 call open
192 jz no_config_file
195 ; Now we have the config file open. Parse the config file and
196 ; run the user interface.
198 %include "ui.inc"
201 ; getlinsec_ext: same as getlinsec, except load any sector from the zero
202 ; block as all zeros; use to load any data derived
203 ; from an ext2 block pointer, i.e. anything *except the
204 ; superblock.*
206 getonesec_ext:
207 mov bp,1
209 getlinsec_ext:
210 cmp eax,[SecPerClust]
211 jae getlinsecsr ; Nothing fancy
213 ; If we get here, at least part of what we want is in the
214 ; zero block. Zero one sector at a time and loop.
215 push eax
216 push cx
217 xchg di,bx
218 xor eax,eax
219 mov cx,SECTOR_SIZE >> 2
220 rep stosd
221 xchg di,bx
222 pop cx
223 pop eax
224 inc eax
225 dec bp
226 jnz getlinsec_ext
230 ; allocate_file: Allocate a file structure
232 ; If successful:
233 ; ZF set
234 ; BX = file pointer
235 ; In unsuccessful:
236 ; ZF clear
238 allocate_file:
239 TRACER 'a'
240 push cx
241 mov bx,Files
242 mov cx,MAX_OPEN
243 .check: cmp dword [bx], byte 0
244 je .found
245 add bx,open_file_t_size ; ZF = 0
246 loop .check
247 ; ZF = 0 if we fell out of the loop
248 .found: pop cx
251 ; open_inode:
252 ; Open a file indicated by an inode number in EAX
254 ; NOTE: This file considers finding a zero-length file an
255 ; error. This is so we don't have to deal with that special
256 ; case elsewhere in the program (most loops have the test
257 ; at the end).
259 ; If successful:
260 ; ZF clear
261 ; SI = file pointer
262 ; EAX = file length in bytes
263 ; ThisInode = the first 128 bytes of the inode
264 ; If unsuccessful
265 ; ZF set
267 ; Assumes CS == DS == ES.
269 open_inode.allocate_failure:
270 xor eax,eax
271 pop bx
272 pop di
275 open_inode:
276 push di
277 push bx
278 call allocate_file
279 jnz .allocate_failure
281 push cx
282 push gs
283 ; First, get the appropriate inode group and index
284 dec eax ; There is no inode 0
285 xor edx,edx
286 mov [bx+file_sector],edx
287 div dword [SuperBlock+s_inodes_per_group]
288 ; EAX = inode group; EDX = inode within group
289 push edx
291 ; Now, we need the block group descriptor.
292 ; To get that, we first need the relevant descriptor block.
294 shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
295 xor edx,edx
296 div dword [ClustSize]
297 ; eax = block #, edx = offset in block
298 add eax,dword [SuperBlock+s_first_data_block]
299 inc eax ; s_first_data_block+1
300 mov cl,[ClustShift]
301 shl eax,cl
302 push edx
303 shr edx,SECTOR_SHIFT
304 add eax,edx
305 pop edx
306 and dx,SECTOR_SIZE-1
307 call getcachesector ; Get the group descriptor
308 add si,dx
309 mov esi,[gs:si+bg_inode_table] ; Get inode table block #
310 pop eax ; Get inode within group
311 movzx edx, word [SuperBlock+s_inode_size]
312 mul edx
313 ; edx:eax = byte offset in inode table
314 div dword [ClustSize]
315 ; eax = block # versus inode table, edx = offset in block
316 add eax,esi
317 shl eax,cl ; Turn into sector
318 push dx
319 shr edx,SECTOR_SHIFT
320 add eax,edx
321 mov [bx+file_in_sec],eax
322 pop dx
323 and dx,SECTOR_SIZE-1
324 mov [bx+file_in_off],dx
326 call getcachesector
327 add si,dx
328 mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2
329 mov di,ThisInode
330 gs rep movsd
332 mov ax,[ThisInode+i_mode]
333 mov [bx+file_mode],ax
334 mov eax,[ThisInode+i_size]
335 mov [bx+file_bytesleft],eax
336 mov si,bx
337 and eax,eax ; ZF clear unless zero-length file
338 pop gs
339 pop cx
340 pop bx
341 pop di
344 section .bss
345 alignb 4
346 ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode
348 section .text
350 ; close_file:
351 ; Deallocates a file structure (pointer in SI)
352 ; Assumes CS == DS.
354 close_file:
355 and si,si
356 jz .closed
357 mov dword [si],0 ; First dword == file_bytesleft
358 xor si,si
359 .closed: ret
362 ; searchdir:
363 ; Search the root directory for a pre-mangled filename in DS:DI.
365 ; NOTE: This file considers finding a zero-length file an
366 ; error. This is so we don't have to deal with that special
367 ; case elsewhere in the program (most loops have the test
368 ; at the end).
370 ; If successful:
371 ; ZF clear
372 ; SI = file pointer
373 ; DX:AX = EAX = file length in bytes
374 ; If unsuccessful
375 ; ZF set
377 ; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
379 searchdir:
380 push bx
381 push cx
382 push bp
383 mov byte [SymlinkCtr],MAX_SYMLINKS
385 mov eax,[CurrentDir]
386 .begin_path:
387 .leadingslash:
388 cmp byte [di],'/' ; Absolute filename?
389 jne .gotdir
390 mov eax,EXT2_ROOT_INO
391 inc di ; Skip slash
392 jmp .leadingslash
393 .gotdir:
395 ; At this point, EAX contains the directory inode,
396 ; and DS:DI contains a pathname tail.
397 .open:
398 push eax ; Save directory inode
400 call open_inode
401 jz .missing ; If error, done
403 mov cx,[si+file_mode]
404 shr cx,S_IFSHIFT ; Get file type
406 cmp cx,T_IFDIR
407 je .directory
409 add sp,4 ; Drop directory inode
411 cmp cx,T_IFREG
412 je .file
413 cmp cx,T_IFLNK
414 je .symlink
416 ; Otherwise, something bad...
417 .err:
418 call close_file
419 .err_noclose:
420 xor eax,eax
421 xor si,si
422 cwd ; DX <- 0
424 .done:
425 and eax,eax ; Set/clear ZF
426 pop bp
427 pop cx
428 pop bx
431 .missing:
432 add sp,4 ; Drop directory inode
433 jmp .done
436 ; It's a file.
438 .file:
439 cmp byte [di],0 ; End of path?
440 je .done ; If so, done
441 jmp .err ; Otherwise, error
444 ; It's a directory.
446 .directory:
447 pop dword [ThisDir] ; Remember what directory we're searching
449 cmp byte [di],0 ; More path?
450 je .err ; If not, bad
452 .skipslash: ; Skip redundant slashes
453 cmp byte [di],'/'
454 jne .readdir
455 inc di
456 jmp .skipslash
458 .readdir:
459 mov cx,[SecPerClust]
460 push cx
461 shl cx,SECTOR_SHIFT
462 mov bx,trackbuf
463 add cx,bx
464 mov [EndBlock],cx
465 pop cx
466 push bx
467 call getfssec
468 pop bx
469 pushf ; Save EOF flag
470 push si ; Save filesystem pointer
471 .getent:
472 cmp bx,[EndBlock]
473 jae .endblock
475 push di
476 cmp dword [bx+d_inode],0 ; Zero inode = void entry
477 je .nope
479 movzx cx,byte [bx+d_name_len]
480 lea si,[bx+d_name]
481 repe cmpsb
482 je .maybe
483 .nope:
484 pop di
485 add bx,[bx+d_rec_len]
486 jmp .getent
488 .endblock:
489 pop si
490 popf
491 jnc .readdir ; There is more
492 jmp .err ; Otherwise badness...
494 .maybe:
495 mov eax,[bx+d_inode]
497 ; Does this match the end of the requested filename?
498 cmp byte [di],0
499 je .finish
500 cmp byte [di],'/'
501 jne .nope
503 ; We found something; now we need to open the file
504 .finish:
505 pop bx ; Adjust stack (di)
506 pop si
507 call close_file ; Close directory
508 pop bx ; Adjust stack (flags)
509 jmp .open
512 ; It's a symlink. We have to determine if it's a fast symlink
513 ; (data stored in the inode) or not (data stored as a regular
514 ; file.) Either which way, we start from the directory
515 ; which we just visited if relative, or from the root directory
516 ; if absolute, and append any remaining part of the path.
518 .symlink:
519 dec byte [SymlinkCtr]
520 jz .err ; Too many symlink references
522 cmp eax,SYMLINK_SECTORS*SECTOR_SIZE
523 jae .err ; Symlink too long
525 ; Computation for fast symlink, as defined by ext2/3 spec
526 xor ecx,ecx
527 cmp [ThisInode+i_file_acl],ecx
528 setne cl ; ECX <- i_file_acl ? 1 : 0
529 cmp [ThisInode+i_blocks],ecx
530 jne .slow_symlink
532 ; It's a fast symlink
533 .fast_symlink:
534 call close_file ; We've got all we need
535 mov si,ThisInode+i_block
537 push di
538 mov di,SymlinkTmpBuf
539 mov ecx,eax
540 rep movsb
541 pop si
543 .symlink_finish:
544 cmp byte [si],0
545 je .no_slash
546 mov al,'/'
547 stosb
548 .no_slash:
549 mov bp,SymlinkTmpBufEnd
550 call strecpy
551 jc .err_noclose ; Buffer overflow
553 ; Now copy it to the "real" buffer; we need to have
554 ; two buffers so we avoid overwriting the tail on the
555 ; next copy
556 mov si,SymlinkTmpBuf
557 mov di,SymlinkBuf
558 push di
559 call strcpy
560 pop di
561 mov eax,[ThisDir] ; Resume searching previous directory
562 jmp .begin_path
564 .slow_symlink:
565 mov bx,SymlinkTmpBuf
566 mov cx,SYMLINK_SECTORS
567 call getfssec
568 ; The EOF closed the file
570 mov si,di ; SI = filename tail
571 mov di,SymlinkTmpBuf
572 add di,ax ; AX = file length
573 jmp .symlink_finish
576 section .bss
577 alignb 4
578 SymlinkBuf resb SYMLINK_SECTORS*SECTOR_SIZE+64
579 SymlinkTmpBuf equ trackbuf
580 SymlinkTmpBufEnd equ trackbuf+SYMLINK_SECTORS*SECTOR_SIZE+64
581 ThisDir resd 1
582 EndBlock resw 1
583 SymlinkCtr resb 1
585 section .text
587 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
588 ; to by ES:DI; ends on encountering any whitespace.
589 ; DI is preserved.
591 ; This verifies that a filename is < FILENAME_MAX characters,
592 ; doesn't contain whitespace, zero-pads the output buffer,
593 ; and removes redundant slashes,
594 ; so "repe cmpsb" can do a compare, and the
595 ; path-searching routine gets a bit of an easier job.
597 ; FIX: we may want to support \-escapes here (and this would
598 ; be the place.)
600 mangle_name:
601 push di
602 push bx
603 xor ax,ax
604 mov cx,FILENAME_MAX-1
605 mov bx,di
607 .mn_loop:
608 lodsb
609 cmp al,' ' ; If control or space, end
610 jna .mn_end
611 cmp al,ah ; Repeated slash?
612 je .mn_skip
613 xor ah,ah
614 cmp al,'/'
615 jne .mn_ok
616 mov ah,al
617 .mn_ok stosb
618 .mn_skip: loop .mn_loop
619 .mn_end:
620 cmp bx,di ; At the beginning of the buffer?
621 jbe .mn_zero
622 cmp byte [di-1],'/' ; Terminal slash?
623 jne .mn_zero
624 .mn_kill: dec di ; If so, remove it
625 inc cx
626 jmp short .mn_end
627 .mn_zero:
628 inc cx ; At least one null byte
629 xor ax,ax ; Zero-fill name
630 rep stosb
631 pop bx
632 pop di
633 ret ; Done
636 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
637 ; filename to the conventional representation. This is needed
638 ; for the BOOT_IMAGE= parameter for the kernel.
640 ; DS:SI -> input mangled file name
641 ; ES:DI -> output buffer
643 ; On return, DI points to the first byte after the output name,
644 ; which is set to a null byte.
646 unmangle_name: call strcpy
647 dec di ; Point to final null byte
652 ; kaboom2: once everything is loaded, replace the part of kaboom
653 ; starting with "kaboom.patch" with this part
655 kaboom2:
656 mov si,err_bootfailed
657 call writestr
658 cmp byte [kaboom.again+1],18h ; INT 18h version?
659 je .int18
660 call getchar
661 call vgaclearmode
662 int 19h ; And try once more to boot...
663 .norge: jmp short .norge ; If int 19h returned; this is the end
664 .int18:
665 call vgaclearmode
666 int 18h
667 .noreg: jmp short .noreg ; Nynorsk
671 ; linsector: Convert a linear sector index in a file to a linear sector number
672 ; EAX -> linear sector number
673 ; DS:SI -> open_file_t
675 ; Returns next sector number in EAX; CF on EOF (not an error!)
677 linsector:
678 push gs
679 push ebx
680 push esi
681 push edi
682 push ecx
683 push edx
684 push ebp
686 push eax ; Save sector index
687 mov cl,[ClustShift]
688 shr eax,cl ; Convert to block number
689 push eax
690 mov eax,[si+file_in_sec]
691 mov bx,si
692 call getcachesector ; Get inode
693 add si,[bx+file_in_off] ; Get *our* inode
694 pop eax
695 lea ebx,[i_block+4*eax]
696 cmp eax,EXT2_NDIR_BLOCKS
697 jb .direct
698 mov ebx,i_block+4*EXT2_IND_BLOCK
699 sub eax,EXT2_NDIR_BLOCKS
700 mov ebp,[PtrsPerBlock1]
701 cmp eax,ebp
702 jb .ind1
703 mov ebx,i_block+4*EXT2_DIND_BLOCK
704 sub eax,ebp
705 mov ebp,[PtrsPerBlock2]
706 cmp eax,ebp
707 jb .ind2
708 mov ebx,i_block+4*EXT2_TIND_BLOCK
709 sub eax,ebp
711 .ind3:
712 ; Triple indirect; eax contains the block no
713 ; with respect to the start of the tind area;
714 ; ebx contains the pointer to the tind block.
715 xor edx,edx
716 div dword [PtrsPerBlock2]
717 ; EAX = which dind block, EDX = pointer within dind block
718 push ax
719 shr eax,SECTOR_SHIFT-2
720 mov ebp,[gs:si+bx]
721 shl ebp,cl
722 add eax,ebp
723 call getcachesector
724 pop bx
725 and bx,(SECTOR_SIZE >> 2)-1
726 shl bx,2
727 mov eax,edx ; The ind2 code wants the remainder...
729 .ind2:
730 ; Double indirect; eax contains the block no
731 ; with respect to the start of the dind area;
732 ; ebx contains the pointer to the dind block.
733 xor edx,edx
734 div dword [PtrsPerBlock1]
735 ; EAX = which ind block, EDX = pointer within ind block
736 push ax
737 shr eax,SECTOR_SHIFT-2
738 mov ebp,[gs:si+bx]
739 shl ebp,cl
740 add eax,ebp
741 call getcachesector
742 pop bx
743 and bx,(SECTOR_SIZE >> 2)-1
744 shl bx,2
745 mov eax,edx ; The int1 code wants the remainder...
747 .ind1:
748 ; Single indirect; eax contains the block no
749 ; with respect to the start of the ind area;
750 ; ebx contains the pointer to the ind block.
751 push ax
752 shr eax,SECTOR_SHIFT-2
753 mov ebp,[gs:si+bx]
754 shl ebp,cl
755 add eax,ebp
756 call getcachesector
757 pop bx
758 and bx,(SECTOR_SIZE >> 2)-1
759 shl bx,2
761 .direct:
762 mov ebx,[gs:bx+si] ; Get the pointer
764 pop eax ; Get the sector index again
765 shl ebx,cl ; Convert block number to sector
766 and eax,[ClustMask] ; Add offset within block
767 add eax,ebx
769 pop ebp
770 pop edx
771 pop ecx
772 pop edi
773 pop esi
774 pop ebx
775 pop gs
779 ; getfssec: Get multiple sectors from a file
781 ; Same as above, except SI is a pointer to a open_file_t
783 ; ES:BX -> Buffer
784 ; DS:SI -> Pointer to open_file_t
785 ; CX -> Sector count (0FFFFh = until end of file)
786 ; Must not exceed the ES segment
787 ; Returns CF=1 on EOF (not necessarily error)
788 ; On return ECX = number of bytes read
789 ; All arguments are advanced to reflect data read.
791 getfssec:
792 push ebp
793 push eax
794 push edx
795 push edi
797 movzx ecx,cx
798 push ecx ; Sectors requested read
799 mov eax,[si+file_bytesleft]
800 add eax,SECTOR_SIZE-1
801 shr eax,SECTOR_SHIFT
802 cmp ecx,eax ; Number of sectors left
803 jbe .lenok
804 mov cx,ax
805 .lenok:
806 .getfragment:
807 mov eax,[si+file_sector] ; Current start index
808 mov edi,eax
809 call linsector
810 push eax ; Fragment start sector
811 mov edx,eax
812 xor ebp,ebp ; Fragment sector count
813 .getseccnt:
814 inc bp
815 dec cx
816 jz .do_read
817 xor eax,eax
818 mov ax,es
819 shl ax,4
820 add ax,bx ; Now DI = how far into 64K block we are
821 not ax ; Bytes left in 64K block
822 inc eax
823 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
824 cmp bp,ax
825 jnb .do_read ; Unless there is at least 1 more sector room...
826 inc edi ; Sector index
827 inc edx ; Linearly next sector
828 mov eax,edi
829 call linsector
830 ; jc .do_read
831 cmp edx,eax
832 je .getseccnt
833 .do_read:
834 pop eax ; Linear start sector
835 pushad
836 call getlinsec_ext
837 popad
838 push bp
839 shl bp,9
840 add bx,bp ; Adjust buffer pointer
841 pop bp
842 add [si+file_sector],ebp ; Next sector index
843 jcxz .done
844 jnz .getfragment
845 ; Fall through
846 .done:
847 pop ecx ; Sectors requested read
848 shl ecx,SECTOR_SHIFT
849 sub [si+file_bytesleft],ecx
850 jnbe .noteof ; CF=0 in this case
851 add ecx,[si+file_bytesleft] ; Actual number of bytes read
852 call close_file
853 stc ; We hit EOF
854 .noteof:
855 pop edi
856 pop edx
857 pop eax
858 pop ebp
861 build_curdir_str:
864 ; -----------------------------------------------------------------------------
865 ; Common modules
866 ; -----------------------------------------------------------------------------
868 %include "getc.inc" ; getc et al
869 %include "conio.inc" ; Console I/O
870 %include "plaincon.inc" ; writechr
871 %include "writestr.inc" ; String output
872 %include "writehex.inc" ; Hexadecimal output
873 %include "configinit.inc" ; Initialize configuration
874 %include "parseconfig.inc" ; High-level config file handling
875 %include "parsecmd.inc" ; Low-level config file handling
876 %include "bcopy32.inc" ; 32-bit bcopy
877 %include "loadhigh.inc" ; Load a file into high memory
878 %include "font.inc" ; VGA font stuff
879 %include "graphics.inc" ; VGA graphics
880 %include "highmem.inc" ; High memory sizing
881 %include "strcpy.inc" ; strcpy()
882 %include "strecpy.inc" ; strcpy with end pointer check
883 %include "cache.inc" ; Metadata disk cache
884 %include "idle.inc" ; Idle handling
885 %include "adv.inc" ; Auxillary Data Vector
886 %include "localboot.inc" ; Disk-based local boot
888 ; -----------------------------------------------------------------------------
889 ; Begin data section
890 ; -----------------------------------------------------------------------------
892 section .data
893 copyright_str db ' Copyright (C) 1994-'
894 asciidec YEAR
895 db ' H. Peter Anvin et al', CR, LF, 0
896 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
897 db 'a key to continue.', CR, LF, 0
898 config_name db 'extlinux.conf',0 ; Unmangled form
901 ; Config file keyword table
903 %include "keywords.inc"
906 ; Extensions to search for (in *forward* order).
908 alignz 4
909 exten_table: db '.cbt' ; COMBOOT (specific)
910 db '.img' ; Disk image
911 db '.bs', 0 ; Boot sector
912 db '.com' ; COMBOOT (same as DOS)
913 db '.c32' ; COM32
914 exten_table_end:
915 dd 0, 0 ; Need 8 null bytes here
918 ; Misc initialized (data) variables
920 %ifdef debug ; This code for debugging only
921 debug_magic dw 0D00Dh ; Debug code sentinel
922 %endif
924 alignz 4
925 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
926 BufSafeBytes dw trackbufsize ; = how many bytes?
927 %ifndef DEPEND
928 %if ( trackbufsize % SECTOR_SIZE ) != 0
929 %error trackbufsize must be a multiple of SECTOR_SIZE
930 %endif
931 %endif