コード例 #1
0
ファイル: sanboot.c プロジェクト: viikasgarg/syslinux
static void sanboot(const char **args)
{
    char *q;
    struct s_PXENV_FILE_EXEC *fx;
    com32sys_t reg;

    memset(&reg, 0, sizeof reg);

    fx = __com32.cs_bounce;
    q = (char *)(fx + 1);

    fx->Status = 1;
    fx->Command.offs = OFFS(q);
    fx->Command.seg = SEG(q);

    q = stpcpy(q, "sanboot");

    while (*args) {
	*q++ = ' ';
	q = stpcpy(q, *args);
	args++;
    }

    memset(&reg, 0, sizeof reg);
    reg.eax.w[0] = 0x0009;
    reg.ebx.w[0] = 0x00e5;	/* PXENV_FILE_EXEC */
    reg.edi.w[0] = OFFS(fx);
    reg.es = SEG(fx);

    __intcall(0x22, &reg, &reg);

    /* This should not return... */
}
コード例 #2
0
ファイル: runimage.c プロジェクト: KryvoyNosochek/syslinux
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
			       uint32_t ipappend_flags, uint32_t type)
{
    static com32sys_t ireg;
    char *bbfilename, *bbcmdline, *bbptr;
    int bytes;

    bbptr = __com32.cs_bounce;

    bytes = strlen(filename) + 1;
    memcpy(bbfilename = bbptr, filename, bytes);
    bbptr += bytes;

    bytes = strlen(cmdline) + 1;
    memcpy(bbcmdline = bbptr, filename, bytes);
    bbptr += bytes;

    ireg.eax.w[0] = 0x0016;
    ireg.ds = SEG(bbfilename);
    ireg.esi.w[0] = OFFS(bbfilename);
    ireg.es = SEG(bbcmdline);
    ireg.ebx.w[0] = OFFS(bbcmdline);
    ireg.ecx.l = ipappend_flags;
    ireg.edx.l = type;

    __intcall(0x22, &ireg, 0);
}
コード例 #3
0
ファイル: syslnx.c プロジェクト: pierre/syslinux-fastboot
void runsyslinuximage(const char*cmd, long ipappend)
{
  unsigned int numfun = 0;
  char *ptr,*cmdline;

  getversion(NULL,&numfun);
  // Function 16h not supported Fall back to runcommand
  if (numfun < 0x16) runsyslinuxcmd(cmd);
  // Try the Run Kernel Image function
  // Split command line into
  strcpy(__com32.cs_bounce,cmd);
  ptr = __com32.cs_bounce;
  // serach for first space or end of string
  while ( (*ptr) && (*ptr != ' ')) ptr++;
  if (!*ptr) cmdline = ptr; // no command line
  else {
     *ptr++='\0'; // terminate kernal name
     cmdline = ptr+1;
     while (*cmdline != ' ') cmdline++; // find first non-space
  }
  // Now call the interrupt
  REG_BX(inreg) = OFFS(cmdline);
  REG_ES(inreg) = SEG(cmdline);
  REG_SI(inreg) = OFFS(__com32.cs_bounce);
  REG_DS(inreg) = SEG(__com32.cs_bounce);
  REG_EDX(inreg) = 0;

  __intcall(0x22,&inreg,&outreg); // If successful does not return
}
コード例 #4
0
ファイル: dwipe.c プロジェクト: sTeeLM/dwipe1_5
/** write_sectors in write.c has BUG!!!
 * write_sectors - write several sectors from disk
 * @drive_info:		driveinfo struct describing the disk
 * @lba:		Position to write
 * @data:		Buffer to write
 * @size:		Size of the buffer (number of sectors)
 *
 * Return the number of sectors write on success or -1 on failure.
 * errno_disk contains the error number.
 **/
static int dwipe_write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
		  const void *data, const int size)
{
    com32sys_t inreg, outreg;
    struct ebios_dapa *dapa = __com32.cs_bounce;
    void *buf = (char *)__com32.cs_bounce + size * SECTOR;

    memcpy(buf, data, size * SECTOR);
    memset(&inreg, 0, sizeof inreg);

    if (drive_info->ebios) {
	dapa->len = sizeof(*dapa);
	dapa->count = size;
	dapa->off = OFFS(buf);
	dapa->seg = SEG(buf);
	dapa->lba = lba;

	inreg.esi.w[0] = OFFS(dapa);
	inreg.ds = SEG(dapa);
	inreg.edx.b[0] = drive_info->disk;
	inreg.eax.w[0] = 0x4300;	/* Extended write */
    } else {
	unsigned int c, h, s;

	if (!drive_info->cbios) {	// XXX errno
	    /* We failed to get the geometry */
	    if (lba)
		return -1;	/* Can only write MBR */

	    s = 1;
	    h = 0;
	    c = 0;
	} else
	    lba_to_chs(drive_info, lba, &s, &h, &c);

	// XXX errno
	if (s > 63 || h > 256 || c > 1023)
	    return -1;

	inreg.eax.w[0] = 0x0301;	/* Write one sector */
	inreg.ecx.b[1] = c & 0xff;
	inreg.ecx.b[0] = s + (c >> 6);
	inreg.edx.b[1] = h;
	inreg.edx.b[0] = drive_info->disk;
	inreg.ebx.w[0] = OFFS(buf);
	inreg.es = SEG(buf);
    }

    /* Perform the write */
    if (int13_retry(&inreg, &outreg)) {
	errno_disk = outreg.eax.b[1];
	return -1;		/* Give up */
    } else
	return size;
}
コード例 #5
0
ファイル: localboot.c プロジェクト: Celelibi/syslinux
/*
 * Boot a specified local disk.  AX specifies the BIOS disk number; or
 * -1 in case we should execute INT 18h ("next device.")
 */
