⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loaderc.c

📁 boot loader bing--boot.asm for fdd and loader c++ -startup.asm
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
xxx - support RDSK and ELF files
xxx - load RDSK files into extended memory if too little conventional memory
xxx - let user change "Physical load address" and "Store boot data in BSS"
xxx - fat_mount() should get hard drive geometry -- somehow
	INT 13h AH=08h should be OK for hard disk (not for floppy, though)
(later)
xxx - let user browse different disks/partitions
xxx - use XMS to access extended memory if HIMEM.SYS loaded
xxx - use VCPI to switch to pmode if EMM386 loaded
xxx - support DOS .EXE files, DOS .COM files, and chainloaded bootsectors
xxx - support binary kernel (let user change load adr, entry point, etc.)
xxx - support ext2 filesystem
*****************************************************************************/
/* portability! These assume sizeof(short)==2 and sizeof(long)==4
They also assume a little-endian CPU like x86.
Big-endian CPUs will need byte-swapping functions here. */
#define	read_le16(X)	*(unsigned short *)(X)
#define	read_le32(X)	*(unsigned long *)(X)

/* some functions return -1 when I don't know what else to return */
#define	ERR_EOF		-2	/* end of file */
#define	ERR_IO		-3	/* disk read error */
#define	ERR_MEM		-4	/* out of memory */
#define	ERR_SW		-5	/* software error ("can't happen") */
#define	ERR_FILE	-6	/* invalid file format */
#define	ERR_FILESYSTEM	-7

#define	SEEK_SET	0
#define	SEEK_CUR	1
#define	SEEK_END	2

/* "An inode is an [unique] integer associated with a file on the filesystem."
For FAT, we use the first cluster of the file as the inode */
typedef unsigned short	inode_t;

typedef unsigned long	sector_t;

typedef unsigned long	pos_t;

typedef struct
{
	unsigned char int13_dev;
	unsigned short sects, heads, bytes_per_sector;
} dev_t;

typedef struct
{
	pos_t pos;
	struct _mount *mount;
	inode_t inode;
	unsigned long file_size;
	unsigned is_dir : 1;
	char name[16]; /* xxx - 16 is arbitrary...maybe use malloc()? */
} file_t;

typedef struct
{
	int (*open_root)(file_t *root_dir, struct _mount *mount);
	int (*readdir)(file_t *dir, file_t *file);
	int (*read)(file_t *file, unsigned char *buf, unsigned len);
/*	void *info; */
	unsigned char info[64]; /* xxx - use malloc() */
} fsinfo_t;

typedef struct _mount
{
	dev_t *dev;
	fsinfo_t fsinfo;
	sector_t partition_start;
	inode_t curr_dir;
} mount_t;

/* non-standard (not ANSI nor UNIX) I/O functions, but they were
eaiser to write than open(), readdir(), etc. (and more efficient,
since they deal directly with inodes, rather than path names) */
static int my_seek(file_t *file, long offset, int whence);
static int my_read(file_t *file, void *buf, unsigned len);
static int my_close(file_t *file);

static void cprintf(const char *fmt, ...);

static mount_t _mount;
/*////////////////////////////////////////////////////////////////////////////
	READ-ONLY DISK CODE AND CACHE
////////////////////////////////////////////////////////////////////////////*/
#include <bios.h> /* biosdisk() */

#define	MAX_CACHE	32	/* 32 sectors == 16K */
#define	BPS		512	/* bytes per sector */

