diff options
author | Gene Cumm <gene.cumm@gmail.com> | 2009-02-08 09:36:59 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-02-09 22:49:17 -0800 |
commit | c1def425e3eeb245da7a59025f2fa37f02368504 (patch) | |
tree | ad741a1bfc81828eb474b77b7c9ec270355c6bc3 | |
parent | 2b02abdaa91f41235f40f846d08bb09d8841baa6 (diff) | |
download | syslinux-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.inc | 71 | ||||
-rw-r--r-- | core/extlinux.asm | 8 | ||||
-rw-r--r-- | core/isolinux.asm | 20 | ||||
-rw-r--r-- | core/ldlinux.asm | 324 | ||||
-rw-r--r-- | core/pxelinux.asm | 7 | ||||
-rw-r--r-- | doc/comboot.txt | 43 |
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. |