From aa6c443b75d3c0d69f57782e74dbb75af54fb696 Mon Sep 17 00:00:00 2001 From: hpa Date: Fri, 6 Apr 2001 02:52:59 +0000 Subject: [PATCH] Current state of isolinux development --- isolinux.asm | 458 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 362 insertions(+), 96 deletions(-) diff --git a/isolinux.asm b/isolinux.asm index 70014e1..b774689 100644 --- a/isolinux.asm +++ b/isolinux.asm @@ -2,11 +2,12 @@ ; $Id$ ; **************************************************************************** ; -; pxelinux.asm +; isolinux.asm ; -; A program to boot Linux kernels off a TFTP server using the Intel PXE -; network booting API. It is based on the SYSLINUX boot loader for -; MS-DOS floppies. +; A program to boot Linux kernels off a CD-ROM using the El Torito +; boot standard in "no emulation" mode, making the entire filesystem +; available. It is based on the SYSLINUX boot loader for MS-DOS +; floppies. ; ; Copyright (C) 1994-2001 H. Peter Anvin ; @@ -18,46 +19,22 @@ ; ; **************************************************************************** - -%include "pxe.inc" - -; -; Macros for byte order of constants -; -%define htons(x) ( ( ((x) & 0FFh) << 8 ) + ( ((x) & 0FF00h) >> 8 ) ) -%define ntohs(x) htons(x) -%define htonl(x) ( ( ((x) & 0FFh) << 24) + ( ((x) & 0FF00h) << 8 ) + ( ((x) & 0FF0000h) >> 8 ) + ( ((x) & 0FF000000h) >> 24) ) -%define ntohl(x) htonl(x) +; NOTE TO SELF: Based on pxelinux.asm,v 1.48 2001/03/30 02:52:17 hpa +; Integrate PXELINUX changes since that version, please ; ; Some semi-configurable constants... change on your own risk. Most are imposed ; by the kernel. ; max_cmd_len equ 255 ; Must be odd; 255 is the kernel limit -FILENAME_MAX_LG2 equ 5 ; log2(Max filename size Including final null) +FILENAME_MAX_LG2 equ 6 ; log2(Max filename size Including final null) FILENAME_MAX equ (1 << FILENAME_MAX_LG2) -REBOOT_TIME equ 5*60 ; If failure, time until full reset HIGHMEM_MAX equ 038000000h ; Highest address for an initrd HIGHMEM_SLOP equ 128*1024 ; Avoid this much memory near the top DEFAULT_BAUD equ 9600 ; Default baud rate for serial port BAUD_DIVISOR equ 115200 ; Serial port parameter -MAX_SOCKETS_LG2 equ 6 ; log2(Max number of open sockets) -MAX_SOCKETS equ (1 << MAX_SOCKETS_LG2) -TFTP_PORT equ htons(69) ; Default TFTP port -PKT_RETRY equ 6 ; Packet transmit retry count -PKT_TIMEOUT equ 8 ; Initial timeout, timer ticks @ 55 ms -TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block) -TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2) - -; -; TFTP operation codes -; -TFTP_RRQ equ htons(1) ; Read request -TFTP_WRQ equ htons(2) ; Write request -TFTP_DATA equ htons(3) ; Data packet -TFTP_ACK equ htons(4) ; ACK packet -TFTP_ERROR equ htons(5) ; ERROR packet -TFTP_OACK equ htons(6) ; OACK packet +MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) +MAX_OPEN equ (1 << MAX_OPEN_LG2) ; ; Should be updated with every release to avoid bootsector/SYS file mismatch @@ -72,14 +49,11 @@ TFTP_OACK equ htons(6) ; OACK packet ; ; ID for SYSLINUX (reported to kernel) ; -syslinux_id equ 032h ; SYSLINUX (3) 2 = PXELINUX +syslinux_id equ 033h ; SYSLINUX (3) 3 = ISOLINUX + ; ; Segments used by Linux ; -; Note: the real_mode_seg is supposed to be 9000h, but PXE uses that -; memory. Therefore, we load it at 5000:0000h and copy it before starting -; the Linux kernel. -; real_mode_seg equ 5000h fake_setup_seg equ real_mode_seg+020h @@ -179,44 +153,15 @@ xfer_buf_seg equ 3000h ; Bounce buffer for I/O to high mem comboot_seg equ 2000h ; COMBOOT image loading zone ; -; BOOTP/DHCP packet pattern -; - struc bootp_t -bootp: -.opcode resb 1 ; BOOTP/DHCP "opcode" -.hardware resb 1 ; ARP hardware type -.hardlen resb 1 ; Hardware address length -.gatehops resb 1 ; Used by forwarders -.ident resd 1 ; Transaction ID -.seconds resw 1 ; Seconds elapsed -.flags resw 1 ; Broadcast flags -.cip resd 1 ; Client IP -.yip resd 1 ; "Your" IP -.sip resd 1 ; Next server IP -.gip resd 1 ; Relay agent IP -.macaddr resb 16 ; Client MAC address -.sname resb 64 ; Server name (optional) -.bootfile resb 128 ; Boot file name -.option_magic resd 1 ; Vendor option magic cookie -.options resb 1260 ; Vendor options - endstruc - -BOOTP_OPTION_MAGIC equ htonl(0x63825363) ; See RFC 2132 - -; -; TFTP connection data structure. Each one of these corresponds to a local -; UDP port. The size of this structure must be a power of 2. -; - struc tftp_port_t -tftp_localport resw 1 ; Local port number (0 = not in use) -tftp_remoteport resw 1 ; Remote port number -tftp_remoteip resd 1 ; Remote IP address -tftp_filepos resd 1 ; Position within file -tftp_filesize resd 1 ; Total file size +; File structure. This holds the information for each currently open file. +; + struc open_file_t +file_sector resd 1 ; Sector pointer (0 = structure free) +file_sectors resd 1 ; Number of sectors left endstruc -%if (tftp_port_t_size & (tftp_port_t_size-1)) -%error "tftp_port_t is not a power of 2" +%if (open_file_t_size & (open_file_t_size-1)) +%error "open_file_t is not a power of 2" %endif ; @@ -373,25 +318,346 @@ A20Tries resb 1 ; Times until giving up on A20 FuncFlag resb 1 ; == 1 if pressed OverLoad resb 1 ; Set if DHCP packet uses "overloading" - alignb tftp_port_t_size -Sockets resb MAX_SOCKETS*tftp_port_t_size - - alignb 16 - ; BOOTP/DHCP packet buffer - - alignb 16 -packet_buf resb 2048 ; Transfer packet -packet_buf_size equ $-packet_buf + alignb open_file_t_size +Files resb MAX_OPEN*open_file_t_size section .text org 7C00h +;; +;; Primary entry point. Because BIOSes are buggy, we only load the first +;; CD-ROM sector (2K) of the file, so the number one priority is actually +;; loading the rest. +;; +bootsec equ $ +_start: ; Far jump makes sure we canonicalize the address + cli ; 1 byte + jmp 0:_start1 ; 5 bytes + nop + nop + + ; This table gets filled in by mkisofs using the + ; -boot-info-table option +bi_pvd: dd 0xdeadbeef ; LBA of primary volume descriptor +bi_file: dd 0xdeadbeef ; LBA of boot file +bi_length: dd 0xdeadbeef ; Length of boot file +bi_csum: dd 0xdeadbeef ; Checksum of boot file +bi_reserved: times 10 dd 0xdeadbeef ; Reserved + +_start1: xor ax,ax + mov es,ax + mov ss,ax + mov ds,ax + mov sp,_start ; Set up stack + sti + + cld + ; + ; Before modifying any memory, get the checksum of bytes 64-2048 + ; +initial_csum: xor edi,edi + mov si,_start1 + mov cx,(2048-64) >> 2 +.loop: lodsd + add edi,eax + loop .loop + mov [FirstSecSum],edi + + ; Set up boot file sizes + mov eax,[bi_length] + sub eax,2048-3 + shr eax,2 ; bytes->dwords + mov [ImageDwords],eax ; boot file dwords + add eax,(2047 >> 2) + shr eax,9 ; dwords->sectors + mov [ImageSectors],ax ; boot file sectors + + mov si,startup_msg + call writemsg + mov [DriveNo],dl + mov al,dl + call writehex2 + call crlf + + ; Now figure out what we're actually doing + ; Note: use passed-in DL value rather than 7Fh because + ; at least some BIOSes will get the wrong value otherwise + mov ax,4B01h ; Get disk emulation status + mov dl,[DriveNo] + mov si,spec_packet + int 13h + jc near spec_query_failed ; Shouldn't happen (BIOS bug) + mov dl,[DriveNo] + cmp [sp_drive],dl ; Should contain the drive number + jne near spec_query_failed + + mov si,spec_ok_msg + call writemsg + mov al,byte [sp_drive] + call writehex2 + call crlf + +found_drive: + ; Get drive information + mov ah,48h + mov dl,[DriveNo] + mov si,drive_params + int 13h + jnc params_ok + + mov si,nosecsize_msg + call writemsg + +params_ok: + ; Check for the sector size (should be 2048, but + ; some BIOSes apparently think we're 512-byte media) + mov si,secsize_msg + call writemsg + mov ax,[dp_secsize] + mov [bdib_secsize],ax + call writehex4 + call crlf + +load_image: + ; Some BIOSes apparently have limitations on the size + ; that may be loaded (despite the El Torito spec being very + ; clear on the fact that it must all be loaded.) Therefore, + ; we load it ourselves, and *bleep* the BIOS. + + mov eax,[bi_file] ; Address of code to load + inc eax ; Don't reload bootstrap code + mov si,offset_msg + call writemsg + call writehex8 + call crlf + + ; Just in case some BIOSes have problems with + ; segment wraparound, use the normalized address + mov bx,(REALOFF >> 4) + mov es,bx + xor bx,bx + mov bp,[ImageSectors] + push ax + mov si,size_msg + call writemsg + mov ax,bp + call writehex4 + call crlf + pop ax + call getlinsec_cdrom + + mov ax,ds + mov es,ax + + mov si,loaded_msg + call writemsg + + ; Verify the checksum on the loaded image. +verify_image: + mov si,REALOFF + mov bx,es + mov ecx,[ImageDwords] + mov edi,[FirstSecSum] ; First sector checksum +.loop es lodsd + add edi,eax + dec ecx + jz .done + and si,si + jnz .loop + ; SI wrapped around, advance ES + add bx,1000h + mov es,bx + jmp short .loop +.done: mov ax,ds + mov es,ax + cmp [bi_csum],edi + je integrity_ok + + mov si,checkerr_msg + call writestr + +integrity_ok: + ; Copy relevant data to BDIB + movzx ax,byte [sp_drive] + mov [bdib_unit],ax + mov ebx,[bi_pvd] + mov [bdib_offset],ebx + + ; Now point to the BDIB and run + mov bx,bdib ; Set up BDIB pointer in ES:BX + + mov si,ready_msg + call writemsg + + jmp all_read ; Jump to main code + + ; INT 13h, AX=4B01h, DL=7Fh failed. Try to scan the entire 80h-FFh from + ; the end. +spec_query_failed: + mov si,spec_err_msg + call writemsg + + mov dl,0FFh +.test_loop: pusha + mov ax,4B01h + mov si,spec_packet + mov byte [si],13 ; Size of buffer + int 13h + popa + jc .still_broken + + mov si,maybe_msg + call writemsg + mov al,dl + call writehex2 + call crlf + + cmp byte [sp_drive],dl + jne .still_broken + + ; Okay, good enough... + mov si,alright_msg + call writemsg + mov [DriveNo],dl + jmp found_drive + +.still_broken: dec dx + cmp dl, 80h + jnb .test_loop + +fatal_error: + mov si,nothing_msg + call writemsg + +.norge: jmp short .norge + + ; Information message (DS:SI) output + ; Prefix with "isoboot: "; first byte is flag if + ; we should set the pause in bdib_flags +writemsg: push ax + push si + mov si,isoboot_str + call writestr + pop si + lodsb + or [bdib_flags],al + call writestr + pop ax + ret + + ; Information string (DS:SI) output +writestr: pushad + pushfd +.loop: lodsb + and al,al + jz .done + mov ah,0Eh + int 10h + jmp short .loop +.done: popfd + popad + ret + + ; Write value in AL, AX or EAX as hex +writehex2: pushad + mov cx,2 + shl eax,24 + jmp short writehex_common +writehex4: pushad + mov cx,4 + shl eax,16 + jmp short writehex_common +writehex8: pushad + mov cx,8 +writehex_common: + pushfd + mov bx,hex_table +.loop: rol eax,4 ; Move bits in question into bottom bits + push eax + and al,0Fh + xlatb + mov ah,0Eh + int 10h + pop eax + loop .loop + popfd + popad + ret + + ; Print newline +crlf: push si + mov si,crlf_str + call writestr + pop si + ret + ; -; Primary entry point. +; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. ; -bootsec equ $ -_start: - jmp 0:_start1 ; Canonicalize address -_start1: +; Note that we can't always do this as a single request, because at least +; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick +; to 32 sectors (64K) per request. +; +getlinsec_cdrom: + mov si,dapa ; Load up the DAPA + mov [si+4],bx + mov bx,es + mov [si+6],bx + mov [si+8],eax +.loop: + push bp ; Sectors left + cmp bp,byte 32 + jbe .bp_ok + mov bp,32 +.bp_ok: + mov [si+2],bp + push si + mov dl,[DriveNo] + mov ah,42h ; Extended Read + call xint13 + pop si + pop bp + movzx eax,word [si+2] ; Sectors we read + add [si+8],eax ; Advance sector pointer + sub bp,ax ; Sectors left + shl ax,11-4 ; 2048-byte sectors -> segment + add [si+6],ax ; Advance buffer pointer + and bp,bp + jnz .loop + mov eax,[si+8] ; Next sector + ret + + ; INT 13h with retry +xint13: mov byte [RetryCount], 6 +.try: pushad + int 13h + jc .error + add sp,byte 8*4 ; Clean up stack + ret +.error: popad + dec byte [RetryCount] + jnz .try + +.real_error: mov si,diskerr_msg + call writemsg + mov al,ah + call writehex2 + call crlf +.norge: jmp short .norge + + +rl_checkpt equ $ ; Must be <= 400h + +%if (rl_checkpt-$$) > 0x800 +%error "Sector 0 overflow" +%endif + +; ---------------------------------------------------------------------------- +; End of code and data that have to be in the first sector +; ---------------------------------------------------------------------------- + + ;;; ********** THIS STUFF HASN'T BEEN UNIFIED PROPERLY *********** + +all_read: pushad ; Paranoia... in case of return to PXE pushfd ; ... save as much state as possible push ds @@ -517,10 +783,10 @@ have_pxe: have_entrypoint: ; -; Clear Sockets structures +; Clear Files structures ; - mov di,Sockets - mov cx,(MAX_SOCKETS*tftp_port_t_size)/4 + mov di,Files + mov cx,(MAX_OPEN*open_file_t_size)/4 xor eax,eax rep stosd @@ -2872,11 +3138,11 @@ searchdir: ; allocate_socket: push cx - mov bx,Sockets - mov cx,MAX_SOCKETS + mov bx,Files + mov cx,MAX_OPEN .check: cmp word [bx], byte 0 je .found - add bx,tftp_port_t_size + add bx,open_file_t_size loop .check xor cx,cx ; ZF = 1 pop cx @@ -2895,9 +3161,9 @@ allocate_socket: push ax mov ax,[NextSocket] inc ax - and ax,((1 << (13-MAX_SOCKETS_LG2))-1) | 0xC000 + and ax,((1 << (13-MAX_OPEN_LG2))-1) | 0xC000 mov [NextSocket],ax - shl cx,13-MAX_SOCKETS_LG2 + shl cx,13-MAX_OPEN_LG2 add cx,ax ; ZF = 0 xchg ch,cl ; Convert to network byte order mov [bx],cx ; Socket in use -- 2.7.4