typedef struct
{
	sector_t sector;
	unsigned char blk[BPS];
} cache_t;
/*****************************************************************************
*****************************************************************************/
static int read_sector(dev_t *dev, sector_t sector, unsigned char **blk)
{
	static unsigned char init, evict;
	static cache_t cache[MAX_CACHE];
/* */
	unsigned short c, h, s, temp;
	unsigned char tries;

	if(!init)
	{
		init = 1;
		for(temp = 0; temp < MAX_CACHE; temp++)
			cache[temp].sector = -1uL;
	}
/* see if this sector is cached */
	for(temp = 0; temp < MAX_CACHE; temp++)
	{
		if(cache[temp].sector == sector)
		{
			(*blk) = cache[temp].blk;
			return 0;
		}
	}
/* not cached, find a free buffer for it */
	for(temp = 0; temp < MAX_CACHE; temp++)
	{
		if(cache[temp].sector == -1uL)
			break;
	}
/* no free buffer, kick out someone else */
	if(temp >= MAX_CACHE)
	{
		temp = evict;
		evict++;
		if(evict >= MAX_CACHE)
			evict = 0;
	}
/* load it */
	cache[temp].sector = sector;
	(*blk) = cache[temp].blk;
/* we can load sector 0 even if we don't know the disk geometry
(which is good, because FAT uses sector 0 to store floppy geometry info) */
	if(sector == 0)
	{
		s = 1;
		h = 0;
		c = 0;
	}
	else
	{
		s = sector % dev->sects + 1;
		h = (sector / dev->sects) % dev->heads;
		c = (sector / dev->sects) / dev->heads;
	}
/* make 3 attempts */
	for(tries = 3; tries != 0; tries--)
	{
		temp = biosdisk(/* _DISK_READ */2, dev->int13_dev,
			h, c, s, 1, *blk);
/* biosdisk() does not return what the Turbo C online help says.
It returns the AH value from INT 13h, not AX
		temp >>= 8; */
		if(temp == 0 || temp == 0x11)
			return 0;
/* reset FDC if error */
		(void)biosdisk(/* _DISK_RESET */0, dev->int13_dev,
			0, 0, 0, 0, 0);
	}
	cprintf("\n\rread_sector: INT 13h disk error 0x%02X, CHS=%u:%u:%u, "
		"dev=0x%02X, *blk=%p\n\r", temp, c, h, s,
		dev->int13_dev, *blk);
	return ERR_IO;
}
/*///////////////////////////////////////////////////////////////////////////
	FAT12/16 FILESYSTEM
////////////////////////////////////////////////////////////////////////////*/
/* NULL, memset, memcmp, memcpy, strchr, strlen, strcpy, strupr, strchr */
#include <string.h>

#define	min(a,b)	(((a) < (b)) ? (a) : (b))

/* bytes per FAT directory entry */
#define	FAT_DIRENT_LEN		32
/* FAT entries 0 and 1 are reserved: */
#define	MAGIC_FAT_CLUSTER	0
#define	MAGIC_ROOT_CLUSTER	1

typedef enum
{
	FAT12, FAT16, FAT32
} fat_type_t;

