📄 loaderc.c
字号:
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, ®s);
/* 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, ®s);
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 + -