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

📄 boot.c

📁 一个类linux的dos下开发的操作系统.
💻 C
📖 第 1 页 / 共 5 页
字号:
	int err;

	dst = sect->adr + virt_to_phys;
	for(size = sect->size; size != 0; )
	{
		count = (size > BUF_SIZE) ? BUF_SIZE : size;
		err = copy_extended_memory(dst, to_linear(_zeroes), count);
		if(err != 0)
			return err;
		size -= count;
		dst += count;
	}
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int copy_pmode_kernel(exec_t *exec, unsigned long virt_to_phys)
{
	unsigned short i;
	sect_t *sect;
	int err;

	sect = exec->section + 0;
	for(i = 0; i < exec->num_sections; i++)
	{
		if(sect->load)
		{
			err = copy_pmode_section(sect, virt_to_phys);
			if(err != 0)
				return err;
		}
		else if(sect->zero)
		{
			err = zero_pmode_bss(sect, virt_to_phys);
			if(err != 0)
				return err;
/* store Cosmos-compatible boot data in BSS
conventional memory size */
			*(unsigned long *)(_zeroes + 0) = _conv_mem_size;
/* extended memory size */
			*(unsigned long *)(_zeroes + 4) = _ext_mem_size;
/* linear address of loaded RDSK file */
			*(unsigned long *)(_zeroes + 8) =
				to_linear(_conv_mem);
/* RDSK file size */
			*(unsigned long *)(_zeroes + 12) = _file_size;
			err = copy_extended_memory(sect->adr + virt_to_phys,
				to_linear(_zeroes), BUF_SIZE);
			if(err != 0)
				return err;
		}
		sect++;
	}
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int load_pmode_kernel(exec_t *exec, unsigned long virt_to_phys,
		unsigned handle)
{
	unsigned short i, progress, incr;
	unsigned long dst, size, pos;
	unsigned char buf[BUF_SIZE];
	int temp, err;
	sect_t *sect;

	sect = exec->section + 0;
/* 3l33t progress bargraph :) */
	cprintf("Loading: [                                "
		"                   ]\r"
		"Loading: [");
	incr = _file_size / 50;	/* 2% increments */
	progress = 0;
	pos = 0;
	for(i = 0; i < exec->num_sections; i++)
	{
		dst = sect->adr + virt_to_phys;
		if(sect->load)
		{
			lseek(handle, sect->off, SEEK_SET);
			for(size = sect->size; size != 0; )
			{
				temp = size < BUF_SIZE ? size : BUF_SIZE;
				temp = read(handle, buf, temp);
				if(temp < 0)
				{
					cprintf("read returned %d\n\r", temp);
					return -1;
				}
				err = copy_extended_memory(dst,
					to_linear(buf), temp);
				if(err != 0)
					return err;
				size -= temp;
				dst += temp;
				pos += temp;
				for(; progress <= pos / incr; progress++)
					cprintf("*");
			}
		}
		else if(sect->zero)
		{
			temp = zero_pmode_bss(sect, virt_to_phys);
			if(temp != 0)
				return temp;
		}
		sect++;
	}
	cprintf("\n\r");
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int load_rdsk_file(unsigned handle)
{
	unsigned char HUGE *conv_mem;
	unsigned progress, incr;
	unsigned long pos;
	int err;

	conv_mem = _conv_mem;
	lseek(handle, 0, SEEK_SET);
/* progress bargraph */
	cprintf("Loading: [                                "
		"                   ]\r"
		"Loading: [");
	incr = _file_size / 50;	/* 2% increments */
	progress = 0;
	pos = 0;
	do
	{
		err = read(handle, conv_mem, 16384);
		if(err < 0)
		{
			cprintf("read returned %d\n\r", err);
			return -1;
		}
		conv_mem += err;
		pos += err;
		for(; progress <= pos / incr; progress++)
			cprintf("*");
	} while(err == 16384);
	cprintf("\n\r");
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int check_memory(exec_t *exec, unsigned long *lva)
{
	unsigned long lowest, highest, temp, conv_mem, ext_mem;
	unsigned short i;

/* find highest and lowest virtual addresses in kernel */
	lowest = -1uL;
	highest = 0;
	for(i = 0; i < exec->num_sections; i++)
	{
		temp = exec->section[i].adr;
		if(temp < lowest)
			lowest = temp;
		temp += exec->section[i].size;
		if(temp > highest)
			highest = temp;
	}
/*cprintf("        lowest adr %08lX, highest adr %08lX\n\r", lowest, highest);*/
/* convert highest address to size */
	highest -= lowest;
/* figure out memory requirements */
	conv_mem = ext_mem = 0;
/* put RDSK file in conventional memory */
	if(exec->rdsk)
		conv_mem += _file_size;
/* put pmode kernel in extended memory */
	if(exec->pmode)
		ext_mem += highest;
/* put real mode kernel in conventional memory */
	else
		conv_mem += highest;
/* check memory requirements
xxx - subtract _DS:_end from _conv_mem */
	if(conv_mem > _conv_mem_size)
	{
		cprintf("not enough conventional memory\n\r");
		return -ENOMEM;
	}
	if(ext_mem > _ext_mem_size)
	{
		cprintf("not enough extended memory\n\r");
		return -ENOMEM;
	}
/* save Lowest Virtual Address */
	*lva = lowest;
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int get_disk_geometry(dev_t *dev)
{
	unsigned char *blk, *ptab_rec;
	unsigned short heads, sects;
	int temp;

	dev->bytes_per_sector = BPS;
/* floppy */
	if(dev->int13_dev < 0x80)
	{
/* read sector 0 of floppy == boot sector */
		temp = read_sector(dev, 0, &blk);
		if(temp != 0)
			return temp;
/* see if it's a FAT (DOS) floppy */
		if(blk[0] == 0xEB && blk[2] == 0x90 &&	/* JMP short, NOP */
			read_le16(blk + 11) == 512 &&	/* bytes/sector */
			blk[13] == 1 &&			/* sectors/cluster */
			blk[21] == 0xF0 &&		/* media ID */
			blk[26] == 2)			/* heads */
/* read disk geometry (i.e. sectors-per-track value)
from BIOS Parameter Block (BPB) of FAT boot sector */
		{
			dev->sects = read_le16(blk + 24);
			dev->heads = read_le16(blk + 26);
		}
/* xxx - otherwise...maybe splice in code to probe disk size, e.g.
http://www.execpc.com/~geezer/osd/boot/size.c

Neither INT 13h AH=08h nor the floppy parameter table at
interrupt vector 1Eh give reliable floppy geometry values. */
		else
		{
			dev->sects = 18;
			dev->heads = 2;
		}
	}
	else
	{
/* hard disk: read sector 0 == MBR == partition table */
		temp = read_sector(dev, 0, &blk);
		if(temp != 0)
			return temp;
		heads = sects = 0;
		ptab_rec = blk + 446;
/* for all four primary partitions... */
		for(temp = 4; temp != 0; temp--, ptab_rec += 16)
		{
/* skip undefined partitions */
			if(ptab_rec[4] == 0)
				continue;
/* all defined partitions must have nonzero ending head value...

xxx - this makes some assumptions that may not hold
for hard disks partitioned and formatted with LBA
(actually, I don't need the disk geometry for LBA, do I?) */
			temp = ptab_rec[5];
			if(temp == 0)
			{
ERR:				cprintf("get_disk_geometry: invalid "
					"partition table for drive "
					"0x%02X\n\r", dev->int13_dev);
				return -1;
			}
/* ...and they must have the SAME ending head value */
			if(heads == 0)
				heads = temp;
			else
			{
				if(temp != heads)
					goto ERR;
			}
/* same drill for ending sector value */
			temp = ptab_rec[6] & 0x3F;
			if(temp == 0)
				goto ERR;
			if(sects == 0)
				sects = temp;
			else
			{
				if(temp != sects)
					goto ERR;
			}
		}
		dev->sects = sects;
		dev->heads = heads + 1;
	}
	DEBUG(cprintf("get_disk_geometry for drive 0x%02X: %u heads, "
		"%u sectors/track\n\r", dev->int13_dev, dev->heads,
		dev->sects);)
	return 0;
}
/*****************************************************************************
*****************************************************************************/
#define	BUFSIZE	4096

#if 1
#define	BOOT_DEV	0
#define	BOOT_PART	0
#define	BOOT_PATH	"/krnl.dsk"

#else
#define	BOOT_DEV	0x80
#define	BOOT_PART	1
#define	BOOT_PATH	"/mystuff/p/k3/krnl.dsk"
#endif

static mount_t _mount;

int main(void)
{
/* open() will overwrite path, so use "char path[]" instead of "char *path" */
	static char path[] = BOOT_PATH;
	static chf_t check_header[] =
	{
		check_exe_header, check_elf_header,
		check_coff_header, check_pe_header
	};
/**/
	unsigned long virt_to_phys;
	int err, handle, i;
	exec_t exec;
	dev_t dev;

	cprintf("Modular Boot Loader\n\r");
/* "_end" was aligned to a paragraph (16-byte) boundary in START.ASM,
so "conv_mem" should also point to a paragraph boundary */
	_conv_mem = MK_FP(_DS, _end);

/* cprintf("        _code=%04X, _data=%04X, _bss=%04X, _end=%04X\n\r",
  _code, _data, _bss, _end);
cprintf("        %u bytes code, %u bytes data, %u bytes BSS\n\r"
   "        (%u bytes on disk, %u bytes in memory)\n\r",
  _data - _code, _bss - _data, _end - _bss,
  _bss - _code, _end - _code);*/

	cprintf("Conventional memory: %luK  Extended memory: %luK  "
		"32-bit CPU: %s\n\r", _conv_mem_size >> 10,
		_ext_mem_size >> 10, _got_32bit_cpu ? "yes" : "no");
	cprintf("File name: %s   ", path);
/* get drive info */
	dev.int13_dev = BOOT_DEV;
	err = get_disk_geometry(&dev);
	if(err != 0)
	{
		cprintf("get_disk_geometry returned %d\n\r", err);
		return 1;
	}
/* mount filesystem */
	err = fat_mount(&_mount, &dev, BOOT_PART);
	if(err != 0)
	{
		cprintf("fat_mount returned %d\n\r", err);
		return 0;
	}
/* open kernel file */
	handle = open((char *)path, 0);
	if(handle != 0)
	{
		cprintf("open returned %d\n\r", handle);
		return 0;
	}
/* get size */
	_file_size = lseek(handle, 0, SEEK_END);
/* check if RDSK format */
	err = check_rdsk_header(&exec, handle);
	if(err == -ERR_FILE_FORMAT)
	{
/* check non-RDSK file formats */
		i = 0;
		memset(&exec, 0, sizeof(exec_t));
		for(; i < sizeof(check_header) / sizeof(check_header[0]); i++)
		{
			err = (check_header[i])(&exec, handle, 0);
			if(err != -ERR_FILE_FORMAT)
				break;
		}
	}
	if(err == -ERR_FILE_FORMAT)
	{
		cprintf("Invalid kernel file\n\r");
		return 1;
	}
	else if(err != 0)
	{
		cprintf("check_header returned %d\n\r", err);
		return 1;
	}
	cprintf("File format: %s\n\r", exec.format_name);
/* check if a 32-bit CPU is required and present */
	if(exec.pmode && !_got_32bit_cpu)
	{
		cprintf("32-bit CPU required (386SX or better)\n\r");
		return 1;
	}
/* check memory requirements */
	if(check_memory(&exec, &virt_to_phys) != 0)
		return 1;
/* convert lowest virtual address to virt_to_phys
xxx - this works only for pmode */
	virt_to_phys = PMODE_LOAD_ADR - virt_to_phys;
/* load RDSK file to conventional memory */
	lseek(handle, 0, SEEK_SET);
	if(exec.rdsk)
	{
		if(load_rdsk_file(handle) != 0)
			return 1;
/* pmode kernel in RDSK file: copy to extended memory */
		if(exec.pmode)
		{
			if(copy_pmode_kernel(&exec, virt_to_phys) != 0)
				return 1;
		}
/* real-mode kernel in RDSK file: copy to conventional memory */
		else
		{
/* xxx - implement */
		}
	}
	else
	{
/* "bare" pmode kernel (ELF, COFF, PE): load to extended memory */
		if(exec.pmode)
		{
			err = load_pmode_kernel(&exec, virt_to_phys, handle);
			if(err != 0)
				return 1;
		}
/* "bare" real mode kernel (DOS .EXE): load to conventional memory */
		else
		{
/* xxx - implement */
		}
	}
/* done with kernel file; close it */
	close(handle);
/* turn off floppy motor */
	outportb(0x3F2, 0);
/* jump to kernel */
	if(exec.pmode)
	{
		err = run_pmode_kernel(exec.entry_pt + virt_to_phys);

⌨️ 快捷键说明

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