Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 58794
b: refs/heads/master
c: d13444a
h: refs/heads/master
v: v3
  • Loading branch information
H. Peter Anvin authored and Linus Torvalds committed Jul 12, 2007
1 parent 6785ba2 commit 945a04e
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 31b54f40e12e4d04941762be6615edaf3c6ed811
refs/heads/master: d13444a5a53b0159e6316a7a7be9890143a5af71
196 changes: 196 additions & 0 deletions trunk/arch/i386/boot/edd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */

/*
* arch/i386/boot/edd.c
*
* Get EDD BIOS disk information
*/

#include "boot.h"
#include <linux/edd.h>

#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)

struct edd_dapa {
u8 pkt_size;
u8 rsvd;
u16 sector_cnt;
u16 buf_off, buf_seg;
u64 lba;
u64 buf_lin_addr;
};

/*
* Read the MBR (first sector) from a specific device.
*/
static int read_mbr(u8 devno, void *buf)
{
struct edd_dapa dapa;
u16 ax, bx, cx, dx, si;

memset(&dapa, 0, sizeof dapa);
dapa.pkt_size = sizeof(dapa);
dapa.sector_cnt = 1;
dapa.buf_off = (size_t)buf;
dapa.buf_seg = ds();
/* dapa.lba = 0; */

ax = 0x4200; /* Extended Read */
si = (size_t)&dapa;
dx = devno;
asm("pushfl; stc; int $0x13; setc %%al; popfl"
: "+a" (ax), "+S" (si), "+d" (dx)
: "m" (dapa)
: "ebx", "ecx", "edi", "memory");

if (!(u8)ax)
return 0; /* OK */

ax = 0x0201; /* Legacy Read, one sector */
cx = 0x0001; /* Sector 0-0-1 */
dx = devno;
bx = (size_t)buf;
asm("pushfl; stc; int $0x13; setc %%al; popfl"
: "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx)
: : "esi", "edi", "memory");

return -(u8)ax; /* 0 or -1 */
}

static u32 read_mbr_sig(u8 devno, struct edd_info *ei)
{
int sector_size;
char *mbrbuf_ptr, *mbrbuf_end;
u32 mbrsig;
u32 buf_base, mbr_base;
extern char _end[];
static char mbr_buf[1024];

sector_size = ei->params.bytes_per_sector;
if (!sector_size)
sector_size = 512; /* Best available guess */

buf_base = (ds() << 4) + (u32)&_end;
mbr_base = (buf_base+sector_size-1) & ~(sector_size-1);
mbrbuf_ptr = mbr_buf + (mbr_base-buf_base);
mbrbuf_end = mbrbuf_ptr + sector_size;

if (!(boot_params.hdr.loadflags & CAN_USE_HEAP))
return 0;
if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
return 0;

if (read_mbr(devno, mbrbuf_ptr))
return 0;

mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
return mbrsig;
}

static int get_edd_info(u8 devno, struct edd_info *ei)
{
u16 ax, bx, cx, dx, di;

memset(ei, 0, sizeof *ei);

/* Check Extensions Present */

ax = 0x4100;
bx = EDDMAGIC1;
dx = devno;
asm("pushfl; stc; int $0x13; setc %%al; popfl"
: "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx)
: : "esi", "edi");

if ((u8)ax)
return -1; /* No extended information */

if (bx != EDDMAGIC2)
return -1;

ei->device = devno;
ei->version = ax >> 8; /* EDD version number */
ei->interface_support = cx; /* EDD functionality subsets */

/* Extended Get Device Parameters */

ei->params.length = sizeof(ei->params);
ax = 0x4800;
dx = devno;
asm("pushfl; int $0x13; popfl"
: "+a" (ax), "+d" (dx)
: "S" (&ei->params)
: "ebx", "ecx", "edi");

/* Get legacy CHS parameters */

/* Ralf Brown recommends setting ES:DI to 0:0 */
ax = 0x0800;
dx = devno;
di = 0;
asm("pushw %%es; "
"movw %%di,%%es; "
"pushfl; stc; int $0x13; setc %%al; popfl; "
"popw %%es"
: "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di)
: : "esi");

if ((u8)ax == 0) {
ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2);
ei->legacy_max_head = dx >> 8;
ei->legacy_sectors_per_track = cx & 0x3f;
}

return 0;
}

void query_edd(void)
{
char eddarg[8];
int do_mbr = 1;
int do_edd = 1;
int devno;
struct edd_info ei, *edp;

if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) {
if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip"))
do_mbr = 0;
else if (!strcmp(eddarg, "off"))
do_edd = 0;
}

edp = (struct edd_info *)boot_params.eddbuf;

if (!do_edd)
return;

for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
/*
* Scan the BIOS-supported hard disks and query EDD
* information...
*/
get_edd_info(devno, &ei);

if (boot_params.eddbuf_entries < EDDMAXNR) {
memcpy(edp, &ei, sizeof ei);
edp++;
boot_params.eddbuf_entries++;
}

if (do_mbr) {
u32 mbr_sig;
mbr_sig = read_mbr_sig(devno, &ei);
boot_params.edd_mbr_sig_buffer[devno-0x80] = mbr_sig;
}
}
}

#endif

0 comments on commit 945a04e

Please sign in to comment.