__export void local_boot(int16_t ax)
{
	com32sys_t ireg, oreg;
	int i;

        memset(&ireg, 0, sizeof(ireg));
	syslinux_force_text_mode();

	writestr(LOCALBOOT_MSG);
	crlf();
	cleanup_hardware();

	if (ax == -1) {
		/* Hope this does the right thing */
		__intcall(0x18, &zero_regs, NULL);

		/* If we returned, oh boy... */
		kaboom();
	}

	/*
	 * Load boot sector from the specified BIOS device and jump to
	 * it.
	 */
	memset(&ireg, 0, sizeof ireg);
	ireg.edx.b[0] = ax & 0xff;
	ireg.eax.w[0] = 0;	/* Reset drive */
	__intcall(0x13, &ireg, NULL);

	memset(&ireg, 0, sizeof(ireg));
	ireg.eax.w[0] = 0x0201;	/* Read one sector */
	ireg.ecx.w[0] = 0x0001;	/* C/H/S = 0/0/1 (first sector) */
	ireg.ebx.w[0] = OFFS(trackbuf);
	ireg.es = SEG(trackbuf);

	for (i = 0; i < retry_count; i++) {
		__intcall(0x13, &ireg, &oreg);

		if (!(oreg.eflags.l & EFLAGS_CF))
			break;
	}

	if (i == retry_count)
		kaboom();

	cli();			/* Abandon hope, ye who enter here */
	memcpy((void *)0x07C00, trackbuf, 512);

	ireg.esi.w[0] = OFFS(trackbuf);
	ireg.edi.w[0] = 0x07C00;
	ireg.edx.w[0] = ax;
	call16(local_boot16, &ireg, NULL);
}
コード例 #6
0
ファイル: execute.c プロジェクト: pierre/syslinux-fastboot
void execute(const char *cmdline, enum kernel_type type)
{
  com32sys_t ireg;
  const char *p, * const *pp;
  char *q = __com32.cs_bounce;
  const char *kernel, *args;

  memset(&ireg, 0, sizeof ireg);

  kernel = q;
  p = cmdline;
  while ( *p && !my_isspace(*p) ) {
    *q++ = *p++;
  }
  *q++ = '\0';

  args = q;
  while ( *p && my_isspace(*p) )
    p++;

  strcpy(q, p);

  if (kernel[0] == '.' && type == KT_NONE) {
    /* It might be a type specifier */
    enum kernel_type type = KT_NONE;
    for (pp = kernel_types; *pp; pp++, type++) {
      if (!strcmp(kernel+1, *pp)) {
	execute(p, type);	/* Strip the type specifier and retry */
      }
    }
  }

  if (type == KT_LOCALBOOT) {
    ireg.eax.w[0] = 0x0014;	/* Local boot */
    ireg.edx.w[0] = strtoul(kernel, NULL, 0);
  } else {
    if (type < KT_KERNEL)
      type = KT_KERNEL;

    ireg.eax.w[0] = 0x0016;	/* Run kernel image */
    ireg.esi.w[0] = OFFS(kernel);
    ireg.ds       = SEG(kernel);
    ireg.ebx.w[0] = OFFS(args);
    ireg.es       = SEG(args);
    ireg.edx.l    = type-KT_KERNEL;
    /* ireg.ecx.l    = 0; */		/* We do ipappend "manually" */
  }

  __intcall(0x22, &ireg, NULL);

  /* If this returns, something went bad; return to menu */
}
コード例 #7
0
ファイル: fd.c プロジェクト: KryvoyNosochek/syslinux
int __start(void)
{
    int whichfd = atou(__com32.cs_cmdline);
    static com32sys_t inreg, outreg;	/* In bss, so zeroed automatically */
    int retry;

    for (retry = 0; retry < 6; retry++) {
	printf(">");
	inreg.eax.w[0] = 0x0201;	/* Read one sector */
	inreg.ecx.w[0] = 0x0001;	/* Cyl 0 sector 1 */
	inreg.edx.b[1] = 0;	/* Head 0 */
	inreg.edx.b[0] = whichfd;	/* Drive number */
	inreg.es = SEG(__com32.cs_bounce);	/* Read into the bounce buffer */
	inreg.ebx.w[0] = OFFS(__com32.cs_bounce);
	__com32.cs_intcall(0x13, &inreg, &outreg);

	if ((outreg.eflags.l & 1) == 0)
	    break;
    }

    if ((outreg.eflags.l & 1) == 0) {
	printf("!\n");
	inreg.eax.w[0] = 0x000d;
	inreg.edx.w[0] = 0;
	inreg.edi.l = (uint32_t) __com32.cs_bounce;
	inreg.ecx.l = 512;
	inreg.ebx.l = whichfd & 0xff;
	inreg.esi.l = 0;	/* No partitions */
	inreg.ds = 0;		/* No partitions */
	__com32.cs_intcall(0x22, &inreg, NULL);
    }

    /* If we get here, badness happened */
    return 255;
}
コード例 #8
0
ファイル: geom.c プロジェクト: 1stMaster/syslinux
/**
 * get_drive_parameters_with_extensions - retrieve disk parameters via AH=48h
 *
 * INT 13 - IBM/MS INT 13 Extensions - GET DRIVE PARAMETERS
 *     AH = 48h
 *     DL = drive (80h-FFh)
 *     DS:SI -> buffer for drive parameters
 * Return: CF clear if successful
 *     AH = 00h
 *     DS:SI buffer filled
 *     CF set on error
 *     AH = error code (see #00234)
 * BUG: several different Compaq BIOSes incorrectly report high-numbered
 *     drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
 *     same geometry as drive 80h; as a workaround, scan through disk
 *     numbers, stopping as soon as the number of valid drives encountered
 *     equals the value in 0040h:0075h
 **/
