summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGene Cumm <gene.cumm@gmail.com>2009-02-08 09:36:59 -0500
committerH. Peter Anvin <hpa@zytor.com>2009-02-09 22:49:17 -0800
commitc1def425e3eeb245da7a59025f2fa37f02368504 (patch)
treead741a1bfc81828eb474b77b7c9ec270355c6bc3
parent2b02abdaa91f41235f40f846d08bb09d8841baa6 (diff)
downloadsyslinux-c1def425e3eeb245da7a59025f2fa37f02368504.tar.gz
COMBOOT API: Add calls for directory functions; Implement for FAT
COMBOOT API: Add calls for directory functions; Implement most only for FAT (SYSLINUX). Uses INT 22h AX= 001Fh, 0020h, 0021h and 0022h to prepare for the COM32 C functions getcwd(), opendir(), readdir(), and closedir(), respectively. INT22h, AX=001Fh will return a valid value for all variants. INT22h, AX= 0020h, 0021h, and 0022h are only implemented for SYSLINUX while other variants will call comapi_err for these 3. Signed-off-by: Gene Cumm <gene.cumm@gmail.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--core/comboot.inc71
-rw-r--r--core/extlinux.asm8
-rw-r--r--core/isolinux.asm20
-rw-r--r--core/ldlinux.asm324
-rw-r--r--core/pxelinux.asm7
-rw-r--r--doc/comboot.txt43
6 files changed, 472 insertions, 1 deletions
diff --git a/core/comboot.inc b/core/comboot.inc
index 7210b8b8..2ff5f33e 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -1047,6 +1047,72 @@ comapi_kbdtable:
stc
ret
+;
+; INT 22h AX=001Fh Get current working directory
+;
+comapi_getcwd:
+ mov P_ES,cs
+ mov P_BX,CurrentDirName
+ clc
+ ret
+
+;
+; INT 22h AX=0020h Open directory
+;
+%if IS_SYSLINUX
+comapi_opendir:
+ push ds
+ mov ds,P_ES
+ mov si,P_SI
+ mov di,InitRD
+ call mangle_name
+ pop ds
+ call searchdir
+ jnz comapi_err ; Didn't find a directory
+ cmp eax,0
+ jz comapi_err ; Found nothing
+ ;ZF is unset
+ call alloc_fill_dir
+ mov P_EAX,eax
+ mov P_CX,SECTOR_SIZE
+ mov P_SI,si
+ clc
+ ret
+%else
+comapi_opendir equ comapi_err
+%endif
+
+;
+; INT 22h AX=0021h Read directory
+;
+%if IS_SYSLINUX
+comapi_readdir:
+ mov es,P_ES
+ mov di,P_DI
+ mov si,P_SI
+ call readdir
+ mov P_EAX,eax
+ mov P_DL,dl
+ mov P_EBX,ebx
+ mov P_SI,si
+ ret
+%else
+comapi_readdir equ comapi_err
+%endif
+
+;
+; INT 22h AX=0022h Close directory
+;
+%if IS_SYSLINUX
+comapi_closedir:
+ mov si,P_SI
+ call close_dir
+ clc
+ ret
+%else
+comapi_closedir equ comapi_err
+%endif
+
section .data
%macro int21 2
@@ -1100,6 +1166,10 @@ int22_table:
dw comapi_getadv ; 001C get pointer to ADV
dw comapi_writeadv ; 001D write ADV to disk
dw comapi_kbdtable ; 001E keyboard remapping table
+ dw comapi_getcwd ; 001F get current working directory
+ dw comapi_opendir ; 0020 open directory
+ dw comapi_readdir ; 0021 read directory
+ dw comapi_closedir ; 0022 close directory
int22_count equ ($-int22_table)/2
APIKeyWait db 0
@@ -1124,3 +1194,4 @@ err_comlarge db 'COMBOOT image too large.', CR, LF, 0
alignb 4
DOSErrTramp resd 33 ; Error trampolines
ConfigName resb FILENAME_MAX
+CurrentDirName resb FILENAME_MAX
diff --git a/core/extlinux.asm b/core/extlinux.asm
index 24d0d926..c7a51e94 100644
--- a/core/extlinux.asm
+++ b/core/extlinux.asm
@@ -42,6 +42,9 @@ MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup
SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink
; (should be >= FILENAME_MAX)
+ROOT_DIR_WORD equ 0x002F
+CUR_DIR_DWORD equ 0x00002F2E
+
;
; This is what we need to do when idle
;
@@ -843,6 +846,8 @@ load_config:
mov si,config_name ; Save config file name
mov di,ConfigName
call strcpy
+ mov dword [CurrentDirName],CUR_DIR_DWORD ; Write './',0,0 to the CurrentDirName
+ call build_curdir_str
mov di,ConfigName
call open
@@ -1515,6 +1520,9 @@ getfssec:
pop ebp
ret
+build_curdir_str:
+ ret
+
; -----------------------------------------------------------------------------
; Common modules
; -----------------------------------------------------------------------------
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 3b970053..2c6d9702 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -36,6 +36,8 @@ MAX_OPEN equ (1 << MAX_OPEN_LG2)
SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+ROOT_DIR_WORD equ 0x002F
+
;
; This is what we need to do when idle
;
@@ -1147,15 +1149,33 @@ get_fs_structures:
; Look for an isolinux directory, and if found,
; make it the current directory instead of the root
; directory.
+ ; Also copy the name of the directory to CurrentDirName
+ mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
mov di,boot_dir ; Search for /boot/isolinux
mov al,02h
+ push di
call searchdir_iso
+ pop di
jnz .found_dir
mov di,isolinux_dir
mov al,02h ; Search for /isolinux
+ push di
call searchdir_iso
+ pop di
jz .no_isolinux_dir
.found_dir:
+ ; Copy current directory name to CurrentDirName
+ push si
+ push di
+ mov si,di
+ mov di,CurrentDirName
+ call strcpy
+ mov byte [di],0 ;done in case it's not word aligned
+ dec di
+ mov byte [di],'/'
+ pop di
+ pop si
+
mov [CurrentDir+dir_len],eax
mov eax,[si+file_left]
mov [CurrentDir+dir_clust],eax
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index c7f6577c..61ce1a0e 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -44,6 +44,11 @@ MAX_OPEN equ (1 << MAX_OPEN_LG2)
SECTOR_SHIFT equ 9
SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+DIRENT_SHIFT equ 5
+DIRENT_SIZE equ (1 << DIRENT_SHIFT)
+
+ROOT_DIR_WORD equ 0x002F
+
;
; This is what we need to do when idle
;
@@ -900,19 +905,40 @@ getfattype:
mov si,config_name ; Save configuration file name
mov di,ConfigName
call strcpy
+ mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
mov eax,[RootDir] ; Make the root directory ...
mov [CurrentDir],eax ; ... the current directory
mov di,syslinux_cfg1
+ push di
call open
+ pop di
jnz .config_open
mov di,syslinux_cfg2
+ push di
call open
+ pop di
jnz .config_open
mov di,syslinux_cfg3
+ push di
call open
+ pop di
jz no_config_file
.config_open:
+ push si
+ mov si,di
+ push si
+ mov di,CurrentDirName
+ ; This is inefficient as it will copy more than needed
+ ; but not by too much
+ call strcpy
+ mov ax,config_name ;Cut it down
+ pop si
+ sub ax,si
+ mov di,CurrentDirName
+ add di,ax
+ mov byte [di],0
+ pop si
mov eax,[PrevDir] ; Make the directory with syslinux.cfg ...
mov [CurrentDir],eax ; ... the current directory
@@ -945,6 +971,37 @@ allocate_file:
ret
;
+; alloc_fill_dir:
+; Allocate then fill a file structure for a directory starting in
+; sector EAX.
+;
+; Assumes DS == ES == CS.
+;
+; If successful:
+; ZF clear
+; SI = file pointer
+; If unsuccessful
+; ZF set
+; EAX clobbered
+;
+alloc_fill_dir:
+ push bx
+ call allocate_file
+ jnz .alloc_failure
+.found:
+ mov si,bx
+ mov [si+file_sector],eax ; Current sector
+ mov dword [si+file_bytesleft],0 ; Current offset
+ mov [si+file_left],eax ; Beginning sector
+ pop bx
+ ret
+
+.alloc_failure:
+ pop bx
+ xor eax,eax ; ZF <- 1
+ ret
+
+;
; search_dos_dir:
; Search a specific directory for a pre-mangled filename in
; MangledBuf, in the directory starting in sector EAX.
@@ -1191,6 +1248,18 @@ close_file:
.closed: ret
;
+; close_dir:
+; Deallocates a directory structure (pointer in SI)
+; Assumes CS == DS.
+;
+close_dir:
+ and si,si
+ jz .closed
+ mov dword [si],0 ; First dword == file_sector
+ xor si,si
+.closed: ret
+
+;
; searchdir:
;
; Open a file
@@ -1224,9 +1293,17 @@ searchdir:
cmp al,'/'
jne .findend
.endpath:
- xchg si,di
+ xchg si,di ; GRC: si begin; di end[ /]+1
pop eax ; <A> Current directory sector
+ ; GRC Here I need to check if di-1 = si which signifies
+ ; we have the desired directory in EAX
+ ; What about where the file name = "."; later
+ mov dx,di
+ dec dx
+ cmp dx,si
+ jz .founddir
+
mov [PrevDir],eax ; Remember last directory searched
push di
@@ -1263,12 +1340,257 @@ searchdir:
xchg eax,[si+file_sector] ; Get sector number and free file structure
jmp .pathwalk ; Walk the next bit of the path
+ ; Found the desired directory; ZF set but EAX not 0
+.founddir:
+ ret
+
.badfile:
xor eax,eax
mov [si],eax ; Free file structure
.notfound:
+ xor eax,eax ; Zero out EAX
+ ret
+
+;
+; readdir: Read one file from a directory
+;
+; ES:DI -> String buffer (filename)
+; DS:SI -> Pointer to open_file_t
+; DS Must be the SYSLINUX Data Segment
+;
+; Returns the file's name in the filename string buffer
+; EAX returns the file size
+; EBX returns the beginning sector (currently without offsetting)
+; DL returns the file type
+; The directory handle's data is incremented to reflect a name read.
+;
+readdir:
+ push ecx
+ push bp ; Using bp to transfer between segment registers
+ push si
+ push es
+ push fs ; Using fs to store the current es (from COMBOOT)
+ push gs
+ mov bp,es
+ mov fs,bp
+ cmp si,0
+ jz .fail
+.load_handle:
+ mov eax,[ds:si+file_sector] ; Current sector
+ mov ebx,[ds:si+file_bytesleft] ; Current offset
+ cmp eax,0
+ jz .fail
+.fetch_cache:
+ call getcachesector
+.move_current:
+ add si,bx ; Resume last position in sector
+ mov ecx,SECTOR_SIZE ; 0 out high part
+ sub cx,bx
+ shr cx,5 ; Number of entries left
+.scanentry:
+ cmp byte [gs:si],0
+ jz .fail
+ cmp word [gs:si+11],0Fh ; Long filename
+ jne .short_entry
+
+.vfat_entry:
+ push eax
+ push ecx
+ push si
+ push di
+.vfat_ln_info: ; Get info about the line that we're on
+ mov al,[gs:si]
+ test al,40h
+ jz .vfat_tail_ln
+ and al,03Fh
+ mov ah,1 ; On beginning line
+ jmp .vfat_ck_ln
+
+.vfat_tail_ln: ; VFAT tail line processing (later in VFAT, head in name)
+ test al,80h ; Invalid data?
+ jnz .vfat_abort
+ mov ah,0 ; Not on beginning line
+ cmp dl,al
+ jne .vfat_abort ; Is this the entry we need?
+ mov bl,[gs:si+13]
+ cmp bl,[VFATCsum]
+ jne .vfat_abort
+ jmp .vfat_cp_ln
+
+.vfat_ck_ln: ; Load this line's VFAT CheckSum
+ mov bl,[gs:si+13]
+ mov [VFATCsum],bl
+.vfat_cp_ln: ; Copy VFAT line
+ dec al ; Store the next line we need
+ mov dx,ax ; Use DX to store the progress
+ mov bx,13
+ mov ah,0
+ mul bl ; Offset for DI
+ add di,ax ; Increment DI
+ inc si ; Align to the real characters
+ mov cx,13 ; 13 characters per VFAT DIRENT
+.vfat_cp_chr:
+ gs lodsw ; Unicode here!!
+ mov bp,ds
+ mov es,bp
+ call ucs2_to_cp ; Convert to local codepage
+ mov bp,fs
+ mov es,bp
+ jc .vfat_abort ;-; Use short name if character not on codepage
+ stosb ; CAN NOT OVERRIDE es
+ cmp al,0
+ jz .vfat_find_next ; Null-terminated string; don't process more
+ cmp cx,3
+ je .vfat_adj_add2
+ cmp cx,9
+ jne .vfat_adj_add0
+.vfat_adj_add3: inc si
+.vfat_adj_add2: inc si
+.vfat_adj_add1: inc si
+.vfat_adj_add0:
+ loop .vfat_cp_chr
+ cmp dh,1 ; Is this the first round?
+ jnz .vfat_find_next
+.vfat_null_term: ; Need to null-terminate if first line as we rolled over the end
+ mov al,0
+ stosb
+
+.vfat_find_next: ;Find the next part of the name
+ pop di
+ pop si
+ pop ecx
+ pop eax
+ cmp dl,0
+ jz .vfat_find_info ; We're done with the name
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .vfat_entry
+ call nextsector
+ jnc .vfat_entry ; CF is set if we're at end
+ jmp .fail
+.vfat_find_info: ; Fetch next entry for the size/"INode"
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .get_info
+ call nextsector
+ jnc .get_info ; CF is set if we're at end
+ jmp .fail
+.vfat_abort: ; Something went wrong, skip
+ pop di
+ pop si
+ pop ecx
+ pop eax
+ jmp .skip_entry
+
+.short_entry:
+ test byte [gs:si+11],8 ; Ignore volume labels //HERE
+ jnz .skip_entry
+ mov edx,eax ;Save current sector
+ push cx
+ push si
+ push di
+ mov cx,8
+.short_file:
+ gs lodsb
+ cmp al,'.'
+ jz .short_dot
+.short_file_loop:
+ cmp al,' '
+ jz .short_skip_bs
+ stosb
+ loop .short_file_loop
+ jmp .short_period
+.short_skip_bs: ; skip blank spaces in FILENAME (before EXT)
+ add si,cx
+ dec si
+.short_period:
+ mov al,'.'
+ stosb
+ mov cx,3
+.short_ext:
+ gs lodsb
+ cmp al,' '
+ jz .short_done
+ stosb
+ loop .short_ext
+ jmp .short_done
+.short_dot:
+ stosb
+ gs lodsb
+ cmp al,' '
+ jz .short_done
+ stosb
+.short_done:
+ mov al,0 ; Null-terminate the short strings
+ stosb
+ pop di
+ pop si
+ pop cx
+ mov eax,edx
+.get_info:
+ mov ebx,[gs:si+28] ; length
+ mov dl,[gs:si+11] ; type
+.next_entry:
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .store_offset
+ call nextsector
+ jnc .store_sect ; CF is set if we're at end
+ jmp .fail
+
+.skip_entry:
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .scanentry
+ call nextsector
+ jnc .scanentry ; CF is set if we're at end
+ jmp .fail
+
+.store_sect:
+ pop gs
+ pop fs
+ pop es
+ pop si
+ mov [ds:si+file_sector],eax
+ mov eax,0 ; Now at beginning of new sector
+ jmp .success
+
+.store_offset:
+ pop gs
+ pop fs
+ pop es
+ pop si ; cx=num remain; SECTOR_SIZE-(cx*32)=cur pos
+ shl ecx,DIRENT_SHIFT
+ mov eax,SECTOR_SIZE
+ sub eax,ecx
+ and eax,0ffffh
+
+.success:
+ mov [ds:si+file_bytesleft],eax
+ ; "INode" number = ((CurSector-RootSector)*SECTOR_SIZE + Offset)/DIRENT_SIZE)
+ mov ecx,eax
+ mov eax,[ds:si+file_sector]
+ sub eax,[RootDir]
+ shl eax,SECTOR_SHIFT
+ add eax,ecx
+ shr eax,DIRENT_SHIFT
+ dec eax
+ xchg eax,ebx ; -> EBX=INode, EAX=FileSize
+ jmp .done
+
+.fail:
+ pop gs
+ pop fs
+ pop es
+ pop si
+ call close_dir
xor eax,eax
+ stc
+.done:
+ pop bp
+ pop ecx
+.end:
ret
section .bss
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index aac1ec27..94f23afb 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -704,6 +704,13 @@ prefix: test byte [DHCPMagic], 04h ; Did we get a path prefix option
call writestr_early
call crlf
+ ; Set CurrentDirName
+ push di
+ mov si,PathPrefix
+ mov di,CurrentDirName
+ call strcpy
+ pop di
+
;
; Load configuration file
;
diff --git a/doc/comboot.txt b/doc/comboot.txt
index 53295020..387303d3 100644
--- a/doc/comboot.txt
+++ b/doc/comboot.txt
@@ -921,3 +921,46 @@ AX=001Eh [3.74] Keyboard remapping table
version, the format code is always 1 and the length is always
256. This version can be updated simply by overwriting the version
in memory; this may not be true in the future.
+
+
+AX=001Fh [BETA-3.74+] Get current working directory
+ Input: AX 0001Eh
+ Output: ES:BX null-terminated directory name string
+
+ Returns the current working directory. For SYSLINUX, ISOLINUX,
+ and PXELINUX, this will be an absolute path. For EXTLINUX, it
+ currently returns "./".
+
+
+AX=0020h [BETA-3.74+] Open directory
+ Input: AX 001Fh
+ ES:SI /-null-terminated directory name
+ Output: SI directory handle
+ EAX clobbered
+
+ Open a directory for reading. Directory name must have a trailing
+ "/" before the null (otherwise, you're looking for a file)(This
+ may change as this is a BETA call).
+
+
+AX=0021h [BETA-3.74+] Read directory
+ Input: AX 0020h
+ SI directory handle
+ ES:DI buffer for file name
+ Output: DL Type of file
+ SI directory handle, or 0 if end of directory was reached
+ EAX Size of file
+ EBX Inode of file
+
+ Read one filename from the directory, incrementing the directory
+ structure at SI as appropriate, storing the filename into the buffer
+ at ES:DI, and returning the type of the file in DL, the file length
+ in EAX, the INode/file number in EBX and the updated directory handle.
+
+
+AX=0022h [BETA-3.74+] Close directory
+ Input: AX 001Fh
+ SI directory handle
+ Output SI 0
+
+ Closes a directory.