typedef struct
{
	unsigned short max_cluster;
	unsigned char sectors_per_cluster;
	sector_t fat_start, root_start, data_start;
	fat_type_t fat_type;
} fat_t;
/*****************************************************************************
e.g. "foo.i" -> "FOO     I  "
'dst' must be >=12 bytes
*****************************************************************************/
static int fat_convert_name_to_fat(char *dst, char *src)
{
	unsigned len;
	char *dot;

/* put src in FAT format */
	memset(dst, ' ', 11);
	dst[11] = '\0';
	dot = strchr(src, '.');

/* xxx - why? trouble with Turbo C 2.0 installation? */
#define NULL 0

/* there is an extension */
	if(dot != NULL)
	{
/* long filenames not supported */
		len = dot - src;
		if(len > 8)
			return ERR_FILESYSTEM;
/* copy filename */
		memcpy(dst, src, len);
		dst[len] = '\0';
/* long extension not supported */
		len = strlen(dot) - 1;
		if(len > 3)
			return ERR_FILESYSTEM;
/* copy extension */
		memcpy(dst + 8, dot + 1, len);
	}
/* no extension */
	else
	{
/* long filenames not supported */
		len = strlen(src);
		if(len > 8)
			return ERR_FILESYSTEM;
/* copy filename */
		strcpy(dst, src);
	}
/* make it upper case */
	strupr(dst);
	return 0;
}
/*****************************************************************************
e.g. "README  TXT" -> "readme.txt"
'dst' must be >=12 bytes
*****************************************************************************/
static void fat_convert_name_from_fat(char *dst, char *src)
{
	unsigned char i;
	char *d = dst;

	for(i = 0; i < 8; i++)
	{
		if(src[i] == ' ')
			break;
		*d = src[i];
		d++;
	}
	if(src[8] != ' ')
	{
		*d = '.';
		d++;
		for(i = 8; i < 11; i++)
		{
			if(src[i] == ' ')
				break;
			*d = src[i];
			d++;
		}
	}
	*d = '\0';
/* make it lower case */
	strlwr(dst);
}
/*****************************************************************************
*****************************************************************************/
static int fat_open_root(file_t *root_dir, mount_t *mount)
{
	root_dir->pos = 0;
	root_dir->mount = mount;
	root_dir->inode = MAGIC_ROOT_CLUSTER;
	root_dir->file_size = -1uL; /* xxx - get root dir size */
	root_dir->is_dir = 1;
	strcpy(root_dir->name, "/");
	return 0;
}
/*****************************************************************************
FAT file attribute bits:
Bit(s)	Description	(Table 01401)
 0	read-only
 1	hidden
 2	system
 3	volume label or LFN
 4	directory
 5	archive
 6	?
 7	if set, file is shareable under Novell NetWare
*****************************************************************************/
static int fat_readdir(file_t *dir, file_t *file)
{
	char dirent[FAT_DIRENT_LEN];
	int err;

	while(1)
	{
/* read one 32-byte FAT directory entry */
		err = my_read(dir, dirent, FAT_DIRENT_LEN);
		if(err != FAT_DIRENT_LEN)
		{
/* short read means end of dir */
			if(err >= 0)
				return ERR_EOF;
			return err;
		}
/* "virgin" dir entry means end of dir, for both root dir and subdir */
		if(dirent[0] == 0)
			return ERR_EOF;
/* deleted file */
		if(dirent[0] == 5 || dirent[0] == '\xE5')
			continue;
/* volume label or LFN */
		if((dirent[11] & 0x08) == 0)
			break;
	}
/* found it! */
	file->pos = 0;
	file->mount = dir->mount;
	file->inode = read_le16(dirent + 26);
	file->file_size = read_le32(dirent + 28);
	if(dirent[11] & 0x10)
		file->is_dir = 1;
	else
		file->is_dir = 0;
	fat_convert_name_from_fat(file->name, dirent);
/* inode==0 is actually a pointer to the root directory */
	if(file->inode == 0)
	{
		if(file->is_dir)
			file->inode = MAGIC_ROOT_CLUSTER;
/* ...but only for directories */
		else
			return -1;
	}
/* xxx - corrupt filesystem; not software error */
	else if(file->inode < 2)
		return ERR_SW;
/* I guess FAT doesn't store the correct size of subdirectories
in the directory entry */
	if(file->file_size == 0)
	{
		if(file->is_dir)
			file->file_size = -1uL;
/* else it's a zero-length file, which is cool */
	}
	return 0;
}
/*****************************************************************************
convert 'cluster' to 'sector', then advance to next cluster in FAT chain
and store next cluster at 'cluster'
*****************************************************************************/
static int fat_walk(file_t *file, sector_t *sector, unsigned short *cluster)
{
	unsigned char buf[2];
	unsigned short entry;
	file_t the_fat;
	sector_t temp;
	fat_t *fat;
	int err;

/* xxx - init the_fat properly */
	fat = (fat_t *)(file->mount->fsinfo.info);
	the_fat.mount = file->mount;
	the_fat.inode = MAGIC_FAT_CLUSTER;
	the_fat.file_size = -1uL;
/* must be cluster within data area of disk */
	temp = (*cluster);
	if(temp < 2)
		return ERR_SW; /* can't (shouldn't) happen */
	temp -= 2;
/* convert cluster to sector */
	temp *= fat->sectors_per_cluster;
	temp += fat->data_start;
	(*sector) = temp;
/* now convert cluster to byte offset into FAT */
	temp = (*cluster);
	if(fat->fat_type == FAT12)
	{
/* 12 bits per FAT entry, so byte offset into FAT is 3/2 * temp */
		temp *= 3;
		the_fat.pos = temp >> 1;
/* read 2-byte entry */
		err = my_read(&the_fat, buf, 2);
		if(err < 0)
			return err;
		entry = read_le16(buf);
/* top 12 bits or bottom 12 bits? */
		if(temp & 1)
			entry >>= 4;
		else
			entry &= 0x0FFF;
	}
	else if(fat->fat_type == FAT16)
	{
/* 16 bits per FAT entry */
		temp <<= 1;
		the_fat.pos = temp;
/* read 2-byte entry */
		err = my_read(&the_fat, buf, 2);
		if(err < 0)
			return err;
		entry = read_le16(buf);
	}
	else
	{
		cprintf("fat_walk: FAT32 not yet supported\n\r");
		return ERR_SW;
	}
/* that's what we want! */
	(*cluster) = entry;
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int fat_read_sector(file_t *file, sector_t rel_sector,
		unsigned char **blk)
{
	unsigned short rel_cluster, abs_cluster;
	sector_t abs_sector;
	fsinfo_t *fsinfo;
	mount_t *mount;
	dev_t *dev;
	fat_t *fat;
	int err;

	mount = file->mount;
	dev = mount->dev;
	fsinfo = &mount->fsinfo;
	fat = (fat_t *)fsinfo->info;
	abs_cluster = file->inode;
/* starting cluster == 0: read from FAT */
	if(abs_cluster == MAGIC_FAT_CLUSTER)
	{
		abs_sector = fat->fat_start + rel_sector;
		if(abs_sector >= fat->root_start)
			return ERR_EOF;
	}
/* starting cluster == 1: read from root directory */
	else if(abs_cluster == MAGIC_ROOT_CLUSTER)
	{
		abs_sector = fat->root_start + rel_sector;
		if(abs_sector >= fat->data_start)
			return ERR_EOF;
	}
/* starting cluster >= 2: normal read from data area of disk */
	else
	{
/* cluster within file */
		rel_cluster = rel_sector / fat->sectors_per_cluster;
/* sector within cluster */
		rel_sector %= fat->sectors_per_cluster;
/* chase clusters, so we go from relative cluster (cluster-within-file)... */
		for(;;)
		{
			if(abs_cluster > fat->max_cluster)
				return ERR_EOF;
			err = fat_walk(file, &abs_sector, &abs_cluster);
			if(err != 0)
				return err;
			if(rel_cluster == 0)
				break;
			rel_cluster--;
		}
/* ...to absolute cluster (cluster-within-disk). fat_walk() also
converted cluster to sector, so add things together to get the
absolute sector number (finally!) */
		abs_sector += rel_sector;
	}
/* load it */
	return read_sector(dev, mount->partition_start + abs_sector, blk);
}
/*****************************************************************************
*****************************************************************************/
static int fat_read(file_t *file, unsigned char *buf, unsigned want)
{
	unsigned short byte_in_sector;
	sector_t rel_sector;
	unsigned got, count;
	unsigned char *blk;
	mount_t *mount;
	dev_t *dev;
	int err;

	if(want == 0)
		return 0;
	mount = file->mount;
	dev = mount->dev;
	count = 0;
	do
	{
		rel_sector = file->pos;
/* byte within sector */
		byte_in_sector = rel_sector % dev->bytes_per_sector;
/* sector within file */
		rel_sector /= dev->bytes_per_sector;
/* read the sector */
		err = fat_read_sector(file, rel_sector, &blk);
		if(err < 0)
			return err;
/* how many bytes can we read from this sector? */
		got = dev->bytes_per_sector - byte_in_sector;
/* nearing end of file? */
		if(file->pos + got > file->file_size)
			got = file->file_size - file->pos;
		if(got == 0)
			break;
/* how many will we actually read from it? */
		got = min(got, want);
/* read them */
		memcpy(buf, blk + byte_in_sector, got);
/* done with this sector
maybe I will need a function like this later?
		uncache_sector(file, sector, blk); */
/* advance pointers */
		file->pos += got;
		buf += got;
		want -= got;
		count += got;
/* done? */
	} while(want != 0);
	return count;
}
/*****************************************************************************
*****************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -