Skip to content

Commit

Permalink
Version 0.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinOConnor committed Feb 26, 2008
1 parent 4b60c00 commit 38fcbfe
Show file tree
Hide file tree
Showing 21 changed files with 848 additions and 186 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -12,7 +12,7 @@ SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c mouse.c output.c boot.c
SRC32=post.c output.c

# Default compiler flags (note -march=armv4 is needed for 16 bit insns)
CFLAGS = -Wall -Os -MD -m32 -march=i386 -mregparm=2 -ffreestanding
CFLAGS = -Wall -g -Os -MD -m32 -march=i386 -mregparm=2 -ffreestanding
CFLAGS16 = -Wall -Os -MD -m32 -DMODE16 -march=i386 -mregparm=2 -ffreestanding -fno-jump-tables

all: $(OUT) $(OUT)rom.bin
Expand Down
54 changes: 50 additions & 4 deletions src/biosvar.h
Expand Up @@ -3,6 +3,8 @@
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#ifndef __BIOSVAR_H
#define __BIOSVAR_H

#include "types.h" // u8
#include "farptr.h" // SET_SEG
Expand All @@ -23,8 +25,8 @@ struct bios_data_area_s {
// 30:00
// u8 stack[256];
// 40:00
u16 port_com1, port_com2, port_com3, port_com4;
u16 port_lpt1, port_lpt2, port_lpt3;
u16 port_com[4];
u16 port_lpt[3];
u16 ebda_seg;
// 40:10
u16 equipment_list_flags;
Expand Down Expand Up @@ -52,7 +54,9 @@ struct bios_data_area_s {
u32 timer_counter;
// 40:70
u8 timer_rollover;
u8 other4[0x0f];
u8 other4[0x07];
u8 lpt_timeout[4];
u8 com_timeout[4];
// 40:80
u16 kbd_buf_start_offset;
u16 kbd_buf_end_offset;
Expand Down Expand Up @@ -123,9 +127,48 @@ struct extended_bios_data_area_s {
#endif // BX_ELTORITO_BOOT
};

// Accessor functions
#define GET_EBDA(var) \
GET_FARVAR(EBDA_SEG, ((struct extended_bios_data_area_s *)0)->var)
#define SET_EBDA(var, val) \
SET_FARVAR(EBDA_SEG, ((struct extended_bios_data_area_s *)0)->var, (val))


/****************************************************************
* Extended Bios Data Area (EBDA)
* Initial Program Load (IPL)
****************************************************************/

// XXX - is this a standard, or just a bochs bios thing?

struct ipl_entry_s {
u16 type;
u16 flags;
u32 vector;
u32 description;
u32 reserved;
};

struct ipl_s {
struct ipl_entry_s table[8];
u16 count;
u16 sequence;
u8 pad[124];
};

#define IPL_TYPE_FLOPPY 0x01
#define IPL_TYPE_HARDDISK 0x02
#define IPL_TYPE_CDROM 0x03
#define IPL_TYPE_BEV 0x80

// Accessor functions
#define GET_IPL(var) \
GET_FARVAR(IPL_SEG, ((struct ipl_s *)0)->var)
#define SET_IPL(var, val) \
SET_FARVAR(IPL_SEG, ((struct ipl_s *)0)->var, (val))


/****************************************************************
* Registers saved/restored in romlayout.S
****************************************************************/

#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; }
Expand Down Expand Up @@ -179,5 +222,8 @@ extern struct bios_config_table_s BIOS_CONFIG_TABLE;
#define SEG_BIOS 0xf000

#define EBDA_SEG 0x9FC0
#define IPL_SEG 0x9FF0
#define EBDA_SIZE 1 // In KiB
#define BASE_MEM_IN_K (640 - EBDA_SIZE)

#endif // __BIOSVAR_H
214 changes: 139 additions & 75 deletions src/boot.c
Expand Up @@ -5,114 +5,178 @@
//
// This file may be distributed under the terms of the GNU GPLv3 license.

#include "types.h" // VISIBLE
#include "util.h" // irq_enable
#include "biosvar.h" // struct bregs
#include "farptr.h" // SET_SEG
#include "config.h" // CONFIG_*
#include "cmos.h" // inb_cmos

static inline void
__call_irq(u8 nr)
{
asm volatile("int %0" : : "N" (nr));
}
//--------------------------------------------------------------------------
// print_boot_device
// displays the boot device
//--------------------------------------------------------------------------

static inline u32
call_irq(u8 nr, struct bregs *callregs)
static const char drivetypes[][10]={
"", "Floppy","Hard Disk","CD-Rom", "Network"
};

static void
print_boot_device(u16 type)
{
u32 flags;
asm volatile(
// Save current registers
"pushal\n"
// Pull in calling registers.
"movl 0x04(%%eax), %%edi\n"
"movl 0x08(%%eax), %%esi\n"
"movl 0x0c(%%eax), %%ebp\n"
"movl 0x14(%%eax), %%ebx\n"
"movl 0x18(%%eax), %%edx\n"
"movl 0x1c(%%eax), %%ecx\n"
"movl 0x20(%%eax), %%eax\n"
// Invoke interrupt
"int %1\n"
// Restore registers
"popal\n"
// Exract flags
"pushfw\n"
"popl %%eax\n"
: "=a" (flags): "N" (nr), "a" (callregs), "m" (*callregs));
return flags;
/* NIC appears as type 0x80 */
if (type == IPL_TYPE_BEV)
type = 0x4;
if (type == 0 || type > 0x4)
BX_PANIC("Bad drive type\n");
printf("Booting from %s...\n", drivetypes[type]);
}

//--------------------------------------------------------------------------
// print_boot_failure
// displays the reason why boot failed
//--------------------------------------------------------------------------
static void
print_boot_failure()
print_boot_failure(u16 type, u8 reason)
{
bprintf(0, "Boot failed\n");
if (type == 0 || type > 0x3)
BX_PANIC("Bad drive type\n");

printf("Boot from %s failed", drivetypes[type]);
if (type < 4) {
/* Report the reason too */
if (reason==0)
printf(": not a bootable disk");
else
printf(": could not read the boot disk");
}
printf("\n");
}

static void
try_boot()
try_boot(u16 seq_nr)
{
// XXX - assume floppy
u16 bootseg = 0x07c0;
SET_IPL(sequence, seq_nr);
u16 bootseg;
u8 bootdrv = 0;
u16 bootdev, bootip;

if (CONFIG_ELTORITO_BOOT) {
bootdev = inb_cmos(CMOS_BIOS_BOOTFLAG2);
bootdev |= ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4);
bootdev >>= 4 * seq_nr;
bootdev &= 0xf;
if (bootdev == 0)
BX_PANIC("No bootable device.\n");

/* Translate from CMOS runes to an IPL table offset by subtracting 1 */
bootdev -= 1;
} else {
if (seq_nr ==2)
BX_PANIC("No more boot devices.");
if (!!(inb_cmos(CMOS_BIOS_CONFIG) & 0x20) ^ (seq_nr == 1))
/* Boot from floppy if the bit is set or it's the second boot */
bootdev = 0x00;
else
bootdev = 0x01;
}

if (bootdev >= GET_IPL(count)) {
BX_INFO("Invalid boot device (0x%x)\n", bootdev);
return;
}
u16 type = GET_IPL(table[bootdev].type);

/* Do the loading, and set up vector as a far pointer to the boot
* address, and bootdrv as the boot drive */
print_boot_device(type);

// Read sector
struct bregs cr;
memset(&cr, 0, sizeof(cr));
cr.dl = bootdrv;
SET_SEG(ES, bootseg);
cr.bx = 0;
cr.ah = 2;
cr.al = 1;
cr.ch = 0;
cr.cl = 1;
cr.dh = 0;
u32 status = call_irq(0x13, &cr);

if (status & F_CF) {
print_boot_failure();
switch(type) {
case IPL_TYPE_FLOPPY: /* FDD */
case IPL_TYPE_HARDDISK: /* HDD */

bootdrv = (type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
bootseg = 0x07c0;

// Read sector
memset(&cr, 0, sizeof(cr));
cr.dl = bootdrv;
cr.es = bootseg;
cr.ah = 2;
cr.al = 1;
cr.cl = 1;
call16_int(0x13, &cr);

if (cr.flags & F_CF) {
print_boot_failure(type, 1);
return;
}

/* Always check the signature on a HDD boot sector; on FDD,
* only do the check if the CMOS doesn't tell us to skip it */
if ((type != IPL_TYPE_FLOPPY)
|| !((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0x01))) {
if (GET_FARVAR(bootseg, *(u16*)0x1fe) != 0xaa55) {
print_boot_failure(type, 0);
return;
}
}

/* Canonicalize bootseg:bootip */
bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
break;
case IPL_TYPE_CDROM: /* CD-ROM */
// XXX
return;
break;
case IPL_TYPE_BEV: {
/* Expansion ROM with a Bootstrap Entry Vector (a far
* pointer) */
u32 vector = GET_IPL(table[bootdev].vector);
bootseg = vector >> 16;
bootip = vector & 0xffff;
break;
}
default:
return;
}

memset(&cr, 0, sizeof(cr));
cr.ip = bootip;
cr.cs = bootseg;
// Set the magic number in ax and the boot drive in dl.
cr.dl = bootdrv;
cr.ax = 0xaa55;
call16(&cr);

u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;

u32 segoff = (bootseg << 16) | bootip;
asm volatile (
"pushf\n"
"pushl %0\n"
"movb %b1, %%dl\n"
// Set the magic number in ax and the boot drive in dl.
"movw $0xaa55, %%ax\n"
// Zero some of the other registers.
"xorw %%bx, %%bx\n"
"movw %%bx, %%ds\n"
"movw %%bx, %%es\n"
"movw %%bx, %%bp\n"
// Go!
"iretw\n"
: : "r" (segoff), "ri" (bootdrv));
// Boot failed: invoke the boot recovery function
memset(&cr, 0, sizeof(cr));
call16_int(0x18, &cr);
}

// Boot Failure recovery: try the next device.
void VISIBLE
handle_18(struct bregs *regs)
handle_18()
{
debug_enter(regs);
try_boot();
debug_enter(NULL);
u16 seq = GET_IPL(sequence) + 1;
try_boot(seq);
}

// INT 19h Boot Load Service Entry Point
void VISIBLE
handle_19(struct bregs *regs)
handle_19()
{
debug_enter(regs);
try_boot();
debug_enter(NULL);
try_boot(0);
}

// Callback from 32bit entry - start boot process
// Called from 32bit code - start boot process
void VISIBLE
begin_boot()
{
irq_enable();
__call_irq(0x19);
struct bregs br;
memset(&br, 0, sizeof(br));
call16_int(0x19, &br);
}

0 comments on commit 38fcbfe

Please sign in to comment.