aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Aleaxander <Aleaxander@gmail.com>2009-06-14 14:22:33 +0800
committerLiu Aleaxander <Aleaxander@gmail.com>2009-06-14 14:22:33 +0800
commit1a4fe28588ed6bf114f3b9e06966406a1b833d6e (patch)
tree94f530c3950cf0815108326aee485138da731638
parent8732ef9b7c9ded79c525ac50932660e73dff7cc0 (diff)
downloadsyslinux-1a4fe28588ed6bf114f3b9e06966406a1b833d6e.tar.gz
syslinux-1a4fe28588ed6bf114f3b9e06966406a1b833d6e.tar.xz
syslinux-1a4fe28588ed6bf114f3b9e06966406a1b833d6e.zip
Core:SYSLINUX: ldlinux.asm converted to C
Well, something goes ugly but it works. And I still need spend some more time to make the code much better.
-rw-r--r--core/Makefile3
-rw-r--r--core/comboot.inc4
-rw-r--r--core/extern.inc3
-rw-r--r--core/fat.c963
-rw-r--r--core/fs.c11
-rw-r--r--core/include/fat_fs.h118
-rw-r--r--core/ldlinux.asm1149
7 files changed, 1105 insertions, 1146 deletions
diff --git a/core/Makefile b/core/Makefile
index c41b423b..c2238972 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -33,7 +33,8 @@ CODEPAGE = cp865
# The targets to build in this directory...
BTARGET = kwdhash.gen \
- extlinux.bin extlinux.bss extlinux.sys
+ extlinux.bin extlinux.bss extlinux.sys \
+ ldlinux.bss ldlinux.sys ldlinux.bin
# All primary source files for the main syslinux files
NASMSRC := $(wildcard *.asm)
diff --git a/core/comboot.inc b/core/comboot.inc
index 8a7d95c4..7c2b6e66 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -911,7 +911,7 @@ comapi_opendir:
cmp eax,0
jz comapi_err ; Found nothing
;ZF is unset
- call alloc_fill_dir
+ pm_call alloc_fill_dir
mov P_EAX,eax
mov P_CX,SECTOR_SIZE
mov P_SI,si
@@ -929,7 +929,7 @@ comapi_readdir:
mov es,P_ES
mov di,P_DI
mov si,P_SI
- call readdir
+ pm_call readdir
mov P_EAX,eax
mov P_DL,dl
mov P_EBX,ebx
diff --git a/core/extern.inc b/core/extern.inc
index fdbe2643..2e6dcd07 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -15,4 +15,7 @@
; fs.c
extern fs_init, searchdir, getfssec, mangle_name, load_config
+ ; fat.c
+ extern alloc_fill_dir, readdir
+
%endif ; EXTERN_INC
diff --git a/core/fat.c b/core/fat.c
new file mode 100644
index 00000000..87e9c0a7
--- /dev/null
+++ b/core/fat.c
@@ -0,0 +1,963 @@
+#include <stdio.h>
+#include <string.h>
+#include "cache.h"
+#include "core.h"
+#include "disk.h"
+#include "fat_fs.h"
+#include "fs.h"
+
+
+#define FILENAME_MAX_LG2 8
+#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
+#define MAX_OPEN_LG2 6
+#define MAX_OPEN (1 << MAX_OPEN_LG2)
+#define ROOT_DIR_WORD 0x002f
+
+/* file structure. This holds the information for each currently open file */
+struct open_file_t {
+ uint32_t file_sector; /* sector pointer ( 0 = structure free ) */
+ uint32_t file_bytesleft; /* number of bytes left */
+ uint32_t file_left; /* number of sectors left */
+ uint32_t pad; /* padding */
+};
+
+extern char Files[MAX_OPEN * sizeof(struct open_file_t)];
+extern char trackbuf[8192];
+
+
+/* the fat bpb data */
+struct fat_bpb fat;
+int FATType = 0;
+
+/* generic information about FAT fs */
+uint32_t FAT; /* Location of (first) FAT */
+uint32_t RootDirArea; /* Location of root directory area */
+uint32_t RootDir; /* Location of root directory proper */
+uint32_t DataArea; /* Location of data area */
+uint32_t TotalSectors; /* Total number of sectors */
+uint32_t ClustSize; /* Bytes/cluster */
+uint32_t ClustMask; /* Sector/cluster - 1 */
+uint8_t CopySuper; /* Distinguish .bs versus .bss */
+uint8_t DriveNumber; /* BIOS drive number */
+uint8_t ClustShift; /* Shift count for sectors/cluster */
+uint8_t ClustByteShift; /* Shift count for bytes/cluster */
+
+int CurrentDir;
+int PrevDir;
+
+/* used for long name entry */
+char MangleBuf[12];
+char entry_name[14];
+char *NameStart;
+int NameLen;
+
+/* do this for readdir, because it called from asm and don't know the fs structure */
+struct fs_info *this_fs = NULL;
+
+/*
+ * Well, I find I can't reference the syslinux_cfg[i] config file name even though I
+ * used extern in C side and global in the ASM side. So I thought I can use a gloabl
+ * pointer called this_filename, points to the current filename. And in the searchdir
+ * function, we use a flag to determine if we need use the this_filename to go on.
+ * Here is the principle:
+ *
+ * if (regs->esi.w[0] == 0xCFCF) ; Called From C File(CFCF)
+ * file_name = this_fs;
+ * else
+ * file_name = (char *)MK_PTR(regs->es, regs->esi.w[0])
+ *
+ *
+ * so if we want call searchdir function from C file, and the filename address
+ * is in the high address(means higher than 1M), we can put regs->edi.w[0] the 0xCFCF
+ * flag, then I hope all will go well.
+ *
+ * (I know it's ugly, sorry)
+ */
+char *this_filename = NULL;
+
+
+/**
+ * allocate_file:
+ *
+ * Allocate a file structure
+ *
+ * @return: if successful return the file pointer, or return NULL
+ *
+ */
+static struct open_file_t *allocate_file()
+{
+ struct open_file_t *file;
+ int i = 0;
+
+ file = (struct open_file_t *)Files;
+
+ for (; i < MAX_OPEN; i ++ ) {
+ if ( file->file_sector == 0 ) /* found it */
+ return file;
+ file ++;
+ }
+
+ return NULL; /* not found */
+}
+
+
+/**
+ * alloc_fill_dir:
+ *
+ * Allocate then fill a file structure for a directory starting in
+ * sector SECTOR. if successful, return the pointer of filled file
+ * structure, or return NULL.
+ *
+ */
+void alloc_fill_dir(com32sys_t *regs)
+{
+ sector_t sector = regs->eax.l;
+ struct open_file_t *file;
+
+ file = allocate_file();
+ if ( !file ) {
+ regs->esi.w[0] = 0;
+ return;
+ }
+
+ file->file_sector = sector; /* current sector */
+ file->file_bytesleft = 0; /* current offset */
+ file->file_left = sector; /* beginning sector */
+
+ regs->esi.w[0] = OFFS_WRT(file, 0);
+}
+
+
+/* Deallocates a file structure */
+static void close_file(struct open_file_t *file)
+{
+ if ( file )
+ file->file_sector = 0;
+}
+
+
+
+/* Deallocates a directory structure */
+/***********
+void close_dir(struct fat_dir_entry *dir)
+{
+ if ( dir )
+ *(uint32_t*)dir = 0;
+}
+***********/
+
+
+/**
+ * getfatsector:
+ *
+ * check for a particular sector in the FAT cache.
+ *
+ */
+struct cache_struct *getfatsector(struct fs_info *fs, uint32_t sector)
+{
+ return get_cache_block(fs->fs_dev, FAT + sector);
+}
+
+
+/**
+ * nextcluster:
+ *
+ * Advance a cluster pointer in clust_num to the next cluster
+ * pointer at in the FAT tables. CF = 0 on return if end of file.
+ *
+ * @param: clust_num;
+ *
+ * @return: the next cluster number
+ *
+ */
+static uint32_t nextcluster(struct fs_info *fs, uint32_t clust_num)
+{
+ uint32_t next_cluster;
+ uint32_t fat_sector;
+ uint32_t offset;
+ int lo, hi;
+ struct cache_struct *cs;
+
+ switch(FATType) {
+ case FAT12:
+ fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT;
+ cs = getfatsector(fs, fat_sector);
+ offset = (clust_num * 3 / 2) & ( SECTOR_SIZE -1 );
+ if ( offset == 0x1ff ) {
+ /*
+ * we got the end of the one fat sector,
+ * but we don't got we have(just one byte, we need two),
+ * so store the low part, then read the next fat
+ * sector, read the high part, then combine it.
+ */
+ lo = *(uint8_t *)(cs->data + offset);
+ cs = getfatsector(fs, fat_sector + 1);
+ hi = *(uint8_t *)cs->data;
+ next_cluster = (hi << 8) + lo;
+ } else
+ next_cluster = *(uint16_t *)(cs->data + offset);
+
+ if ( clust_num & 0x0001 )
+ next_cluster >>= 4; /* cluster number is ODD */
+ else
+ next_cluster &= 0x0fff; /* cluster number is EVEN */
+ if ( next_cluster > 0x0ff0 )
+ goto fail;
+ break;
+
+ case FAT16:
+ fat_sector = clust_num >> (SECTOR_SHIFT - 1);
+ offset = clust_num & ( (1 << (SECTOR_SHIFT-1)) -1);
+ cs = getfatsector(fs, fat_sector);
+ next_cluster = ((uint16_t *)cs->data)[offset];
+ if ( next_cluster > 0xfff0 )
+ goto fail;
+ break;
+
+ case FAT32:
+ fat_sector = clust_num >> (SECTOR_SHIFT - 2);
+ offset = clust_num & ( (1 << (SECTOR_SHIFT-2)) -1);
+ cs = getfatsector(fs, fat_sector);
+ next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff;
+ if ( next_cluster > 0x0ffffff0 )
+ goto fail;
+ break;
+ }
+
+ return next_cluster;
+
+ fail:
+ /* got an unexcepted cluster number, so return ZERO */
+ return 0;
+}
+
+
+
+/**
+ * nextsector:
+ *
+ * given a sector on input, return the next sector of the
+ * same filesystem object, which may be the root directory or a
+ * cluster chain. Returns EOF.
+ *
+ */
+static uint32_t nextsector(struct fs_info *fs, uint32_t sector)
+{
+ uint32_t data_sector;
+ uint32_t cluster;
+
+ if ( sector < DataArea ) {
+ sector ++;
+ /* if we reached the end of root area */
+ if ( sector == DataArea )
+ sector = 0; /* return 0 */
+ return sector;
+ }
+
+ data_sector = sector - DataArea;
+ if ( (data_sector+1) & ClustMask ) /* in a cluster */
+ return (++sector);
+
+ /* got a new cluster */
+ cluster = nextcluster(fs, (data_sector >> ClustShift) + 2);
+ if ( !cluster )
+ return 0;
+
+ /* return the start of the new cluster */
+ sector = ( (cluster - 2) << ClustShift ) + DataArea;
+ return sector;
+}
+
+
+
+
+
+/**
+ * __getfssec:
+ *
+ * get multiple sectors from a file
+ *
+ * This routine makes sure the subransfers do not cross a 64K boundary
+ * and will correct the situation if it does, UNLESS *sectos* cross
+ * 64K boundaries.
+ *
+ * @param: buf
+ * @param: file structure
+ * @param: sectors
+ *
+ */
+static void __getfssec(struct fs_info *fs, char *buf, struct open_file_t *file, uint32_t sectors)
+{
+ uint32_t curr_sector = file->file_sector;
+ uint32_t frag_start , next_sector;
+ uint32_t con_sec_cnt;
+
+ while (sectors) {
+ /* get fragment */
+ con_sec_cnt = 0;
+ frag_start = curr_sector;
+
+ do {
+ /* get consective sector count */
+ con_sec_cnt ++;
+ sectors --;
+ if ( sectors == 0 )
+ break;
+
+ next_sector = nextsector(fs, curr_sector);
+ if ( !next_sector )
+ break;
+ }while( next_sector == (++curr_sector) );
+
+#if 0 /* Debug message */
+ printf("You are reading stores at sector --0x%x--0x%x\n",
+ frag_start, frag_start + con_sec_cnt -1);
+#endif
+
+ /* do read */
+ read_sectors(buf, frag_start, con_sec_cnt);
+ buf += con_sec_cnt << 9;/* adjust buffer pointer */
+
+ if ( !sectors )
+ break;
+ //curr_sector --; /* this is the last sector actually read */
+ curr_sector = next_sector;
+ }
+
+ /* update the file_sector filed for the next read */
+ file->file_sector = nextsector(fs, curr_sector);
+}
+
+
+
+/**
+ * getfssec:
+ *
+ * get multiple sectors from a file
+ *
+ *
+ * @param: buf
+ * @param: file
+ * @param: sectors
+ * @param: have_more
+ *
+ * @return: number of bytes read
+ *
+ */
+uint32_t vfat_getfssec(struct fs_info *fs, char *buf,
+ void *open_file, int sectors, int *have_more)
+{
+ uint32_t bytes_read = sectors << SECTOR_SHIFT;
+ struct open_file_t *file = (struct open_file_t *)open_file;
+
+ if ( sectors > file->file_left )
+ sectors = file->file_left;
+
+ __getfssec(fs, buf, file, sectors);
+
+ if ( bytes_read >= file->file_bytesleft ) {
+ bytes_read = file->file_bytesleft;
+ *have_more = 0;
+ } else
+ *have_more = 1;
+ file->file_bytesleft -= bytes_read;
+ file->file_left -= sectors;
+
+ return bytes_read;
+}
+
+/**
+ * mangle_name:
+ *
+ * Mangle a filename pointed to by src into a buffer pointed to by dst;
+ * ends on encountering any whitespace.
+ *
+ */
+void vfat_mangle_name(char *dst, char *src)
+{
+ char *p = dst;
+ int i = FILENAME_MAX -1;
+
+ while(*src > ' ') {
+ if ( *src == '\\' )
+ *src = '/';
+
+ if (*src == '/') {
+ if (*(src+1) == '/') {
+ src ++;
+ i --;
+ continue;
+ }
+ }
+ i --;
+ *dst++ = *src++;
+ }
+
+ while (1) {
+ if (dst == p)
+ break;
+ if ((*(dst-1) != '/') && (*(dst-1) != '.'))
+ break;
+
+ dst --;
+ i ++;
+ }
+
+ i ++;
+ for (; i > 0; i --)
+ *dst++ = '\0';
+}
+
+
+/**
+ * mangle_dos_name:
+ *
+ * Mangle a dos filename component pointed to by FILENAME
+ * into MangleBuf; ends on encountering any whitespace or
+ * slash.
+ *
+ * WARNING: saves pointers into the buffer for longname matchs!
+ *
+ * @param: filename
+ * @param: MangleBuf
+ *
+ */
+/**
+ * for now, it can't handle this case:
+ * xyxzxyxjfdkfjdjf.txt as it will just output the first 11 chars
+ * but not care the dot char at the later, so I think we need do
+ * this, but it seems that the SYSLINUX doesn't do it, so I will
+ * make it stay as what it was orignal.
+ *
+ */
+static void mangle_dos_name(char *MangleBuf, char *filename)
+{
+
+ char *dst = MangleBuf;
+ char *src = filename;
+ int i = 0;
+ unsigned char c;
+
+ NameStart = filename;
+
+ for (; i < 11; i ++)
+ MangleBuf[i] = ' ';
+
+ for (i = 0; i < 11; i++) {
+ c = *src ++;
+
+ if ( (c <= ' ') || (c == '/') )
+ break;
+
+ if ( c == '.' ) {
+ dst = &MangleBuf[8];
+ i = 7;
+ continue;
+ }
+
+ if (c >= 'a' && c <= 'z')
+ c -= 32;
+ if ( (c == 0xe5) && (i == 11) )
+ c = 0x05;
+
+ *dst++ = c;
+ }
+ MangleBuf[12] = '\0';
+
+ while( (*src != '/') && (*src > ' ') )
+ src ++;
+
+ NameLen = src - filename;
+}
+
+
+
+static void unicode_to_ascii(char *entry_name, uint16_t *unicode_buf)
+{
+ int i = 0;
+
+ for (; i < 13; i++) {
+ if ( unicode_buf[i] == 0xffff ) {
+ entry_name[i] = '\0';
+ return;
+ }
+ entry_name[i] = (char)unicode_buf[i];
+ }
+}
+
+/**
+ * long_entry_name:
+ *
+ * get the long entry name
+ *
+ */
+static void long_entry_name(struct fat_long_name_entry *dir)
+{
+ uint16_t unicode_buf[13];
+
+ memcpy(unicode_buf, dir->name1, 5 * 2);
+ memcpy(unicode_buf + 5, dir->name2, 6 * 2);
+ memcpy(unicode_buf + 11,dir->name3, 2 * 2);
+
+ unicode_to_ascii(entry_name, unicode_buf);
+
+}
+
+
+static uint8_t get_checksum(char *dir_name)
+{
+ int i;
+ uint8_t sum=0;
+
+ for (i=11; i; i--)
+ sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++;
+ return sum;
+}
+
+static inline uint32_t first_sector(struct fat_dir_entry *dir)
+{
+ uint32_t first_clust, sector;
+
+ first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
+ sector = ((first_clust - 2) << ClustShift) + DataArea;
+
+ return sector;
+}
+
+
+/* try with the biggest long name */
+char long_name[0x40 * 13];
+
+/**
+ * search_dos_dir:
+ *
+ * search a specific directory for a pre-mangled filename in
+ * MangleBuf, in the directory starting in sector SECTOR
+ *
+ * NOTE: This file considers finding a zero-length file an
+ * error. This is so we don't have to deal with that special
+ * case elsewhere in the program (most loops have the test
+ * at the end).
+ *
+ * @param: MangleBuf
+ * @param: dir_sector, directory sector
+ *
+ * @out: file pointer
+ * @out: file length (MAY BE ZERO!)
+ * @out: file attribute
+ * @out: dh, clobbered.
+ *
+ */
+static struct open_file_t* search_dos_dir(struct fs_info *fs, char *MangleBuf,
+ uint32_t dir_sector, uint32_t *file_len, uint8_t *attr)
+{
+ struct open_file_t* file;
+ struct cache_struct* cs;
+ struct fat_dir_entry *dir;
+ struct fat_long_name_entry *long_dir;
+
+ uint8_t VFATInit, VFATNext, VFATCsum;
+ uint8_t id;
+ uint32_t slots;
+ uint32_t entries;
+ int checksum;
+
+ file = allocate_file();
+ if ( !file )
+ return NULL;
+
+ /*
+ * Compute the value of a possible VFAT longname
+ * "last" entry (which, of coures, comes first ...)
+ */
+ slots = (NameLen + 12) / 13;
+ slots |= 0x40;
+ VFATInit = slots;
+ VFATNext = slots;
+
+ do {
+ cs = get_cache_block(fs->fs_dev, dir_sector);
+ dir = (struct fat_dir_entry *)cs->data;
+ entries = SECTOR_SIZE / 32;
+
+ /* scan all the entries in a sector */
+ do {
+ if ( dir->name[0] == 0 )
+ return NULL; /* Hit directory high water mark */
+
+ if ( dir->attr == 0x0f ) {
+ /* it's a long name entry */
+ long_dir = (struct fat_long_name_entry *)dir;
+ id = long_dir->id;
+ if ( id !=VFATNext )
+ goto not_match;
+
+ if ( id & 0x40 ) {
+ /*get the initial checksum value*/
+ VFATCsum = long_dir->checksum;
+ } else {
+ if ( long_dir->checksum != VFATCsum )
+ goto not_match;
+ }
+
+ id &= 0x3f;
+ VFATNext = --id;
+
+ /* got the long entry name */
+ long_entry_name(long_dir);
+ memcpy(long_name + id * 13, entry_name, 13);
+
+ /*
+ * if we got the last entry?
+ * if so, check it, or go on with the next entry
+ */
+ if ( id == 0 ) {
+ if ( strcmp(long_name, NameStart) )
+ goto not_match;
+ }
+
+ goto next_entry;
+
+ } else {
+ /* it's a short entry */
+ if ( dir->attr & 0x08 ) /* ingore volume labels */
+ goto not_match;
+
+
+ /* If we have a long name match, then VFATNext must be 0 */
+ if ( !VFATNext ) {
+ /*
+ * we already have a VFAT long name match, however,
+ * the match is only valid if the checksum matchs.
+ */
+ checksum = get_checksum(dir->name);
+ if ( checksum == VFATCsum )
+ goto found; /* got a match on long name */
+
+ } else {
+ if ( strncmp(MangleBuf, dir->name, 11) == 0 )
+ goto found;
+ }
+ }
+
+ not_match:/* find it again */
+ VFATNext = VFATInit;
+
+ next_entry:
+ dir ++;
+
+ }while ( --entries );
+
+ dir_sector = nextsector(fs, dir_sector);
+
+ }while ( dir_sector ); /* scan another secotr */
+
+ found:
+ *file_len = file->file_bytesleft = dir->file_size;
+ file->file_sector = first_sector(dir);
+ *attr = dir->attr;
+
+ return file;
+}
+
+
+
+/**
+ * searchdir:
+ *
+ * open a file
+ *
+ * @param: filename, the file we wanna open
+ * @param: file_len, to return the file length
+ *
+ * @return: return the file structure on successful, or NULL.
+ *
+ */
+void vfat_searchdir(char *filename, struct file *file)
+{
+ uint32_t dir_sector;
+ uint32_t file_len = 0;
+ uint8_t attr = 0;
+ char *p;
+ struct open_file_t *open_file = NULL;
+
+ if (file->fs != this_fs)
+ this_fs = file->fs;
+
+ dir_sector = CurrentDir;
+ if ( *filename == '/' ) {
+ dir_sector = RootDir;
+ filename ++;
+ }
+
+ while ( *filename ) {
+ p = filename;
+
+ /* try to find the end */
+ while ( (*p > ' ') && (*p != '/') )
+ p ++;
+
+ if (filename == p)
+ //return NULL;
+ goto fail;
+
+ PrevDir = dir_sector;
+
+ mangle_dos_name(MangleBuf, filename);
+ open_file = search_dos_dir(file->fs, MangleBuf, dir_sector, &file_len, &attr);
+ if (! open_file)
+ goto fail;
+
+ if ( *p != '/' ) /* we got a file */
+ break;
+
+ if ( (attr & 0x10) == 0 ) /* subdirectory */
+ //return NULL;
+ goto fail;
+
+ dir_sector = open_file->file_sector;
+ close_file(open_file);
+
+ filename = p + 1; /* search again */
+ }
+
+ if ( (attr & 0x18) || (file_len == 0) ) {
+ fail:
+ file_len = 0;
+ open_file = NULL;
+ } else {
+ open_file->file_bytesleft = file_len;
+ open_file->file_left = ( file_len + SECTOR_SIZE -1 ) >> SECTOR_SHIFT;
+ }
+
+ file->file_len = file_len;
+ file->open_file = (void *)open_file;
+}
+
+
+
+
+/**
+ * readdir:
+ *
+ * read one file from a directory
+ *
+ * returns the file's name in the filename string buffer
+ *
+ * @param: filename
+ * @param: file
+ *
+ */
+void readdir(com32sys_t *regs)/*
+ struct fs_info *fs, struct open_file_t* dir_file,
+ char* filename, uint32_t *file_len, uint8_t *attr)
+ */
+{
+ uint32_t sector, sec_off;
+
+ /* make it to be 1 to check if we have met a long name entry before */
+ uint8_t id = 1;
+ uint8_t init_id, next_id;
+ uint8_t entries_left;
+ int i;
+
+ char *filename = (char *)MK_PTR(regs->es, regs->edi.w[0]);
+ struct open_file_t *dir_file = (struct open_file_t *)MK_PTR(regs->ds, regs->esi.w[0]);
+
+ struct cache_struct *cs;
+ struct fat_dir_entry *dir;
+ struct fat_long_name_entry *long_dir;
+ struct open_file_t file;
+
+ sector = dir_file->file_sector;
+ sec_off = dir_file->file_bytesleft;
+ if ( !sector )
+ goto fail;
+
+ entries_left = (SECTOR_SIZE - sec_off) >> 5;
+ cs = get_cache_block(this_fs->fs_dev, sector);
+ dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */
+
+ while ( 1 ) {
+ if ( dir->name[0] == 0 )
+ goto fail;
+
+ if ( dir->attr == FAT_ATTR_LONG_NAME ) {
+ /* it's a long name */
+ long_dir = (struct fat_long_name_entry *)dir;
+
+ if ( long_dir->id & 0x40 ) {
+ init_id = id = long_dir->id & 0x3f;
+ id--;
+ } else {
+ next_id = (long_dir->id & 0x3f) - 1;
+ id--;
+ if ( id != next_id )
+ goto next_entry;
+ }
+
+ long_entry_name(long_dir);
+ memcpy(filename + id * 13, entry_name, 13);
+
+
+ /*
+ * we need go on with the next entry
+ * and we will fall through to next entry
+ */
+
+ } else {
+ /* it's a short entry */
+
+ if ( !id ) /* we got a long name match */
+ break;
+
+ if ( dir->attr & FAT_ATTR_VOLUME_ID )
+ goto next_entry;
+
+ for( i = 0; i < 8; i ++) {
+ if ( dir->name[i] == ' ' )
+ break;
+ *filename++ = dir->name[i];
+ }
+
+ *filename++ = '.';
+
+ for ( i = 8; i < 11; i ++) {
+ if ( dir->name[i] == ' ' )
+ break;
+ *filename ++ = dir->name[i];
+ }
+
+ /* check if we have got an extention */
+ if ( ! *(filename - 1) )
+ *(filename -2) = '\0';
+ else
+ *filename = '\0';
+
+ break;
+ }
+
+ next_entry:
+ dir ++;
+ entries_left --;
+
+ if ( !entries_left ) {
+ sector = nextsector(this_fs, sector);
+ if ( !sector )
+ goto fail;
+ cs = get_cache_block(this_fs->fs_dev, sector);
+ dir = (struct fat_dir_entry *)cs->data;
+ }
+ }
+
+ /* finally , we get what we want */
+ entries_left --;
+ if ( !entries_left ) {
+ sector = nextsector(this_fs, sector);
+ if ( !sector )
+ goto fail;
+ }
+
+ file.file_sector = sector;
+ file.file_bytesleft = (SECTOR_SIZE - (entries_left << DIRENT_SHIFT) ) & 0xffff;
+
+ regs->eax.l = dir->file_size;
+ regs->ebx.l = first_sector(dir);
+ regs->edx.b[0] = dir->attr;
+
+ return;
+
+ fail:
+ //close_dir(dir);
+ regs->eax.l = 0;
+}
+
+void vfat_load_config(com32sys_t *regs)
+{
+ char syslinux_cfg1[] = "/boot/syslinux/syslinux.cfg";
+ char syslinux_cfg2[] = "/syslinux/syslinux.cfg";
+ char syslinux_cfg3[] = "/syslinux.cfg";
+ char config_name[] = "syslinux.cfg";
+
+
+ char *syslinux_cfg[]= {syslinux_cfg1, syslinux_cfg2, syslinux_cfg3};
+ com32sys_t oregs;
+ int i = 0;
+
+ *(uint16_t *)CurrentDirName = ROOT_DIR_WORD;
+ CurrentDir = RootDir;
+
+ strcpy(ConfigName, config_name);
+ for (; i < 3; i++) {
+ regs->edi.w[0] = 0xCFCF; /* Mark we use the this_filename to pass filename para */
+ this_filename = syslinux_cfg[i];
+ memset(&oregs, 0, sizeof oregs);
+ call16(core_open, regs, &oregs);
+
+ /* if zf flag set, then failed; try another */
+ if (! (oregs.eflags.l & EFLAGS_ZF))
+ break;
+ }
+ if ( i == 3 ) {
+ printf("no config file found\n");
+ return; /* no config file */
+ }
+
+ strcpy(CurrentDirName, syslinux_cfg[i]);
+ CurrentDirName[strlen(syslinux_cfg[i])-strlen(config_name)] = '\0';
+ CurrentDir = PrevDir;
+}
+
+static inline void bsr(uint8_t *res, int num)
+{
+ int i = 0;
+ while (num >>= 1)
+ i ++;
+ *res = i;
+}
+
+/* init. the fs meta data, return the block size in bits */
+int vfat_fs_init()
+{
+ int sectors_per_fat;
+ uint32_t clust_num;
+ int RootDirSize;
+
+ /* get the fat bpb information */
+ read_sectors((char *)&fat, 0, 1);
+
+ TotalSectors = fat.bxSectors ? : fat.bsHugeSectors;
+ FAT = fat.bxResSectors;
+
+ sectors_per_fat = fat.bxFATsecs ? : fat.u.fat32.bxFATsecs_32;
+ RootDir = RootDirArea = FAT + sectors_per_fat * fat.bxFATs;
+ RootDirSize = (fat.bxRootDirEnts+SECTOR_SIZE/32-1) >> (SECTOR_SHIFT-5);
+ DataArea = RootDirArea + RootDirSize;
+
+ bsr(&ClustShift, fat.bxSecPerClust);
+ ClustByteShift = ClustShift + SECTOR_SHIFT;
+ ClustMask = fat.bxSecPerClust - 1;
+ ClustSize = fat.bxSecPerClust << SECTOR_SHIFT;
+
+
+ clust_num = (TotalSectors - DataArea) >> ClustShift;
+ if ( clust_num < 4085 )
+ FATType = FAT12;
+ else if ( clust_num < 65525 )
+ FATType = FAT16;
+ else
+ FATType = FAT32;
+
+ /* for SYSLINUX, the cache is based on sector size */
+ return SECTOR_SHIFT;
+}
+
+const struct fs_ops vfat_fs_ops = {
+ .fs_name = "vfat",
+ .fs_init = vfat_fs_init,
+ .searchdir = vfat_searchdir,
+ .getfssec = vfat_getfssec,
+ .mangle_name = vfat_mangle_name,
+ .unmangle_name = NULL,
+ .load_config = vfat_load_config
+};
diff --git a/core/fs.c b/core/fs.c
index 617e3e5e..2878c384 100644
--- a/core/fs.c
+++ b/core/fs.c
@@ -55,9 +55,15 @@ void getfssec(com32sys_t *regs)
void searchdir(com32sys_t *regs)
{
- char *filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);
+ char *filename;
struct file file;
+ if (regs->edi.w[0] == 0xCFCF) {
+ /* check fat.c for more information */
+ extern char *this_filename;
+ filename = this_filename;
+ } else
+ filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);
#if 0
printf("filename: %s\n", filename);
#endif
@@ -119,7 +125,8 @@ void device_init(struct device *dev, uint8_t device_num, sector_t offset)
*
*/
if ( USE_CACHE(dev->device_number) ) {
- /* I can't use __lowmem here, 'cause it will cause the error:
+ /* FIX!!
+ I can't use __lowmem here, 'cause it will cause the error:
"auxseg/lowmem region collides with xfer_buf_seg" */
//static __lowmem char cache_buf[65536];
dev->cache_data = core_cache_buf;
diff --git a/core/include/fat_fs.h b/core/include/fat_fs.h
new file mode 100644
index 00000000..0f7176b6
--- /dev/null
+++ b/core/include/fat_fs.h
@@ -0,0 +1,118 @@
+#ifndef FAT_FS_H
+#define FAT_FS_H
+
+#include <stdint.h>
+
+#define FAT_DIR_ENTRY_SIZE 32
+#define DIRENT_SHIFT 5
+
+#define FAT_ATTR_READ_ONLY 0x01
+#define FAT_ATTR_HIDDEN 0x02
+#define FAT_ATTR_SYSTEM 0x04
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIRECTORY 0x10
+#define FAT_ATTR_ARCHIVE 0x20
+
+#define FAT_MAXFILE 256
+
+#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_VOLUME_ID)
+
+#define FAT_ATTR_VALID (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_DIRECTORY \
+ | FAT_ATTR_ARCHIVE)
+
+enum fat_type{ FAT12, FAT16, FAT32 };
+
+/*
+ * The fat file system structures
+ */
+
+struct fat_bpb {
+ uint8_t jmp_boot[3];
+ uint8_t oem_name[8];
+ uint16_t sector_size;
+ uint8_t bxSecPerClust;
+ uint16_t bxResSectors;
+ uint8_t bxFATs;
+ uint16_t bxRootDirEnts;
+ uint16_t bxSectors;
+ uint8_t media;
+ uint16_t bxFATsecs;
+ uint16_t sectors_per_track;
+ uint16_t num_heads;
+ uint32_t num_hidden_sectors;
+ uint32_t bsHugeSectors;
+
+ union {
+ struct {
+ uint8_t num_ph_drive;
+ uint8_t reserved;
+ uint8_t boot_sig;
+ uint32_t num_serial;
+ uint8_t label[11];
+ uint8_t fstype[8];
+ } __attribute__ ((packed)) fat12_16;
+
+ struct {
+ uint32_t bxFATsecs_32;
+ uint16_t extended_flags;
+ uint16_t fs_version;
+ uint32_t root_cluster;
+ uint16_t fs_info;
+ uint16_t backup_boot_sector;
+ uint8_t reserved[12];
+ uint8_t num_ph_drive;
+ uint8_t reserved1;
+ uint8_t boot_sig;
+ uint32_t num_serial;
+ uint8_t label[11];
+ uint8_t fstype[8];
+ } __attribute__ ((packed)) fat32;
+
+ } __attribute__ ((packed)) u;
+
+} __attribute__ ((packed));
+
+
+
+struct fat_dir_entry {
+ char name[11];
+ uint8_t attr;
+ uint8_t nt_reserved;
+ uint8_t c_time_tenth;
+ uint16_t c_time;
+ uint16_t c_date;
+ uint16_t a_date;
+ uint16_t first_cluster_high;
+ uint16_t w_time;
+ uint16_t w_date;
+ uint16_t first_cluster_low;
+ uint32_t file_size;
+} __attribute__ ((packed));
+
+
+
+struct fat_long_name_entry {
+ uint8_t id;
+ uint16_t name1[5];
+ uint8_t attr;
+ uint8_t reserved;
+ uint8_t checksum;
+ uint16_t name2[6];
+ uint16_t first_cluster;
+ uint16_t name3[2];
+} __attribute__ ((packed));
+
+__lowmem char syslinux_cfg1[] = "/boot/syslinux/syslinux.cfg";
+__lowmem char syslinux_cfg2[] = "/syslinux/syslinux.cfg";
+__lowmem char syslinux_cfg3[] = "/syslinux.cfg";
+__lowmem char config_name[] = "syslinux.cfg";
+
+
+
+#endif /* fat_fs.h */
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index 23bc5413..0f207248 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -120,7 +120,11 @@ CopySuper resb 1 ; Distinguish .bs versus .bss
ClustShift resb 1 ; Shift count for sectors/cluster
ClustByteShift resb 1 ; Shift count for bytes/cluster
+; global syslinux_cfg_buffer
+;syslinux_cfg_buffer resb 28 ; the syslinux config file name buffer, used by vfat_load_config
+
alignb open_file_t_size
+ global Files
Files resb MAX_OPEN*open_file_t_size
;
@@ -128,91 +132,7 @@ Files resb MAX_OPEN*open_file_t_size
;
%include "diskstart.inc"
-;
-; Common initialization code
-;
-%include "init.inc"
-%include "cpuinit.inc"
-
-;
-; Compute some information about this filesystem.
-;
-
-; First, generate the map of regions
-genfatinfo:
- mov edx,[bxSectors]
- and dx,dx
- jnz .have_secs
- mov edx,[bsHugeSectors]
-.have_secs:
- mov [TotalSectors],edx
-
- mov eax,[bxResSectors]
- mov [FAT],eax ; Beginning of FAT
- mov edx,[bxFATsecs]
- and dx,dx
- jnz .have_fatsecs
- mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
-.have_fatsecs:
- imul edx,[bxFATs]
- add eax,edx
- mov [RootDirArea],eax ; Beginning of root directory
- mov [RootDir],eax ; For FAT12/16 == root dir location
-
- mov edx,[bxRootDirEnts]
- add dx,SECTOR_SIZE/32-1
- shr dx,SECTOR_SHIFT-5
- mov [RootDirSize],edx
- add eax,edx
- mov [DataArea],eax ; Beginning of data area
-
-; Next, generate a cluster size shift count and mask
- mov eax,[bxSecPerClust]
- bsr cx,ax
- mov [ClustShift],cl
- push cx
- add cl,SECTOR_SHIFT
- mov [ClustByteShift],cl
- pop cx
- dec ax
- mov [ClustMask],eax
- inc ax
- shl eax,SECTOR_SHIFT
- mov [ClustSize],eax
-
-;
-; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
-;
-getfattype:
- mov eax,[TotalSectors]
- sub eax,[DataArea]
- shr eax,cl ; cl == ClustShift
- mov cl,nextcluster_fat12-(nextcluster+2)
- cmp eax,4085 ; FAT12 limit
- jb .setsize
- mov cl,nextcluster_fat16-(nextcluster+2)
- cmp eax,65525 ; FAT16 limit
- jb .setsize
- ;
- ; FAT32, root directory is a cluster chain
- ;
- mov cl,[ClustShift]
- mov eax,[bootsec+44] ; Root directory cluster
- sub eax,2
- shl eax,cl
- add eax,[DataArea]
- mov [RootDir],eax
- mov cl,nextcluster_fat28-(nextcluster+2)
- mov byte [SuperSize],superblock_len_fat32
-.setsize:
- mov byte [nextcluster+1],cl
-
-;
-; Initialize the metadata cache
-;
- mov eax, 9
- pm_call cache_init
;
; Now, everything is "up and running"... patch kaboom for more
@@ -243,45 +163,8 @@ getfattype:
;
; Load configuration file
;
- 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 core_open
- pop di
- jnz .config_open
- mov di,syslinux_cfg2
- push di
- call core_open
- pop di
- jnz .config_open
- mov di,syslinux_cfg3
- push di
- call core_open
- pop di
+ pm_call load_config
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
;
; Now we have the config file open. Parse the config file and
@@ -289,327 +172,7 @@ getfattype:
;
%include "ui.inc"
-;
-; allocate_file: Allocate a file structure
-;
-; If successful:
-; ZF set
-; BX = file pointer
-; In unsuccessful:
-; ZF clear
-;
-allocate_file:
- TRACER 'a'
- push cx
- mov bx,Files
- mov cx,MAX_OPEN
-.check: cmp dword [bx], byte 0
- je .found
- add bx,open_file_t_size ; ZF = 0
- loop .check
- ; ZF = 0 if we fell out of the loop
-.found: pop cx
- 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.
-;
-; NOTE: This file considers finding a zero-length file an
-; error. This is so we don't have to deal with that special
-; case elsewhere in the program (most loops have the test
-; at the end).
-;
-; Assumes DS == ES == CS.
-;
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length (MAY BE ZERO!)
-; DL = file attribute
-; DH = clobbered
-; If unsuccessful
-; ZF set
-; EAX, SI, DX clobbered
-;
-
-search_dos_dir:
- push bx
- call allocate_file
- jnz .alloc_failure
-
- push cx
- push gs
- push es
- push ds
- pop es ; ES = DS
-
- ; Compute the value of a possible VFAT longname
- ; "last" entry (which, of course, comes first...)
- push ax
- push dx
- mov ax,[NameLen]
- add ax,12
- xor dx,dx
- mov cx,13
- div cx
- or al,40h
- mov [VFATInit],al
- mov [VFATNext],al
- pop dx
- pop ax
-
-.scansector:
- ; EAX <- directory sector to scan
- pm_call get_cache_block
- ; GS:SI now points to this sector
-
- mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
-.scanentry:
- cmp byte [gs:si],0
- jz .failure ; Hit directory high water mark
- cmp word [gs:si+11],0Fh ; Long filename
- jne .short_entry
-
- ; Process a VFAT long entry
- pusha
- mov al,[gs:si]
- cmp al,[VFATNext]
- jne .not_us
- mov bl,[gs:si+13]
- test al,40h
- jz .match_csum
- ; Get the initial checksum value
- mov [VFATCsum],bl
- jmp .done_csum
-.match_csum:
- cmp bl,[VFATCsum]
- jne .not_us ; Checksum mismatch
-.done_csum:
- and ax,03fh
- jz .not_us ; Can't be zero...
- dec ax
- mov [VFATNext],al ; Optimistically...
- mov bx,ax
- shl bx,2 ; *4
- add ax,bx ; *5
- add bx,bx ; *8
- add bx,ax ; *13
- cmp bx,[NameLen]
- jae .not_us
- mov di,[NameStart]
- inc si
- mov cx,13
-.vfat_cmp:
- gs lodsw
- push bx
- cmp bx,[NameLen]
- jae .vfat_tail
- movzx bx,byte [bx+di]
- add bx,bx
- cmp ax,[cp_unicode+bx] ; Primary case
- je .ucs_ok
- cmp ax,[cp_unicode_alt+bx] ; Alternate case
- je .ucs_ok
- ; Mismatch...
- jmp .not_us_pop
-.vfat_tail:
- ; *AT* the end we should have 0x0000, *AFTER* the end
- ; we should have 0xFFFF...
- je .vfat_end
- inc ax ; 0xFFFF -> 0x0000
-.vfat_end:
- and ax,ax
- jnz .not_us_pop
-.ucs_ok:
- pop bx
- inc bx
- 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_cmp
- ; Okay, if we got here we had a match on this particular
- ; entry... live to see another one.
- popa
- jmp .next_entry
-
-.not_us_pop:
- pop bx
-.not_us:
- popa
- jmp .nomatch
-
-.short_entry:
- test byte [gs:si+11],8 ; Ignore volume labels
- jnz .nomatch
-
- cmp byte [VFATNext],0 ; Do we have a longname match?
- jne .no_long_match
-
- ; We already have a VFAT longname match, however,
- ; the match is only valid if the checksum matches
- push cx
- push si
- push ax
- xor ax,ax
- mov cx,11
-.csum_loop:
- gs lodsb
- ror ah,1
- add ah,al
- loop .csum_loop
- cmp ah,[VFATCsum]
- pop ax
- pop si
- pop cx
- je .found ; Got a match on longname
-
-.no_long_match: ; Look for a shortname match
- push cx
- push si
- push di
- mov di,MangledBuf
- mov cx,11
- gs repe cmpsb
- pop di
- pop si
- pop cx
- je .found
-.nomatch:
- ; Reset the VFAT matching state machine
- mov dh,[VFATInit]
- mov [VFATNext],dh
-.next_entry:
- add si,32
- dec cx
- jnz .scanentry
-
- call nextsector
- jnc .scansector ; CF is set if we're at end
-
- ; If we get here, we failed
-.failure:
- pop es
- pop gs
- pop cx
-.alloc_failure:
- pop bx
- xor eax,eax ; ZF <- 1
- ret
-.found:
- mov eax,[gs:si+28] ; File size
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [bx+4],eax ; Sector count
-
- mov cl,[ClustShift]
- mov dx,[gs:si+20] ; High cluster word
- shl edx,16
- mov dx,[gs:si+26] ; Low cluster word
- sub edx,2
- shl edx,cl
- add edx,[DataArea]
- mov [bx],edx ; Starting sector
-
- mov eax,[gs:si+28] ; File length again
- mov dl,[gs:si+11] ; File attribute
- mov si,bx ; File pointer...
- and si,si ; ZF <- 0
-
- pop es
- pop gs
- pop cx
- pop bx
- ret
-
- section .data16
- alignz 4
- ; Note: we have no use of the first 32 bytes (header),
- ; nor of the folloing 32 bytes (case mapping of control
- ; characters), as long as we adjust the offsets appropriately.
-codepage equ $-(32+32)
-codepage_data: incbin "codepage.cp",32+32
-cp_uppercase equ codepage+cp.uppercase
-cp_unicode equ codepage+cp.unicode
-cp_unicode_alt equ codepage+cp.unicode_alt
-codepage_end equ $
-
section .text16
-;
-; Input: UCS-2 character in AX
-; Output: Single byte character in AL, ZF = 1
-; On failure, returns ZF = 0
-;
-ucs2_to_cp:
- push es
- push di
- push cx
- push cs
- pop es
- mov di,cp_unicode
- mov cx,512
- repne scasw
- xchg ax,cx
- pop cx
- pop di
- pop es
- not ax ; Doesn't change the flags!
- ret
-
- section .bss16
-VFATInit resb 1
-VFATNext resb 1
-VFATCsum resb 1
-
- section .text16
-;
-; close_file:
-; Deallocates a file structure (pointer in SI)
-; Assumes CS == DS.
-;
-close_file:
- and si,si
- jz .closed
- mov dword [si],0 ; First dword == file_sector
- xor si,si
-.closed: ret
;
; close_dir:
@@ -623,340 +186,7 @@ close_dir:
xor si,si
.closed: ret
-;
-; searchdir:
-;
-; Open a file
-;
-; On entry:
-; DS:DI = filename
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length in bytes
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES, and trashes BX and CX.
-;
-searchdir:
- mov eax,[CurrentDir]
- cmp byte [di],'/' ; Root directory?
- jne .notroot
- mov eax,[RootDir]
- inc di
-.notroot:
-
-.pathwalk:
- push eax ; <A> Current directory sector
- mov si,di
-.findend:
- lodsb
- cmp al,' '
- jbe .endpath
- cmp al,'/'
- jne .findend
-.endpath:
- 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
- call mangle_dos_name ; MangledBuf <- component
- call search_dos_dir
- pop di
- jz .notfound ; Pathname component missing
-
- cmp byte [di-1],'/' ; Do we expect a directory
- je .isdir
-
- ; Otherwise, it should be a file
-.isfile:
- test dl,18h ; Subdirectory|Volume Label
- jnz .badfile ; If not a file, it's a bad thing
-
- ; SI and EAX are already set
- mov [si+file_bytesleft],eax
- push eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [si+file_left],eax ; Sectors left
- pop eax
- and eax,eax ; EAX != 0
- jz .badfile
- ret ; Done!
-
- ; If we expected a directory, it better be one...
-.isdir:
- test dl,10h ; Subdirectory
- jz .badfile
-
- xor eax,eax
- 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:
- pm_call get_cache_block
-.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]
- je .vfat_cp_ln
- jmp .vfat_abort
-
-.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 cx,13 ; 13 characters per VFAT DIRENT
- cbw ; AH <- 0
- mul cl ; Offset for DI
- add di,ax ; Increment DI
- inc si ; Align to the real characters
-.vfat_cp_chr:
- gs lodsw ; Unicode here!!
- call ucs2_to_cp ; Convert to local codepage
- jnz .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 .bss16
- alignb 4
-PrevDir resd 1 ; Last scanned directory
-
- section .text16
;
;
@@ -971,65 +201,13 @@ kaboom2:
call getchar
call vgaclearmode
int 19h ; And try once more to boot...
-.norge: jmp short .norge ; If int 19h returned; this is the end
+.norge: jmp short .norge ; If int 19h returned; this is the end
.int18:
call vgaclearmode
int 18h
-.noreg: jmp short .noreg ; Nynorsk
+.noreg: jmp short .noreg ; Nynorsk
-;
-; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
-; to by ES:DI; ends on encountering any whitespace.
-; DI is preserved.
-;
-; This verifies that a filename is < FILENAME_MAX characters,
-; doesn't contain whitespace, zero-pads the output buffer,
-; and removes trailing dots and redundant slashes, plus changes
-; backslashes to forward slashes,
-; so "repe cmpsb" can do a compare, and the path-searching routine
-; gets a bit of an easier job.
-;
-;
-mangle_name:
- push di
- push bx
- xor ax,ax
- mov cx,FILENAME_MAX-1
- mov bx,di
-.mn_loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .mn_end
- cmp al,'\' ; Backslash?
- jne .mn_not_bs
- mov al,'/' ; Change to forward slash
-.mn_not_bs:
- cmp al,ah ; Repeated slash?
- je .mn_skip
- xor ah,ah
- cmp al,'/'
- jne .mn_ok
- mov ah,al
-.mn_ok stosb
-.mn_skip: loop .mn_loop
-.mn_end:
- cmp bx,di ; At the beginning of the buffer?
- jbe .mn_zero
- cmp byte [es:di-1],'.' ; Terminal dot?
- je .mn_kill
- cmp byte [es:di-1],'/' ; Terminal slash?
- jne .mn_zero
-.mn_kill: dec di ; If so, remove it
- inc cx
- jmp short .mn_end
-.mn_zero:
- inc cx ; At least one null byte
- xor ax,ax ; Zero-fill name
- rep stosb
- pop bx
- pop di
- ret ; Done
;
; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
@@ -1048,318 +226,7 @@ unmangle_name: call strcpy
dec di ; Point to final null byte
ret
-;
-; mangle_dos_name:
-; Mangle a DOS filename component pointed to by DS:SI
-; into [MangledBuf]; ends on encountering any whitespace or
-; slash.
-;
-; WARNING: saves pointers into the buffer for longname
-; matches!
-;
-; Assumes CS == DS == ES.
-;
-
-mangle_dos_name:
- pusha
- mov di,MangledBuf
- mov [NameStart],si
-
- mov cx,11 ; # of bytes to write
- mov bx,cp_uppercase ; Case-conversion table
-.loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .end
- cmp al,'/' ; Slash, too
- je .end
- cmp al,'.' ; Period -> space-fill
- je .is_period
- xlatb ; Convert to upper case
- mov ah,cl ; If the first byte (only!)...
- cmp ax,0BE5h ; ... equals E5 hex ...
- jne .charok
- mov al,05h ; ... change it to 05 hex
-.charok: stosb
- loop .loop ; Don't continue if too long
- ; Find the end for the benefit of longname search
-.find_end:
- lodsb
- cmp al,' '
- jna .end
- cmp al,'/'
- jne .find_end
-.end:
- dec si
- sub si,[NameStart]
- mov [NameLen],si
- mov al,' ' ; Space-fill name
- rep stosb ; Doesn't do anything if CX=0
- popa
- ret ; Done
-
-.is_period:
- mov al,' ' ; We need to space-fill
-.period_loop: cmp cx,3 ; If <= 3 characters left
- jbe .loop ; Just ignore it
- stosb ; Otherwise, write a space
- loop .period_loop ; Dec CX and *always* jump
-
- section .bss16
- alignb 2
-NameStart resw 1
-NameLen resw 1
-MangledBuf resb 11
-
- section .text16
-;
-; getfssec_edx: Get multiple sectors from a file
-;
-; This routine makes sure the subtransfers do not cross a 64K boundary,
-; and will correct the situation if it does, UNLESS *sectors* cross
-; 64K boundaries.
-;
-; ES:BX -> Buffer
-; EDX -> Current sector number
-; CX -> Sector count (0FFFFh = until end of file)
-; Must not exceed the ES segment
-; Returns EDX=0, CF=1 on EOF (not necessarily error)
-; All arguments are advanced to reflect data read.
-;
-getfssec_edx:
- push ebp
- push eax
-.getfragment:
- xor ebp,ebp ; Fragment sector count
- push edx ; Starting sector pointer
-.getseccnt:
- inc bp
- dec cx
- jz .do_read
- xor eax,eax
- mov ax,es
- shl ax,4
- add ax,bx ; Now AX = how far into 64K block we are
- not ax ; Bytes left in 64K block
- inc eax
- shr eax,SECTOR_SHIFT ; Sectors left in 64K block
- cmp bp,ax
- jnb .do_read ; Unless there is at least 1 more sector room...
- mov eax,edx ; Current sector
- inc edx ; Predict it's the linearly next sector
- call nextsector
- jc .do_read
- cmp edx,eax ; Did it match?
- jz .getseccnt
-.do_read:
- pop eax ; Starting sector pointer
- call getlinsecsr
- lea eax,[eax+ebp-1] ; This is the last sector actually read
- shl bp,9
- add bx,bp ; Adjust buffer pointer
- call nextsector
- jc .eof
- mov edx,eax
- and cx,cx
- jnz .getfragment
-.done:
- pop eax
- pop ebp
- ret
-.eof:
- xor edx,edx
- stc
- jmp .done
-
-;
-; getfssec: Get multiple sectors from a file
-;
-; Same as above, except SI is a pointer to a open_file_t
-;
-; ES:BX -> Buffer
-; DS:SI -> Pointer to open_file_t
-; CX -> Sector count (0FFFFh = until end of file)
-; Must not exceed the ES segment
-; Returns CF=1 on EOF (not necessarily error)
-; ECX returns number of bytes read.
-; All arguments are advanced to reflect data read.
-;
-getfssec:
- push edx
- movzx edx,cx
- push edx ; Zero-extended CX
- cmp edx,[si+file_left]
- jbe .sizeok
- mov edx,[si+file_left]
- mov cx,dx
-.sizeok:
- sub [si+file_left],edx
- mov edx,[si+file_sector]
- call getfssec_edx
- mov [si+file_sector],edx
- pop ecx ; Sectors requested read
- shl ecx,SECTOR_SHIFT
- cmp ecx,[si+file_bytesleft]
- ja .eof
-.noteof:
- sub [si+file_bytesleft],ecx ; CF <- 0
- pop edx
- ret
-.eof:
- mov ecx,[si+file_bytesleft]
- call close_file
- pop edx
- stc
- ret
-
-;
-; nextcluster: Advance a cluster pointer in EDI to the next cluster
-; pointed at in the FAT tables. CF=0 on return if end of file.
-;
-nextcluster:
- jmp strict short nextcluster_fat28 ; This gets patched
-
-nextcluster_fat12:
- push eax
- push edx
- push bx
- push cx
- push si
- mov edx,edi
- shr edi,1
- pushf ; Save the shifted-out LSB (=CF)
- add edx,edi
- mov eax,edx
- shr eax,9
- call getfatsector
- mov bx,dx
- and bx,1FFh
- mov cl,[gs:si+bx]
- inc edx
- mov eax,edx
- shr eax,9
- call getfatsector
- mov bx,dx
- and bx,1FFh
- mov ch,[gs:si+bx]
- popf
- jnc .even
- shr cx,4
-.even: and cx,0FFFh
- movzx edi,cx
- cmp di,0FF0h
- pop si
- pop cx
- pop bx
- pop edx
- pop eax
- ret
-
-;
-; FAT16 decoding routine.
-;
-nextcluster_fat16:
- push eax
- push si
- push bx
- mov eax,edi
- shr eax,SECTOR_SHIFT-1
- call getfatsector
- mov bx,di
- add bx,bx
- and bx,1FEh
- movzx edi,word [gs:si+bx]
- cmp di,0FFF0h
- pop bx
- pop si
- pop eax
- ret
-;
-; FAT28 ("FAT32") decoding routine.
-;
-nextcluster_fat28:
- push eax
- push si
- push bx
- mov eax,edi
- shr eax,SECTOR_SHIFT-2
- call getfatsector
- mov bx,di
- add bx,bx
- add bx,bx
- and bx,1FCh
- mov edi,dword [gs:si+bx]
- and edi,0FFFFFFFh ; 28 bits only
- cmp edi,0FFFFFF0h
- pop bx
- pop si
- pop eax
- ret
-
-;
-; nextsector: Given a sector in EAX on input, return the next sector
-; of the same filesystem object, which may be the root
-; directory or a cluster chain. Returns EOF.
-;
-; Assumes CS == DS.
-;
-nextsector:
- push edi
- push edx
- mov edx,[DataArea]
- mov edi,eax
- sub edi,edx
- jae .isdata
-
- ; Root directory
- inc eax
- cmp eax,edx
- cmc
- jmp .done
-
-.isdata:
- not edi
- test edi,[ClustMask]
- jz .endcluster
-
- ; It's not the final sector in a cluster
- inc eax
- jmp .done
-
-.endcluster:
- push gs ; nextcluster trashes gs
- push cx
- not edi
- mov cl,[ClustShift]
- shr edi,cl
- add edi,2
-
- ; Now EDI contains the cluster number
- call nextcluster
- cmc
- jc .exit ; There isn't anything else...
-
- ; New cluster number now in EDI
- sub edi,2
- shl edi,cl ; CF <- 0, unless something is very wrong
- lea eax,[edi+edx]
-.exit:
- pop cx
- pop gs
-.done:
- pop edx
- pop edi
- ret
-
-;
-; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
-; and return a pointer in GS:SI, loading it if needed.
-;
-; Assumes CS == DS.
-;
-getfatsector:
- add eax,[FAT] ; FAT starting address
- pm_call get_cache_block
+
; -----------------------------------------------------------------------------
; Common modules