Logo Search packages:      
Sourcecode: mbr version File versions  Download package

bios.c

#include "harness.h"
#include "vm86.h"
#include <string.h>

typedef unsigned char      BYTE;
typedef unsigned short     WORD;
typedef unsigned long      DWORD;
typedef unsigned long long QWORD;

typedef struct
{
  BYTE  size;
  BYTE  reserved;
  WORD  count;
  WORD  addr;
  WORD  seg;
  QWORD block;
} disk_address_packet;

#define EFLAGS(v86) ((v86)->regs.eflags)

#define AX(v86) (0[(unsigned short *)(&(v86)->regs.eax)])
#define AL(v86) (0[(unsigned char *)(&(v86)->regs.eax)])
#define AH(v86) (1[(unsigned char *)(&(v86)->regs.eax)])

#define BX(v86) (0[(unsigned short *)(&(v86)->regs.ebx)])

#define ECX(v86) ((v86)->regs.ecx)
#define CX(v86) (0[(unsigned short *)(&(v86)->regs.ecx)])
#define CL(v86) (0[(unsigned char *)(&(v86)->regs.ecx)])
#define CH(v86) (1[(unsigned char *)(&(v86)->regs.ecx)])

#define EDX(v86) ((v86)->regs.edx)
#define DX(v86) (0[(unsigned short *)(&(v86)->regs.edx)])
#define DL(v86) (0[(unsigned char *)(&(v86)->regs.edx)])
#define DH(v86) (1[(unsigned char *)(&(v86)->regs.edx)])

#define SI(v86) (0[(unsigned short *)(&(v86)->regs.esi)])

#define CS(v86) ((v86)->regs.cs)
#define DS(v86) ((v86)->regs.ds)
#define ES(v86) ((v86)->regs.es)

#define EBP(v86) ((v86)->regs.ebp)
#define BP(v86) (1[(unsigned short *)(&(v86)->regs.ebp)])

#define EIP(v86) ((v86)->regs.eip)

#define FAR(seg, off) ((void*)(16*(unsigned long)(seg)+(off)))

static unsigned int interfaces_enabled = 0;
static unsigned int current_year = 2001, current_month = 1, current_day = 1;

void bios_init()
{
  set_shift_state(0);
}

void set_interfaces(unsigned int enable, unsigned int mask)
{
  interfaces_enabled = (interfaces_enabled & mask) | enable;
}

void set_date(unsigned int y, unsigned int m, unsigned int d)
{
  current_year = y;
  current_month = m;
  current_day = d;
}

int handle_int_10(struct vm86plus_struct *v86)
{
  switch (AH(v86))
  {
  case 0x0e: /* Character output */
    outputc(AL(v86));
    return 1;
  }
  return 0;
}

static void read_sector(unsigned char *data, DWORD location_lo,
                  DWORD location_hi)
{
  /* 0xe4 is inb - should abort if executed. */
  memset(data, 0xe4, 512);
  *(WORD*)(data+  0) = 0xe4cd; /* int 0xe4 */
  *(DWORD*)(data+ 2) = 0xdecea5ed;
  *(DWORD*)(data+ 6) = location_lo ^ 0x5569aa96;
  *(DWORD*)(data+10) = location_hi ^ 0x3ca55ac3;
  *(WORD*)(data+510) = 0xaa55; /* Signature */
}

/* Handle an INT_13 event.  Return true if it is handled. */
int handle_int_13(struct vm86plus_struct *v86)
{
  unsigned int drive = DL(v86);
  unsigned int head = DH(v86);
  unsigned int cylinder = CH(v86) | (((int)CL(v86) & 0xc0) << 2);
  unsigned int sector = CL(v86) & 0x3f;
  
  /* Clear the error flag for most cases. */
  EFLAGS(v86) &= ~CF;

  /* Check the sub-function. */
  switch (AH(v86))
  {
  case 0x2: /* Disk read. */
    if (AL(v86) != 1) /* Only allow 1 sector. */
      break;
    outputf("Read sector d%d h%d c%d s%d to %04x:%04x\n", drive, head,
          cylinder, sector, ES(v86), BX(v86));
    read_sector(FAR(ES(v86), BX(v86)),
            (sector<<0)|(cylinder<<16),
            (head<<0)|(drive<<16));
    return 1;

  case 0x3: /* Disk write. */
    if (AL(v86) != 1) /* Only allow 1 sector. */
      break;
    outputf("Write sector d%d h%d c%d s%d to %04x:%04x\n", drive, head,
          cylinder, sector, ES(v86), BX(v86));
    compare_mbr(FAR(ES(v86), BX(v86)));
    return 1;

  case 0x41: /* Big disk installation check. */
    /* Make sure the parameters are initialised. */
    if (BX(v86)!=0x55aa)
      break;

    /* Only support hard disks. */
    if (0x80&~DL(v86))
      break;

    /* Is the interface enabled? */
    if (interfaces_enabled & INTERFACE_BIG_DISK)
    {
      /* Yes.  We support this. */
      BX(v86) = 0xaa55;
      AH(v86) = 0x01; /* Major version. */
      AL(v86) = 0x95; /* Random number. */
      CX(v86) = 1; /* Only support functions 0x42-0x44,0x47,0x48. */
      DH(v86) = 0; /* Extension version. */
      /* FIXME: Could have bad support bitmap.  Could change version
         numbers. */
    }
    else
    {
      /* No.  We don't support this. */
      EFLAGS(v86) |= CF;
      AH(v86) = 0x1;
    }
    return 1;

  case 0x42: /* Extended read. */
  {
    disk_address_packet *pkt;

    /* Abort if this interface isn't enabled. */
    if (INTERFACE_BIG_DISK & ~interfaces_enabled)
      break;

    /* Only support hard disks. */
    if (0x80&~DL(v86))
      break;

    /* Get a pointer to the parameters. */
    pkt = FAR(DS(v86), SI(v86));

    /* The size must be correct. */
    if (pkt->size != sizeof(*pkt) || pkt->reserved != 0 ||
      pkt->count != 1)
      break;

    outputf("Read sector #0x%08x%08x to %04x:%04x\n",
          (int)(pkt->block>>32), (int)(pkt->block),
          pkt->seg, pkt->addr);

    /* Fill in the data. */
    read_sector(FAR(pkt->seg, pkt->addr), pkt->block, pkt->block>>32);

    /* FIXME: Could return error. */
    EFLAGS(v86) &= ~CF;
    AH(v86) = 0;
    return 1;
  }

  case 0x43: /* Extended write. */
    break; /* Not supported. */
  case 0x44: /* Verify sectors. */
    break; /* Not supported. */
  case 0x47: /* Extended seek. */
    break; /* Not supported. */
  case 0x48: /* Get drive parameters. */
    break; /* Not supported. */
  }
  return 0;
}

int handle_int_16(struct vm86plus_struct *v86)
{
  unsigned long key;

  switch (AH(v86))
  {
  case 0: /* Get key stroke */
    AX(v86) = get_key_event();
    return 1;

  case 1: /* Check for key stroke */
    key = peek_key_event();
    if (key == NO_KEY)
    {
      EFLAGS(v86) |= ZF;
    }
    else
    {
      EFLAGS(v86) &= ~(unsigned long)ZF;
      AX(v86) = key;
    }
    return 1;
  }
  return 0;
}

int handle_int_1a(struct vm86plus_struct *v86)
{
  unsigned int time;

  switch (AH(v86))
  {
  case 0: /* Get time */
    time = get_time();
    CX(v86) = (time>>16) & 0xffff;
    DX(v86) = (time>>0)  & 0xffff;
    return 1;
  }
  return 0;
}

void handle_int_e4(struct vm86plus_struct *v86)
{
  DWORD *data = FAR(CS(v86), EIP(v86));
  DWORD location_lo = data[1]^0x5569aa96;
  DWORD location_hi = data[2]^0x3ca55ac3;

  if (data[0] != 0xdecea5ed)
    return;

  outputf("Exit: %04lx %04lx %04lx %04lx\n",
        location_hi>>16, location_hi&0xffff,
        location_lo>>16, location_lo&0xffff);
}

void set_shift_state (unsigned long state)
{
  unsigned char *flag = (void*)0x417;
  *flag = state;
}

/*  */
/* Local Variables: */
/* mode:c */
/* c-indentation-style: "whitesmith" */
/* c-basic-offset: 2 */
/* End: */

Generated by  Doxygen 1.6.0   Back to index