freebsd-skq/sys/boot/i386/common/drv.c
jhb 6ba84c2a51 - Add a new header for the x86 boot code that defines various structures
and constants related to the BIOS Enhanced Disk Drive Specification.
- Use this header instead of magic numbers and various duplicate structure
  definitions for doing I/O.
- Use an actual structure for the request to fetch drive parameters in
  drvsize() rather than a gross hack of a char array with some magic
  size.  While here, change drvsize() to only pass the 1.1 version of
  the structure and not request device path information.  If we want
  device path information you have to set the length of the device
  path information as an input (along with probably checking the actual
  EDD version to see which size one should use as the device path
  information is variable-length).  This fixes data smashing problems
  from passing an EDD 3 structure to BIOSes supporting EDD 4.

Reviewed by:	avg
Tested by:	Dennis Koegel  dk neveragain.de
MFC after:	1 week
2011-10-25 19:54:06 +00:00

120 lines
2.5 KiB
C

/*-
* Copyright (c) 1998 Robert Nordier
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms are freely
* permitted provided that the above copyright notice and this
* paragraph and the following disclaimer are duplicated in all
* such forms.
*
* This software is provided "AS IS" and without any express or
* implied warranties, including, without limitation, the implied
* warranties of merchantability and fitness for a particular
* purpose.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <btxv86.h>
#include "rbx.h"
#include "util.h"
#include "drv.h"
#include "edd.h"
#ifdef USE_XREAD
#include "xreadorg.h"
#endif
#ifdef GPT
static struct edd_params params;
uint64_t
drvsize(struct dsk *dskp)
{
params.len = sizeof(struct edd_params);
v86.ctl = V86_FLAGS;
v86.addr = 0x13;
v86.eax = 0x4800;
v86.edx = dskp->drive;
v86.ds = VTOPSEG(&params);
v86.esi = VTOPOFF(&params);
v86int();
if (V86_CY(v86.efl)) {
printf("error %u\n", v86.eax >> 8 & 0xff);
return (0);
}
return (params.sectors);
}
#endif /* GPT */
#ifndef USE_XREAD
static struct edd_packet packet;
#endif
int
drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
{
static unsigned c = 0x2d5c7c2f;
if (!OPT_CHECK(RBX_QUIET))
printf("%c\b", c = c << 8 | c >> 24);
#ifndef USE_XREAD
packet.len = sizeof(struct edd_packet);
packet.count = nblk;
packet.off = VTOPOFF(buf);
packet.seg = VTOPSEG(buf);
packet.lba = lba;
v86.ctl = V86_FLAGS;
v86.addr = 0x13;
v86.eax = 0x4200;
v86.edx = dskp->drive;
v86.ds = VTOPSEG(&packet);
v86.esi = VTOPOFF(&packet);
#else /* USE_XREAD */
v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
v86.addr = XREADORG; /* call to xread in boot1 */
v86.es = VTOPSEG(buf);
v86.eax = lba;
v86.ebx = VTOPOFF(buf);
v86.ecx = lba >> 32;
v86.edx = nblk << 8 | dskp->drive;
#endif /* USE_XREAD */
v86int();
if (V86_CY(v86.efl)) {
printf("%s: error %u lba %u\n",
BOOTPROG, v86.eax >> 8 & 0xff, lba);
return (-1);
}
return (0);
}
#ifdef GPT
int
drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
{
packet.len = sizeof(struct edd_packet);
packet.count = nblk;
packet.off = VTOPOFF(buf);
packet.seg = VTOPSEG(buf);
packet.lba = lba;
v86.ctl = V86_FLAGS;
v86.addr = 0x13;
v86.eax = 0x4300;
v86.edx = dskp->drive;
v86.ds = VTOPSEG(&packet);
v86.esi = VTOPOFF(&packet);
v86int();
if (V86_CY(v86.efl)) {
printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
return (-1);
}
return (0);
}
#endif /* GPT */