static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
{
    com32sys_t inreg, outreg;
    struct edd_device_parameters *dp = __com32.cs_bounce;

    memset(&inreg, 0, sizeof inreg);

    /*
     * The caller shall set this value to the maximum Result Buffer
     * length, in bytes. If the length of this buffer is less than 30
     * bytes, this function shall not return the pointer to Drive Parameter
     * Table (DPT) extension. If the buffer length is 30 or greater on
     * entry, it shall be set to 30 on exit. If the buffer length is
     * between 26 and 29, it shall be set to 26 on exit.
     * If the buffer length is less than 26 on entry an error shall be
     * returned.
     */
    dp->len = sizeof(struct edd_device_parameters);

    inreg.esi.w[0] = OFFS(dp);
    inreg.ds = SEG(dp);
    inreg.edx.b[0] = drive_info->disk;
    inreg.eax.b[1] = 0x48;

    __intcall(0x13, &inreg, &outreg);

    /* CF set on error */
    if (outreg.eflags.l & EFLAGS_CF)
	return outreg.eax.b[1];

    memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);

    return 0;
}
コード例 #9
0
ファイル: syslinux.c プロジェクト: numascale/firmware
int OS::udp_read(void *buf, const size_t len, uint32_t *from_ip)
{
	int ret = 0;

	t_PXENV_UDP_READ *pxe_read_param = (t_PXENV_UDP_READ *)lzalloc(sizeof(t_PXENV_UDP_READ) + len);
	xassert(pxe_read_param);
	char *buf_reloc = (char *)pxe_read_param + sizeof(*pxe_read_param);

	pxe_read_param->s_port = htons(UDP_PORT_NO);
	pxe_read_param->d_port = htons(UDP_PORT_NO);
	pxe_read_param->buffer.seg = SEG(buf_reloc);
	pxe_read_param->buffer.offs = OFFS(buf_reloc);
	pxe_read_param->buffer_size = len;
	pxeapi_call(PXENV_UDP_READ, (uint8_t *)pxe_read_param);

	if ((pxe_read_param->status == PXENV_STATUS_SUCCESS) &&
	    (pxe_read_param->s_port == htons(UDP_PORT_NO))) {
		memcpy(buf, buf_reloc, pxe_read_param->buffer_size);
		*from_ip = pxe_read_param->src_ip;
		ret = pxe_read_param->buffer_size;
	}

	lfree(pxe_read_param);
	return ret;
}
コード例 #10
0
ファイル: gpxecmd.c プロジェクト: Celelibi/syslinux
static void gpxecmd(const char **args)
{
    char *q;
    struct s_PXENV_FILE_EXEC *fx;

    fx = lmalloc(sizeof *fx);
    if (!fx)
	return;

    q = (char *)(fx + 1);

    fx->Status = 1;
    fx->Command.offs = OFFS(q);
    fx->Command.seg = SEG(q);

    while (*args) {
	q = stpcpy(q, *args);
	*q++ = ' ';
	args++;
    }
    *--q = '\0';

    pxe_call(PXENV_FILE_EXEC, fx);

    /* This should not return... */
}
コード例 #11
0
ファイル: clk_trimtaip.c プロジェクト: execunix/vinos
/* parse_cvt_fnc_t cvt_trimtaip */
static u_long
cvt_trimtaip(
	     unsigned char *buffer,
	     int            size,
	     struct format *format,
	     clocktime_t   *clock_time,
	     void          *local
	     )
{
	long gpsfix;
	u_char calc_csum = 0;
	long   recv_csum;
	int	 i;

	if (!Strok(buffer, format->fixed_string)) return CVT_NONE;
#define	OFFS(x) format->field_offsets[(x)].offset
#define	STOI(x, y) \
	Stoi(&buffer[OFFS(x)], y, \
	     format->field_offsets[(x)].length)
		if (	STOI(O_DAY,	&clock_time->day)	||
			STOI(O_MONTH,	&clock_time->month)	||
			STOI(O_YEAR,	&clock_time->year)	||
			STOI(O_HOUR,	&clock_time->hour)	||
			STOI(O_MIN,	&clock_time->minute)	||
			STOI(O_SEC,	&clock_time->second)	||
			STOI(O_USEC,	&clock_time->usecond)||
			STOI(O_GPSFIX,	&gpsfix)
			) return CVT_FAIL|CVT_BADFMT;

	clock_time->usecond *= 1000;
	/* Check that the checksum is right */
	for (i=OFFS(O_CHKSUM)-1; i >= 0; i--) calc_csum ^= buffer[i];
	recv_csum =	(hexval(buffer[OFFS(O_CHKSUM)]) << 4) |
		hexval(buffer[OFFS(O_CHKSUM)+1]);
	if (recv_csum < 0) return CVT_FAIL|CVT_BADTIME;
	if (((u_char) recv_csum) != calc_csum) return CVT_FAIL|CVT_BADTIME;

	clock_time->utcoffset = 0;

	/* What should flags be set to ? */
	clock_time->flags = PARSEB_UTC;

	/* if the current GPS fix is 9 (unknown), reject */
	if (0 > gpsfix || gpsfix > 9) clock_time->flags |= PARSEB_POWERUP;

	return CVT_OK;
}
コード例 #12
0
ファイル: syslnx.c プロジェクト: pierre/syslinux-fastboot
void runsyslinuxcmd(const char *cmd)
{
  strcpy(__com32.cs_bounce, cmd);
  REG_AX(inreg) = 0x0003; // Run command
  REG_BX(inreg) = OFFS(__com32.cs_bounce);
  REG_ES(inreg) = SEG(__com32.cs_bounce);
  __intcall(0x22, &inreg, &outreg);
}
コード例 #13
0
ファイル: syslinux.c プロジェクト: numascale/firmware
static int pxeapi_call(int func, const uint8_t *buf)
{
	static com32sys_t inargs, outargs;
	inargs.eax.w[0] = 0x0009; /* Call PXE Stack */
	inargs.ebx.w[0] = func; /* PXE function number */
	inargs.edi.w[0] = OFFS(buf);
	inargs.es = SEG(buf);
	__intcall(0x22, &inargs, &outargs);
	return outargs.eax.w[0] == PXENV_EXIT_SUCCESS;
}
コード例 #14
0
static void dump_e820(void)
{
    com32sys_t ireg, oreg;
    struct e820_data ed;
    uint32_t type;
    void *low_ed;

    low_ed = lmalloc(sizeof ed);
    if (!low_ed)
        return;

    memset(&ireg, 0, sizeof ireg);

    ireg.eax.w[0] = 0xe820;
    ireg.edx.l = 0x534d4150;
    ireg.ecx.l = sizeof(struct e820_data);
    ireg.edi.w[0] = OFFS(low_ed);
    ireg.es = SEG(low_ed);

    memset(&ed, 0, sizeof ed);
    ed.extattr = 1;

    do {
        memcpy(low_ed, &ed, sizeof ed);

        __intcall(0x15, &ireg, &oreg);
        if (oreg.eflags.l & EFLAGS_CF ||
                oreg.eax.l != 0x534d4150 || oreg.ecx.l < 20)
            break;

        memcpy(&ed, low_ed, sizeof ed);

        if (oreg.ecx.l >= 24) {
            /* ebx base length end type */
            printf("%8x %016llx %016llx %016llx %d [%x]",
                   ireg.ebx.l, ed.base, ed.len, ed.base + ed.len, ed.type,
                   ed.extattr);
        } else {
            /* ebx base length end */
            printf("%8x %016llx %016llx %016llx %d [-]",
                   ireg.ebx.l, ed.base, ed.len, ed.base + ed.len, ed.type);
            ed.extattr = 1;
        }

        type = ed.type - 1;
        if (type < sizeof(e820_types) / sizeof(e820_types[0]))
            printf(" %s", e820_types[type]);

        putchar('\n');

        ireg.ebx.l = oreg.ebx.l;
    } while (ireg.ebx.l);

    lfree(low_ed);
}
コード例 #15
0
ファイル: syslinux.c プロジェクト: numascale/firmware
void OS::udp_write(const void *buf, const size_t len, uint32_t to_ip)
{
	t_PXENV_UDP_WRITE *pxe_write_param = (t_PXENV_UDP_WRITE *)lzalloc(sizeof(t_PXENV_UDP_WRITE) + len);
	xassert(pxe_write_param);
	char *buf_reloc = (char *)pxe_write_param + sizeof(*pxe_write_param);

	pxe_write_param->ip = to_ip;
	pxe_write_param->src_port = htons(UDP_PORT_NO);
	pxe_write_param->dst_port = htons(UDP_PORT_NO);
	pxe_write_param->buffer.seg = SEG(buf_reloc);
	pxe_write_param->buffer.offs = OFFS(buf_reloc);
	pxe_write_param->buffer_size = len;

	memcpy(buf_reloc, buf, len);
	pxeapi_call(PXENV_UDP_WRITE, (uint8_t *)pxe_write_param);
	lfree(pxe_write_param);
}
コード例 #16
0
ファイル: meminfo.c プロジェクト: pierre/syslinux-fastboot
static void dump_e820(void)
{
  com32sys_t ireg, oreg;
  struct e820_data ed;
  uint32_t type;

  memset(&ireg, 0, sizeof ireg);

  ireg.eax.w[0] = 0xe820;
  ireg.edx.l    = 0x534d4150;
  ireg.ecx.l    = sizeof(struct e820_data);
  ireg.edi.w[0] = OFFS(__com32.cs_bounce);
  ireg.es       = SEG(__com32.cs_bounce);

  memset(&ed, 0, sizeof ed);
  ed.extattr = 1;

  do {
    memcpy(__com32.cs_bounce, &ed, sizeof ed);

    __intcall(0x15, &ireg, &oreg);
    if (oreg.eflags.l & EFLAGS_CF ||
	oreg.eax.l != 0x534d4150 ||
	oreg.ecx.l < 20)
      break;

    memcpy(&ed, __com32.cs_bounce, sizeof ed);

    if (oreg.ecx.l < 24)
      ed.extattr = 1;

    /* ebx base length end type */
    printf("%8x %016llx %016llx %016llx %d [%x]",
	   ireg.ebx.l, ed.base, ed.len, ed.base+ed.len, ed.type, ed.extattr);

    type = ed.type - 1;
    if (type < sizeof(e820_types)/sizeof(e820_types[0]))
      printf(" %s", e820_types[type]);

    putchar('\n');

    ireg.ebx.l = oreg.ebx.l;
  } while (ireg.ebx.l);
}
コード例 #17
0
ファイル: syslinux.c プロジェクト: numascale/firmware
bool OS::memmap_entry(uint64_t *base, uint64_t *length, uint64_t *type)
{
	state.eax.l = 0xe820;
	state.edx.l = STR_DW_N("SMAP");
	state.ecx.l = sizeof(*ent);
	state.edi.w[0] = OFFS(ent);
	state.es = SEG(ent);

	__intcall(0x15, &state, &state);
	xassert(state.eax.l == STR_DW_N("SMAP"));

	// detect if bootloader is called again
	if (!ent->length)
		fatal("Bootloader already executed; check boot configuration!");

	*base = ent->base;
	*length = ent->length;
	*type = ent->type;

	return state.ebx.l > 0;
}
コード例 #18
0
ファイル: sanboot.c プロジェクト: viikasgarg/syslinux
static bool is_gpxe(void)
{
    const struct syslinux_version *sv;
    com32sys_t reg;
    struct s_PXENV_FILE_CHECK_API *fca;

    sv = syslinux_version();
    if (sv->filesystem != SYSLINUX_FS_PXELINUX)
	return false;		/* Not PXELINUX */

    fca = __com32.cs_bounce;
    memset(fca, 0, sizeof *fca);
    fca->Size = sizeof *fca;
    fca->Magic = 0x91d447b2;

    memset(&reg, 0, sizeof reg);
    reg.eax.w[0] = 0x0009;
    reg.ebx.w[0] = 0x00e6;	/* PXENV_FILE_API_CHECK */
    reg.edi.w[0] = OFFS(fca);
    reg.es = SEG(fca);

    __intcall(0x22, &reg, &reg);

    if (reg.eflags.l & EFLAGS_CF)
	return false;		/* Cannot invoke PXE stack */

    if (reg.eax.w[0] || fca->Status)
	return false;		/* PXE failure */

    if (fca->Magic != 0xe9c17b20)
	return false;		/* Incorrect magic */

    if (fca->Size < sizeof *fca)
	return false;		/* Short return */

    if (!(fca->APIMask & (1 << 5)))
	return false;		/* No FILE EXEC */

    return true;
}
コード例 #19
0
ファイル: pxe.c プロジェクト: emmericp/syslinux
/*
 * the ASM pxenv function wrapper, return 1 if error, or 0
 *
 */
__export int pxe_call(int opcode, void *data)
{
    static DECLARE_INIT_SEMAPHORE(pxe_sem, 1);
    extern void pxenv(void);
    com32sys_t regs;

    sem_down(&pxe_sem, 0);

#if 0
    dprintf("pxe_call op %04x data %p\n", opcode, data);
#endif

    memset(&regs, 0, sizeof regs);
    regs.ebx.w[0] = opcode;
    regs.es       = SEG(data);
    regs.edi.w[0] = OFFS(data);
    call16(pxenv, &regs, &regs);

    sem_up(&pxe_sem);

    return regs.eflags.l & EFLAGS_CF;  /* CF SET if fail */
}
コード例 #20
0
ファイル: read.c プロジェクト: 1stMaster/syslinux
/**
 * read_sectors - read several sectors from disk
 * @drive_info:		driveinfo struct describing the disk
 * @data:		Pre-allocated buffer for output
 * @lba:		Position to read
 * @sectors:		Number of sectors to read
 *
 * Return the number of sectors read on success or -1 on failure.
 * errno_disk contains the error number.
 **/
int read_sectors(struct driveinfo *drive_info, void *data,
		 const unsigned int lba, const int sectors)
{
    com32sys_t inreg, outreg;
    struct ebios_dapa *dapa = __com32.cs_bounce;
    void *buf = (char *)__com32.cs_bounce + sectors * SECTOR;
    char *bufp = data;

    if (get_drive_parameters(drive_info) == -1)
	return -1;

    memset(&inreg, 0, sizeof inreg);

    if (drive_info->ebios) {
	dapa->len = sizeof(*dapa);
	dapa->count = sectors;
	dapa->off = OFFS(buf);
	dapa->seg = SEG(buf);
	dapa->lba = lba;

	inreg.esi.w[0] = OFFS(dapa);
	inreg.ds = SEG(dapa);
	inreg.edx.b[0] = drive_info->disk;
	inreg.eax.b[1] = 0x42;	/* Extended read */
    } else {
	unsigned int c, h, s;

	if (!drive_info->cbios) {	// XXX errno
	    /* We failed to get the geometry */
	    if (lba)
		return -1;	/* Can only read MBR */

	    s = 1;
	    h = 0;
	    c = 0;
	} else
	    lba_to_chs(drive_info, lba, &s, &h, &c);

	// XXX errno
	if (s > 63 || h > 256 || c > 1023)
	    return -1;

	inreg.eax.w[0] = 0x0201;	/* Read one sector */
	inreg.ecx.b[1] = c & 0xff;
	inreg.ecx.b[0] = s + (c >> 6);
	inreg.edx.b[1] = h;
	inreg.edx.b[0] = drive_info->disk;
	inreg.ebx.w[0] = OFFS(buf);
	inreg.es = SEG(buf);
    }

    /* Perform the read */
    if (int13_retry(&inreg, &outreg)) {
	errno_disk = outreg.eax.b[1];
	return -1;		/* Give up */
    }

    memcpy(bufp, buf, sectors * SECTOR);

    return sectors;
}
コード例 #21
0
ファイル: vesa.c プロジェクト: Distrotech/syslinux
static int vesa_getmodes(lua_State *L)
{
  com32sys_t rm;
  uint16_t mode, *mode_ptr;
  struct vesa_general_info *gi;
  struct vesa_mode_info *mi;
  int nmode = 1;
  int rv = -1;

  gi = lmalloc(sizeof *gi);
  if (!gi)
      return -1;

  mi = lmalloc(sizeof *mi);
  if (!mi)
      goto out;

  memset(&rm, 0, sizeof(rm));
  memset(gi, 0, sizeof *gi);

  gi->signature = VBE2_MAGIC;   /* Get VBE2 extended data */
  rm.eax.w[0] = 0x4F00;         /* Get SVGA general information */
  rm.edi.w[0] = OFFS(gi);
  rm.es      = SEG(gi);
  __intcall(0x10, &rm, &rm);

  if ( rm.eax.w[0] != 0x004F )
    goto out;                   /* Function call failed */
  if ( gi->signature != VESA_MAGIC ) {
    rv = -2;                   /* No magic */
    goto out;
  }
  if ( gi->version < 0x0102 ) {
    rv = -3;                   /* VESA 1.2+ required */
    goto out;
  }

  lua_newtable(L);      /* list of modes */

  /* Copy general info */
  memcpy(&__vesa_info.gi, gi, sizeof *gi);

  /* Search for a 640x480 mode with a suitable color and memory model... */

  mode_ptr = GET_PTR(gi->video_mode_ptr);

  while ((mode = *mode_ptr++) != 0xFFFF) {
    mode &= 0x1FF;              /* The rest are attributes of sorts */

    printf("Found mode: 0x%04x (%dx%dx%d)\n", mode, mi->h_res, mi->v_res, mi->bpp);

    memset(&rm, 0, sizeof(rm));
    memset(mi, 0, sizeof *mi);
    rm.eax.w[0] = 0x4F01;       /* Get SVGA mode information */
    rm.ecx.w[0] = mode;
    rm.edi.w[0] = OFFS(mi);
    rm.es  = SEG(mi);
    __intcall(0x10, &rm, &rm);

    /* Must be a supported mode */
    if ( rm.eax.w[0] != 0x004f )
      continue;

    lua_pushnumber(L, nmode++);
    lua_newtable(L); /* mode info */

    lua_pushstring(L, "mode");
    lua_pushnumber(L, mode);
    lua_settable(L,-3);

    lua_pushstring(L, "hres");
    lua_pushnumber(L, mi->h_res);
    lua_settable(L,-3);

    lua_pushstring(L, "vres");
    lua_pushnumber(L, mi->v_res);
    lua_settable(L,-3);

    lua_pushstring(L, "bpp");
    lua_pushnumber(L, mi->bpp);
    lua_settable(L,-3);

    lua_settable(L, -3); /* add to mode list */

  }

  rv = 1;
out:
  lfree(mi);
  lfree(gi);
  return rv;
}
コード例 #22
0
ファイル: vesainfo.c プロジェクト: Celelibi/syslinux
static void print_modes(void)
{
	static com32sys_t rm;
	struct vesa_general_info *gi;
	struct vesa_mode_info *mi;
	uint16_t mode, *mode_ptr;
	int lines;

	struct vesa_info *vesa;

	vesa = lmalloc(sizeof(*vesa));
	if (!vesa) {
		printf("vesainfo.c32: fail in lmalloc\n");
		return;
	}
	gi = &vesa->gi;
	mi = &vesa->mi;

        memset(&rm, 0, sizeof rm);
	gi->signature = VBE2_MAGIC;	/* Get VBE2 extended data */
	rm.eax.w[0] = 0x4F00;	/* Get SVGA general information */
	rm.edi.w[0] = OFFS(gi);
	rm.es = SEG(gi);
	__intcall(0x10, &rm, &rm);

    if (rm.eax.w[0] != 0x004F) {
	printf("No VESA BIOS detected\n");
	goto exit;
    } else if (gi->signature != VESA_MAGIC) {
	printf("VESA information structure has bad magic, trying anyway...\n");
    }

    printf("VBE version %d.%d\n"
	   "Mode   attrib h_res v_res bpp layout rpos gpos bpos\n",
	   (gi->version >> 8) & 0xff, gi->version & 0xff);

    lines = 1;

    mode_ptr = GET_PTR(gi->video_mode_ptr);

    while ((mode = *mode_ptr++) != 0xFFFF) {
	if (++lines >= 23) {
	    wait_key();
	    lines = 0;
	}

        memset(&rm, 0, sizeof rm);
	rm.eax.w[0] = 0x4F01;	/* Get SVGA mode information */
	rm.ecx.w[0] = mode;
	rm.edi.w[0] = OFFS(mi);
	rm.es = SEG(mi);
	__intcall(0x10, &rm, &rm);

	/* Must be a supported mode */
	if (rm.eax.w[0] != 0x004f)
	    continue;

	printf("0x%04x 0x%04x %5u %5u %3u %6u %4u %4u %4u\n",
	       mode, mi->mode_attr, mi->h_res, mi->v_res, mi->bpp,
	       mi->memory_layout, mi->rpos, mi->gpos, mi->bpos);
    }

exit:
	lfree(vesa);
	return;
}
コード例 #23
0
ファイル: env.c プロジェクト: digidotcom/yocto-uboot
/* ********** extern stuff **********/

extern env_t* env_ptr;          /* common/env_<nand/eeprom>.c */
extern int _do_setenv( int flag, int argc, char *argv[] );  /* common/cmd_nvedit.c */
extern int _do_orig_setenv (int flag, int argc, char *argv[]);

/* ********** local functions **********/

static const env_param_t* EnvVarInNVRAM( const char* szArg );
static int EnvVarStoreToNVRAM( const env_param_t* pParam, const char* szVal );

/* ********** local variables **********/

static const env_param_t l_axParam[] = {
        { "ethaddr",      ENV_MAC, OFFS( xID.axMAC[ 0 ] ), 1 },
        { "wlanaddr",     ENV_MAC, OFFS( xID.axMAC[ 1 ] ), 1 },
        { "eth1addr",     ENV_MAC, OFFS( eth1addr ), 1 },
        { "btaddr",       ENV_MAC, OFFS( btaddr1 ), 1 },
        { "ipaddr",       ENV_IP,  OFFS( xIP.axDevice[ 0 ].uiIP ) },
        { "ipaddr_wlan",  ENV_IP,  OFFS( xIP.axDevice[ 1 ].uiIP ) },
        { "ipaddr1",      ENV_IP,  OFFS( eth1dev.uiIP ) },
        { "netmask",      ENV_IP,  OFFS( xIP.axDevice[ 0 ].uiNetMask ) },
        { "netmask_wlan", ENV_IP,  OFFS( xIP.axDevice[ 1 ].uiNetMask ) },
        { "netmask1",     ENV_IP,  OFFS( eth1dev.uiNetMask ) },
        { "serverip",     ENV_IP,  OFFS( xIP.uiIPServer ) },
        { "gatewayip",    ENV_IP,  OFFS( xIP.uiIPGateway) },
        { "dnsip",        ENV_IP,  OFFS( xIP.auiIPDNS[ 0 ] ) },
        { "dnsip2",       ENV_IP,  OFFS( xIP.auiIPDNS[ 1 ] ) },
        { "dhcp",         ENV_BOOL_ON, OFFS( xIP.axDevice[ 0 ].flags.bDHCP ) },
        { "dhcp_wlan",    ENV_BOOL_ON, OFFS( xIP.axDevice[ 1 ].flags.bDHCP ) },
コード例 #24
0
	BACKGROUNDPEN, TEXTPEN, FILLPEN, HIGHLIGHTTEXTPEN, SHINEPEN, TEXTPEN,
	SHINEPEN, SHADOWPEN, BACKGROUNDPEN, TEXTPEN, -4, BACKGROUNDPEN
};

/** Which part of editor to modify according to color changes **/
UBYTE Modif[] = {
	EDIT_AREA, EDIT_AREA, EDIT_AREA, EDIT_AREA, 0, 0, EDIT_GUI, EDIT_GUI,
	EDIT_GUI, EDIT_GUI, EDIT_GUI, EDIT_GUI
};

/** Little wrapper **/
#define	OFFS(x)		(UBYTE)(offsetof(PREFS,x))

/** Offset of structure PREFS **/
UBYTE offsets[] = {
	OFFS(use_pub), OFFS(wordssep),         OFFS(attrtxt), OFFS(attrtxt.ta_YSize),
	OFFS(attrscr), OFFS(attrscr.ta_YSize), OFFS(left),    OFFS(scrw),
	OFFS(scrd),    OFFS(modeid),           OFFS(vmd),     OFFS(pen)
};
/** And correspond size (0=null-terminated string) **/
UBYTE sizefields[] = {
	12*sizeof(char),  0, 0, sizeof(prefs.attrtxt)-sizeof(STRPTR), 0,
	sizeof(prefs.attrscr)-sizeof(STRPTR), 4*sizeof(prefs.left), sizeof(prefs.scrw),
	sizeof(prefs.scrd), sizeof(prefs.modeid), sizeof(prefs.vmd), sizeof(prefs.pen)
};

UBYTE FontName[60];

/*** Convert a TextFont struct into a TextAttr ***/
void text_to_attr(struct TextFont *src, struct TextAttr *dest)
{
コード例 #25
0
ファイル: mem.c プロジェクト: 1stMaster/syslinux
static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
{
    com32sys_t ireg, oreg;
    struct e820_entry *e820buf = __com32.cs_bounce;
    struct AddrRangeDesc *ard;
    size_t ard_count, ard_space;

    /* Use INT 12h to get DOS memory */
    __intcall(0x12, &__com32_zero_regs, &oreg);
    *dosmem = oreg.eax.w[0] << 10;
    if (*dosmem < 32 * 1024 || *dosmem > 640 * 1024) {
	/* INT 12h reports nonsense... now what? */
	uint16_t ebda_seg = *(uint16_t *) 0x40e;
	if (ebda_seg >= 0x8000 && ebda_seg < 0xa000)
	    *dosmem = ebda_seg << 4;
	else
	    *dosmem = 640 * 1024;	/* Hope for the best... */
    }

    /* Allocate initial space */
    *ardp = ard = malloc(RANGE_ALLOC_BLOCK * sizeof *ard);
    if (!ard)
	return 0;

    ard_count = 0;
    ard_space = RANGE_ALLOC_BLOCK;

    /* First try INT 15h AX=E820h */
    memset(&ireg, 0, sizeof ireg);
    ireg.eax.l = 0xe820;
    ireg.edx.l = 0x534d4150;
    /* ireg.ebx.l    = 0; */
    ireg.ecx.l = sizeof(*e820buf);
    ireg.es = SEG(e820buf);
    ireg.edi.w[0] = OFFS(e820buf);
    memset(e820buf, 0, sizeof *e820buf);

    do {
	__intcall(0x15, &ireg, &oreg);

	if ((oreg.eflags.l & EFLAGS_CF) ||
	    (oreg.eax.l != 0x534d4150) || (oreg.ecx.l < 20))
	    break;

	if (ard_count >= ard_space) {
	    ard_space += RANGE_ALLOC_BLOCK;
	    *ardp = ard = realloc(ard, ard_space * sizeof *ard);
	    if (!ard)
		return ard_count;
	}

	ard[ard_count].size = 20;
	ard[ard_count].BaseAddr = e820buf->start;
	ard[ard_count].Length = e820buf->len;
	ard[ard_count].Type = e820buf->type;
	ard_count++;

	ireg.ebx.l = oreg.ebx.l;
    } while (oreg.ebx.l);

    if (ard_count)
	return ard_count;

    ard[0].size = 20;
    ard[0].BaseAddr = 0;
    ard[0].Length = *dosmem << 10;
    ard[0].Type = 1;

    /* Next try INT 15h AX=E801h */
    ireg.eax.w[0] = 0xe801;
    __intcall(0x15, &ireg, &oreg);

    if (!(oreg.eflags.l & EFLAGS_CF) && oreg.ecx.w[0]) {
	ard[1].size = 20;
	ard[1].BaseAddr = 1 << 20;
	ard[1].Length = oreg.ecx.w[0] << 10;
	ard[1].Type = 1;

	if (oreg.edx.w[0]) {
	    ard[2].size = 20;
	    ard[2].BaseAddr = 16 << 20;
	    ard[2].Length = oreg.edx.w[0] << 16;
	    ard[2].Type = 1;
	    return 3;
	} else {
	    return 2;
	}
    }

    /* Finally try INT 15h AH=88h */
    ireg.eax.w[0] = 0x8800;
    if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) {
	ard[1].size = 20;
	ard[1].BaseAddr = 1 << 20;
	ard[1].Length = oreg.ecx.w[0] << 10;
	ard[1].Type = 1;
	return 2;
    }

    return 1;			/* ... problematic ... */
}
コード例 #26
0
ファイル: lua-timer.c プロジェクト: e8johan/murphy
 * Lua timer class
 */

#define OFFS(m) MRP_OFFSET(timer_lua_t, m)
#define RDONLY  MRP_LUA_CLASS_READONLY
#define NOTIFY  MRP_LUA_CLASS_NOTIFY
#define NOFLAGS MRP_LUA_CLASS_NOFLAGS

MRP_LUA_METHOD_LIST_TABLE(timer_lua_methods,
                          MRP_LUA_METHOD_CONSTRUCTOR(timer_lua_create));

MRP_LUA_METHOD_LIST_TABLE(timer_lua_overrides,
                          MRP_LUA_OVERRIDE_CALL     (timer_lua_create));

MRP_LUA_MEMBER_LIST_TABLE(timer_lua_members,
    MRP_LUA_CLASS_INTEGER("interval", OFFS(msecs)   , NULL, NULL, NOTIFY)
    MRP_LUA_CLASS_LFUNC  ("callback", OFFS(callback), NULL, NULL, NOTIFY)
    MRP_LUA_CLASS_ANY    ("data"    , OFFS(data)    , NULL, NULL, NOTIFY)
    MRP_LUA_CLASS_BOOLEAN("oneshot" , OFFS(oneshot) , NULL, NULL, NOTIFY));


typedef enum {
    TIMER_MEMBER_INTERVAL,
    TIMER_MEMBER_CALLBACK,
    TIMER_MEMBER_DATA,
    TIMER_MEMBER_ONESHOT
} timer_member_t;

MRP_LUA_DEFINE_CLASS(timer, lua, timer_lua_t, timer_lua_destroy,
                     timer_lua_methods, timer_lua_overrides,
                     timer_lua_members, NULL, timer_lua_changed,
コード例 #27
0
ファイル: diskio_bios.c プロジェクト: hildred/syslinux
static int chs_rdwr_sectors(struct disk *disk, void *buf,
			    sector_t lba, size_t count, bool is_write)
{
    char *ptr = buf;
    char *tptr;
    size_t chunk, freeseg;
    int sector_shift = disk->sector_shift;
    uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
    uint32_t t;
    uint32_t c, h, s;
    com32sys_t ireg, oreg;
    size_t done = 0;
    size_t bytes;
    int retry;
    uint32_t maxtransfer = disk->maxtransfer;

    if (lba + disk->part_start >= chs_max(disk))
	return 0;		/* Impossible CHS request */

    memset(&ireg, 0, sizeof ireg);

    ireg.eax.b[1] = 0x02 + is_write;
    ireg.edx.b[0] = disk->disk_number;

    while (count) {
	chunk = count;
	if (chunk > maxtransfer)
	    chunk = maxtransfer;

	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;

	if ((size_t)buf <= 0xf0000 && freeseg) {
	    /* Can do a direct load */
	    tptr = ptr;
	} else {
	    /* Either accessing high memory or we're crossing a 64K line */
	    tptr = core_xfer_buf;
	    freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
	}
	if (chunk > freeseg)
	    chunk = freeseg;

	s = xlba % disk->s;
	t = xlba / disk->s;
	h = t % disk->h;
	c = t / disk->h;

	if (chunk > (disk->s - s))
	    chunk = disk->s - s;

	bytes = chunk << sector_shift;

	if (tptr != ptr && is_write)
	    memcpy(tptr, ptr, bytes);

	ireg.eax.b[0] = chunk;
	ireg.ecx.b[1] = c;
	ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
	ireg.edx.b[1] = h;
	ireg.ebx.w[0] = OFFS(tptr);
	ireg.es       = SEG(tptr);

	retry = RETRY_COUNT;

        for (;;) {
	    if (c < 1024) {
		dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
			ireg.edx.b[0], chunk, xlba, c, h, s+1,
			ireg.es, ireg.ebx.w[0],
			(ireg.eax.b[1] & 1) ? "<-" : "->",
			ptr);

		__intcall(0x13, &ireg, &oreg);
		if (!(oreg.eflags.l & EFLAGS_CF))
		    break;

		dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);

		if (retry--)
		    continue;

		/*
		 * For any starting value, this will always end with
		 * ..., 1, 0
		 */
		chunk >>= 1;
		if (chunk) {
		    maxtransfer = chunk;
		    retry = RETRY_COUNT;
		    ireg.eax.b[0] = chunk;
		    continue;
		}
	    }

	    printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
		   oreg.eax.w[0],
		   is_write ? "writing" : "reading",
		   lba, c, h, s+1);
	    return done;	/* Failure */
	}

	bytes = chunk << sector_shift;

	if (tptr != ptr && !is_write)
	    memcpy(ptr, tptr, bytes);

	/* If we dropped maxtransfer, it eventually worked, so remember it */
	disk->maxtransfer = maxtransfer;

	ptr   += bytes;
	xlba  += chunk;
	count -= chunk;
	done  += chunk;
    }
コード例 #28
0
ファイル: config.c プロジェクト: yudatun/external_mtools
    { "double-density-3-1/2",	12, 80, 2, 9 },
    { "720k",			12, 80, 2, 9 },

    { "dd514",			12, 40, 2, 9 },
    { "double-density-5-1/4",	12, 40, 2, 9 },
    { "360k",			12, 40, 2, 9 },

    { "320k",			12, 40, 2, 8 },
    { "180k",			12, 40, 1, 9 },
    { "160k",			12, 40, 1, 8 }
};

#define OFFS(x) ((caddr_t)&((struct device *)0)->x)

static switches_t dswitches[]= {
    { "FILE", OFFS(name), T_STRING },
    { "OFFSET", OFFS(offset), T_UINT },
    { "PARTITION", OFFS(partition), T_UINT },
    { "FAT", OFFS(fat_bits), T_INT },
    { "FAT_BITS", OFFS(fat_bits), T_UINT },
    { "MODE", OFFS(mode), T_UINT },
    { "TRACKS",  OFFS(tracks), T_UINT },
    { "CYLINDERS",  OFFS(tracks), T_UINT },
    { "HEADS", OFFS(heads), T_UINT },
    { "SECTORS", OFFS(sectors), T_UINT },
    { "HIDDEN", OFFS(hidden), T_UINT },
    { "PRECMD", OFFS(precmd), T_STRING },
    { "BLOCKSIZE", OFFS(blocksize), T_UINT },
    { "CODEPAGE", OFFS(codepage), T_UINT }
};
コード例 #29
0
ファイル: clk_hopf6021.c プロジェクト: sambuc/netbsd
/* parse_cvt_fnc_t cvt_hopf6021 */
static u_long
cvt_hopf6021(
	     unsigned char *buffer,
	     int            size,
	     struct format *format,
	     clocktime_t   *clock_time,
	     void          *local
	     )
{
	unsigned char status,weekday;

	if (!Strok(buffer, format->fixed_string))
	{
		return CVT_NONE;
	}

	if (  STOI(O_DAY,   &clock_time->day)    ||
	      STOI(O_MONTH, &clock_time->month)  ||
	      STOI(O_YEAR,  &clock_time->year)   ||
	      STOI(O_HOUR,  &clock_time->hour)   ||
	      STOI(O_MIN,   &clock_time->minute) ||
	      STOI(O_SEC,   &clock_time->second)
	      )
	{
		return CVT_FAIL|CVT_BADFMT;
	}

	clock_time->usecond   = 0;
	clock_time->utcoffset = 0;

	status = (u_char) hexval(buffer[OFFS(O_FLAGS)]);
	weekday= (u_char) hexval(buffer[OFFS(O_WDAY)]);

	if ((status == 0xFF) || (weekday == 0xFF))
	{
		return CVT_FAIL|CVT_BADFMT;
	}

	clock_time->flags  = 0;

	if (weekday & HOPF_UTC)
	{
		clock_time->flags |= PARSEB_UTC;
	}
	else
	{
		if (status & HOPF_DST)
		{
			clock_time->flags     |= PARSEB_DST;
			clock_time->utcoffset  = -2*60*60; /* MET DST */
		}
		else
		{
			clock_time->utcoffset  = -1*60*60; /* MET */
		}
	}

	clock_time->flags |= (status & HOPF_DSTWARN)  ? PARSEB_ANNOUNCE : 0;

	switch (status & HOPF_MODE)
	{
	    case HOPF_INVALID:  /* Time/Date invalid */
		clock_time->flags |= PARSEB_POWERUP;
		break;

	    case HOPF_INTERNAL: /* internal clock */
		clock_time->flags |= PARSEB_NOSYNC;
		break;

	    case HOPF_RADIO:    /* Radio clock */
	    case HOPF_RADIOHP:  /* Radio clock high precision */
		break;

	    default:
		return CVT_FAIL|CVT_BADFMT;
	}

	return CVT_OK;
}
コード例 #30
0
ファイル: initvesa.c プロジェクト: Celelibi/syslinux
void set_graphics_mode(const struct multiboot_header *mbh,
		       struct multiboot_info *mbi)
{
    com32sys_t rm;
    uint16_t mode, bestmode, *mode_ptr;
    struct vesa_general_info *gi;
    struct vesa_mode_info *mi;
    int pxf, bestpxf;
    int wantx, wanty;
    int err, besterr;
    bool better;
    addr_t viaddr;

    /* Only do this if requested by the OS image */
    if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0)
	return;

    gi = lmalloc(sizeof *gi);
    if (!gi)
	return;

    mi = lmalloc(sizeof *mi);
    if (!mi)
	goto out;

    memset(&rm, 0, sizeof rm);
    memset(gi, 0, sizeof *gi);

    gi->signature = VBE2_MAGIC;	/* Get VBE2 extended data */
    rm.eax.w[0] = 0x4F00;	/* Get SVGA general information */
    rm.edi.w[0] = OFFS(gi);
    rm.es = SEG(gi);
    __intcall(0x10, &rm, &rm);

    if (rm.eax.w[0] != 0x004F)
	goto out;		/* Function call failed */
    if (gi->signature != VESA_MAGIC)
	goto out;		/* No magic */
    if (gi->version < 0x0102)
	goto out;		/* VESA 1.2+ required */

    memcpy(&vesa_info.gi, gi, sizeof *gi);

    /* Search for a suitable mode with a suitable color and memory model... */

    mode_ptr = GET_PTR(gi->video_mode_ptr);
    bestmode = 0;
    bestpxf = 0;
    wantx = mbh->width  ? mbh->width  : 0xffff;
    wanty = mbh->height ? mbh->height : 0xffff;
    besterr = wantx + wanty;

    while ((mode = *mode_ptr++) != 0xFFFF) {
	mode &= 0x1FF;		/* The rest are attributes of sorts */

        memset(&rm, 0, sizeof rm);
	memset(mi, 0, sizeof *mi);
	rm.eax.w[0] = 0x4F01;	/* Get SVGA mode information */
	rm.ecx.w[0] = mode;
	rm.edi.w[0] = OFFS(mi);
	rm.es = SEG(mi);
	__intcall(0x10, &rm, &rm);

	/* Must be a supported mode */
	if (rm.eax.w[0] != 0x004f)
	    continue;

	/* Must be an LFB color graphics mode supported by the hardware.

	   The bits tested are:
	   7 - linear frame buffer
	   4 - graphics mode
	   3 - color mode
	   1 - mode information available (mandatory in VBE 1.2+)
	   0 - mode supported by hardware
	 */
	if ((mi->mode_attr & 0x009b) != 0x009b)
	    continue;

	/* We don't support multibank (interlaced memory) modes */
	/*
	 *  Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
	 * specification which states that banks == 1 for unbanked modes;
	 * fortunately it does report bank_size == 0 for those.
	 */
	if (mi->banks > 1 && mi->bank_size)
	    continue;

	/* Must either be a packed-pixel mode or a direct color mode
	   (depending on VESA version ); must be a supported pixel format */

	if (mi->bpp == 32 &&
	    (mi->memory_layout == 4 ||
	     (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
	      mi->bpos == 0)))
	    pxf = 32;
	else if (mi->bpp == 24 &&
		 (mi->memory_layout == 4 ||
		  (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
		   mi->bpos == 0)))
	    pxf = 24;
	else if (mi->bpp == 16 &&
		 (mi->memory_layout == 4 ||
		  (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
		   mi->bpos == 0)))
	    pxf = 16;
	else if (mi->bpp == 15 &&
		 (mi->memory_layout == 4 ||
		  (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 &&
		   mi->bpos == 0)))
	    pxf = 15;
	else
	    continue;

	better = false;
	err = abs(mi->h_res - wantx) + abs(mi->v_res - wanty);

#define IS_GOOD(mi, bestx, besty) \
	((mi)->h_res >= (bestx) && (mi)->v_res >= (besty))

	if (!bestpxf)
	    better = true;
	else if (!IS_GOOD(&vesa_info.mi, wantx, wanty) &&
		 IS_GOOD(mi, wantx, wanty))
	    /* This matches criteria, which the previous one didn't */
	    better = true;
	else if (IS_GOOD(&vesa_info.mi, wantx, wanty) &&
		 !IS_GOOD(mi, wantx, wanty))
	    /* This doesn't match criteria, and the previous one did */
	    better = false;
	else if (err < besterr)
	    better = true;
	else if (err == besterr && (pxf == (int)mbh->depth || pxf > bestpxf))
	    better = true;

	if (better) {
	    bestmode = mode;
	    bestpxf = pxf;
	    memcpy(&vesa_info.mi, mi, sizeof *mi);
	}
    }

    if (!bestpxf)
	goto out;		/* No mode found */

    mi = &vesa_info.mi;
    mode = bestmode;

    /* Now set video mode */
    memset(&rm, 0, sizeof rm);
    rm.eax.w[0] = 0x4F02;	/* Set SVGA video mode */
    mode |= 0x4000;		/* Request linear framebuffer */
    rm.ebx.w[0] = mode;
    __intcall(0x10, &rm, &rm);
    if (rm.eax.w[0] != 0x004F)
	goto out;		/* Failed to set mode */

    mbi->flags |= MB_INFO_VIDEO_INFO;
    mbi->vbe_mode = mode;
    viaddr = map_data(&vesa_info, sizeof vesa_info, 4, 0);
    mbi->vbe_control_info = viaddr + offsetof(struct vesa_info, gi);
    mbi->vbe_mode_info = viaddr + offsetof(struct vesa_info, mi);

    /* Get the VBE 2.x PM entry point if supported */
    rm.eax.w[0] = 0x4F0A;
    rm.ebx.w[0] = 0;
    __intcall(0x10, &rm, &rm);
    if (rm.eax.w[0] == 0x004F) {
	mbi->vbe_interface_seg = rm.es;
	mbi->vbe_interface_off = rm.edi.w[0];
	mbi->vbe_interface_len = rm.ecx.w[0];
    }

    /* In theory this should be:
     *
     * UsingVga = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
     *
     * However, that would assume all systems that claim to handle text
     * output in VESA modes actually do that...
     */
    graphics_using_vga(0x0F, vesa_info.mi.h_res, vesa_info.mi.v_res);

out:
    lfree(mi);
    lfree(gi);
}