📄 loaderc.c
字号:
/* #include <stdlib.h> malloc() */
static int fat_mount(mount_t *mount, dev_t *dev, unsigned char part)
{
unsigned char *blk, *ptab_rec; /* partition table record */
unsigned long total_sectors;
fat_type_t fat_type;
fsinfo_t *fsinfo;
fat_t *fat;
int err;
mount->curr_dir = MAGIC_ROOT_CLUSTER;
dev->bytes_per_sector = BPS;
/* floppy */
if(dev->int13_dev < 0x80)
{
fat_type = FAT12;
/* read sector 0 of floppy (boot sector) */
mount->partition_start = 0;
err = read_sector(dev, mount->partition_start, &blk);
if(err != 0)
return err;
/* make sure it's a FAT disk */
if((blk[0] != 0xEB && blk[0] != 0xE9) || /* JMP (SHORT) */
read_le16(blk + 0x0B) != 512 || /* bytes/sector */
blk[0x0D] != 1 || /* sectors/cluster */
blk[0x15] != 0xF0 || /* media ID */
blk[0x1A] != 2) /* heads */
{
NOT: cprintf("Partition %u on drive 0x%02X is "
"not a FAT12 or FAT16 partition\n\r",
part, dev->int13_dev);
return -1;
}
/* read disk geometry from BIOS Parameter Block (BPB) of FAT boot sector */
dev->sects = read_le16(blk + 0x18);
dev->heads = read_le16(blk + 0x1A);
}
/* hard disk */
else
{
if(part > 3)
{
cprintf("fat_mount: partition number must be 0-3\n\r");
return -1;
}
/* read sector 0 of hard disk (MBR; partition table) */
err = read_sector(dev, 0, &blk);
if(err != 0)
return err;
/* xxx - finish initializing dev */
dev->sects = 63;
dev->heads = 255;
/* point to 16-byte partition table record */
ptab_rec = blk + 446 + 16 * part;
switch(ptab_rec[4])
{
case 1:
fat_type = FAT12;
break;
case 4:
fat_type = FAT16; /* up to 32 meg */
break;
case 6:
fat_type = FAT16; /* DOS 3.31+, >32 meg */
break;
default:
goto NOT;
}
mount->partition_start = read_le32(ptab_rec + 8);
/* read sector 0 of partition (boot sector) */
err = read_sector(dev, mount->partition_start, &blk);
if(err != 0)
return err;
/* make sure it's a FAT disk */
if((blk[0] != 0xEB && blk[0] != 0xE9) || /* JMP (SHORT) */
read_le16(blk + 0x0B) != 512) /* bytes/sector */
goto NOT;
}
/* fat = malloc(sizeof(fat_t));
if(fat == NULL)
return ERR_MEM; */
mount->dev = dev;
/* init mount->fsinfo */
fsinfo = &mount->fsinfo;
fat = (fat_t *)fsinfo->info;
fsinfo->open_root = fat_open_root;
fsinfo->readdir = fat_readdir;
fsinfo->read = fat_read;
/* init mount->fsinfo->info
fsinfo->info = fat; */
memcpy(fsinfo->info, fat, sizeof(fat));
fat = (fat_t *)fsinfo->info;
fat->sectors_per_cluster = blk[13];
fat->fat_start = read_le16(blk + 14); /* reserved_sectors */
fat->root_start = fat->fat_start +
blk[16] * /* num_fats */
read_le16(blk + 22); /* sectors_per_fat */
fat->data_start = fat->root_start +
(FAT_DIRENT_LEN * /* bytes_per_dir_ent */
read_le16(blk + 17)) / /* num_root_dir_ents */
BPS; /* bytes_per_sector */
total_sectors = read_le16(blk + 19);
if(total_sectors == 0)
total_sectors = read_le32(blk + 32);
fat->max_cluster = total_sectors /
fat->sectors_per_cluster -
fat->data_start - 1;
fat->fat_type = fat_type;
#if 0
cprintf("disk CHS=??:%u:%u\n\r", dev->heads, dev->sects);
cprintf("drive 0x%02X, partition %u: %s partition starting at sector %lu\n\r",
dev->int13_dev, part, fat->fat_type == FAT12 ? "FAT12" : "FAT16",
mount->partition_start);
cprintf("%u sector(s)/cluster, ", fat->sectors_per_cluster);
cprintf("%u FATs, ", blk[0x10]);
cprintf("root at sector %lu, ", fat->root_start);
cprintf("data at sector %lu\n\r", fat->data_start);
cprintf("FAT(s) at sector %lu, ", fat->fat_start);
cprintf("%u entries in root dir, ", read_le16(blk + 0x11));
cprintf("%lu total sectors ", total_sectors);
if(total_sectors >= 16384)
cprintf("(%luM)\n\r\n\r", total_sectors / 2048);
else
cprintf("(%luK)\n\r\n\r", total_sectors / 2);
#endif
return 0;
}
/*////////////////////////////////////////////////////////////////////////////
VFS
////////////////////////////////////////////////////////////////////////////*/
/*****************************************************************************
read directory entry from directory 'dir'
stores entry at 'file' (we use file_t instead of a DIR type)
*****************************************************************************/
static int my_readdir(file_t *dir, file_t *file)
{
fsinfo_t *fsinfo;
mount_t *mount;
mount = dir->mount;
fsinfo = &mount->fsinfo;
return fsinfo->readdir(dir, file);
}
/*****************************************************************************
find file 'name' in already-opened directory 'dir';
stores result at 'file' if success
*****************************************************************************/
static int my_find(file_t *dir, file_t *file, char *name)
{
int err;
/* seek to beginning of dir */
err = my_seek(dir, 0, SEEK_SET);
if(err != 0)
return err;
/* read one 32-byte directory entry */
do
{
err = my_readdir(dir, file);
if(err != 0)
return err;
} while(strcmp(name, file->name));
return 0;
}
/*****************************************************************************
convert path from relative to absolute, if necessary?
remove superfluous components of path (e.g. /./ )?
figure out mount point based on absolute path?
*****************************************************************************/
static int my_open(file_t *file, char *path)
{
char done = 0, *slash;
file_t search_dir;
fsinfo_t *fsinfo;
mount_t *mount;
int err;
file->mount = mount = &_mount;
fsinfo = &mount->fsinfo;
if(path[0] == '/')
{
/* skip first '/' */
path++;
/* open root dir */
err = fsinfo->open_root(&search_dir, mount);
if(err != 0)
return err;
/* done already? */
if(path[0] == '\0')
{
memcpy(file, &search_dir, sizeof(file_t));
return 0;
}
}
/* xxx - relative pathnames are not yet handled */
else
return -1;
done = 0;
do
{
/* pick out one name in path */
slash = strchr(path, '/');
if(slash == NULL)
{
slash = path + strlen(path);
done = 1;
}
*slash = '\0';
/* find file/dir of this name in search_dir */
err = my_find(&search_dir, file, path);
if(err != 0)
{
my_close(&search_dir);
return err;
}
if(done)
break;
/* CD to subdirectory */
memcpy(&search_dir, file, sizeof(file_t));
/* advance to next name+ext pair in pathname
+1 to skip '/' */
path = slash + 1;
} while(path[0] != '\0');
return 0;
}
/*****************************************************************************
*****************************************************************************/
static int my_read(file_t *file, void *buf, unsigned len)
{
fsinfo_t *fsinfo;
mount_t *mount;
mount = file->mount;
fsinfo = &mount->fsinfo;
return fsinfo->read(file, buf, len);
}
/*****************************************************************************
*****************************************************************************/
static int my_seek(file_t *file, long offset, int whence)
{
switch(whence)
{
case SEEK_SET:
/* nothing */
break;
case SEEK_CUR:
offset += file->pos;
break;
case SEEK_END:
offset = (file->file_size - 1) - offset;
break;
default:
return -1;
}
if(offset < 0)
offset = 0;
else if(offset >= file->file_size - 1)
offset = file->file_size - 1;
file->pos = offset;
return 0;
}
/*****************************************************************************
*****************************************************************************/
#pragma argsused
static int my_close(file_t *file)
{
return 0;
}
/*////////////////////////////////////////////////////////////////////////////
CONSOLE ROUTINES
////////////////////////////////////////////////////////////////////////////*/
#include <stdarg.h> /* va_list, va_start(), va_end() */
#include <string.h> /* strlen() */
#include <dos.h> /* struct REGPACK, intr() */
/* note that Turbo C 2.0 intr() is buggy (doesn't load register BP properly),
so I've written my own version in LOADERA.ASM */
int vsprintf(char *, const char *, void *);
static unsigned char _attrib = 0x07; /* white on black */
/*****************************************************************************
*****************************************************************************/
static void gotoxy(unsigned char x, unsigned char y)
{
struct REGPACK regs;
regs.r_dx = y;
regs.r_dx <<= 8;
regs.r_dx |= x;
regs.r_bx = 0; /* BH=video page 0 */
regs.r_ax = 0x0200; /* AH=subfunction 2 (move csr) */
intr(0x10, ®s);
}
/*****************************************************************************
*****************************************************************************/
static void textattr(int a)
{
_attrib = a;
}
/*****************************************************************************
*****************************************************************************/
static void cprintf(const char *fmt, ...)
{
struct REGPACK regs;
char buf[200];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
regs.r_bx = 0; /* BH=video page 0 */
regs.r_ax = 0x0300; /* AH=subfunction 3: get cursor pos to DH,DL */
intr(0x10, ®s);
regs.r_es = _DS;
regs.r_bp = (unsigned)buf;
regs.r_cx = strlen(buf);
regs.r_bx = _attrib; /* BH=video page 0, BL=attribute */
regs.r_ax = 0x1301; /* AH=subfunction 13h, AL=write mode 1 */
intr(0x10, ®s);
}
/*****************************************************************************
*****************************************************************************/
static int getch(void)
{
static short prev = -1;
struct REGPACK regs;
int ret_val;
if(prev != -1)
{
ret_val = prev;
prev = -1;
}
else
{
regs.r_ax = 0; /* AH=subfunction 0 (get key) */
intr(0x16, ®s);
ret_val = regs.r_ax & 0xFF;
if(ret_val == 0)
{
regs.r_ax >>= 8;
prev = regs.r_ax;
}
}
return ret_val;
}
/*****************************************************************************
*****************************************************************************/
static void erase_screen(unsigned char x, unsigned char y,
unsigned char wd, unsigned char ht)
{
struct REGPACK regs;
regs.r_ax = 0x0600; /* AH=subfunction 6 (scroll), AH=0 (erase) */
regs.r_bx = _attrib;
regs.r_bx <<= 8; /* BH=attribute */
regs.r_cx = y;
regs.r_cx <<= 8; /* CH=row */
regs.r_cx |= x; /* CL=col */
regs.r_dx = (y + ht - 1);
regs.r_dx <<= 8; /* DH=height */
regs.r_dx |= (x + wd - 1);/* DL=width */
intr(0x10, ®s);
}
/*////////////////////////////////////////////////////////////////////////////
KERNEL FILES
////////////////////////////////////////////////////////////////////////////*/
#define MAX_SECT 4
typedef struct /* section in executable file */
{
char sect_name[12];
unsigned long adr, size, off;
/* section flags */
unsigned bss : 1;
unsigned read : 1;
unsigned write : 1;
unsigned exec : 1;
} sect_t;
typedef struct /* entire executable file */
{
unsigned long entry_pt;
unsigned short num_sections;
sect_t section[MAX_SECT];
char format_name[32];
unsigned pmode : 1;
unsigned cosmos : 1;
} exec_t;
/*****************************************************************************
returns -1 if file is not COFF,
returns ERR_FILE if invalid COFF file,
*****************************************************************************/
/* COFF file header */
#define COFF_FILE_MAGIC 0 /* 0x014C */
#define COFF_FILE_SECT_NUM 2 /* number of sections */
#define COFF_FILE_TIMEDATE 4 /* time and date stamp */
#define COFF_FILE_SYMTAB_OFF 8 /* file offset of symbol table */
#define COFF_FILE_SYMTAB_NUM 12 /* number of symtab entries */
#define COFF_FILE_OPTHDR_SIZE 16 /* "optional" (aout) header size */
#define COFF_FILE_FLAGS 18
/* 20 bytes to here */
#define COFF_FILE_HDRLEN 20
#define COFF_AOUT_MAGIC 20 /* 0x010B */
#define COFF_AOUT_VER 22
#define COFF_AOUT_CODE_SIZE 24
#define COFF_AOUT_DATA_SIZE 28
#define COFF_AOUT_BSS_SIZE 32
#define COFF_AOUT_ENTRY 36 /* initial EIP */
#define COFF_AOUT_CODE_BASE 40
#define COFF_AOUT_DATA_BASE 44
/* 48 bytes to here */
#define AOUT_FILE_HDRLEN 48
/* COFF section header */
#define COFF_SECT_NAME 0 /* ".text", ".data", etc. */
#define COFF_SECT_PADR 8 /* physical adr */
#define COFF_SECT_VADR 12 /* virtual adr */
#define COFF_SECT_SIZE 16
#define COFF_SECT_OFF 20 /* file offset of section */
#define COFF_SECT_RELOC_OFF 24 /* file offset of relocations */
#define COFF_SECT_LINENUM_OFF 28 /* file offset of line number info */
#define COFF_SECT_RELOC_NUM 32 /* number of relocations */
#define COFF_SECT_LINENUM_NUM 34 /* number of line numbers */
#define COFF_SECT_FLAGS 36
/* 40 bytes long */
#define COFF_SECT_HDRLEN 40
static int read_coff_file(exec_t *exec, file_t *file, unsigned long offset)
{
unsigned char file_hdr[AOUT_FILE_HDRLEN], sect_hdr[COFF_SECT_HDRLEN];
unsigned short aout_hdrlen, i;
sect_t *sect;
int temp;
(void)my_seek(file, offset, SEEK_SET);
/* read file header and a.out header */
temp = my_read(file, file_hdr, AOUT_FILE_HDRLEN);
if(temp < 0)
return temp;
/* short file is not a COFF file
return -1 instead of ERR_FILE */
if(temp != AOUT_FILE_HDRLEN)
return -1;
if(read_le16(file_hdr + COFF_FILE_MAGIC) != 0x014C)
return -1;
/* OK, it's COFF. Check for 3 sections (.text, .data, .bss) */
exec->num_sections = read_le16(file_hdr + COFF_FILE_SECT_NUM);
if(exec->num_sections != 3)
{
ERR: cprintf("invalid COFF file");
/* oops, I thought it was COFF... */
return ERR_FILE;
}
/* check flags for F_EXEC */
if((read_le16(file_hdr + COFF_FILE_FLAGS) & 0x0002) == 0)
goto ERR;
if(read_le16(file_hdr + COFF_AOUT_MAGIC) != 0x010B)
goto ERR;
aout_hdrlen = read_le16(file_hdr + COFF_FILE_OPTHDR_SIZE);
exec->entry_pt = read_le32(file_hdr + COFF_AOUT_ENTRY);
/* skip to first section */
my_seek(file, offset + COFF_FILE_HDRLEN + aout_hdrlen, SEEK_SET);
sect = exec->section;
for(i = 0; i < exec->num_sections; i++)
{
/* read section header */
temp = my_read(file, sect_hdr, COFF_SECT_HDRLEN);
if(temp != COFF_SECT_HDRLEN)
goto ERR;
/* code; STYP_TEXT */
if(!memcmp(sect_hdr + COFF_SECT_NAME, ".text", 5) &&
(read_le32(sect_hdr + COFF_SECT_FLAGS) & 0xE0) == 0x20)
{
sect->exec = 1;
sect->size = read_le32(sect_hdr + COFF_SECT_SIZE);
}
/* data; STYP_DATA */
else if(!memcmp(sect_hdr + COFF_SECT_NAME, ".data", 5) &&
(read_le32(sect_hdr + COFF_SECT_FLAGS) & 0xE0) == 0x40)
{
sect->write = 1;
sect->size = read_le32(sect_hdr + COFF_SECT_SIZE);
}
/* BSS; STYP_BSS */
else if(!memcmp(sect_hdr + COFF_SECT_NAME, ".bss", 5) &&
(read_le32(sect_hdr + COFF_SECT_FLAGS) & 0xE0) == 0x80)
{
sect->bss = 1;
sect->write = 1;
sect->size = read_le32(file_hdr + COFF_AOUT_BSS_SIZE);
/* sect->size = read_le32(sect_hdr + COFF_SECT_SIZE);*/
}
/* anything else */
else
{
cprintf("bad section '%-8.8s' in COFF file",
(char *)sect_hdr + COFF_SECT_NAME);
return ERR_FILE;
}
sect->read = 1;
strcpy(sect->sect_name, (char *)sect_hdr + COFF_SECT_NAME);
sect->off = read_le32(sect_hdr + COFF_SECT_OFF);
/* sect->adr = read_le32(sect_hdr + COFF_SECT_PADR); */
sect->adr = read_le32(sect_hdr + COFF_SECT_VADR);
sect++;
}
strcpy(exec->format_name, "DJGPP COFF");
exec->pmode = 1;
return 0;
}
/*****************************************************************************
returns -1 if file is not PE,
returns ERR_FILE if invalid PE file,
*****************************************************************************/
static int read_pe_file(exec_t *exec, file_t *file, unsigned long offset)
{
unsigned long new_exe_offset;
unsigned char buf[64];
int temp;
(void)my_seek(file, offset, SEEK_SET);
/* read DOS "MZ" EXE file header */
temp = my_read(file, buf, 64);
if(temp < 0)
return temp;
/* short file is not a PE file
return -1 instead of temp_FILE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -