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

📄 loaderc.c

📁 boot loader bing--boot.asm for fdd and loader c++ -startup.asm
💻 C
📖 第 1 页 / 共 3 页
字号:
	if(temp != 64)
		return -1;
	if(buf[0] != 'M' || buf[1] != 'Z')
		return -1;
/* skip to new-style EXE header and read it */
	new_exe_offset = read_le32(buf + 60);
	temp = my_seek(file, offset + new_exe_offset, SEEK_SET);
	if(temp < 0)
		return temp;
	temp = my_read(file, buf, 4);
	if(temp < 0)
		return temp;
	if(temp != 4)
/* could be DOS .EXE
		return ERR_FILE; */
		return -1;
	if(buf[0] != 'P' || buf[1] != 'E')
		return -1;
/* beyond the 4-byte "PE" signature, it's just like COFF */
	temp = read_coff_file(exec, file, offset + new_exe_offset + 4);
	strcpy(exec->format_name, "Win32 PE");
	return temp;
}
/*////////////////////////////////////////////////////////////////////////////
	MAIN
////////////////////////////////////////////////////////////////////////////*/
#define	WIDTH		80
#define	HEIGHT		25

#define	BANNER_HT	4

#define	LISTBOX_X	0
#define	LISTBOX_Y	(1 + BANNER_HT)

#define	LISTBOX_HT	15
#define	LISTBOX_COLS	3
#define	LISTBOX_COLWD	13
#define	LISTBOX_WD	(LISTBOX_COLS * LISTBOX_COLWD)

#define	LISTBOX_FILES	(LISTBOX_HT * LISTBOX_COLS)

#define	INFO_X		(WIDTH / 2 + 1)
#define	INFO_Y		LISTBOX_Y
#define	INFO_WD		(WIDTH / 2 - 1)
#define	INFO_HT		(HEIGHT - INFO_Y)

#define	MSG_X		0
#define	MSG_Y		(LISTBOX_Y + LISTBOX_HT + 1)
#define	MSG_WD		(WIDTH - MSG_X)
#define	MSG_HT		(HEIGHT - MSG_Y)

#define	LOADBUF_SIZE	4096

/* IMPORTS
from LIBA.ASM */
int enable_pmode(int enable_a20, unsigned long phys_entry_pt);

char _got_32bit_cpu = 1;
static unsigned char _windows, _load_buffer[LOADBUF_SIZE];
unsigned long _ext_mem_size = 1048576L, _conv_mem_size = 655360L;
/*****************************************************************************
*****************************************************************************/
static int copy_extended_memory(unsigned long dst_adr,
		unsigned long src_adr, unsigned short count)
{
/* global descriptor table, from Table 00499 of Ralf Brown's list */
	unsigned char gdt[] =
	{
/* 0 */		0,    0,    0, 0, 0, 0,    0,    0,/* used by BIOS */
/* 8 */		0,    0,    0, 0, 0, 0,    0,    0,/* used by BIOS */
/* page-granular 32-bit data segments with limit 4 Gbytes - 1 */
/* 10h */	0xFF, 0xFF, 0, 0, 0, 0x93, 0xCF, 0,/* src seg */
/* 18h */	0xFF, 0xFF, 0, 0, 0, 0x93, 0xCF, 0,/* dst seg */
/* 20h */	0,    0,    0, 0, 0, 0,    0,    0,/* used by BIOS for CS */
/* 28h */	0,    0,    0, 0, 0, 0,    0,    0/* used by BIOS for SS */
	};
	struct REGPACK regs;

/* fill in src segment descriptor */
	gdt[0x12] = src_adr;
	src_adr >>= 8;
	gdt[0x13] = src_adr;
	src_adr >>= 8;
	gdt[0x14] = src_adr;
	src_adr >>= 8;
	gdt[0x17] = src_adr;
/* fill in dst segment descriptor */
	gdt[0x1A] = dst_adr;
	dst_adr >>= 8;
	gdt[0x1B] = dst_adr;
	dst_adr >>= 8;
	gdt[0x1C] = dst_adr;
	dst_adr >>= 8;
	gdt[0x1F] = dst_adr;
/* call INT 15h AH=87h to copy */
	regs.r_ax = 0x8700;
	count >>= 1;	/* words! */
	regs.r_cx = count;
	regs.r_es = _SS;/* ES:SI -> GDT */
	regs.r_si = (unsigned)gdt;
	intr(0x15, &regs);
/* return status byte from AH
Borland compiler bug strikes again! put shifts on their own line of code
http://www.execpc.com/~geezer/embed/bugs.htm
	return regs.r_ax >> 8; */
	regs.r_ax >>= 8;
	if(regs.r_ax != 0)
	{
		cprintf("error from 0x%X in copy_extended_memory\n",
			regs.r_ax);
		return -1;
	}
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static unsigned long get_linear_adr(void far *foo)
{
	unsigned long ret_val;

	ret_val = FP_SEG(foo);
	ret_val <<= 4;
	ret_val += FP_OFF(foo);
	return ret_val;
}
/*****************************************************************************
*****************************************************************************/
static void find_extremes(exec_t *exec, unsigned long *lowest,
		unsigned long *highest)
{
	unsigned short temp;
	unsigned long high;

	*lowest = -1uL;
	*highest = 0uL;
	for(temp = 0; temp < exec->num_sections; temp++)
	{
		if(exec->section[temp].adr < *lowest)
			*lowest = exec->section[temp].adr;
		high = exec->section[temp].adr + exec->section[temp].size;
		if(high > *highest)
			*highest = high;
	}
}
/*****************************************************************************
*****************************************************************************/
static int zero_bss(exec_t *exec, unsigned long start, unsigned long end)
{
	unsigned long adr;

	memset(_load_buffer, 0, LOADBUF_SIZE);
/* put Cosmos-compatible boot data in the BSS */
	if(exec->cosmos)
	{
		*(unsigned long *)(_load_buffer + 0) = _conv_mem_size;
		*(unsigned long *)(_load_buffer + 4) = _ext_mem_size;
/* location of loaded RDSK image
		*(unsigned long *)(_load_buffer + 8) =
			get_linear_adr(_conv_mem); */
	}
	for(adr = start; adr < end; adr += LOADBUF_SIZE)
	{
		if(copy_extended_memory(adr, get_linear_adr(_load_buffer),
			LOADBUF_SIZE) != 0)
				return -1;
		memset(_load_buffer, 0, LOADBUF_SIZE);
	}
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int load_section(file_t *file, unsigned long start, unsigned long end)
{
	unsigned long adr;
	int temp;

/* load it: */
	for(adr = start; adr < end; adr += LOADBUF_SIZE)
	{
/* load a block */
		temp = my_read(file, _load_buffer, LOADBUF_SIZE);
		if(temp == 0)
			break;
		else if(temp < 0)
		{
			cprintf("error reading disk/file");
			return temp;
		}
/* copy it to where it belongs */
		if(copy_extended_memory(adr, get_linear_adr(_load_buffer),
			LOADBUF_SIZE) != 0)
				return -1;
	}
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int run_pmode_kernel(file_t *file, exec_t *exec, unsigned long phys)
{
	unsigned long lowest, highest, virt_to_phys, start, end;
	unsigned short temp;
	sect_t *sect;

/* find lowest and highest virtual addresses */
	find_extremes(exec, &lowest, &highest);
/* compute virt_to_phys */
	virt_to_phys = phys - lowest;
/* for each section: */
	sect = exec->section + 0;
	for(temp = 0; temp < exec->num_sections; temp++)
	{
/* figure out where to load it */
		start = virt_to_phys + sect->adr;
		end = start + sect->size;
/* BSS */
		if(sect->bss)
		{
			if(zero_bss(exec, start, end) != 0)
				return -1;
		}
/* preloaded section other than BSS
		else if(_preload_adr != 0)
		{
			if(copy_extended_memory(start, sect->off +
				_preload_adr, sect->size) != 0)
					return -1;
		} */
/* non-BSS section not yet loaded */
		else
		{
			(void)my_seek(file, sect->off, SEEK_SET);
			if(load_section(file, start, end) != 0)
				return -1;
		}
		sect++;
	}
/* turn of floppy drive motor(s) */
	outportb(0x3F2, 0);
/* enable pmode and jump to kernel */
	temp = enable_pmode(virt_to_phys + highest >= 0x100000L,
		virt_to_phys + exec->entry_pt);
	cprintf("error from enable_pmode: ");
	if(temp == 1)
		cprintf("32-bit CPU required");
	else if(temp == 2)
		cprintf("could not enable A20 gate");
	else
		cprintf("unknown error %d", temp);
	return -1;
}
/*****************************************************************************
*****************************************************************************/
static int load_kernel(file_t *file)
{
	unsigned long lowest, highest, phys = 0x110000L;
	unsigned char csr_y;
	int err, temp;
	sect_t *sect;
	exec_t exec;

/* display file name */
	textattr(0x78);		/* dark gray on white */
	csr_y = INFO_Y;
	gotoxy(INFO_X, csr_y++);
	cprintf("File name:    %-12.12s", file->name);
	gotoxy(INFO_X, csr_y++);

/* identify file */
	memset(&exec, 0, sizeof(exec));
	err = read_coff_file(&exec, file, 0);
	if(err == -1)
		err = read_pe_file(&exec, file, 0);
	if(err < 0)
	{
		textattr(0x4E);
		cprintf("unknown file format");
ERR:
		textattr(0x78);
		goto OUT;
	}
/* display info */
	cprintf("File format:  %s", exec.format_name);

	gotoxy(INFO_X, csr_y++);
	cprintf("Enable pmode: %s", exec.pmode ? "yes" : "no");

	gotoxy(INFO_X, csr_y++);
	if(exec.pmode && !_got_32bit_cpu)
	{
		textattr(0x4E); /* yellow on red */
		cprintf("32-bit CPU required");
		err = -1;
		goto ERR;
	}
	cprintf("Virtual entry point:    %8lX", exec.entry_pt);
	find_extremes(&exec, &lowest, &highest);

/* usually, the .text section is at the lowest address,
so it's the virtual load (start) address */
	gotoxy(INFO_X, csr_y++);
	cprintf("Virtual load address:   %8lX", lowest);

/* maybe the sections are not contiguous (i.e. there are gaps
between them), so the extent of the kernel is not neccessarily
the sum of the section sizes */
	gotoxy(INFO_X, csr_y++);
	cprintf("Kernel extent (size):   %8lX", highest - lowest);

	gotoxy(INFO_X, csr_y++);
	cprintf("Physical load address:  ");
	textattr(0x0F);	/* bright white on black */
	cprintf("%8.8lX", phys);
	textattr(0x78);

	if(phys >= 0x100000L)
	{
		if(phys + (highest - lowest) > (_ext_mem_size + 0x100000L))
		{
			textattr(0x4E);
			cprintf("not enough extended memory");
			err = ERR_MEM;
			goto ERR;
		}
	}
	else
	{
		if(phys + (highest - lowest) > _conv_mem_size)
		{
			textattr(0x4E);
			cprintf("not enough conventional memory");
			err = ERR_MEM;
			goto ERR;
		}
	}
	gotoxy(INFO_X, csr_y++);
	cprintf("Store boot data in BSS: ");
	textattr(0x0F);	/* bright white on black */
	cprintf("%-3s", exec.cosmos ? "yes" : "no ");
	textattr(0x78);

	csr_y++;
	if(exec.num_sections != 0)
	{
		gotoxy(INFO_X, csr_y++);
		cprintf("Section  Section  Section  Section");
		gotoxy(INFO_X, csr_y++);
		cprintf("name     address  offset   size");
		gotoxy(INFO_X, csr_y++);
		cprintf("-------- -------- -------- --------");
	}
	sect = exec.section + 0;
	for(temp = 0; temp < exec.num_sections; temp++)
	{
		gotoxy(INFO_X, csr_y + temp);
		cprintf("%-8.8s %8lX %8lX %8lX",
			sect->sect_name, sect->adr, sect->off, sect->size);
		sect++;
	}
	gotoxy(MSG_X, MSG_Y);
	if(_windows)
	{
		textattr(0x4E);
		cprintf("Can't boot pmode OS from Windows");
		textattr(0x78);
		err = -1;
	}
	else
	{
		cprintf("Press Enter to boot");
		err = 0;
	}
OUT:
	getch();
	if(err == 0)
		err = run_pmode_kernel(file, &exec, phys);
	erase_screen(INFO_X, INFO_Y, INFO_WD, INFO_HT);
	erase_screen(MSG_X, MSG_Y, MSG_WD, MSG_HT);
	return err;
}
/*****************************************************************************
*****************************************************************************/
static int list_files(file_t *dir)
{
	unsigned num_files_to_skip = 0, num_files_in_dir = -1u, f;
	int key, err, highlighted_file = 0;
	file_t highlighted_ent, ent;

	do
	{
/* seek to beginning of dir */
		err = my_seek(dir, 0, SEEK_SET);
		if(err != 0)
			return err;
/* maybe skip some files */
		for(f = 0; f < num_files_to_skip; f++)
		{
			err = my_readdir(dir, &ent);
			if(err != 0)
				return err;
		}
/* list some files */
		for(; f < num_files_to_skip + LISTBOX_FILES; f++)
		{
			err = my_readdir(dir, &ent);
			if(err == ERR_EOF)
				num_files_in_dir = f;
			else if(err != 0)
				return err;
			if(f >= num_files_in_dir)
				break;
			gotoxy(LISTBOX_X + ((f - num_files_to_skip) %
				LISTBOX_COLS) * LISTBOX_COLWD,
				LISTBOX_Y + ((f - num_files_to_skip) /
				LISTBOX_COLS));
			if(f == highlighted_file)
			{
				textattr(0x1F); /* bright white on blue */
				memcpy(&highlighted_ent, &ent, sizeof(ent));
			}
/* xxx - use function to access is_dir field? my_fstat() ? */
			else if(ent.is_dir)
				textattr(0x01);	/* blue on black */
			else
				textattr(0x07);	/* white on black */
			if(ent.is_dir)
				cprintf("/%-*.*s", LISTBOX_COLWD - 1,
					LISTBOX_COLWD - 1, ent.name);
			else
				cprintf("%-*.*s", LISTBOX_COLWD,
					LISTBOX_COLWD, ent.name);
			textattr(0x07);
		}
/* use keyboard for navigation */
		key = getch();
		if(key == 0)
			key = 0x100 | getch();
		if(key == 0x14D)
			highlighted_file++;
		else if(key == 0x14B)
			highlighted_file--;
		else if(key == 0x148)
			highlighted_file -= LISTBOX_COLS;
		else if(key == 0x150)
			highlighted_file += LISTBOX_COLS;
		else if(key == 13)
		{
			if(highlighted_ent.is_dir)
			{
				dir->inode = highlighted_ent.inode;
				dir->file_size = -1uL;
					/* highlighted_ent.file_size; */
				erase_screen(LISTBOX_X, LISTBOX_Y,
					LISTBOX_WD, LISTBOX_HT);
				num_files_to_skip = 0;
				num_files_in_dir = -1u;
				highlighted_file = 0;
			}
			else
			{
				(void)load_kernel(&highlighted_ent);
			}
		}
		if(highlighted_file < 0)
			highlighted_file = 0;
		else if(highlighted_file < num_files_to_skip)
			num_files_to_skip -= LISTBOX_COLS;
		else if(highlighted_file >= num_files_in_dir)
			highlighted_file = num_files_in_dir - 1;
		else if(highlighted_file >= num_files_to_skip + LISTBOX_FILES)
			num_files_to_skip += LISTBOX_COLS;
	} while(key != 27);
	return 0;
}
/*****************************************************************************
*****************************************************************************/
int main(void)
{
	struct REGPACK regs;
	file_t dir;
	dev_t dev;
	int temp;

/* make sure it's really DOS */
	regs.r_ax = 0x1600;
	intr(0x2F, &regs);
	regs.r_ax &= 0xFF;
	if(regs.r_ax != 0 && regs.r_ax != 0x80)
		_windows = 1;
/* */
	textattr(0x70);
	erase_screen(0, 0, WIDTH, HEIGHT);
	gotoxy(0, 0);
	cprintf("BING bootloader version 0.4 - "
		"http://www.execpc.com/~geezer/os");
	gotoxy(0, 1);
	cprintf("Conventional memory: %luK  Extended memory: %luK  "
		"32-bit CPU: %s", _conv_mem_size >> 10, _ext_mem_size >> 10,
		_got_32bit_cpu ? "yes" : "no");
	gotoxy(0, 2);
/* cprintf("%u bytes code/data, %u bytes BSS, %u bytes total",
  bdata - begin, edata - bdata, edata - begin); */
	gotoxy(0, 3);
	cprintf("Use the arrow keys to select a kernel file, "
		"then press Enter");
/* floppy: int13_dev = 0 (partition number is not used)
hard disk: int13_dev = 0x80; specify partition number 0-3 */
	dev.int13_dev = 0x80;
	temp = fat_mount(&_mount, &dev, 1/* =part */);
	if(temp != 0)
	{
		cprintf("fat_mount returned %d\n\r", temp);
		return 0;
	}
	temp = my_open(&dir, "/");
/*	temp = my_open(&dir, "/tc/p/boot/test");
	temp = my_open(&dir, "/tc/p/k4"); */
	if(temp != 0)
	{
		cprintf("my_open returned %d\n\r", temp);
		return 0;
	}
	temp = list_files(&dir);
	if(temp != 0)
	{
		cprintf("list_files returned %d\n\r", temp);
		return 0;
	}
	temp = my_close(&dir);
	if(temp != 0)
	{
		cprintf("my_closedir returned %d\n\r", temp);
		return 0;
	}
	return 0;
}

⌨️ 快捷键说明

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