📄 boot.c
字号:
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 + -