;; $Id: comboot.inc,v 1.39 2005/01/20 18:43:22 hpa Exp $ ;; ----------------------------------------------------------------------- ;; ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, ;; Boston MA 02111-1307, USA; either version 2 of the License, or ;; (at your option) any later version; incorporated herein by reference. ;; ;; ----------------------------------------------------------------------- ;; ;; comboot.inc ;; ;; Common code for running a COMBOOT image ;; section .text ; Parameter registers definition; this is the definition ; of the stack frame used by INT 21h and INT 22h. %define P_FLAGS word [bp+44] %define P_FLAGSL byte [bp+44] %define P_FLAGSH byte [bp+45] %define P_CS word [bp+42] %define P_IP word [bp+40] %define P_DS word [bp+38] %define P_ES word [bp+36] %define P_FS word [bp+34] %define P_GS word [bp+32] %define P_EAX dword [bp+28] %define P_AX word [bp+28] %define P_HAX word [bp+30] %define P_AL byte [bp+28] %define P_AH byte [bp+29] %define P_ECX dword [bp+24] %define P_CX word [bp+24] %define P_HCX word [bp+26] %define P_CL byte [bp+24] %define P_CH byte [bp+25] %define P_EDX dword [bp+20] %define P_DX word [bp+20] %define P_HDX word [bp+22] %define P_DL byte [bp+20] %define P_DH byte [bp+21] %define P_EBX dword [bp+16] %define P_BX word [bp+16] %define P_HBX word [bp+18] %define P_BL byte [bp+16] %define P_BH byte [bp+17] %define P_EBP dword [bp+8] %define P_BP word [bp+8] %define P_HBP word [bp+10] %define P_ESI dword [bp+4] %define P_SI word [bp+4] %define P_HSI word [bp+6] %define P_EDI dword [bp] %define P_DI word [bp] %define P_HDI word [bp+2] ; Looks like a COMBOOT image but too large comboot_too_large: mov si,err_comlarge call cwritestr jmp enter_command ; ; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file, ; except that it may, of course, not contain any DOS system calls. We ; do, however, allow the execution of INT 20h to return to SYSLINUX. ; is_comboot_image: and dx,dx jnz comboot_too_large cmp ax,0ff00h ; Max size in bytes jae comboot_too_large push si ; Save file handle call make_plain_cmdline call comboot_setup_api mov cx,comboot_seg mov es,cx xor di,di mov cx,64 ; 256 bytes (size of PSP) xor eax,eax ; Clear PSP rep stosd mov word [es:0], 020CDh ; INT 20h instruction ; First non-free paragraph ; This is valid because comboot_seg == real_mode_seg ; == the highest segment used by all derivatives int 12h ; Get DOS memory size shl ax,6 ; Kilobytes -> paragraphs mov word [es:02h],ax %ifndef DEPEND %if real_mode_seg != comboot_seg %error "This code assumes real_mode_seg == comboot_seg" %endif %endif ; Copy the command line from high memory mov si,cmd_line_here mov cx,125 ; Max cmdline len (minus space and CR) mov di,081h ; Offset in PSP for command line mov al,' ' ; DOS command lines begin with a space stosb .loop: es lodsb and al,al jz .done stosb loop .loop .done: mov al,0Dh ; CR after last character stosb mov ax,di sub al,82h ; Include space but not CR mov [es:80h],al ; Store command line length ; Now actually load the file... pop si ; File handle mov bx,100h ; Load at :0100h mov cx,0FF00h >> SECTOR_SHIFT ; Absolute maximum # of sectors call getfssec ; And invoke the program... mov [SavedSSSP],sp mov [SavedSSSP+2],ss ; Save away SS:SP mov ax,es mov ds,ax mov ss,ax xor sp,sp push word 0 ; Return to address 0 -> exit jmp comboot_seg:100h ; Run it ; Proper return vector comboot_return: cli ; Don't trust anyone xor ax,ax jmp comboot_exit ; ; Set up the COMBOOT API interrupt vectors. This is also used ; by the COM32 code. ; comboot_setup_api: mov di,4*0x20 ; DOS interrupt vectors mov eax,comboot_return ; INT 20h = exit stosd mov ax,comboot_int21 ; INT 21h = DOS-compatible syscalls stosd mov ax,comboot_int22 ; INT 22h = proprietary syscalls stosd mov ax,comboot_bogus mov cx,29 ; All remaining DOS vectors rep stosd ret ; INT 21h: generic DOS system call comboot_int21: cli push ds push es push fs push gs pushad cld mov bp,cs mov ds,bp mov es,bp mov bp,sp ; Set up stack frame call adjust_screen ; The COMBOOT program might have changed the screen mov cx,int21_count mov si,int21_table .again: lodsb cmp al,P_AH lodsw loopne .again ; The last function in the list is the ; "no such function" function clc call ax ; Call the invoked function comboot_resume: setc P_FLAGSL ; Propagate CF->error popad pop gs pop fs pop es pop ds iret ; Attempted to execute non-21h DOS system call comboot_bogus: cli ; Don't trust anyone mov ax,err_notdos ; ; Generic COMBOOT return to command line code ; AX -> message (if any) ; BX -> where to go next ; comboot_exit: mov bx,enter_command ; Normal return to command prompt comboot_exit_special: xor dx,dx mov ds,dx mov es,dx lss sp,[SavedSSSP] sti cld call adjust_screen ; The COMBOOT program might have changed the screen and ax,ax je .nomsg mov si,KernelCName call cwritestr xchg si,ax call cwritestr .nomsg: jmp bx ; ; INT 21h system calls ; comboot_getkey: ; 01 = get key with echo call vgashowcursor call comboot_getchar call vgahidecursor call writechr clc ret comboot_writechr: ; 02 = writechr mov al,P_DL call writechr clc ret comboot_writeserial: ; 04 = write serial port mov al,P_DL call write_serial clc ret comboot_getkeynoecho: ; 08 = get key w/o echo call comboot_getchar clc ret comboot_writestr: ; 09 = write DOS string mov es,P_DS mov si,P_DX .loop: es lodsb cmp al,'$' ; End string with $ - bizarre je .done call writechr jmp short .loop .done: clc ret comboot_checkkey: ; 0B = check keyboard status cmp byte [APIKeyFlag],00h jnz .waiting call pollchar .waiting: setz al dec al ; AL = 0FFh if present, 0 if not mov P_AL,al clc ret comboot_checkver: ; 30 = check DOS version ; We return 0 in all DOS-compatible version registers, ; but the high part of eax-ebx-ecx-edx spell "SYSLINUX" mov P_EAX,'SY' << 16 mov P_EBX,'SL' << 16 mov P_ECX,'IN' << 16 mov P_EDX,'UX' << 16 ret comboot_getchar: cmp byte [APIKeyFlag],00h jne .queued call getchar ; If not queued get input and al,al ; Function key? (CF <- 0) jnz .done mov [APIKeyWait],ah ; High part of key inc byte [APIKeyFlag] ; Set flag .done: mov P_AL,al ret .queued: mov al,[APIKeyWait] dec byte [APIKeyFlag] jmp .done ; ; INT 22h - SYSLINUX-specific system calls ; System call number in ax ; comboot_int22: cli push ds push es push fs push gs pushad cld mov bp,cs mov ds,bp mov es,bp mov bp,sp ; Set up stack frame call adjust_screen ; The COMBOOT program might have changed the screen cmp ax,int22_count jb .ok xor ax,ax ; Function 0 -> unimplemented .ok: xchg ax,bx add bx,bx ; CF <- 0 call [bx+int22_table] jmp comboot_resume ; On return ; ; INT 22h AX=0000h Unimplemented call ; comapi_err: stc ret ; ; INT 22h AX=0001h Get SYSLINUX version ; comapi_get_version: ; Number of API functions supported mov P_AX,int22_count ; SYSLINUX version mov P_CX,(VER_MAJOR << 8)+VER_MINOR ; SYSLINUX derivative ID byte mov P_DX,my_id ; For future use mov P_BX,cs ; cs == 0 mov P_ES,ds ; ES:SI -> version banner mov P_SI,syslinux_banner ; ES:DI -> copyright string mov P_DI,copyright_str comapi_nop: clc ret ; ; INT 22h AX=0002h Write string ; ; Write null-terminated string in ES:BX ; comapi_writestr: mov ds,P_ES mov si,P_BX call writestr clc ret ; ; INT 22h AX=0003h Run command ; ; Terminates the COMBOOT program and executes the command line in ; ES:BX as if it had been entered by the user. ; comapi_run: mov ds,P_ES mov si,P_BX mov di,command_line call strcpy xor ax,ax mov bx,load_kernel ; Run a new kernel jmp comboot_exit_special ; Terminate task, clean up ; ; INT 22h AX=0004h Run default command ; ; Terminates the COMBOOT program and executes the default command line ; as if a timeout had happened or the user pressed . ; comapi_run_default: mov bx,auto_boot jmp comboot_exit_special ; ; INT 22h AX=0005h Force text mode ; ; Puts the video in standard text mode ; comapi_textmode: call vgaclearmode clc ret ; ; INT 22h AX=0006h Open file ; comapi_open: push ds mov ds,P_ES mov si,P_SI mov di,InitRD push di call mangle_name pop di pop ds call searchdir jz .err mov P_AX,ax mov P_HAX,dx mov P_CX,SECTOR_SIZE mov P_SI,si clc ret .err: stc ret ; ; INT 22h AX=0007h Read file ; comapi_read: mov es,P_ES mov bx,P_BX mov si,P_SI mov cx,P_CX call getfssec jnc .noteof xor si,si ; SI <- 0 on EOF, CF <- 0 .noteof: mov P_SI,si ret ; ; INT 22h AX=0008h Close file ; comapi_close: ; Do nothing for now. Eventually implement ; an internal API for this. clc ret ; ; INT 22h AX=0009h Call PXE stack ; %if IS_PXELINUX comapi_pxecall: mov bx,P_BX mov es,P_ES mov di,P_DI call pxenv mov P_AX,ax clc ret %else comapi_pxecall equ comapi_err ; Not available %endif ; ; INT 22h AX=000Ah Get Derivative-Specific Info ; comapi_derinfo: mov P_AL,my_id %if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX mov al,[DriveNumber] mov P_DL,al mov P_ES,cs mov P_BX,PartInfo %elif IS_PXELINUX mov ax,[APIVer] mov P_DX,ax mov ax,[StrucPtr] mov P_BX,ax mov ax,[StrucPtr+2] mov P_ES,ax mov ax,[InitStack] mov P_SI,ax mov ax,[InitStack+2] mov P_FS,ax %elif IS_ISOLINUX mov al,[DriveNo] mov P_DL,al mov P_ES,cs mov P_BX,spec_packet %endif clc ret ; ; INT 22h AX=000Bh Get Serial Console Configuration ; comapi_serialcfg: mov ax,[SerialPort] mov P_DX,ax mov ax,[BaudDivisor] mov P_CX,ax mov ax,[FlowControl] or al,ah mov ah,[FlowIgnore] shr ah,4 test byte [DisplayCon],01h jnz .normalconsole or ah,80h .normalconsole: mov P_BX,ax clc ret ; ; INT 22h AX=000Ch Perform final cleanup ; comapi_cleanup: %if IS_PXELINUX ; Unload PXE if requested test dl,3 setnz [KeepPXE] sub bp,sp ; unload_pxe may move the stack around call unload_pxe add bp,sp ; restore frame pointer... %elif IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX ; Restore original FDC table mov eax,[OrigFDCTabPtr] mov [fdctab],eax %endif ; Reset the floppy disk subsystem xor ax,ax xor dx,dx int 13h clc ret ; ; INT 22h AX=000Dh Clean up then replace bootstrap ; comapi_chainboot: call comapi_cleanup mov eax,P_EDI mov [trackbuf+4],eax ; Copy from mov eax,P_ECX mov [trackbuf+8],eax ; Total bytes mov eax,7C00h mov [trackbuf],eax ; Copy to mov [EntryPoint],eax ; CS:IP entry point mov esi,P_ESI mov edx,P_EBX mov bx,P_DS jmp replace_bootstrap_one ; ; INT 22h AX=000Eh Get configuration file name ; comapi_configfile: mov P_ES,cs mov P_BX,ConfigName clc ret ; ; INT 22h AX=000Fh Get IPAPPEND strings ; %if IS_PXELINUX comapi_ipappend: mov P_ES,cs mov P_CX,numIPAppends mov P_BX,IPAppends clc ret section .data alignb 2, db 0 IPAppends dw IPOption dw BOOTIFStr numIPAppends equ ($-IPAppends)/2 %else comapi_ipappend equ comapi_err %endif ; ; INT 22h AX=0010h Resolve hostname ; %if IS_PXELINUX comapi_dnsresolv: mov ds,P_ES mov si,P_BX call dns_resolv mov P_EAX,eax ret %else comapi_dnsresolv equ comapi_err %endif section .data %macro int21 2 db %1 dw %2 %endmacro ; ; INT 22h AX=0011h Maximum number of shuffle descriptors ; comapi_maxshuffle: mov P_CX,(2*trackbufsize)/12 ret ; ; INT 22h AX=0012h Cleanup, shuffle and boot ; comapi_shuffle: call comapi_cleanup mov cx,P_CX cmp cx,(2*trackbufsize)/12 ja .error push cx ; On stack: descriptor count lea cx,[ecx+ecx*2] ; CX *= 3 mov fs,P_ES mov si,P_DI mov di,trackbuf push di ; On stack: descriptor list address fs rep movsd ; Copy the list mov eax,P_EBP mov [EntryPoint],eax ; CS:IP entry point mov esi,P_ESI mov edx,P_EBX mov bx,P_DS jmp replace_bootstrap .error: stc ret ; ; INT 22h AX=0013h Idle call ; comapi_idle: DO_IDLE clc ret int21_table: int21 00h, comboot_return int21 01h, comboot_getkey int21 02h, comboot_writechr int21 04h, comboot_writeserial int21 08h, comboot_getkeynoecho int21 09h, comboot_writestr int21 0Bh, comboot_checkkey int21 30h, comboot_checkver int21 4Ch, comboot_return int21 -1, comboot_bogus int21_count equ ($-int21_table)/3 align 2, db 0 int22_table: dw comapi_err ; 0000 unimplemented syscall dw comapi_get_version ; 0001 get SYSLINUX version dw comapi_writestr ; 0002 write string dw comapi_run ; 0003 run specified command dw comapi_run_default ; 0004 run default command dw comapi_textmode ; 0005 force text mode dw comapi_open ; 0006 open file dw comapi_read ; 0007 read file dw comapi_close ; 0008 close file dw comapi_pxecall ; 0009 call PXE stack dw comapi_derinfo ; 000A derivative-specific info dw comapi_serialcfg ; 000B get serial port config dw comapi_cleanup ; 000C perform final cleanup dw comapi_chainboot ; 000D clean up then bootstrap dw comapi_configfile ; 000E get name of config file dw comapi_ipappend ; 000F get ipappend strings dw comapi_dnsresolv ; 0010 resolve hostname dw comapi_maxshuffle ; 0011 maximum shuffle descriptors dw comapi_shuffle ; 0012 cleanup, shuffle and boot dw comapi_idle ; 0013 idle call int22_count equ ($-int22_table)/2 APIKeyWait db 0 APIKeyFlag db 0