home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / trees / syslinux / source / ldlinux.asm next >
Assembly Source File  |  1996-11-02  |  85KB  |  2,780 lines

  1. ; ****************************************************************************
  2. ;
  3. ;  LDLINUX.ASM
  4. ;
  5. ;  A program to boot Linux kernels off an MS-DOS formatted floppy disk.     This
  6. ;  functionality is good to have for installation floppies, where it may
  7. ;  be hard to find a functional Linux system to run LILO off.
  8. ;
  9. ;  This program allows manipulation of the disk to take place entirely
  10. ;  from MS-LOSS, and can be especially useful in conjunction with the
  11. ;  umsdos filesystem.
  12. ;
  13. ;  This file is loaded in stages; first the boot sector at offset 7C00h,
  14. ;  then the first sector (cluster, really, but we can only assume 1 sector)
  15. ;  of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h
  16. ;
  17. ;   Copyright (C) 1994-96  H. Peter Anvin
  18. ;
  19. ;   This code is free software under the terms of the GNU General Public
  20. ;   License, version 2, or at your option any later version.
  21. ;
  22. ; ****************************************************************************
  23.  
  24.         page 79
  25. ;         page 59
  26.  
  27. ;         jumps             ; Assemble with /m option!!!!
  28.         smart            ; Optimizes some for us
  29. ;
  30. ; Some semi-configurable constants... change on your own risk
  31. ;
  32. max_cmd_len    equ 2047        ; Must be odd; 2047 is the kernel limit
  33. retry_count    equ 6            ; How patient are we with the disk?
  34.  
  35. ;
  36. ; Should be updated with every release to avoid bootsector/SYS file mismatch
  37. ;
  38. version_str     equ '1.30'              ; Must be 4 characters long!!!
  39. ;
  40. ; Debgging stuff
  41. ;
  42. ;debug           equ 1                  ; Uncomment to enable debugging
  43. ;
  44. ; ID for SYSLINUX (reported to kernel)
  45. ;
  46. syslinux_id    equ 031h        ; SYSLINUX (3) version 1.x (1)
  47. ;
  48. ; Segments used by Linux
  49. ;
  50. real_mode_seg    segment at 9000h    ; Real-mode Linux code
  51.         org 20h
  52. kern_cmd_magic    dw ?            ; Magic # for command line
  53. kern_cmd_offset dw ?            ; Offset for kernel command line
  54.         org 497
  55. bs_setupsecs    db ?            ; Sectors for setup code (0 -> 4)
  56. bs_rootflags    dw ?            ; Root readonly flag
  57. bs_syssize    dw ?
  58. bs_swapdev    dw ?            ; Swap device (obsolete)
  59. bs_ramsize    dw ?            ; Ramdisk flags, formerly ramdisk size
  60. bs_vidmode    dw ?            ; Video mode
  61. bs_rootdev    dw ?            ; Root device
  62. bs_bootsign    dw ?            ; Boot sector signature (0AA55h)
  63. su_jump        db ?            ; 0EBh
  64. su_jump2    db ?
  65. su_header    dd ?            ; New setup code: header
  66. su_version    dw ?            ; See linux/arch/i386/boot/setup.S
  67. su_switch    dw ?
  68. su_setupseg    dw ?
  69. su_startsys    dw ?
  70. su_kver        dw ?            ; Kernel version pointer
  71. su_loader    db ?            ; Loader ID
  72. su_loadflags    db ?            ; Load high flag
  73. su_movesize    dw ?
  74. su_code32start    dd ?            ; Start of code loaded high
  75. su_ramdiskat    dd ?            ; Start of initial ramdisk
  76. su_ramdisklen    label dword        ; Length of initial ramdisk
  77. su_ramdisklen1    dw ?
  78. su_ramdisklen2    dw ?
  79. su_bsklugeoffs    dw ?
  80. su_bsklugeseg    dw ?
  81. su_heapend    dw ?
  82.         org 8000h-12        ; Were bootsect.S puts it...
  83. linux_stack    label byte
  84. linux_fdctab    label byte
  85.         org 8000h
  86. cmd_line_here    equ $            ; Should be out of the way
  87. real_mode_seg    ends
  88.  
  89. setup_seg    segment at 9020h    ; The setup code wants to be run
  90.         org 0h            ; as 9020:0000, not 9000:0200
  91. setup_entry    equ $
  92. setup_seg    ends
  93.  
  94. ;
  95. ; Magic number of su_header field
  96. ;
  97. HEADER_ID       equ 053726448h          ; HdrS (in littleendian hex)
  98. ;
  99. ; Flags for the su_loadflags field
  100. ;
  101. LOAD_HIGH    equ 01h            ; Large kernel, load high
  102. CAN_USE_HEAP    equ 80h                 ; Boot loader reports heap size
  103. ;
  104. ; The following structure is used for "virtual kernels"; i.e. LILO-style
  105. ; option labels.  The options we permit here are `kernel' and `append
  106. ; Since there is no room in the bottom 64K for up to 16 of these, we
  107. ; stick them at 8000:0000 and copy them down before we need them.
  108. ;
  109. ; Note: this structure can be added to, but must be less than 4K in size.
  110. ;
  111. vkernel        struc
  112. vk_vname    db 11 dup (?)        ; Virtual name **MUST BE FIRST!**
  113.         db 3 dup (?)        ; Alignment filler
  114. vk_rname    db 11 dup (?)        ; Real name
  115.         db ?            ; Filler
  116. vk_appendlen    dw ?
  117. vk_append    db (max_cmd_len+1) dup (?) ; Command line
  118. vkernel        ends
  119. ;
  120. vk_seg          segment at 8000h        ; This is where we stick'em
  121. vk_seg        ends
  122. ;
  123. ; Our segment (is always at 0000h, unless we're debugging.)
  124. ;
  125. _text        segment para 'code'
  126.         assume cs:_text
  127.         org 0h
  128. zero_offset    equ $
  129.  
  130.         org 4*1Eh        ; In the interrupt table
  131. fdctab        label dword
  132. fdctab1        dw ?
  133. fdctab2        dw ?
  134.  
  135.         org 0100h
  136. bogus        label far        ; To keep TLINK or EXE2BIN happy
  137. ;
  138. ; Hook for debugger stuff.  This gets automatically removed when
  139. ; generating the real thing.
  140. ;
  141. ; Initialize the registers for debugger operation
  142. ;
  143.         assume ds:_text, es:_text, ss:_text
  144.         cli
  145.         mov ax,cs
  146.         mov ds,ax
  147.         mov es,ax
  148.         mov ss,ax
  149.         mov sp,offset StackBuf
  150.         sti
  151.         cld
  152. ;
  153. ; Load the actual boot sector so we can copy the data block
  154. ;
  155.         xor ax,ax        ; Reset floppy
  156.         xor dx,dx
  157.         int 13h
  158.         mov cx,6        ; Retry count...
  159. debug_tryloop:    push cx
  160.         mov bx,offset trackbuf
  161.         mov cx,0001h
  162.         xor dx,dx
  163.         mov ax,0201h
  164.         int 13h
  165.         pop cx
  166.         jnc debug_okay
  167.         loop debug_tryloop
  168.         int 3            ; Halt! (Breakpoint)
  169. debug_okay:    mov si,(offset trackbuf)+0bh
  170.         mov di,offset bsBytesPerSec
  171.         mov cx,33h
  172.         rep movsb
  173. ;
  174. ; Save bogus "BIOS floppy block" info to the stack in case we hit kaboom
  175. ;
  176.         push si
  177.         push si
  178.         push si            ; Writing to the trackbuf is harmless
  179. ;
  180. ; Copy the BIOS data area
  181. ;
  182.                 push ds
  183.                 xor ax,ax
  184.                 mov ds,ax
  185.                 mov si,0400h
  186.                 mov di,si
  187.                 mov cx,0100h
  188.                 rep movsw
  189.                 pop ds
  190. ;
  191. ;
  192. ; A NOP where we can breakpoint, then jump into the code *after*
  193. ; the segment register initialization section
  194. ;
  195.         nop
  196.         jmp debugentrypt
  197.  
  198.                 org 0484h
  199. BIOS_vidrows    db ?                    ; Number of screen rows
  200.  
  201.         org 0600h
  202. trackbuf    label byte        ; Track buffer goes here
  203. trackbufsize    equ 16384        ; Safe size of track buffer
  204. ;        trackbuf ends at 4600h
  205.                 org 6000h               ; Here we keep our BSS stuff
  206. StackBuf    equ $            ; Start the stack here (grow down)
  207. VKernelBuf    vkernel <>        ; "Current" vkernel
  208.         align 4
  209. AppendBuf       db (max_cmd_len+1) dup (?) ; append=
  210. FKeyName    db 10*16 dup(?)        ; File names for F-key help
  211. NumBuf        db 16 dup(?)        ; Buffer to load number
  212. NumBufEnd    equ offset NumBuf+15    ; Pointer to last byte in NumBuf
  213. RootDir        label dword        ; Location of root directory
  214. RootDir1    dw ?
  215. RootDir2    dw ?
  216. DataArea    label dword        ; Location of data area
  217. DataArea1    dw ?
  218. DataArea2    dw ?
  219. FBytes        label dword        ; Used by open/getc
  220. FBytes1        dw ?
  221. FBytes2        dw ?
  222. RootDirSize    dw ?            ; Root dir size in sectors
  223. DirScanCtr    dw ?            ; Used while searching directory
  224. DirBlocksLeft    dw ?            ; Ditto
  225. EndofDirSec    dw ?            ; = trackbuf+bsBytesPerSec-31
  226. RunLinClust    dw ?            ; Cluster # for LDLINUX.SYS
  227. ClustSize    dw ?            ; Bytes/cluster
  228. SecPerClust    dw ?            ; Same as bsSecPerClust, but a word
  229. BufSafe        dw ?            ; Clusters we can load into trackbuf
  230. BufSafeSec    dw ?            ; = how many sectors?
  231. BufSafeBytes    dw ?            ; = how many bytes?
  232. EndOfGetCBuf    dw ?            ; = getcbuf+BufSafeBytes
  233. HighMemSize    dw ?            ; High memory (K)
  234. KernelClust    dw ?            ; Kernel size in clusters
  235. KernelK        dw ?            ; Kernel size in kilobytes
  236. InitRDClust    dw ?            ; Ramdisk size in clusters
  237. InitRDat    dw ?            ; Load address (x256)
  238. ClustPerMoby    dw ?            ; Clusters per 64K
  239. FClust        dw ?            ; Number of clusters in open/getc file
  240. FNextClust    dw ?            ; Pointer to next cluster in d:o
  241. FPtr        dw ?            ; Pointer to next char in buffer
  242. CmdOptPtr       dw ?                    ; Pointer to first option on cmd line
  243. KernelCNameLen  dw ?                    ; Length of unmangled kernel name
  244. InitRDCNameLen  dw ?                    ; Length of unmangled initrd name
  245. NextCharJump    dw ?                    ; Routine to interpret next print char
  246. HiLoadAddr      dw ?                    ; Address pointer for high load loop
  247. TextAttrBX      label word
  248. TextAttribute   db ?                    ; Text attribute for message file
  249. TextPage        db ?                    ; Active display page
  250. CursorDX        label word
  251. CursorCol       db ?                    ; Cursor column for message file
  252. CursorRow       db ?                    ; Cursor row for message file
  253. ScreenSize      label word
  254. VidCols         db ?                    ; Columns on screen-1
  255. VidRows         db ?                    ; Rows on screen-1
  256. RetryCount      db ?                    ; Used for disk access retries
  257. KbdFlags    db ?            ; Check for keyboard escapes
  258. MNameBuf        db 11 dup(?)            ; Generic mangled file name buffer
  259. KernelName      db 11 dup(?)            ; Mangled name for kernel
  260. InitRD          db 11 dup(?)            ; initrd= mangled name
  261. KernelCName     db 13 dup(?)            ; Unmangled kernel name
  262. InitRDCName     db 13 dup(?)            ; Unmangled initrd name
  263.                 org 7C00h
  264. bootsec        equ $
  265.         jmp short start        ; 2 bytes
  266.         nop            ; 1 byte
  267. ;
  268. ; "Superblock" follows -- it's in the boot sector, so it's already
  269. ; loaded and ready for us
  270. ;
  271.         org 7C03h
  272. bsOemName    db 'SYSLINUX'        ; The SYS command sets this, so...
  273. bsBytesPerSec    dw ?
  274. bsSecPerClust    db ?
  275. bsResSectors    dw ?
  276. bsFATs        db ?
  277. bsRootDirEnts    dw ?
  278. bsSectors    dw ?
  279. bsMedia        db ?
  280. bsFATsecs    dw ?
  281. bsSecPerTrack    dw ?
  282. bsHeads        dw ?
  283. bsHiddenSecs    label dword
  284. bsHidden1    dw ?
  285. bsHidden2    dw ?
  286. bsHugeSectors    label dword
  287. bsHugeSec1    dw ?
  288. bsHugeSec2    dw ?
  289. bsDriveNumber    db ?
  290. bsReserved1    db ?
  291. bsBootSignature db ?            ; 29h if the following fields exist
  292. bsVolumeID    dd ?
  293. bsVolumeLabel    db 11 dup(?)
  294. bsFileSysType    db 8 dup(?)        ; Must be FAT12 for this version
  295. ;
  296. ; Note we don't check the constraints above now; we did that at install
  297. ; time (we hope!)
  298. ;
  299.  
  300. start        label near
  301. floppy_table    label byte        ; No sense in wasting memory
  302.         cli            ; No interrupts yet, please
  303.         xor ax,ax
  304.         mov es,ax
  305.         mov ss,ax
  306.         mov sp,offset StackBuf    ; Just below BSS
  307.         assume es:_text, ss:_text, ds:NOTHING
  308. ;
  309. ; Now sautee the BIOS floppy info block to that it will support decent-
  310. ; size transfers; the floppy block is 11 bytes and is stored in the
  311. ; INT 1Eh vector (brilliant waste of resources, eh?)
  312. ;
  313. ; Of course, if BIOSes had been properly programmed, we wouldn't have
  314. ; had to waste precious boot sector space with this code.
  315. ;
  316.         mov bx,offset fdctab
  317.         lds si,ss:[bx]        ; DS:SI -> original
  318.         push ds            ; Save on stack in case
  319.         push si            ; we have to bail
  320.         push bx
  321.         mov cx,6        ; 12 bytes
  322.         mov di,offset floppy_table
  323.         push di
  324.         cld
  325.         rep movsw        ; Faster to move words
  326.         pop di
  327.         mov ds,ax        ; Now we can point DS to here, too
  328.         assume ds:_text
  329.         mov cl,byte ptr bsSecPerTrack ; Patch the sector count
  330.         mov [di+4],cl
  331. ;         mov byte ptr [di+9],0Fh ; I have no clue what this does???
  332.         mov [bx+2],ax        ; Segment 0
  333.         mov [bx],di        ; offset floppy_block
  334. ;
  335. ; Ready to enable interrupts, captain
  336. ;
  337.         sti
  338. ;
  339. ; Reset floppy system to load new parameter block
  340. ;
  341.         xor dx,dx
  342.         int 13h            ; AH = 00h already
  343. ;
  344. ; Now we have to do some arithmetric to figure out where things are located.
  345. ; If Microsoft had had brains they would already have done this for us,
  346. ; and stored it in the superblock at format time, but here we go,
  347. ; wasting precious boot sector space again...
  348. ;
  349. debugentrypt:
  350.         mov al,bsFATs        ; Number of FATs
  351.         jc kaboom        ; If the floppy init failed
  352.                     ; (too far to be above the mov)
  353.         cbw            ; Clear AH
  354.         mul bsFATsecs        ; Get the size of the FAT area
  355.         add ax,bsHidden1    ; Add hidden sectors
  356.         adc dx,bsHidden2
  357.         add ax,bsResSectors    ; And reserved sectors (why two?)
  358.         adc dx,0
  359.  
  360.         mov RootDir1,ax        ; Location of root directory
  361.         mov RootDir2,dx
  362.         mov DataArea1,ax
  363.         mov DataArea2,dx
  364.         push ax
  365.         push dx
  366.  
  367.         mov ax,32        ; Size of a directory entry
  368.         mul bsRootDirEnts
  369.         mov bx,bsBytesPerSec
  370.         add ax,bx        ; Round up, not down
  371.         dec ax
  372.         div bx            ; Now we have the size of the root dir
  373.         mov RootDirSize,ax
  374.         mov DirScanCtr,ax
  375.         add bx,(offset trackbuf)-31
  376.         mov EndofDirSec,bx    ; End of a single directory sector
  377.  
  378.         add DataArea1,ax    ; Now we have the location of the
  379.         adc DataArea2,0        ; first data cluster
  380. ;
  381. ; Now the fun begins.  We have to search the root directory for
  382. ; LDLINUX.SYS and load the first sector, so we have a little more
  383. ; space to have fun with.  Then we can go chasing through the FAT.
  384. ; Joy!!
  385. ;
  386. sd_nextsec:    pop dx
  387.         pop ax
  388.         push ax
  389.         push dx
  390.         mov bx,offset trackbuf
  391.         call getonesec
  392.         mov si,offset trackbuf
  393. sd_nextentry:    cmp byte ptr [si],0    ; Directory high water mark
  394. jz_kaboom:    jz kaboom
  395.         mov di,offset ldlinux_sys
  396.         mov cx,11
  397.         push si
  398.         repe cmpsb
  399.         pop si
  400.         je found_it
  401.         add si,32        ; Distance to next
  402.         cmp si,EndofDirSec
  403.         jb sd_nextentry
  404.         add ax,1
  405.         adc dx,0
  406.         dec DirScanCtr
  407.         jnz sd_nextsec
  408. ;
  409. ; kaboom: write a message and bail out.
  410. ;
  411. kaboom        proc near
  412.         mov si,offset bailmsg
  413.         call writestr        ; Returns with AL = 0
  414.         cbw            ; Sets AH = 0 (shorter than XOR)
  415.         int 16h            ; Wait for keypress
  416.         mov sp,(offset StackBuf)-2*3 ; Reset stack
  417.         pop si            ; BIOS floppy block address
  418.         cli
  419.         pop [si]        ; Restore location
  420.         pop [si+2]
  421.         sti
  422.         int 19h            ; And try once more to boot...
  423. norge:        jmp short norge        ; If int 19h returned... oh boy...
  424. kaboom        endp
  425. ;
  426. ; found_it: now we compute the location of the first sector, then
  427. ;        load it and JUMP (since we're almost out of space)
  428. ;
  429. found_it:    pop ax
  430.         pop ax
  431.         mov al,bsSecPerClust
  432.         cbw            ; We won't have 128 sec/cluster
  433.         mov bp,ax        ; Load an entire cluster
  434.         mov bx,[si+26]        ; First cluster
  435.         push bx            ; Remember which cluster it was
  436.         dec bx            ; First cluster is cluster 2
  437.         dec bx
  438.         mul bx
  439.         add ax,DataArea1
  440.         adc dx,DataArea2
  441.         mov bx,offset ldlinux_magic
  442.         call getlinsec
  443.         mov si,offset bs_magic
  444.         mov di,offset ldlinux_magic
  445.         mov cx,magic_len
  446.         repe cmpsb        ; Make sure that the bootsector
  447.         jne kaboom
  448.         jmp ldlinux_ent        ; matches LDLINUX.SYS
  449. ;
  450. ; writestr: write a null-terminated string to the console
  451. ;
  452. writestr    proc near
  453. wstr_1:         lodsb
  454.         and al,al
  455.                 jz return
  456.         mov ah,0Eh        ; Write to screen as TTY
  457.         mov bx,0007h        ; White on black, current page
  458.         int 10h
  459.         jmp short wstr_1
  460. writestr    endp
  461. ;
  462. ; disk_error: decrement the retry count and bail if zero
  463. ;
  464. disk_error:    dec si            ; SI holds the disk retry counter
  465.         jz kaboom
  466.         xchg ax,bx        ; Shorter than MOV
  467.         pop bx
  468.         pop cx
  469.         pop dx
  470.         jmp disk_try_again
  471. ;
  472. ; getonesec: like getlinsec, but pre-sets the count to 1
  473. ;
  474. getonesec    proc near
  475.         mov bp,1
  476.         ; Fall through to getlinsec
  477. getonesec    endp
  478. ;
  479. ; getlinsec: load a sequence of BP floppy sector given by the linear sector
  480. ;         number in DX:AX into the buffer at ES:BX.    We try to optimize
  481. ;         by loading up to a whole track at a time, but the user
  482. ;         is responsible for not crossing a 64K boundary.
  483. ;         (Yes, BP is weird for a count, but it was available...)
  484. ;
  485. ;         On return, BX points to the first byte after the transferred
  486. ;         block.
  487. ;
  488. getlinsec    proc near
  489.         mov si,bsSecPerTrack
  490.         div si            ; Convert linear to sector/track
  491.         mov cx,dx        ; Save sector
  492.         xor dx,dx        ; 32-bit track number
  493.         div bsHeads        ; Convert track to head/cyl
  494.         ;
  495.         ; Now we have AX = cyl, DX = head, CX = sector (0-based)
  496.         ; for the very first sector, SI = bsSecPerTrack
  497.         ;
  498. gls_nexttrack:    push si
  499.         push bp
  500.         sub si,cx        ; Sectors left on track
  501.         cmp bp,si
  502.         jna gls_lasttrack
  503.         mov bp,si        ; No more than a trackful, please!
  504. gls_lasttrack:    push ax            ; Cylinder #
  505.         push dx            ; Head #
  506.         push bp            ; Number of sectors we're transferring
  507.  
  508.         push cx
  509.         mov cl,6        ; Because IBM was STOOPID
  510.         shl ah,cl        ; and thought 8 bits was enough
  511.                     ; then thought 10 bits was enough...
  512.         pop cx            ; Sector #
  513.         inc cx            ; Sector numbers are 1-based
  514.         or cl,ah
  515.         mov ch,al
  516.         mov dh,dl
  517.         mov dl,bsDriveNumber
  518.         xchg ax,bp        ; Sector to transfer count
  519.                     ; (xchg shorter than mov)
  520.         mov ah,02h        ; Read it!
  521. ;
  522. ; Do the disk transfer... save the registers in case we fail :(
  523. ;
  524.         mov si,retry_count    ; # of times to retry a disk access
  525. disk_try_again: push dx
  526.         push cx
  527.         push bx
  528.         push ax
  529.         push si
  530.         int 13h
  531.         pop si
  532.         pop bx
  533.         jc disk_error
  534. ;
  535. ; It seems the following test fails on some machines (buggy BIOS?)
  536. ;
  537. ;         cmp al,bl         ; Check that we got what we asked for
  538. ;         jne disk_error
  539. ;
  540. ; Disk access successful
  541. ;
  542.         pop bx            ; Buffer location
  543.         pop si            ; Not needed anymore
  544.         pop si            ; Neither is this
  545.         pop si            ; Sector transferred count
  546.         mov ax,si        ; Reduce sector left count
  547.         mul bsBytesPerSec    ; Figure out how much to advance ptr
  548.         add bx,ax        ; Update buffer location
  549.         pop dx            ; Head #
  550.         pop ax            ; Cyl #
  551.         inc dx            ; Next track on cyl
  552.         cmp dx,bsHeads        ; Was this the last one?
  553.         jb gls_nonewcyl
  554.         inc ax            ; If so, new cylinder
  555.         xor dx,dx        ; First head on new cylinder
  556. gls_nonewcyl:    pop bp            ; Sectors left to transfer
  557.         xor cx,cx        ; First sector on new track
  558.         sub bp,si        ; Reduce with # of sectors just read
  559.         pop si
  560.         ja gls_nexttrack
  561. return:        ret
  562. getlinsec    endp
  563.  
  564. bailmsg        db 'Boot failed: change disks and press any key', 0Dh, 0Ah, 0
  565.  
  566. bs_checkpt    equ $            ; Must be <= 7DE5h
  567.  
  568.         org 7DE5h
  569. bs_magic    label byte        ; The following 32 bytes should
  570.                     ; match ldlinux_magic
  571. ldlinux_sys    db 'LDLINUX SYS'    ; Looks like this in the root dir
  572.         db ' '
  573. bs_version    db version_str
  574.         db ' '
  575. bs_date        db ??date        ; 8 bytes date
  576. magic_len    equ $-bs_magic
  577.  
  578. bootsignature    dw 0AA55h
  579.  
  580. ;
  581. ; ===========================================================================
  582. ;  End of boot sector
  583. ; ===========================================================================
  584. ;  Start of LDLINUX.SYS
  585. ; ===========================================================================
  586. ;
  587. ; Put the FAT right after the code, aligned on a sector boundary
  588. ;
  589. FAT        equ (ldlinux_end-zero_offset+511) and 0FE00h
  590. ;
  591. ; Put getc buffer right after FAT (the FAT buffer is 6K, the max size
  592. ; of a 12-bit FAT)
  593. ;
  594. getcbuf        equ FAT+6*1024
  595. ;
  596. ; This "magic number" works well with the "type" command... :-)
  597. ;
  598. ldlinux_magic    db 'LDLINUX'
  599. missing_dot    db ' '
  600.         db 'SYS ', version_str, ' ', ??date
  601. magic_eof    db 0Dh, 0Ah, 01Ah
  602.  
  603.         org 7E20h
  604. ldlinux_ent    label near
  605. ;
  606. ; The boot sector left the cluster number of this first LDLINUX.SYS
  607. ; sector on the stack.    We'll need it later, so we should pop it off
  608. ;
  609.         pop RunLinClust
  610. ;
  611. ; Tell the user we got this far
  612. ;
  613.         mov si,offset crlf
  614.         call writestr
  615.         mov missing_dot,'.'
  616.         mov magic_eof,0
  617.         mov si,offset ldlinux_magic
  618.         call writestr
  619. ;
  620. ; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS.
  621. ; We can really only rely on a single sector having been loaded.  Hence
  622. ; we should load the FAT into RAM and start chasing pointers...
  623. ;
  624.         mov bx,offset FAT        ; Where it goes in memory
  625.         mov ax,bsHidden1        ; Hidden sectors
  626.         mov dx,bsHidden2
  627.         add ax,bsResSectors        ; plus reserved sectors = FAT
  628.         adc dx,0
  629.         mov bp,bsFATsecs        ; Sectors/FAT
  630.         call getlinsec            ; Load it in...
  631. ;
  632. ; Fine, now we have the FAT in memory.    How big is a cluster, really?
  633. ; Also figure out how many clusters will fit in an 8K buffer, and how
  634. ; many sectors and bytes that is
  635. ;
  636.         mov al,bsSecPerClust        ; We do this in the boot
  637.         xor ah,ah            ; sector, too, but there
  638.         mov SecPerClust,ax        ; wasn't space to save it
  639.         mul bsBytesPerSec
  640.         mov ClustSize,ax        ; Bytes/cluster
  641.         mov bx,ax
  642.         mov ax,trackbufsize
  643.         xor dx,dx
  644.         div bx
  645.         mov BufSafe,ax            ; # of cluster in trackbuf
  646.         mul SecPerClust
  647.         mov BufSafeSec,ax
  648.         mul bsBytesPerSec
  649.         mov BufSafeBytes,ax
  650.         add ax,getcbuf            ; getcbuf is same size as
  651.         mov EndOfGetCBuf,ax        ; trackbuf, for simplicity
  652. ;
  653. ; Now we read the rest of LDLINUX.SYS.    Don't bother loading the first
  654. ; cluster again, though.
  655. ;
  656.         mov bx,offset ldlinux_magic
  657.         add bx,ClustSize
  658.         mov si,RunLinClust
  659.         call nextcluster
  660.         xor dx,dx
  661.         mov ax,ldlinux_len-1        ; To be on the safe side
  662.         add ax,ClustSize
  663.         div ClustSize            ; the number of clusters
  664.         dec ax                ; We've already read one
  665.         jz all_read_jmp
  666.         mov cx,ax
  667.         call getfssec
  668. ;
  669. ; All loaded up
  670. ;
  671. all_read_jmp:
  672.         mov si,offset copyright_str
  673.         call writestr
  674.         jmp all_read
  675. ;
  676. ; -----------------------------------------------------------------------------
  677. ; Subroutines that have to be in the first sector
  678. ; -----------------------------------------------------------------------------
  679. ;
  680. ; getfssec: Get multiple clusters from a file, given the starting cluster.
  681. ;
  682. ;    This routine makes sure the subtransfers do not cross a 64K boundary,
  683. ;    and will correct the situation if it does, UNLESS *sectors* cross
  684. ;    64K boundaries.
  685. ;
  686. ;    ES:BX    -> Buffer
  687. ;    SI    -> Starting cluster number (2-based)
  688. ;    CX    -> Cluster count (0FFFFh = until end of file)
  689. ;
  690.                         ; 386 check
  691. getfssec    proc near
  692. getfragment:    xor bp,bp            ; Fragment sector count
  693.         mov ax,si            ; Get sector address
  694.         dec ax                ; Convert to 0-based
  695.         dec ax
  696.         mul SecPerClust
  697.         add ax,DataArea1
  698.         adc dx,DataArea2
  699. getseccnt:                    ; See if we can read > 1 clust
  700.         add bp,SecPerClust
  701.         dec cx                ; Reduce clusters left to find
  702.         mov di,si            ; Predict next cluster
  703.         inc di
  704.         call nextcluster
  705.         jc gfs_eof            ; At EOF?
  706.         jcxz endfragment        ; Or was it the last we wanted?
  707.         cmp si,di            ; Is file continuous?
  708.         jz getseccnt            ; Yes, we can get
  709. endfragment:    clc                ; Not at EOF
  710. gfs_eof:    pushf                ; Remember EOF or not
  711.         push si
  712.         push cx
  713. gfs_getchunk:
  714.         push ax
  715.         push dx
  716.         mov ax,es            ; Check for 64K boundaries.
  717.         shl ax,1            ; This really belongs in
  718.         shl ax,1            ; getlinsec, but it would
  719.         shl ax,1            ; make it not fit in the boot
  720.         shl ax,1            ; sector.
  721.         add ax,bx
  722.         xor dx,dx
  723.         neg ax
  724.         jnz gfs_partseg
  725.         inc dx                ; Full 64K segment
  726. gfs_partseg:
  727.         div bsBytesPerSec        ; How many sectors fit?
  728.         mov si,bp
  729.         sub si,ax            ; Compute remaining sectors
  730.         jbe gfs_lastchunk
  731.         mov bp,ax
  732.         pop dx
  733.         pop ax
  734.         push si                ; Save remaining sector count
  735.         push ax                ; Save position
  736.         push dx
  737.         push bp                ; Save sectors to transfer
  738.         call getlinsec
  739.         pop bp
  740.         pop dx
  741.         pop ax
  742.         add ax,bp            ; Advance sector pointer
  743.         adc dx,0
  744.         pop bp                ; Load remaining sector counter
  745.         jmp gfs_getchunk
  746. gfs_lastchunk:    pop dx
  747.         pop ax        
  748.         call getlinsec
  749.         pop cx
  750.         pop si
  751.         popf
  752.         jcxz gfs_return            ; If we hit the count limit
  753.         jnc getfragment            ; If we didn't hit EOF
  754. gfs_return:    ret
  755. getfssec    endp
  756. ;
  757. ; nextcluster: Advance a cluster pointer in SI to the next cluster
  758. ;           pointed at in the FAT tables (note: FAT12 assumed)
  759. ;           Sets CF on return if end of file.
  760. ;
  761. nextcluster    proc near
  762.         push bx
  763.         mov bx,si            ; Multiply by 3/2
  764.         shr bx,1
  765.         pushf                ; CF now set if odd
  766.         add si,bx
  767.         mov si,word ptr FAT[si]
  768.         popf
  769.         jnc nc_even
  770.         shr si,1            ; Needed for odd only
  771.         shr si,1
  772.         shr si,1
  773.         shr si,1
  774. nc_even:
  775.         and si,0FFFh
  776.         cmp si,0FF0h            ; Clears CF if at end of file
  777.         cmc                ; But we want it SET...
  778.         pop bx
  779. nc_return:    ret
  780. nextcluster    endp
  781.  
  782. ;
  783. ; Debug routine
  784. ;
  785.         ifdef debug
  786. safedumpregs    proc near
  787.         cmp Debug_Magic,0D00Dh
  788.         jnz nc_return
  789.         jmp dumpregs
  790. safedumpregs    endp
  791.         endif
  792.  
  793. ;
  794. ; Data that has to be in the first sector
  795. ;
  796. copyright_str   db '  Copyright (C) 1994-96 H. Peter Anvin'
  797. crlf        db 0Dh, 0Ah, 0
  798.  
  799. rl_checkpt    equ $                ; Must be <= 8000h
  800.  
  801. ; ----------------------------------------------------------------------------
  802. ;  End of code and data that have to be in the first sector
  803. ; ----------------------------------------------------------------------------
  804.  
  805. all_read    label near
  806. ;
  807. ; Check that no moron is trying to boot Linux on a 286 or so.  According
  808. ; to Intel, the way to check is to see if the high 4 bits of the FLAGS
  809. ; register are either all stuck at 1 (8086/8088) or all stuck at 0
  810. ; (286 in real mode), if not it is a 386 or higher.  They didn't
  811. ; say how to check for a 186/188, so I *hope* it falls out as a 8086
  812. ; or 286 in this test.
  813. ;
  814. ; Also, provide an escape route in case it doesn't work.
  815. ;
  816. check_escapes:
  817.         mov ah,02h            ; Check keyboard flags
  818.         int 16h
  819.         mov KbdFlags,al            ; Save for boot prompt check
  820.         test al,04h            ; Ctrl->skip 386 check
  821.         jnz skip_checks
  822. test_8086:
  823.         pushf                ; Get flags
  824.         pop ax
  825.         and ax,0FFFh            ; Clear top 4 bits
  826.         push ax                ; Load into FLAGS
  827.         popf
  828.         pushf                ; And load back
  829.         pop ax
  830.         and ax,0F000h            ; Get top 4 bits
  831.         cmp ax,0F000h            ; If set -> 8086/8088
  832.         je not_386
  833. test_286:
  834.         pushf                ; Get flags
  835.         pop ax
  836.         or ax,0F000h            ; Set top 4 bits
  837.         push ax
  838.         popf
  839.         pushf
  840.         pop ax
  841.         and ax,0F000h            ; Get top 4 bits
  842.         jnz is_386            ; If not clear -> 386
  843. not_386:
  844.         mov si,offset err_not386
  845.         call writestr
  846.         jmp kaboom
  847. is_386:
  848.         .386                ; Now we know it's a 386
  849. ;
  850. ; Now check that there is at least 608K of low (DOS) memory
  851. ; (608K = 9800h segments)
  852. ;
  853.         int 12h
  854.         cmp ax,608
  855.         jae enough_ram
  856.         mov si,offset err_noram
  857.         call writestr
  858.         jmp kaboom
  859. enough_ram:
  860. skip_checks:
  861. ;
  862. ; Initialization that does not need to go into the any of the pre-load
  863. ; areas
  864. ;
  865.                 mov al,BIOS_vidrows
  866.                 and al,al
  867.                 jnz vidrows_is_ok
  868.                 mov al,25                       ; No vidrows in BIOS, assume 25
  869. vidrows_is_ok:  mov VidRows,al
  870.                 mov ah,0fh
  871.                 int 10h                         ; Read video state
  872.                 mov TextPage,bh
  873.                 dec ah                          ; Store count-1 (same as rows)
  874.                 mov VidCols,ah
  875. ;
  876. ; Now we're all set to start with our *real* business.    First load the
  877. ; configuration file (if any) and parse it.
  878. ;
  879. ; In previous versions I avoided using 32-bit registers because of a
  880. ; rumour some BIOSes clobbered the upper half of 32-bit registers at
  881. ; random.  I figure, though, that if there are any of those still left
  882. ; they probably won't be trying to install Linux on them...
  883. ;
  884. ; The code is still ripe with 16-bitisms, though.  Not worth the hassle
  885. ; to take'm out.
  886. ;
  887.         mov si,offset linuxauto_cmd    ; Default command: "linux auto"
  888.         mov di,offset default_cmd
  889.                 mov cx,linuxauto_len
  890.         rep movsb
  891. ;
  892. ; Load configuration file
  893. ;
  894.         mov di,offset syslinux_cfg
  895.         call open
  896.         jz no_config_file
  897. parse_config:
  898.         call getkeyword
  899.                 jc end_config_file              ; Config file loaded
  900.         cmp ax,'ed'            ; DEfault (reversed due to
  901.                         ; screwy assembler)
  902.         je pc_default
  903.         cmp ax,'pa'            ; APpend
  904.         je pc_append
  905.         cmp ax,'it'            ; TImeout
  906.         je pc_timeout
  907.         cmp ax,'rp'            ; PRompt
  908.         je pc_prompt
  909.         cmp ax,'id'            ; DIsplay
  910.         je pc_display
  911.         cmp ax,'al'            ; LAbel
  912.         je pc_label
  913.         cmp ax,'ek'            ; KErnel
  914.         je pc_kernel
  915.                 cmp ax,'mi'                     ; IMplicit
  916.                 je pc_implicit
  917.         cmp al,'f'            ; F-key
  918.         je pc_fkey
  919.         jmp parse_config
  920. pc_default:    mov di,offset default_cmd    ; "default" command
  921.         call getline
  922.         mov si,offset auto_cmd        ; add "auto"+null
  923.                 mov cx,auto_len
  924.         rep movsb
  925.         jmp parse_config
  926. pc_append:      cmp VKernelCtr,0                ; "append" command
  927.         ja pc_append_vk
  928.                 mov di,offset AppendBuf
  929.         call getline
  930.                 sub di,offset AppendBuf
  931. pc_app1:        mov AppendLen,di
  932.                 jmp parse_config
  933. pc_append_vk:    mov di,offset VKernelBuf.vk_append    ; "append" command (vkernel)
  934.         call getline
  935.         sub di,offset VKernelBuf.vk_append
  936.                 cmp di,2
  937.                 jne pc_app2
  938.                 cmp VKernelBuf.vk_append,'-'
  939.                 jne pc_app2
  940.                 mov di,0                        ; If "append -" -> null string
  941. pc_app2:        mov VKernelBuf.vk_appendlen,di
  942.         jmp parse_config    
  943. pc_kernel:    cmp VKernelCtr,0        ; "kernel" command
  944.         je parse_config            ; (vkernel only)
  945.         mov di,offset trackbuf
  946.         push di
  947.         call getline
  948.         pop si
  949.         mov di,offset VKernelBuf.vk_rname
  950.         call mangle_name
  951.         jmp parse_config
  952. pc_timeout:    call getint            ; "timeout" command
  953.         jc parse_config
  954.         mov ax,0D215h            ; There are approx 1.D215h
  955.         mul bx                ; clock ticks per 1/10 s
  956.         add bx,dx
  957.         mov KbdTimeOut,bx
  958.         jmp parse_config
  959. pc_display:    mov di,offset trackbuf
  960.         push di
  961.         call getline            ; Get filename to display
  962.         pop si
  963.         mov di,offset MNameBuf        ; Mangled name buffer
  964.         push di
  965.         call mangle_name        ; Mangle file name
  966.         pop di
  967.         call searchdir            ; Search for file
  968.         jz parse_config            ; File not found?
  969.         call get_msg_file        ; Load and display file
  970.         jmp parse_config
  971. pc_prompt:    call getint            ; "prompt" command
  972.         jc parse_config
  973.         mov ForcePrompt,bx
  974.         jmp parse_config
  975. pc_implicit:    call getint                     ; "implicit" command
  976.                 jc parse_config
  977.                 mov AllowImplicit,bx
  978.                 jmp parse_config
  979. pc_fkey:    sub ah,'1'
  980.         jnb pc_fkey1
  981.         mov ah,9            ; F10
  982. pc_fkey1:    xor cx,cx
  983.         mov cl,ah
  984.         push cx
  985.         mov ax,1
  986.         shl ax,cl
  987.         or FKeyMap, ax            ; Mark that we have this loaded
  988.         mov di,offset trackbuf
  989.         push di
  990.         call getline            ; Get filename to display
  991.         pop si
  992.         pop di
  993.         shl di,4            ; Multiply number by 16
  994.         add di,offset FKeyName
  995.         call mangle_name        ; Mangle file name
  996.         jmp parse_config
  997. pc_label:    call commit_vk            ; Commit any current vkernel
  998.         mov di,offset trackbuf        ; Get virtual filename
  999.         push di
  1000.         call getline
  1001.         pop si
  1002.         mov di,offset VKernelBuf.vk_vname
  1003.         call mangle_name        ; Mangle virtual name
  1004.         inc VKernelCtr            ; One more vkernel
  1005.         mov si,offset VKernelBuf.vk_vname ; By default, rname == vname
  1006.         mov di,offset VKernelBuf.vk_rname
  1007.         mov cx,11
  1008.         rep movsb
  1009.                 mov si,offset AppendBuf         ; Default append==global append
  1010.                 mov di,offset VKernelBuf.vk_append
  1011.                 mov cx,AppendLen
  1012.                 mov VKernelBuf.vk_appendlen,cx
  1013.                 rep movsb
  1014.         jmp parse_config
  1015. ;
  1016. ; commit_vk: Store the current VKernelBuf into buffer segment
  1017. ;
  1018. commit_vk    proc near
  1019.         cmp VKernelCtr,0
  1020.         je cvk_ret            ; No VKernel = return
  1021.         cmp VKernelCtr,16        ; Above limit?
  1022.         ja cvk_overflow
  1023.         mov di,VKernelCtr
  1024.         dec di
  1025.         shl di,12            ; 4K/buffer
  1026.         mov si,offset VKernelBuf
  1027.         mov cx,1024            ; = 4K bytes
  1028.         push es
  1029.         push vk_seg
  1030.         pop es
  1031.         rep movsd            ; Copy to buffer segment
  1032.         pop es
  1033. cvk_ret:    ret
  1034. cvk_overflow:    mov VKernelCtr,16        ; No more than 16, please
  1035.         ret
  1036. commit_vk    endp
  1037. ;
  1038. ; End of configuration file
  1039. ;
  1040. end_config_file:
  1041.         call commit_vk            ; Commit any current vkernel
  1042. no_config_file:
  1043. ;
  1044. ; Check whether or not we are supposed to display the boot prompt.
  1045. ;
  1046. check_for_key:
  1047.         cmp ForcePrompt,0        ; Force prompt?
  1048.         jnz enter_command
  1049.         test KbdFlags,5Bh        ; Caps, Scroll, Shift, Alt
  1050.         jz auto_boot            ; If neither, default boot
  1051.  
  1052. enter_command:
  1053.         mov si,offset boot_prompt
  1054.         call writestr
  1055.  
  1056.         mov di,offset command_line
  1057. ;
  1058. ; get the very first character -- we can either time
  1059. ; out, or receive a character press at this time.  Some dorky BIOSes stuff
  1060. ; a return in the buffer on bootup, so wipe the keyboard buffer first.
  1061. ;
  1062. clear_buffer:    mov ah,1            ; Check for pending char
  1063.         int 16h
  1064.         jz get_char_time
  1065.         xor ax,ax            ; Get char
  1066.         int 16h
  1067.         jmp clear_buffer
  1068. get_char_time:    mov cx,KbdTimeOut
  1069.         and cx,cx
  1070.         jz get_char            ; Timeout == 0 -> no timeout
  1071.         inc cx                ; The first loop will happen
  1072.                         ; immediately as we don't
  1073.                         ; know the appropriate DX value
  1074. time_loop:    push cx
  1075. tick_loop:    push dx
  1076.         mov ah,1            ; Check for pending keystroke
  1077.         int 16h
  1078.         jnz get_char_pop
  1079.         xor ax,ax
  1080.         int 1Ah                ; Get time "of day"
  1081.         pop ax
  1082.         cmp dx,ax            ; Has the timer advanced?
  1083.         je tick_loop
  1084.         pop cx
  1085.         loop time_loop            ; If so, decrement counter
  1086.         jmp command_done        ; Timeout!
  1087. get_char_pop:    pop eax                ; Clear the stack
  1088. get_char:    xor ax,ax            ; Get char
  1089.         int 16h
  1090.         and al,al
  1091.         jz func_key
  1092.         cmp al,' '            ; ASCII?
  1093.         jb not_ascii
  1094.         ja enter_char
  1095.         cmp di,offset command_line    ; Space must not be first
  1096.         je get_char
  1097. enter_char:    cmp di,max_cmd_len+offset command_line ; Check there's space
  1098.         jnb get_char
  1099.         stosb                ; Save it
  1100.         call writechr            ; Echo to screen
  1101.         jmp get_char
  1102. not_ascii:    cmp al,0Dh            ; Enter
  1103.         je command_done
  1104.         cmp al,08h            ; Backspace
  1105.         jne get_char
  1106.         cmp di,offset command_line    ; Make sure there is anything
  1107.         je get_char            ; to erase
  1108.         dec di                ; Unstore one character
  1109.         mov si,offset wipe_char        ; and erase it from the screen
  1110.         call writestr
  1111.         jmp get_char
  1112. func_key:
  1113.         push di
  1114.         cmp ah,68            ; F10
  1115.         ja get_char
  1116.         sub ah,59            ; F1
  1117.         jb get_char
  1118.         mov cl,ah
  1119.         shr ax,4            ; Convert to x16
  1120.         mov bx,1
  1121.         shl bx,cl
  1122.         and bx,FKeyMap
  1123.         jz get_char            ; Undefined F-key
  1124.         mov di,ax
  1125.         add di,offset FKeyName
  1126.         call searchdir
  1127.         jz fk_nofile
  1128.         call get_msg_file
  1129.         jmp fk_wrcmd
  1130. fk_nofile:
  1131.         mov si,offset crlf
  1132.         call writestr
  1133. fk_wrcmd:
  1134.         mov si,offset boot_prompt
  1135.         call writestr
  1136.         pop di                ; Command line write pointer
  1137.         push di
  1138.         mov byte ptr [di],0        ; Null-terminate command line
  1139.         mov si,offset command_line
  1140.         call writestr            ; Write command line so far
  1141.         pop di
  1142.         jmp get_char
  1143. auto_boot:
  1144.         mov si,offset default_cmd
  1145.         mov di,offset command_line
  1146.         mov cx,(max_cmd_len+4) shr 2
  1147.         rep movsd
  1148.         jmp load_kernel
  1149. command_done:
  1150.         mov si,offset crlf
  1151.         call writestr
  1152.         cmp di,offset command_line    ; Did we just hit return?
  1153.         je auto_boot
  1154.         xor al,al            ; Store a final null
  1155.         stosb
  1156.  
  1157. load_kernel    label near            ; Load the kernel now
  1158. ;
  1159. ; First we need to mangle the kernel name the way DOS would...
  1160. ;
  1161.         mov si,offset command_line
  1162.                 mov di,offset KernelName
  1163.                 push si
  1164.                 push di
  1165.         call mangle_name
  1166.         pop di
  1167.                 pop si
  1168. ;
  1169. ; Fast-forward to first option (we start over from the beginning, since
  1170. ; mangle_name doesn't necessarily return a consistent ending state.)
  1171. ;
  1172. clin_non_wsp:   lodsb
  1173.                 cmp al,' '
  1174.                 ja clin_non_wsp
  1175. clin_is_wsp:    and al,al
  1176.                 jz clin_opt_ptr
  1177.                 lodsb
  1178.                 cmp al,' '
  1179.                 jbe clin_is_wsp
  1180. clin_opt_ptr:   dec si                          ; Point to first nonblank
  1181.                 mov CmdOptPtr,si                ; Save ptr to first option
  1182. ;
  1183. ; Now check if it is a "virtual kernel"
  1184. ;
  1185.         mov cx,VKernelCtr
  1186.         push ds
  1187.         push vk_seg
  1188.         pop ds
  1189.                 assume ds:vk_seg
  1190.         cmp cx,0
  1191.         je not_vk
  1192.         xor si,si            ; Point to first vkernel
  1193. vk_check:    pusha
  1194.         mov cx,11
  1195.         repe cmpsb            ; Is this it?
  1196.         je vk_found
  1197.         popa
  1198.         add si,4096            ; 4K per vkernel structure
  1199.         loop vk_check
  1200. not_vk:        pop ds
  1201.                 assume ds:_text
  1202. ;
  1203. ; Not a "virtual kernel" - check that's OK and construct the command line
  1204. ;
  1205.                 cmp AllowImplicit,0
  1206.                 je bad_implicit
  1207.                 push es
  1208.                 push si
  1209.                 push di
  1210.                 mov di,real_mode_seg
  1211.                 mov es,di
  1212.                 mov si,offset AppendBuf
  1213.                 mov di,offset cmd_line_here
  1214.                 mov cx,AppendLen
  1215.                 rep movsb
  1216.                 mov CmdLinePtr,di
  1217.                 pop di
  1218.                 pop si
  1219.                 pop es
  1220. ;
  1221. ; Find the kernel on disk
  1222. ;
  1223. get_kernel:     mov si,offset KernelName
  1224.                 mov di,offset KernelCName
  1225.                 call unmangle_name              ; Get human form
  1226.                 sub di,offset KernelCName
  1227.                 mov KernelCNameLen,di
  1228.                 mov di,offset KernelName        ; Search on disk
  1229.                 call searchdir
  1230.                 jnz kernel_good
  1231. bad_kernel:     mov si,offset err_notfound      ; Complain about missing kernel
  1232.         call writestr
  1233.                 mov si,offset KernelCName
  1234.                 call writestr
  1235.                 mov si,offset crlf
  1236.                 jmp abort_load                  ; Ask user for clue
  1237. ;
  1238. ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
  1239. ;
  1240. bad_implicit:   mov si,offset KernelName        ; For the error message
  1241.                 mov di,offset KernelCName
  1242.                 call unmangle_name
  1243.                 jmp bad_kernel
  1244. ;
  1245. ; vk_found: We *are* using a "virtual kernel"
  1246. ;
  1247.                 assume ds:vk_seg
  1248. vk_found:    popa
  1249.         push di
  1250.         mov di,offset VKernelBuf
  1251.         mov cx,(size vkernel+3) shr 2
  1252.         rep movsd
  1253.         push es                ; Restore old DS
  1254.         pop ds
  1255.         assume ds:_text
  1256.         push es
  1257.         push real_mode_seg
  1258.         pop es
  1259.         mov di,offset cmd_line_here
  1260.         mov si,offset VKernelBuf.vk_append
  1261.         mov cx,VKernelBuf.vk_appendlen
  1262.         rep movsb
  1263.         mov CmdLinePtr,di        ; Where to add rest of cmd
  1264.         pop es
  1265.                 pop di                          ; DI -> KernelName
  1266.         push di    
  1267.         mov si,offset VKernelBuf.vk_rname
  1268.         mov cx,11
  1269.         rep movsb
  1270.         pop di
  1271.         jmp get_kernel
  1272. ;
  1273. ; kernel_corrupt: Called if the kernel file does not seem healthy
  1274. ;
  1275. kernel_corrupt: mov si,offset err_notkernel
  1276.                 jmp abort_load
  1277. kernel_good:
  1278. ;
  1279. ; This is it!  We have a name (and location on the disk)... let's load
  1280. ; that sucker!!
  1281. ;
  1282. ; A Linux kernel consists of three parts: boot sector, setup code, and
  1283. ; kernel code.    The boot sector is never executed when using an external
  1284. ; booting utility, but it contains some status bytes that are necessary.
  1285. ; The boot sector and setup code together form exactly 5 sectors that
  1286. ; should be loaded at 9000:0.  The subsequent code should be loaded
  1287. ; at 1000:0.  For simplicity, we load the whole thing at 0F60:0, and
  1288. ; copy the latter stuff afterwards.
  1289. ;
  1290. ; NOTE: In the previous code I have avoided making any assumptions regarding
  1291. ; the size of a sector, in case this concept ever gets extended to other
  1292. ; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT
  1293. ; filesystem, of course).  However, a "sector" when it comes to Linux booting
  1294. ; stuff means 512 bytes *no matter what*, so here I am using that piece
  1295. ; of knowledge.
  1296. ;
  1297. ; First check that our kernel is at least 64K and less than 8M (if it is
  1298. ; more than 8M, we need to change the logic for loading it anyway...)
  1299. ;
  1300. load_it:
  1301.                 cmp dx,80h                      ; 8 megs
  1302.         ja kernel_corrupt
  1303.         and dx,dx
  1304.         jz kernel_corrupt
  1305. kernel_sane:    push ax
  1306.         push dx
  1307.         push si
  1308.         mov si,offset loading_msg
  1309.                 call cwritestr
  1310. ;
  1311. ; Now start transferring the kernel
  1312. ;
  1313.         push real_mode_seg
  1314.         pop es
  1315.         assume es:real_mode_seg
  1316.  
  1317.         push ax
  1318.         push dx
  1319.         div ClustSize            ; # of clusters total
  1320.         and dx,dx            ; Round up
  1321.         setnz dl
  1322.         movzx dx,dl
  1323.         add ax,dx
  1324.                 mov KernelClust,ax
  1325.         pop dx
  1326.         pop ax
  1327.         add ax,1023
  1328.         adc dx,0
  1329.         mov bx,1024
  1330.         div bx                ; Get number of kilobytes
  1331.         mov KernelK,ax
  1332. ;
  1333. ; Now, if we transfer these straight, we'll hit 64K boundaries.     Hence we
  1334. ; have to see if we're loading more than 64K, and if so, load it step by
  1335. ; step.
  1336. ;
  1337.         mov dx,1            ; 10000h
  1338.         xor ax,ax
  1339.         div ClustSize
  1340.         mov ClustPerMoby,ax        ; Clusters/64K
  1341. ;
  1342. ; Start by loading the bootsector/setup code, to see if we need to
  1343. ; do something funky.  It should fit in the first 32K (loading 64K won't
  1344. ; work since we might have funny stuff up near the end of memory).
  1345. ; If we have larger than 32K clusters, yes, we're hosed.
  1346. ;
  1347.         call abort_check        ; Check for abort key
  1348.         mov cx,ClustPerMoby
  1349.         shr cx,1            ; Half a moby
  1350.         sub KernelClust,cx
  1351.         xor bx,bx
  1352.                 pop si                          ; Cluster pointer on stack
  1353.         call getfssec
  1354.         jc kernel_corrupt        ; Failure in first 32K
  1355.                 cmp bs_bootsign,0AA55h
  1356.         jne kernel_corrupt        ; Boot sec signature missing
  1357.         cmp byte ptr su_jump, 0EBh    ; Jump opcode
  1358.         jne kernel_corrupt
  1359. ;
  1360. ; Get the BIOS' idea of what the size of high memory is
  1361. ;
  1362.         push si                ; Save our cluster pointer!
  1363.         mov ah,88h
  1364.         int 15h
  1365.         cmp ax,14*1024            ; Don't trust memory >15M
  1366.         jna hms_ok
  1367.         mov ax,14*1024
  1368. hms_ok:        mov HighMemSize,ax
  1369. ;
  1370. ; Construct the command line (append options have already been copied)
  1371. ;
  1372.         mov kern_cmd_magic,0A33Fh    ; Command line magic no
  1373.         mov kern_cmd_offset,offset cmd_line_here
  1374.         mov di,CmdlinePtr
  1375.                 mov si,offset boot_image        ; BOOT_IMAGE=
  1376.                 mov cx,boot_image_len
  1377.                 rep movsb
  1378.                 mov si,offset KernelCName       ; Unmangled kernel name
  1379.                 mov cx,KernelCNameLen
  1380.                 rep movsb
  1381.                 mov al,' '                      ; Space
  1382.                 stosb
  1383.                 mov si,CmdOptPtr                ; Options from user input
  1384.         mov cx,(kern_cmd_len+3) shr 2
  1385.         rep movsd
  1386. ;
  1387.                 ifdef debug
  1388.                 push ds                         ; DEBUG DEBUG DEBUG
  1389.                 push es
  1390.                 pop ds
  1391.                 mov si,offset cmd_line_here
  1392.                 call cwritestr
  1393.                 pop ds
  1394.                 mov si,offset crlf
  1395.                 call cwritestr
  1396.                 endif
  1397. ;
  1398. ; Scan through the command line for anything that looks like we might be
  1399. ; interested in.  The original version of this code automatically assumed
  1400. ; the first option was BOOT_IMAGE=, but that is no longer certain.
  1401. ;
  1402.         mov si,offset cmd_line_here
  1403.                 mov initrd_flag,0
  1404.                 push es
  1405.                 pop ds
  1406.                 assume ds:real_mode_seg
  1407. get_next_opt:   lodsb
  1408.         and al,al
  1409.         jz cmdline_end
  1410.         cmp al,' '
  1411.         jbe get_next_opt
  1412.         dec si
  1413.                 mov eax,[si]
  1414.                 cmp eax,'=agv'                  ; vga=
  1415.         je is_vga_cmd
  1416.                 cmp eax,'=mem'                  ; mem=
  1417.         je is_mem_cmd
  1418.                 push es                         ; Save ES->real_mode_seg
  1419.                 push cs
  1420.                 pop es                          ; Set ES <- normal DS
  1421.                 assume es:_text
  1422.                 mov di,offset initrd_cmd
  1423.         mov cx,initrd_cmd_len
  1424.         repe cmpsb
  1425.                 jne not_initrd
  1426.         mov di,offset InitRD
  1427.                 push si                         ; mangle_dir mangles si
  1428.                 call mangle_name                ; Mangle ramdisk name
  1429.                 pop si
  1430.         cmp [InitRD],' '        ; Null filename?
  1431.                 seta initrd_flag                ; Set flag if not
  1432. not_initrd:     pop es                          ; Restore ES->real_mode_seg
  1433.                 assume es:real_mode_seg
  1434. skip_this_opt:  lodsb                           ; Load from command line
  1435.                 cmp al,' '
  1436.                 ja skip_this_opt
  1437.                 dec si
  1438.                 jmp get_next_opt
  1439. is_vga_cmd:
  1440.                 add si,4
  1441.                 mov eax,[si]
  1442.                 mov bx, -1
  1443.                 cmp eax, 'mron'                 ; vga=normal
  1444.                 je vc0
  1445.                 and eax, 0ffffffh               ; 3 bytes
  1446.                 mov bx, -2
  1447.                 cmp eax, 'txe'                  ; vga=ext
  1448.                 je vc0
  1449.                 mov bx, -3
  1450.                 cmp eax, 'ksa'                  ; vga=ask
  1451.                 je vc0
  1452.                 call parseint                   ; vga=<number>
  1453.         jc skip_this_opt        ; Not an integer
  1454. vc0:        mov bs_vidmode, bx        ; Set video mode
  1455.         jmp skip_this_opt
  1456. is_mem_cmd:
  1457.                 add si,4
  1458.                 call parseint
  1459.         jc skip_this_opt        ; Not an integer
  1460.         shr ebx,10            ; Convert to kilobytes
  1461.                 sub ebx,1024                    ; Don't count first meg
  1462.         cmp ebx,14*1024            ; Only trust < 15M point
  1463.                 jna memcmd_fair
  1464.         mov bx,14*1024
  1465. memcmd_fair:    mov HighMemSize,bx
  1466.         jmp skip_this_opt
  1467. cmdline_end:
  1468.                 push cs                         ; Restore standard DS
  1469.                 pop ds
  1470.                 assume ds:_text
  1471. ;
  1472. ; Now check if we have a large kernel, which needs to be loaded high
  1473. ;
  1474.         cmp su_header,HEADER_ID        ; New setup code ID
  1475.         jne old_kernel            ; Old kernel, load low
  1476.         cmp su_version,0200h        ; Setup code version 2.0
  1477.         jb old_kernel            ; Old kernel, load low
  1478.                 cmp su_version,0201h            ; Version 2.01+?
  1479.                 jb new_kernel                   ; If 2.00, skip this step
  1480.                 mov su_heapend,offset linux_stack ; Set up the heap
  1481.                 or su_loadflags,80h             ; Let the kernel know we cared
  1482. ;
  1483. ; We definitely have a new-style kernel.  Let the kernel know who we are,
  1484. ; and that we are clueful
  1485. ;
  1486. new_kernel:
  1487.         mov su_loader, syslinux_id    ; Show some ID
  1488. ;
  1489. ; Now see if we have an initial RAMdisk; if so, do requisite computation
  1490. ;
  1491.                 test initrd_flag,1
  1492.                 jz nk_noinitrd
  1493.                 push es                         ; ES->real_mode_seg
  1494.                 push ds
  1495.                 pop es                          ; We need ES==DS
  1496.                 assume es:_text
  1497.                 mov si,offset InitRD
  1498.                 mov di,offset InitRDCName
  1499.                 call unmangle_name              ; Create human-readable name
  1500.                 sub di,offset InitRDCName
  1501.                 mov InitRDCNameLen,di
  1502.                 mov di,offset InitRD
  1503.                 call searchdir                  ; Look for it in directory
  1504.                 pop es
  1505.                 assume es:real_mode_seg
  1506.         jz initrd_notthere
  1507.         mov initrd_ptr,si        ; Save cluster pointer
  1508.         mov su_ramdisklen1,ax        ; Ram disk length
  1509.         mov su_ramdisklen2,dx
  1510.         div ClustSize
  1511.         and dx,dx            ; Round up
  1512.         setnz dl
  1513.         movzx dx,dl
  1514.         add ax,dx
  1515.         mov InitRDClust,ax        ; Ramdisk clusters
  1516.                 mov eax,su_ramdisklen
  1517.                 shr eax,10                      ; Convert to kilobytes
  1518.                 mov dx,HighMemSize              ; End of memory
  1519.                 add dx,1024                     ; Add "low" memory
  1520.                 sub dx,ax                       ; Subtract size of ramdisk
  1521.                 and dx,0ffc0h                   ; Round down to 64K boundary
  1522.                 shl dx,2                        ; Convert to 256-byte blocks
  1523.                 mov InitRDat,dx                 ; Load address
  1524.         call loadinitrd            ; Load initial ramdisk
  1525. ;
  1526. ; About to load the kernel, so print the kernel signon
  1527. ;
  1528. nk_noinitrd:
  1529.                 mov si,offset KernelCName       ; Print kernel name part of
  1530.                 call cwritestr                  ; "Loading" message
  1531.                 mov si,offset dotdot_msg        ; Print dots
  1532.                 call cwritestr
  1533.                 test su_loadflags, LOAD_HIGH    ; Is high load flag set?
  1534.                 jnz high_kernel                 ; Yes, load high
  1535.                 jmp low_kernel                  ; No, load low
  1536. initrd_notthere:
  1537.                 mov si, offset err_noinitrd
  1538.                 call writestr
  1539.                 mov si, offset InitRDCName
  1540.                 call writestr
  1541.                 mov si, offset crlf
  1542.                 jmp abort_load
  1543. ;
  1544. ; If we get here, we need to load kernel high
  1545. ;
  1546. no_high_mem:    mov si, offset err_nohighmem    ; Error routine
  1547.                 jmp abort_load
  1548. high_kernel:
  1549.                 mov ax,HighMemSize
  1550.         cmp ax,KernelK
  1551.         jb no_high_mem            ; Not enough high memory
  1552. ;
  1553. ; Move the stuff beyond the setup code to high memory at 100000h
  1554. ;
  1555.                 mov bx,1                        ; 1 boot sector
  1556.                 add bl,bs_setupsecs             ; Plus setup sectors
  1557.                 sbb bh,0
  1558.                 shl bx,1                        ; Convert to 256-byte blocks
  1559.                 mov ax,1080h                    ; 108000h = 1M + 32K
  1560.                 sub ax,bx                       ; Adjust pointer to 2nd block
  1561.                 mov HiLoadAddr,ax
  1562.                 shl bx,8                        ; Convert to a byte address
  1563.                 mov cx,4000h                    ; Cheating!  Copy all 32K
  1564.                 mov di,1000h                    ; Copy to address 100000h
  1565.                 call upload                     ; Transfer to high memory
  1566. ;
  1567.                 push 7000h                      ; Segment 7000h is xfer buffer
  1568.                 pop es
  1569.                 assume es:NOTHING               ; ES points to transfer buffer
  1570. high_load_loop: 
  1571.                 mov si,offset dot_msg           ; Progress report
  1572.                 call cwritestr
  1573.                 call abort_check
  1574.                 mov cx,KernelClust
  1575.         cmp cx,ClustPerMoby
  1576.         jna high_last_moby
  1577.         mov cx,ClustPerMoby
  1578. high_last_moby:
  1579.         sub KernelClust,cx
  1580.         xor bx,bx            ; Load at offset 0
  1581.                 pop si                          ; Restore cluster pointer
  1582.                 call getfssec
  1583.                 push si                         ; Save cluster pointer
  1584.                 pushf                           ; Save EOF
  1585.                 xor bx,bx
  1586.                 mov di,HiLoadAddr               ; Destination address
  1587.                 mov cx,8000h                    ; Cheating - transfer 64K
  1588.                 call upload                     ; Transfer to high memory
  1589.                 popf                            ; Restore EOF
  1590.                 jc high_load_done               ; If EOF we are done
  1591.                 add HiLoadAddr,100h             ; Point to next 64K
  1592.                 cmp KernelClust,0               ; Are we done?
  1593.         jne high_load_loop        ; Apparently not
  1594. high_load_done:
  1595.         pop si                ; No longer needed
  1596.         push real_mode_seg
  1597.         pop es
  1598.         assume es:real_mode_seg
  1599.         jmp load_done
  1600. ;
  1601. ; Load low kernel
  1602. ;
  1603. old_kernel:
  1604.                 test initrd_flag,1              ; Old kernel can't have initrd
  1605.                 jz low_kernel
  1606.                 mov si,offset err_oldkernel
  1607.                 jmp abort_load
  1608.                 ; An old kernel is always loaded low...
  1609. low_kernel:
  1610. ;
  1611. ; Low kernel: check that it will fit as a low kernel,
  1612. ;             save the vkernel buffers into high memory in case we abort the
  1613. ;             load, then transfer the kernel to low memory
  1614. ;
  1615.                 cmp KernelK,512                 ; 512K maximum
  1616.                 jna low_kernel_ok
  1617.                 jmp kernel_corrupt
  1618. low_kernel_ok:  push es
  1619.                 mov bx,vk_seg
  1620.                 mov es,bx
  1621.                 xor bx,bx
  1622.                 mov di,1000h                    ; 100000h
  1623.                 mov cx,8000h                    ; 64K
  1624.                 call upload
  1625.                 pop es
  1626.                 mov VKernelsHigh,1              ; VKernels now in high memory
  1627. ;
  1628. ; Transfer the already loaded protected-mode code down, then load the rest
  1629. ;
  1630.                 mov bx,1                        ; 1 boot sector
  1631.                 add bl,bs_setupsecs             ; Plus setup sectors
  1632.                 sbb bh,0
  1633.                 shl bx,5                        ; Convert to a paragraph number
  1634.                 push bx                         ; Save paragraph
  1635.                 add bx,real_mode_seg
  1636.                 push ds                         ; Save DS
  1637.                 mov ds,bx
  1638.                 mov ax,1000h                    ; New kernel start at...
  1639.                 mov es,ax
  1640.                 assume es:NOTHING
  1641.                 xor si,si
  1642.                 xor di,di
  1643.                 mov cx,2000h                    ; Cheating: copy 32K
  1644.                 rep movsd                       ; Copy down non-setup code
  1645.                 pop ds
  1646.                 pop bx                          ; Segment count of setup
  1647.                 mov ax,1800h                    ; Paragraph for moby 2 if
  1648.                                                 ; setup is 0K
  1649.                 sub ax,bx                       ; AX now = this moby segment
  1650. loadmoby:
  1651.                 mov si,offset dot_msg
  1652.                 call cwritestr
  1653.                 call abort_check
  1654.                 pop si                          ; Restore cluster pointer
  1655.         mov cx,KernelClust
  1656.         cmp cx,ClustPerMoby
  1657.         jna last_moby
  1658.         mov cx,ClustPerMoby
  1659. last_moby:
  1660.         sub KernelClust,cx
  1661.         xor bx,bx            ; Load at zero
  1662.                 mov es,ax                       ; Segment address
  1663.                 push ax                         ; Save segment address
  1664.                 call getfssec
  1665.                 pop ax
  1666.         jc load_done
  1667.         cmp KernelClust,0
  1668.         jz load_done
  1669.                 push si                         ; Save cluster pointer
  1670.                 add ax,1000h                    ; Advance to next moby
  1671.                 jmp loadmoby
  1672. ;
  1673. ; This is where both the high and low load routines end up after having
  1674. ; loaded
  1675. ;
  1676.  
  1677. load_done:
  1678.                 mov ax,real_mode_seg
  1679.                 mov es,ax
  1680.                 assume es:real_mode_seg
  1681.  
  1682.                 mov si,offset dot_msg
  1683.                 call cwritestr
  1684. ;
  1685. ; If the default root device is set to FLOPPY (0000h), change to
  1686. ; /dev/fd0 (0200h)
  1687. ;
  1688.         cmp bs_rootdev,0
  1689.         jne root_not_floppy
  1690.         mov bs_rootdev,0200h
  1691. root_not_floppy:
  1692. ;
  1693. ; Copy the disk table to high memory, then re-initialize the floppy
  1694. ; controller
  1695. ;
  1696.         mov si,offset floppy_table
  1697.         mov di,offset linux_fdctab
  1698.         mov cx,3            ; 12 bytes
  1699.         push di
  1700.         rep movsd
  1701.         pop di
  1702.         cli
  1703.         mov [fdctab1],di        ; Save new floppy tab pos
  1704.         mov [fdctab2],es
  1705.         sti
  1706.         xor ax,ax
  1707.         xor dx,dx
  1708.         int 13h
  1709. ;
  1710. ; Linux wants the floppy motor shut off before starting the kernel,
  1711. ; at least bootsect.S seems to imply so
  1712. ;
  1713. kill_motor:
  1714.         mov dx,03F2h
  1715.         xor al,al
  1716.         out dx,al
  1717. ;
  1718. ; Now we're as close to be done as we can be and still use our normal
  1719. ; routines, print a CRLF to end the row of dots
  1720. ;
  1721.                 call abort_check        ; Last chance!!
  1722.         mov si,offset crlf
  1723.         call writestr
  1724. ;
  1725. ; If we're debugging, wait for a keypress so we can read any debug messages
  1726. ;
  1727.                 ifdef debug
  1728.                 xor ax,ax
  1729.                 int 16h
  1730.                 endif
  1731. ;
  1732. ; Set up segment registers and the Linux real-mode stack
  1733. ;
  1734.         mov ax,real_mode_seg
  1735.         mov ds,ax
  1736.                 mov es,ax
  1737.         mov fs,ax
  1738.         mov gs,ax
  1739.         cli
  1740.         mov ss,ax
  1741.         mov sp,offset linux_stack
  1742.         sti
  1743. ;
  1744. ; We're done... now RUN THAT KERNEL!!!!
  1745. ;
  1746.         jmp far ptr setup_entry
  1747. ;
  1748. ; cwritestr: write a null-terminated string to the console, saving
  1749. ;            registers on entry (we can't use this in the boot sector,
  1750. ;            since we haven't verified 386-ness yet)
  1751. ;
  1752.                 assume ds:NOTHING, es:NOTHING
  1753. cwritestr       proc near
  1754.                 pusha
  1755. cwstr_1:        lodsb
  1756.         and al,al
  1757.                 jz cwstr_2
  1758.         mov ah,0Eh        ; Write to screen as TTY
  1759.         mov bx,0007h        ; White on black, current page
  1760.         int 10h
  1761.                 jmp short cwstr_1
  1762. cwstr_2:        popa
  1763.                 ret
  1764. cwritestr       endp
  1765. ;
  1766. ; Load RAM disk into high memory
  1767. ;
  1768.                 assume ds:_text, es:real_mode_seg
  1769. loadinitrd    proc near
  1770.                 push es                         ; Save ES on entry
  1771.                 mov ax,real_mode_seg
  1772.                 mov es,ax
  1773.                 mov si,initrd_ptr
  1774.         and si,si
  1775.                 mov di,InitRDat                 ; initrd load address
  1776.                 movzx eax,di
  1777.                 shl eax,8                       ; Convert to bytes
  1778.         mov su_ramdiskat,eax        ; Offset for ram disk
  1779.         push si
  1780.                 mov si,offset InitRDCName       ; Write ramdisk name
  1781.                 call cwritestr
  1782.                 mov si,offset dotdot_msg        ; Write dots
  1783.                 call cwritestr
  1784. rd_load_loop:    
  1785.         mov si,offset dot_msg        ; Progress report
  1786.                 call cwritestr
  1787.         pop si                ; Restore cluster pointer
  1788.                 call abort_check
  1789.                 mov cx,InitRDClust
  1790.         cmp cx,ClustPerMoby
  1791.         jna rd_last_moby
  1792.         mov cx,ClustPerMoby
  1793. rd_last_moby:
  1794.         sub InitRDClust,cx
  1795.         xor bx,bx            ; Load at offset 0
  1796.         assume es:NOTHING
  1797.                 push 7000h                      ; Segment 7000h
  1798.         pop es
  1799.         call getfssec
  1800.                 push si                         ; Save cluster pointer
  1801.                 pushf                           ; Remember EOF
  1802.         mov si,offset prot_xfer_gdt
  1803.                 xor bx,bx
  1804.                 mov di,InitRDat
  1805.                 mov cx,8000h                    ; Always transfer 64K
  1806.                 call upload
  1807.                 popf
  1808.                 jc rd_load_done                 ; EOF?
  1809.                 add InitRDat,100h               ; Point to next 64K
  1810.         cmp InitRDClust,0        ; Are we done?
  1811.         jne rd_load_loop        ; Apparently not
  1812. rd_load_done:
  1813.                 pop si                          ; Clean up the stack
  1814.                 mov si,offset crlf_msg
  1815.         call writestr
  1816.                 mov si,offset loading_msg       ; Write new "Loading " for
  1817.                 call writestr                   ; the benefit of the kernel
  1818.                 pop es                          ; Restore original ES
  1819.                 ret
  1820. loadinitrd      endp
  1821. ;
  1822. ; upload: upload a chunk of data to high memory
  1823. ;         es:bx = source address
  1824. ;         di    = linear target address (x 256)
  1825. ;         cx    = count (words) - max 8000h for now
  1826. ;
  1827.                 assume ds:_text
  1828.  
  1829. upload          proc near
  1830.                 pushad
  1831.                 push es
  1832.                 mov eax,09300000h       ; Compute linear base [93h in field
  1833.                 mov ax,es               ; right beyond the 3-byte address
  1834.                 shl eax,4               ; field!
  1835.                 movzx ebx,bx
  1836.                 add eax,ebx
  1837.                 mov dword ptr px_src_low,eax
  1838. ul_dl:          push cs                 ; Set ES=CS (=DS)
  1839.                 pop es
  1840.                 mov px_dst,di           ; Save destination address
  1841.                 push cx                 ; Save count
  1842.                 xor eax,eax
  1843.                 mov di,offset px_wipe_1
  1844.                 mov cx,4
  1845.                 stosd
  1846.                 mov di,offset px_wipe_2
  1847.                 mov cx,4
  1848.                 stosd
  1849.                 pop cx
  1850.                 mov si,offset prot_xfer_gdt
  1851.                 mov ah,87h
  1852.                 int 15h
  1853.                 jc ul_error
  1854.                 pop es
  1855.                 popad
  1856.                 ret
  1857. ul_error:       pop ax                  ; Leave ES=CS (=DS)
  1858.                 popad
  1859.                 mov si,offset err_highload
  1860.                 jmp abort_load
  1861. upload          endp
  1862. ;
  1863. ; download: same as upload, except si = linear source address (x 256)
  1864. ;           currently used only to recover the vkernels in case of an
  1865. ;           aborted low-kernel load (don't you love corner cases?)
  1866. ;
  1867. download        proc near
  1868.                 pushad
  1869.                 push es
  1870.                 mov px_src_low,0
  1871.                 mov px_src,si
  1872.                 jmp ul_dl
  1873. download        endp
  1874. ;
  1875. ; GDT for protected-mode transfers (int 15h AH=87h).  Note that the low
  1876. ; 8 bits are set to zero in all transfers, so they never change in this
  1877. ; block.
  1878. ;
  1879.                 align 4
  1880. prot_xfer_gdt   label byte
  1881. px_wipe_1       db 16 dup(0)            ; Reserved
  1882.                 dw 0FFFFh               ; Limit: 64K
  1883. px_src_low      db 0                    ; Low 8 bits of source address
  1884. px_src          dw 0                    ; High 16 bits of source address
  1885.                 db 93h                  ; Segment access flags
  1886.                 dw 0                    ; Reserved
  1887.                 dw 0FFFFh               ; Limit: 64K
  1888. px_dst_low      db 00h                  ; Low 8 bits of destination address
  1889. px_dst          dw 0                    ; High 16 bits of destination address
  1890.                 db 93h                  ; Segment access flags
  1891.                 dw 0                    ; Reserved
  1892. px_wipe_2       db 16 dup(0)            ; Reserved
  1893. ;
  1894. ; abort_check: let the user abort with <ESC> or <Ctrl-C>
  1895. ;
  1896. abort_check    proc near
  1897.                 pusha
  1898. ac1:
  1899.         mov ah,1            ; Check for pending keystroke
  1900.         int 16h
  1901.                 jz ac_ret                       ; If no pending keystroke
  1902.         xor ax,ax            ; Load pending keystroke
  1903.         int 16h
  1904.         cmp al,27            ; <ESC> aborts (DOS geeks)
  1905.         je ac2
  1906.         cmp al,3            ; So does Ctrl-C (UNIX geeks)
  1907.         jne ac1                ; Unknown key... try again
  1908. ac2:                        ; If we get here, ABORT!
  1909.                 mov si,offset aborted_msg
  1910.                 ; Fall through to abort_load
  1911. abort_check     endp
  1912. ;
  1913. ; abort_load: Called by various routines which wants to print a fatal
  1914. ;             error message and return to the command prompt.  Since this
  1915. ;             may happen at just about any stage of the boot process, assume
  1916. ;             our state is messed up, and just reset the segment registers
  1917. ;             and the stack forcibly.
  1918. ;
  1919. ;             SI    = offset (in _text) of error message to print
  1920. ;
  1921. abort_load      proc near
  1922.                 mov ax,cs                       ; Restore CS = DS = ES
  1923.                 mov ds,ax
  1924.                 mov es,ax
  1925.                 cli
  1926.                 mov sp,(offset StackBuf)-2*3    ; Reset stack
  1927.                 mov ss,ax                       ; Just in case...
  1928.                 sti
  1929.                 call writestr                   ; Expects SI -> error msg
  1930.                 cmp VKernelsHigh,0
  1931.                 je al_ok
  1932.                 mov si,1000h                    ; VKernels stashed high
  1933.                 mov di,vk_seg                   ; Recover
  1934.                 shr di,4
  1935.                 mov cx,8000h
  1936.                 call download
  1937.                 mov VKernelsHigh,0
  1938. al_ok:          jmp enter_command               ; Return to command prompt
  1939. ;
  1940. ; End of abort_check
  1941. ;
  1942. ac_ret:         popa
  1943.                 ret
  1944. abort_load      endp
  1945. ;
  1946. ; searchdir: Search the root directory for a pre-mangled filename in
  1947. ;         DS:DI.  This routine is similar to the one in the boot
  1948. ;         sector, but is a little less Draconian when it comes to
  1949. ;         error handling, plus it reads the root directory in
  1950. ;         larger chunks than a sector at a time (which is probably
  1951. ;         a waste of coding effort, but I like to do things right).
  1952. ;
  1953. ;         NOTE: This file considers finding a zero-length file an
  1954. ;         error.  This is so we don't have to deal with that special
  1955. ;         case elsewhere in the program (most loops have the test
  1956. ;         at the end).
  1957. ;
  1958. ;         If successful:
  1959. ;        ZF clear
  1960. ;        SI    = cluster # for the first cluster
  1961. ;        DX:AX    = file length in bytes
  1962. ;         If unsuccessful
  1963. ;        ZF set
  1964. ;
  1965.                 assume ds:_text, es:_text
  1966.  
  1967. searchdir    proc near
  1968.         mov ax,bsRootDirEnts
  1969.         mov DirScanCtr,ax
  1970.         mov ax,RootDirSize
  1971.         mov DirBlocksLeft,ax
  1972.         mov ax,RootDir1
  1973.         mov dx,RootDir2
  1974. scan_group:
  1975.         mov bp,DirBlocksLeft
  1976.         and bp,bp
  1977.         jz dir_return
  1978.         cmp bp,BufSafeSec
  1979.         jna load_last
  1980.         mov bp,BufSafeSec
  1981. load_last:
  1982.         sub DirBlocksLeft,bp
  1983.         push ax
  1984.         push dx
  1985.         mov ax,bsBytesPerSec
  1986.         mul bp
  1987.         add ax,offset trackbuf-31
  1988.         mov EndofDirSec,ax    ; End of loaded
  1989.         pop dx
  1990.         pop ax
  1991.         push bp            ; Save number of sectors
  1992.         push ax            ; Save present location
  1993.         push dx
  1994.         push di            ; Save name
  1995.         mov bx,offset trackbuf
  1996.         call getlinsec
  1997.         pop di
  1998.         pop dx
  1999.         pop ax
  2000.         pop bp
  2001.         mov si,offset trackbuf
  2002. dir_test_name:    cmp byte ptr [si],0    ; Directory high water mark
  2003.         je dir_return        ; Failed
  2004.                 test byte ptr [si+11],010h ; Check it really is a file
  2005.                 jnz dir_not_this
  2006.         push di
  2007.         push si
  2008.         mov cx,11        ; Filename = 11 bytes
  2009.         repe cmpsb
  2010.         pop si
  2011.         pop di
  2012.         je dir_success
  2013. dir_not_this:   add si,32
  2014.         dec DirScanCtr
  2015.         jz dir_return        ; Out of it...
  2016.         cmp si,EndofDirSec
  2017.         jb dir_test_name
  2018.         add ax,bp        ; Increment linear sector number
  2019.         adc dx,0
  2020.         jmp scan_group
  2021. dir_success:
  2022.         mov ax,[si+28]        ; Length of file
  2023.         mov dx,[si+30]
  2024.         mov si,[si+26]        ; Cluster pointer
  2025.         mov bx,ax
  2026.         or bx,dx        ; Sets ZF iff DX:AX is zero
  2027. dir_return:
  2028.         ret
  2029. searchdir    endp
  2030. ;
  2031. ; writechr:    Write a single character in AL to the screen without
  2032. ;        mangling any registers
  2033. ;
  2034. writechr    proc near
  2035.         pusha
  2036.         mov ah,0Eh
  2037.         mov bx,0007h        ; white text on this page
  2038.         int 10h
  2039.         popa
  2040.         ret
  2041. writechr    endp
  2042. ;
  2043. ; get_msg_file: Load a text file and write its contents to the screen,
  2044. ;               interpreting color codes.  Is called with SI and DX:AX
  2045. ;               set by routine searchdir
  2046. ;
  2047. get_msg_file    proc near
  2048.                 mov NextCharJump,offset msg_putchar ; State machine for color
  2049.                 mov TextAttribute,07h           ; Default grey on white
  2050.                 pusha
  2051.                 mov bh,TextPage
  2052.                 mov ah,03h                      ; Read cursor position
  2053.                 int 10h
  2054.                 mov CursorDX,dx
  2055.                 popa
  2056. get_msg_chunk:  push ax                         ; DX:AX = length of file
  2057.                 push dx
  2058.         mov bx,offset trackbuf
  2059.         mov cx,BufSafe
  2060.         call getfssec
  2061.                 pop dx
  2062.                 pop ax
  2063.         push si                ; Save current cluster
  2064.         mov si,offset trackbuf
  2065.         mov cx,BufSafeBytes        ; No more than many bytes
  2066. print_msg_file: push cx
  2067.                 push ax
  2068.         push dx
  2069.         lodsb
  2070.                 cmp al,1Ah                      ; ASCII EOF?
  2071.         je msg_done_pop
  2072.                 call NextCharJump               ; Do what shall be done
  2073.         pop dx
  2074.         pop ax
  2075.                 pop cx
  2076.         sub ax,1
  2077.         sbb dx,0
  2078.         mov bx,ax
  2079.         or bx,dx
  2080.         jz msg_done
  2081.         loop print_msg_file
  2082.         pop si
  2083.         jmp get_msg_chunk
  2084. msg_done_pop:
  2085.                 add sp,6                        ; Lose 3 words on the stack
  2086. msg_done:
  2087.         pop si
  2088.         ret
  2089. msg_putchar:                                    ; Normal character
  2090.                 cmp al,0Fh                      ; ^O = color code follows
  2091.                 je msg_ctrl_o
  2092.                 cmp al,0Dh                      ; Ignore <CR>
  2093.                 je msg_ignore
  2094.                 cmp al,0Ah                      ; <LF> = newline
  2095.                 je msg_newline
  2096.                 cmp al,0Ch                      ; <FF> = clear screen
  2097.                 je msg_formfeed
  2098.                 mov bx,TextAttrBX
  2099.                 mov ah,09h                      ; Write character/attribute
  2100.                 mov cx,1                        ; One character only
  2101.                 int 10h                         ; Write to screen
  2102.                 mov al,CursorCol
  2103.                 inc ax
  2104.                 cmp al,VidCols
  2105.                 ja msg_newline
  2106.                 mov CursorCol,al
  2107. msg_gotoxy:     mov bh,TextPage
  2108.                 mov dx,CursorDX
  2109.                 mov ah,02h                      ; Set cursor position
  2110.                 int 10h
  2111. msg_ignore:     ret
  2112. msg_ctrl_o:                                     ; ^O = color code follows
  2113.                 mov NextCharJump,offset msg_setbg
  2114.                 ret
  2115. msg_newline:                                    ; Newline char or end of line
  2116.                 mov CursorCol,0
  2117.                 mov al,CursorRow
  2118.                 inc ax
  2119.                 cmp al,VidRows
  2120.                 ja msg_scroll
  2121.                 mov CursorRow,al
  2122.                 jmp msg_gotoxy
  2123. msg_scroll:     xor cx,cx                       ; Upper left hand corner
  2124.                 mov dx,ScreenSize
  2125.                 mov CursorRow,dh                ; New cursor at the bottom
  2126.                 mov bh,TextAttribute
  2127.                 mov ax,0601h                    ; Scroll up one line
  2128.                 int 10h
  2129.                 jmp msg_gotoxy
  2130. msg_formfeed:                                   ; Form feed character
  2131.                 xor cx,cx
  2132.                 mov CursorDX,cx                 ; Upper lefthand corner
  2133.                 mov dx,ScreenSize
  2134.                 mov bh,TextAttribute
  2135.                 mov ax,0600h                    ; Clear screen region
  2136.                 int 10h
  2137.                 jmp msg_gotoxy
  2138. msg_setbg:                                      ; Color background character
  2139.                 call unhexchar
  2140.                 jc msg_color_bad
  2141.                 shl al,4
  2142.                 mov TextAttribute,al
  2143.                 mov NextCharJump,offset msg_setfg
  2144.                 ret
  2145. msg_setfg:                                      ; Color foreground character
  2146.                 call unhexchar
  2147.                 jc msg_color_bad
  2148.                 or TextAttribute,al             ; setbg set foreground to 0
  2149.                 mov NextCharJump,offset msg_putchar
  2150.                 ret
  2151. msg_color_bad:
  2152.                 mov TextAttribute,07h           ; Default attribute
  2153.                 mov NextCharJump,offset msg_putchar
  2154.                 ret
  2155. get_msg_file    endp
  2156. ;
  2157. ; open,getc:    Load a file a character at a time for parsing in a manner
  2158. ;        similar to the C library getc routine.    Only one simultaneous
  2159. ;        use is supported.  Note: "open" trashes the trackbuf.
  2160. ;
  2161. ;        open:    Input:    mangled filename in DS:DI
  2162. ;            Output: ZF set on file not found or zero length
  2163. ;
  2164. ;        getc:    Output: CF set on end of file
  2165. ;                Character loaded in AL
  2166. ;
  2167. open        proc near
  2168.         call searchdir
  2169.         jz open_return
  2170.         pushf
  2171.         mov FBytes1,ax
  2172.         mov FBytes2,dx
  2173.         add ax,ClustSize
  2174.         adc dx,0
  2175.         sub ax,1
  2176.         sbb dx,0
  2177.         div ClustSize
  2178.         mov FClust,ax        ; Number of clusters
  2179.         mov FNextClust,si    ; Cluster pointer
  2180.         mov ax,EndOfGetCBuf    ; Pointer at end of buffer ->
  2181.         mov FPtr,ax        ;  nothing loaded yet
  2182.         popf            ; Restore no ZF
  2183. open_return:    ret
  2184. open        endp
  2185. ;
  2186. getc        proc near
  2187.         mov ax,FBytes1
  2188.         or ax,FBytes2
  2189.         jz getc_end
  2190.         mov si,FPtr
  2191.         cmp si,EndOfGetCBuf
  2192.         jb getc_loaded
  2193.         ; Buffer empty -- load another set
  2194.         mov cx,FClust
  2195.         cmp cx,BufSafe
  2196.         jna getc_oksize
  2197.         mov cx,BufSafe
  2198. getc_oksize:    sub FClust,cx        ; Reduce remaining clusters
  2199.         mov si,FNextClust
  2200.         mov bx,getcbuf
  2201.         push bx
  2202.         push es            ; ES may be != DS, save old ES
  2203.         push ds            ; Trackbuf is in DS, not ES
  2204.         pop es
  2205.         call getfssec        ; Load a trackbuf full of data
  2206.         mov FNextClust,si    ; Store new next pointer
  2207.         pop es            ; Restore ES
  2208.         pop si            ; SI -> newly loaded data
  2209. getc_loaded:    lodsb            ; Load a byte
  2210.         mov FPtr,si        ; Update next byte pointer
  2211.         dec FBytes        ; Update bytes left counter (CF = 1)
  2212. getc_end:    cmc            ; Set CF = 1 on EOF, 0 if not
  2213.         ret
  2214. getc        endp
  2215. ;
  2216. ; ungetc:    Push a character (in AL) back into the getc buffer
  2217. ;        Note: if more than one byte is pushed back, this may cause
  2218. ;        bytes to be written below the getc buffer boundary.  If there
  2219. ;        is a risk for this to occur, the getcbuf base address should
  2220. ;        be moved up.
  2221. ;
  2222. ungetc        proc near
  2223.         mov si,FPtr
  2224.         dec si
  2225.         mov [si],al
  2226.         mov FPtr,si
  2227.         inc FBytes
  2228.         ret
  2229. ungetc        endp
  2230. ;
  2231. ; skipspace:    Skip leading whitespace using "getc".  If we hit end-of-line
  2232. ;        or end-of-file, return with carry set; ZF = true of EOF
  2233. ;        ZF = false for EOLN; otherwise CF = ZF = 0.
  2234. ;
  2235. ;        Otherwise AL = first character after whitespace
  2236. ;
  2237. skipspace    proc near
  2238. skipspace_loop: call getc
  2239.         jc skipspace_eof
  2240.         cmp al,1Ah            ; DOS EOF
  2241.         je skipspace_eof
  2242.         cmp al,0Ah
  2243.         je skipspace_eoln
  2244.         cmp al,' '
  2245.         jbe skipspace_loop
  2246.         ret                ; CF = ZF = 0
  2247. skipspace_eof:    cmp al,al            ; Set ZF
  2248.         stc                ; Set CF
  2249.         ret
  2250. skipspace_eoln: add al,0FFh            ; Set CF, clear ZF
  2251.         ret
  2252. skipspace    endp
  2253. ;
  2254. ; getkeyword:    Get a keyword from the current "getc" file; only the two
  2255. ;        first characters are considered significant.
  2256. ;
  2257. ;        Lines beginning with ASCII characters 33-47 are treated
  2258. ;        as comments and ignored; other lines are checked for
  2259. ;        validity by scanning through the keywd_table.
  2260. ;
  2261. ;        The keyword and subsequent whitespace is skipped.
  2262. ;
  2263. ;        On EOF, CF = 1; otherwise, CF = 0, AL:AH = lowercase char pair
  2264. ;
  2265. getkeyword    proc near
  2266. gkw_find:    call skipspace
  2267.         jz gkw_eof        ; end of file
  2268.         jc gkw_find        ; end of line: try again
  2269.         cmp al,'0'
  2270.         jb gkw_skipline        ; skip comment line
  2271.         push ax
  2272.         call getc
  2273.         pop bx
  2274.         jc gkw_eof
  2275.         mov bh,al        ; Move character pair into BL:BH
  2276.         or bx,2020h        ; Lower-case it
  2277.         mov si,offset keywd_table
  2278. gkw_check:    lodsw
  2279.         and ax,ax
  2280.         jz gkw_badline        ; Bad keyword, write message
  2281.         cmp ax,bx
  2282.         jne gkw_check
  2283.         push ax
  2284. gkw_skiprest:
  2285.         call getc
  2286.         jc gkw_eof_pop
  2287.         cmp al,'0'
  2288.         ja gkw_skiprest
  2289.         call ungetc
  2290.         call skipspace
  2291.         jz gkw_eof_pop
  2292.                 jc gkw_missingpar       ; Missing parameter after keyword
  2293.         call ungetc        ; Return character to buffer
  2294.         clc            ; Successful return
  2295. gkw_eof_pop:    pop ax
  2296. gkw_eof:    ret            ; CF = 1 on all EOF conditions
  2297. gkw_missingpar: pop ax
  2298.                 mov si,offset err_noparm
  2299.                 call writestr
  2300.                 jmp gkw_find
  2301. gkw_badline_pop: pop ax
  2302. gkw_badline:    mov si,offset err_badcfg
  2303.         call writestr
  2304.         jmp gkw_find
  2305. gkw_skipline:    cmp al,10        ; Scan for LF
  2306.         je gkw_find
  2307.         call getc
  2308.         jc gkw_eof
  2309.         jmp gkw_skipline
  2310. getkeyword    endp
  2311. ;
  2312. ; getint:    Load an integer from the getc file.
  2313. ;        Return CF if error; otherwise return integer in EBX
  2314. ;
  2315. getint        proc near
  2316.         mov di,offset NumBuf
  2317. gi_getnum:    cmp di,NumBufEnd    ; Last byte in NumBuf
  2318.         jae gi_loaded
  2319.         push di
  2320.         call getc
  2321.         pop di
  2322.         jc gi_loaded
  2323.         stosb
  2324.         cmp al,'-'
  2325.         jnb gi_getnum
  2326.         call ungetc        ; Unget non-numeric
  2327. gi_loaded:    mov byte ptr [di],0
  2328.         mov si,offset NumBuf
  2329.         ; Fall through to parseint
  2330. getint        endp
  2331. ;
  2332. ; parseint:    Convert an integer to a number in EBX
  2333. ;        Get characters from string in DS:SI
  2334. ;        Return CF on error
  2335. ;        DS:SI points to first character after number
  2336. ;
  2337. ;               Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M
  2338. ;
  2339. parseint    proc near
  2340.                 push eax
  2341.                 push ecx
  2342.         push bp
  2343.         xor eax,eax        ; Current digit (keep eax == al)
  2344.         mov ebx,eax        ; Accumulator
  2345.         mov ecx,ebx        ; Base
  2346.                 xor bp,bp               ; Used for negative flag
  2347. pi_begin:    lodsb
  2348.         cmp al,'-'
  2349.         jne pi_not_minus
  2350.         xor bp,1        ; Set unary minus flag
  2351.         jmp pi_begin
  2352. pi_not_minus:
  2353.         cmp al,'0'
  2354.         jb pi_err
  2355.         je pi_octhex
  2356.         cmp al,'9'
  2357.         ja pi_err
  2358.         mov cl,10        ; Base = decimal
  2359.         jmp pi_foundbase
  2360. pi_octhex:
  2361.         lodsb
  2362.         cmp al,'0'
  2363.         jb pi_km        ; Value is zero
  2364.         or al,20h        ; Downcase
  2365.         cmp al,'x'
  2366.         je pi_ishex
  2367.         cmp al,'7'
  2368.         ja pi_err
  2369.         mov cl,8        ; Base = octal
  2370.         jmp pi_foundbase
  2371. pi_ishex:
  2372.         mov al,'0'        ; No numeric value accrued yet
  2373.         mov cl,16        ; Base = hex
  2374. pi_foundbase:
  2375.                 call unhexchar
  2376.                 jc pi_km                ; Not a (hex) digit
  2377.                 cmp al,cl
  2378.         jae pi_km        ; Invalid for base
  2379.         imul ebx,ecx        ; Multiply accumulated by base
  2380.                 add ebx,eax             ; Add current digit
  2381.         lodsb
  2382.         jmp pi_foundbase
  2383. pi_km:
  2384.         dec si            ; Back up to last non-numeric
  2385.         lodsb
  2386.         or al,20h
  2387.         cmp al,'k'
  2388.         je pi_isk
  2389.         cmp al,'m'
  2390.         je pi_ism
  2391.         dec si            ; Back up
  2392. pi_fini:    and bp,bp
  2393.         jz pi_ret        ; CF=0!
  2394.         neg ebx            ; Value was negative
  2395. pi_done:    clc
  2396. pi_ret:        pop bp
  2397.                 pop ecx
  2398.                 pop eax
  2399.         ret
  2400. pi_err:        stc
  2401.         jmp pi_ret
  2402. pi_isk:        shl ebx,10        ; x 2^10
  2403.         jmp pi_done
  2404. pi_ism:        shl ebx,20        ; x 2^20
  2405.         jmp pi_done
  2406. parseint    endp
  2407. ;
  2408. ; unhexchar:    Convert a hexadecimal digit in AL to the equivalent number;
  2409. ;               return CF=1 if not a hex digit
  2410. ;
  2411. unhexchar       proc near
  2412.                 cmp al,'0'
  2413.                 jb uxc_err
  2414.                 cmp al,'9'
  2415.                 ja uxc_1
  2416.                 sub al,'0'              ; CF=0
  2417.                 ret
  2418. uxc_1:          cmp al,'A'
  2419.                 jb uxc_err
  2420.                 cmp al,'F'
  2421.                 ja uxc_2
  2422.                 sub al,'A'-10           ; CF=0
  2423.                 ret
  2424. uxc_2:          cmp al,'a'
  2425.                 jb uxc_err
  2426.                 cmp al,'f'
  2427.                 ja uxc_err
  2428.                 sub al,'a'-10           ; CF=0
  2429.                 ret
  2430. uxc_err:        stc
  2431.                 ret
  2432. unhexchar       endp
  2433. ;
  2434. ;
  2435. ; getline:    Get a command line, converting control characters to spaces
  2436. ;               and collapsing streches to one; a space is appended to the
  2437. ;               end of the string, unless the line is empty.
  2438. ;        The line is terminated by ^J, ^Z or EOF and is written
  2439. ;        to ES:DI.  On return, DI points to first char after string.
  2440. ;        CF is set if we hit EOF.
  2441. ;
  2442. getline        proc near
  2443.         call skipspace
  2444.                 mov dl,1                ; Empty line -> empty string.
  2445.                 jz gl_eof               ; eof
  2446.                 jc gl_eoln              ; eoln
  2447.         call ungetc
  2448. gl_fillloop:    push dx
  2449.         push di
  2450.         call getc
  2451.         pop di
  2452.         pop dx
  2453.         jc gl_ret        ; CF set!
  2454.         cmp al,' '
  2455.         jna gl_ctrl
  2456.         xor dx,dx
  2457. gl_store:    stosb
  2458.         jmp gl_fillloop
  2459. gl_ctrl:    cmp al,10
  2460.         je gl_ret        ; CF clear!
  2461.         cmp al,26
  2462.         je gl_eof
  2463.         and dl,dl
  2464.         jnz gl_fillloop        ; Ignore multiple spaces
  2465.         mov al,' '        ; Ctrl -> space
  2466.         inc dx
  2467.         jmp gl_store
  2468. gl_eoln:        clc                     ; End of line is not end of file
  2469.                 jmp gl_ret
  2470. gl_eof:         stc
  2471. gl_ret:        pushf            ; We want the last char to be space!
  2472.         and dl,dl
  2473.         jnz gl_xret
  2474.         mov al,' '
  2475.         stosb
  2476. gl_xret:    popf
  2477.         ret
  2478. getline        endp
  2479.  
  2480.         ifdef debug        ; This code for debugging only
  2481. ;
  2482. ; dumpregs:    Dumps the contents of all registers
  2483. ;
  2484.                 assume ds:_text, es:NOTHING, fs:NOTHING, gs:NOTHING
  2485. dumpregs    proc near        ; When calling, IP is on stack
  2486.         pushf            ; Store flags
  2487.         pusha
  2488.         push ds
  2489.         push es
  2490.         push fs
  2491.         push gs
  2492.         push cs            ; Set DS <- CS
  2493.         pop ds
  2494.         cld            ; Clear direction flag
  2495.         mov si,offset crlf
  2496.         call writestr
  2497.         mov bx,sp
  2498.         add bx,26
  2499.         mov si,offset regnames
  2500.         mov cx,2        ; 2*7 registers to dump
  2501. dump_line:    push cx
  2502.         mov cx,7        ; 7 registers per line
  2503. dump_reg:    push cx
  2504.         mov cx,4        ; 4 characters/register name
  2505. wr_reg_name:    lodsb
  2506.         call writechr
  2507.         loop wr_reg_name
  2508.         mov ax,ss:[bx]
  2509.         dec bx
  2510.         dec bx
  2511.         call writehex
  2512.         pop cx
  2513.         loop dump_reg
  2514.         mov al,0Dh        ; <CR>
  2515.         call writechr
  2516.         mov al,0Ah        ; <LF>
  2517.         call writechr
  2518.         pop cx
  2519.         loop dump_line
  2520.         pop gs
  2521.         pop fs
  2522.         pop es
  2523.         pop ds
  2524.         popa            ; Restore the remainder
  2525.         popf            ; Restore flags
  2526.         ret
  2527. dumpregs    endp
  2528.  
  2529. regnames    db ' IP: FL: AX: CX: DX: BX: SP: BP: SI: DI: DS: ES: FS: GS:'
  2530.  
  2531. ;
  2532. ; writehex:    Writes a 16-bit hexadecimal number (in AX)
  2533. ;
  2534. writehex    proc near
  2535.         push bx
  2536.         push cx
  2537.         mov cx,4        ; 4 numbers
  2538. write_hexdig:    xor bx,bx
  2539.         push cx
  2540.         mov cx,4        ; 4 bits/digit
  2541. xfer_digit:    shl ax,1
  2542.         rcl bx,1
  2543.         loop xfer_digit
  2544.         push ax
  2545.         mov ax,bx
  2546.         or al,'0'
  2547.         cmp al,'9'
  2548.         jna ok_digit
  2549.         add al,'A'-'0'-10
  2550. ok_digit:    call writechr
  2551.         pop ax
  2552.         pop cx
  2553.         loop write_hexdig
  2554.         pop cx
  2555.         pop bx
  2556.         ret
  2557. writehex    endp
  2558.  
  2559. debug_magic    dw 0D00Dh
  2560.  
  2561.         endif ; debug
  2562. ;
  2563. ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
  2564. ;           to by ES:DI; ends on encountering any whitespace
  2565. ;
  2566.                 assume ds:NOTHING, es:NOTHING
  2567.  
  2568. mangle_name     proc near
  2569.         mov cx,11            ; # of bytes to write
  2570. mn_loop:
  2571.         lodsb
  2572.         cmp al,' '            ; If control or space, end
  2573.         jna mn_end
  2574.         cmp al,'.'            ; Period -> space-fill
  2575.         je mn_is_period
  2576.         cmp al,'a'
  2577.         jb mn_not_lower
  2578.         cmp al,'z'
  2579.         ja mn_not_uslower
  2580.         sub al,020h
  2581.         jmp short mn_not_lower
  2582. mn_is_period:    mov al,' '            ; We need to space-fill
  2583. mn_period_loop: cmp cx,3            ; If <= 3 characters left
  2584.         jbe mn_loop            ; Just ignore it
  2585.         stosb                ; Otherwise, write a period
  2586.         loop mn_period_loop        ; Dec CX and (always) jump
  2587. mn_not_uslower: cmp al,ucase_low
  2588.         jb mn_not_lower
  2589.         cmp al,ucase_high
  2590.         ja mn_not_lower
  2591.         mov bx,(offset ucase_tab)-ucase_low
  2592.                 xlatb cs:[bx]
  2593. mn_not_lower:    stosb
  2594.         loop mn_loop            ; Don't continue if too long
  2595. mn_end:
  2596.         mov al,' '            ; Space-fill name
  2597.         rep stosb            ; Doesn't do anything if CX=0
  2598.         ret                ; Done
  2599. mangle_name    endp
  2600. ;
  2601. ; Upper-case table for extended characters; this is technically code page 865,
  2602. ; but code page 437 users will probably not miss not being able to use the
  2603. ; cent sign in kernel images too much :-)
  2604. ;
  2605. ; The table only covers the range 129 to 164; the rest we can deal with.
  2606. ;
  2607. ucase_low    equ 129
  2608. ucase_high    equ 164
  2609. ucase_tab    db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
  2610.         db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
  2611.         db 157, 156, 157, 158, 159, 'AIOU', 165
  2612.  
  2613. ;
  2614. ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
  2615. ;                filename to the conventional representation.  This is needed
  2616. ;                for the BOOT_IMAGE= parameter for the kernel.
  2617. ;                NOTE: A 13-byte buffer is mandatory, even if the string is
  2618. ;                known to be shorter.
  2619. ;
  2620. ;                DS:SI -> input mangled file name
  2621. ;                ES:DI -> output buffer
  2622. ;
  2623. ;                On return, DI points to the first byte after the output name,
  2624. ;                which is set to a null byte.
  2625. ;
  2626. unmangle_name   proc near
  2627.                 push si                 ; Save pointer to original name
  2628.                 mov cx,8
  2629.                 mov bp,di
  2630. un_copy_body:   lodsb
  2631.                 call lower_case
  2632.                 stosb
  2633.                 cmp al,' '
  2634.                 jbe un_cb_space
  2635.                 mov bp,di               ; Position of last nonblank+1
  2636. un_cb_space:    loop un_copy_body
  2637.                 mov di,bp
  2638.                 mov al,'.'              ; Don't save
  2639.                 stosb
  2640.                 mov cx,3
  2641. un_copy_ext:    lodsb
  2642.                 call lower_case
  2643.                 stosb
  2644.                 cmp al,' '
  2645.                 jbe un_ce_space
  2646.                 mov bp,di
  2647. un_ce_space:    loop un_copy_ext
  2648.                 mov di,bp
  2649.                 mov byte ptr es:[di], 0
  2650.                 pop si
  2651.                 ret
  2652. unmangle_name   endp
  2653. ;
  2654. ; lower_case: Lower case a character in AL
  2655. ;
  2656. lower_case      proc near
  2657.                 cmp al,'A'
  2658.                 jb lc_ret
  2659.                 cmp al,'Z'
  2660.                 ja lc_1
  2661.                 or al,20h
  2662.                 ret
  2663. lc_1:           cmp al,lcase_low
  2664.                 jb lc_ret
  2665.                 cmp al,lcase_high
  2666.                 ja lc_ret
  2667.                 push bx
  2668.                 mov bx, (offset lcase_tab)-lcase_low
  2669.                 xlatb cs:[bx]
  2670.                 pop bx
  2671. lc_ret:         ret
  2672. lower_case      endp
  2673. ;
  2674. ; Lower-case table for codepage 865
  2675. ;
  2676. lcase_low       equ 128
  2677. lcase_high      equ 165
  2678. lcase_tab       db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
  2679.                 db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
  2680.                 db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
  2681.                 db 161, 162, 163, 164, 164
  2682. ;
  2683. ; Various initialized or semi-initialized variables
  2684. ;
  2685. boot_prompt    db 'boot: ',0
  2686. wipe_char    db 08h, ' ', 08h, 0
  2687. err_notfound    db 'Could not find kernel image: ',0
  2688. err_notkernel    db 0Dh, 0Ah, 'Invalid or corrupt kernel image: ',0
  2689. err_not386    db 'It appears your computer uses a 286 or lower CPU.'
  2690.         db 0Dh, 0Ah
  2691.         db 'You cannot run Linux unless you have a 386 or higher CPU'
  2692.         db 0Dh, 0Ah
  2693.         db 'in your machine.  If you get this message in error, hold'
  2694.         db 0Dh, 0Ah
  2695.         db 'down the Ctrl key while booting, and I will take your'
  2696.         db 0Dh, 0Ah
  2697.         db 'word for it.', 0Dh, 0Ah, 0
  2698. err_noram    db 'It appears your computer has less than 608K of low ("DOS")'
  2699.         db 0Dh, 0Ah
  2700.         db 'RAM.  Linux needs at least this amount to boot.  If you get'
  2701.         db 0Dh, 0Ah
  2702.         db 'this message in error, hold down the Ctrl key while'
  2703.         db 0Dh, 0Ah
  2704.         db 'booting, and I will take your word for it.', 0Dh, 0Ah, 0
  2705. err_badcfg      db 'Unknown keyword in syslinux.cfg.', 0Dh, 0Ah, 0
  2706. err_noparm      db 'Missing parameter in syslinux.cfg.', 0Dh, 0Ah, 0
  2707. err_noinitrd    db 0Dh, 0Ah, 'Could not find ramdisk image: ', 0
  2708. err_nohighmem   db 'Not enough memory to load specified kernel.', 0Dh, 0Ah, 0
  2709. err_highload    db 0Dh, 0Ah, 'Kernel transfer failure.', 0Dh, 0Ah, 0
  2710. err_oldkernel   db 'Cannot load a ramdisk with an old kernel image.'
  2711.                 db 0Dh, 0Ah, 0
  2712. loading_msg     db 'Loading ', 0
  2713. dotdot_msg      db '.'
  2714. dot_msg         db '.', 0
  2715. aborted_msg    db ' aborted.'            ; Fall through to crlf_msg!
  2716. crlf_msg    db 0Dh, 0Ah, 0
  2717. syslinux_cfg    db 'SYSLINUXCFG'
  2718. ;
  2719. ; Command line options we'd like to take a look at
  2720. ;
  2721. ; mem= and vga= are handled as normal 32-bit integer values
  2722. initrd_cmd    db 'initrd='
  2723. initrd_cmd_len    equ 7
  2724. ;
  2725. ; Config file keyword table
  2726. ;
  2727.         align 2
  2728. keywd_table    db 'ap' ; append
  2729.         db 'de' ; default
  2730.         db 'ti' ; timeout
  2731.         db 'di' ; display
  2732.         db 'pr' ; prompt
  2733.         db 'la' ; label
  2734.         db 'ke' ; kernel
  2735.                 db 'im' ; implicit
  2736.         db 'f1' ; F1
  2737.         db 'f2' ; F2
  2738.         db 'f3' ; F3
  2739.         db 'f4' ; F4
  2740.         db 'f5' ; F5
  2741.         db 'f6' ; F6
  2742.         db 'f7' ; F7
  2743.         db 'f8' ; F8
  2744.         db 'f9' ; F9
  2745.         db 'f0' ; F10
  2746.         dw 0
  2747. ;
  2748. ; Misc initialized (data) variables
  2749. ;
  2750. AppendLen       dw 0                    ; Bytes in append= command
  2751. KbdTimeOut      dw 0                    ; Keyboard timeout (if any)
  2752. FKeyMap        dw 0            ; Bitmap for F-keys loaded
  2753. CmdLinePtr    dw cmd_line_here    ; Command line advancing pointer
  2754. initrd_flag    label byte
  2755. initrd_ptr    dw 0            ; Initial ramdisk pointer/flag
  2756. VKernelCtr    dw 0            ; Number of registered vkernels
  2757. ForcePrompt    dw 0            ; Force prompt
  2758. AllowImplicit   dw 1                    ; Allow implicit kernels
  2759. VKernelsHigh    db 0                    ; vkernel buffers in high memory
  2760. ;
  2761. ; Stuff for the command line; we do some trickery here with equ to avoid
  2762. ; tons of zeros appended to our file and wasting space
  2763. ;
  2764. linuxauto_cmd    db 'linux '
  2765. auto_cmd    db 'auto',0
  2766. linuxauto_len   equ $-linuxauto_cmd
  2767. auto_len        equ $-auto_cmd
  2768. boot_image      db 'BOOT_IMAGE='
  2769. boot_image_len  equ $-boot_image
  2770.                 align 4                 ; For the good of REP MOVSD
  2771. command_line    equ $
  2772. default_cmd    equ $+(max_cmd_len+2)
  2773. ldlinux_end    equ default_cmd+(max_cmd_len+1)
  2774. kern_cmd_len    equ ldlinux_end-command_line
  2775. ldlinux_len    equ ldlinux_end-ldlinux_magic
  2776.  
  2777. _text        ends
  2778.         end bogus        ; Bogus entrypoint for EXE2BIN
  2779.  
  2780.