aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/ata.c284
-rw-r--r--src/ata.h (renamed from src/atabits.h)24
-rw-r--r--src/biosvar.h2
-rw-r--r--src/block.c211
-rw-r--r--src/boot.c10
-rw-r--r--src/cdrom.c10
-rw-r--r--src/config.h10
-rw-r--r--src/disk.c74
-rw-r--r--src/disk.h41
-rw-r--r--src/floppy.c4
-rw-r--r--src/post.c6
12 files changed, 366 insertions, 312 deletions
diff --git a/Makefile b/Makefile
index 37589097..2b8d0d23 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ VERSION=pre-0.4.2-$(shell date +"%Y%m%d_%H%M%S")-$(shell hostname)
OUT=out/
# Source files
-SRCBOTH=output.c util.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \
+SRCBOTH=output.c util.c block.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \
serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
pnpbios.c pirtable.c vgahooks.c pmm.c
SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c font.c
diff --git a/src/ata.c b/src/ata.c
index 5dac4e97..49af87f8 100644
--- a/src/ata.c
+++ b/src/ata.c
@@ -1,6 +1,6 @@
// Low level ATA disk access
//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -16,14 +16,14 @@
#include "pci_regs.h" // PCI_INTERRUPT_LINE
#include "boot.h" // add_bcv_hd
#include "disk.h" // struct ata_s
-#include "atabits.h" // ATA_CB_STAT
+#include "ata.h" // ATA_CB_STAT
#define IDE_SECTOR_SIZE 512
#define CDROM_SECTOR_SIZE 2048
#define IDE_TIMEOUT 32000 //32 seconds max for IDE ops
-struct ata_s ATA VAR16_32;
+struct ata_channel_s ATA_channels[CONFIG_MAX_ATA_INTERFACES] VAR16_32;
/****************************************************************
@@ -82,11 +82,11 @@ ndelay_await_not_bsy(u16 iobase1)
static void
ata_reset(int driveid)
{
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
u8 channel = ataid / 2;
u8 slave = ataid % 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
- u16 iobase2 = GET_GLOBAL(ATA.channels[channel].iobase2);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
+ u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
dprintf(6, "ata_reset driveid=%d\n", driveid);
// Pulse SRST
@@ -118,7 +118,7 @@ ata_reset(int driveid)
}
// On a user-reset request, wait for RDY if it is an ATA device.
- u8 type=GET_GLOBAL(ATA.devices[driveid].type);
+ u8 type=GET_GLOBAL(Drives.drives[driveid].type);
if (type == DTYPE_ATA)
status = await_rdy(iobase1);
@@ -133,9 +133,9 @@ static int
isready(int driveid)
{
// Read the status from controller
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
u8 channel = ataid / 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
u8 status = inb(iobase1 + ATA_CB_STAT);
return (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY;
}
@@ -143,6 +143,9 @@ isready(int driveid)
static int
process_ata_misc_op(struct disk_op_s *op)
{
+ if (!CONFIG_ATA)
+ return 0;
+
switch (op->command) {
default:
return 0;
@@ -178,11 +181,11 @@ struct ata_pio_command {
static int
send_cmd(int driveid, struct ata_pio_command *cmd)
{
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
u8 channel = ataid / 2;
u8 slave = ataid % 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
- u16 iobase2 = GET_GLOBAL(ATA.channels[channel].iobase2);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
+ u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
// Disable interrupts
outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
@@ -246,10 +249,10 @@ ata_transfer(struct disk_op_s *op, int iswrite, int blocksize)
dprintf(16, "ata_transfer id=%d write=%d count=%d bs=%d buf=%p\n"
, op->driveid, iswrite, op->count, blocksize, op->buf_fl);
- u8 ataid = GET_GLOBAL(ATA.devices[op->driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[op->driveid].cntl_id);
u8 channel = ataid / 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
- u16 iobase2 = GET_GLOBAL(ATA.channels[channel].iobase2);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
+ u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
int count = op->count;
void *buf_fl = op->buf_fl;
int status;
@@ -345,6 +348,9 @@ ata_cmd_data(struct disk_op_s *op, int iswrite, int command)
int
process_ata_op(struct disk_op_s *op)
{
+ if (!CONFIG_ATA)
+ return 0;
+
switch (op->command) {
case CMD_READ:
return ata_cmd_data(op, 0, ATA_CMD_READ_SECTORS);
@@ -364,10 +370,10 @@ process_ata_op(struct disk_op_s *op)
static int
send_atapi_cmd(int driveid, u8 *cmdbuf, u8 cmdlen, u16 blocksize)
{
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
u8 channel = ataid / 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
- u16 iobase2 = GET_GLOBAL(ATA.channels[channel].iobase2);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
+ u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
struct ata_pio_command cmd;
cmd.sector_count = 0;
@@ -458,111 +464,6 @@ ata_cmd_packet(int driveid, u8 *cmdbuf, u8 cmdlen
/****************************************************************
- * Disk geometry translation
- ****************************************************************/
-
-static u8
-get_translation(int driveid)
-{
- if (! CONFIG_COREBOOT) {
- // Emulators pass in the translation info via nvram.
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
- u8 channel = ataid / 2;
- u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
- translation >>= 2 * (ataid % 4);
- translation &= 0x03;
- return translation;
- }
-
- // On COREBOOT, use a heuristic to determine translation type.
- u16 heads = GET_GLOBAL(ATA.devices[driveid].pchs.heads);
- u16 cylinders = GET_GLOBAL(ATA.devices[driveid].pchs.cylinders);
- u16 spt = GET_GLOBAL(ATA.devices[driveid].pchs.spt);
-
- if (cylinders <= 1024 && heads <= 16 && spt <= 63)
- return TRANSLATION_NONE;
- if (cylinders * heads <= 131072)
- return TRANSLATION_LARGE;
- return TRANSLATION_LBA;
-}
-
-static void
-setup_translation(int driveid)
-{
- u8 translation = get_translation(driveid);
- SET_GLOBAL(ATA.devices[driveid].translation, translation);
-
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
- u8 channel = ataid / 2;
- u8 slave = ataid % 2;
- u16 heads = GET_GLOBAL(ATA.devices[driveid].pchs.heads);
- u16 cylinders = GET_GLOBAL(ATA.devices[driveid].pchs.cylinders);
- u16 spt = GET_GLOBAL(ATA.devices[driveid].pchs.spt);
- u64 sectors = GET_GLOBAL(ATA.devices[driveid].sectors);
-
- dprintf(1, "ata%d-%d: PCHS=%u/%d/%d translation="
- , channel, slave, cylinders, heads, spt);
- switch (translation) {
- case TRANSLATION_NONE:
- dprintf(1, "none");
- break;
- case TRANSLATION_LBA:
- dprintf(1, "lba");
- spt = 63;
- if (sectors > 63*255*1024) {
- heads = 255;
- cylinders = 1024;
- break;
- }
- u32 sect = (u32)sectors / 63;
- heads = sect / 1024;
- if (heads>128)
- heads = 255;
- else if (heads>64)
- heads = 128;
- else if (heads>32)
- heads = 64;
- else if (heads>16)
- heads = 32;
- else
- heads = 16;
- cylinders = sect / heads;
- break;
- case TRANSLATION_RECHS:
- dprintf(1, "r-echs");
- // Take care not to overflow
- if (heads==16) {
- if (cylinders>61439)
- cylinders=61439;
- heads=15;
- cylinders = (u16)((u32)(cylinders)*16/15);
- }
- // then go through the large bitshift process
- case TRANSLATION_LARGE:
- if (translation == TRANSLATION_LARGE)
- dprintf(1, "large");
- while (cylinders > 1024) {
- cylinders >>= 1;
- heads <<= 1;
-
- // If we max out the head count
- if (heads > 127)
- break;
- }
- break;
- }
- // clip to 1024 cylinders in lchs
- if (cylinders > 1024)
- cylinders = 1024;
- dprintf(1, " LCHS=%d/%d/%d\n", cylinders, heads, spt);
-
- SET_GLOBAL(ATA.devices[driveid].lchs.heads, heads);
- SET_GLOBAL(ATA.devices[driveid].lchs.cylinders, cylinders);
- SET_GLOBAL(ATA.devices[driveid].lchs.spt, spt);
-}
-
-
-/****************************************************************
* ATA detect and init
****************************************************************/
@@ -586,8 +487,8 @@ extract_identify(int driveid, u16 *buffer)
dprintf(3, "Identify w0=%x w2=%x\n", buffer[0], buffer[2]);
// Read model name
- char *model = ATA.devices[driveid].model;
- int maxsize = ARRAY_SIZE(ATA.devices[driveid].model);
+ char *model = Drives.drives[driveid].model;
+ int maxsize = ARRAY_SIZE(Drives.drives[driveid].model);
int i;
for (i=0; i<maxsize/2; i++) {
u16 v = buffer[27+i];
@@ -601,7 +502,7 @@ extract_identify(int driveid, u16 *buffer)
model[i] = 0x00;
// Common flags.
- SET_GLOBAL(ATA.devices[driveid].removable, (buffer[0] & 0x80) ? 1 : 0);
+ SET_GLOBAL(Drives.drives[driveid].removable, (buffer[0] & 0x80) ? 1 : 0);
}
static int
@@ -621,25 +522,22 @@ init_drive_atapi(int driveid, u16 *buffer)
// Success - setup as ATAPI.
extract_identify(driveid, buffer);
- SET_GLOBAL(ATA.devices[driveid].type, DTYPE_ATAPI);
- SET_GLOBAL(ATA.devices[driveid].blksize, CDROM_SECTOR_SIZE);
- SET_GLOBAL(ATA.devices[driveid].sectors, (u64)-1);
+ SET_GLOBAL(Drives.drives[driveid].type, DTYPE_ATAPI);
+ SET_GLOBAL(Drives.drives[driveid].blksize, CDROM_SECTOR_SIZE);
+ SET_GLOBAL(Drives.drives[driveid].sectors, (u64)-1);
u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
// Report drive info to user.
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
u8 channel = ataid / 2;
u8 slave = ataid % 2;
printf("ata%d-%d: %s ATAPI-%d %s\n", channel, slave
- , ATA.devices[driveid].model, extract_version(buffer)
+ , Drives.drives[driveid].model, extract_version(buffer)
, (iscd ? "CD-Rom/DVD-Rom" : "Device"));
// fill cdidmap
- if (iscd) {
- u8 cdcount = GET_GLOBAL(ATA.cdcount);
- SET_GLOBAL(ATA.idmap[1][cdcount], driveid);
- SET_GLOBAL(ATA.cdcount, cdcount+1);
- }
+ if (iscd)
+ map_cd_drive(driveid);
return 0;
}
@@ -661,28 +559,28 @@ init_drive_ata(int driveid, u16 *buffer)
// Success - setup as ATA.
extract_identify(driveid, buffer);
- SET_GLOBAL(ATA.devices[driveid].type, DTYPE_ATA);
- SET_GLOBAL(ATA.devices[driveid].blksize, IDE_SECTOR_SIZE);
+ SET_GLOBAL(Drives.drives[driveid].type, DTYPE_ATA);
+ SET_GLOBAL(Drives.drives[driveid].blksize, IDE_SECTOR_SIZE);
- SET_GLOBAL(ATA.devices[driveid].pchs.cylinders, buffer[1]);
- SET_GLOBAL(ATA.devices[driveid].pchs.heads, buffer[3]);
- SET_GLOBAL(ATA.devices[driveid].pchs.spt, buffer[6]);
+ SET_GLOBAL(Drives.drives[driveid].pchs.cylinders, buffer[1]);
+ SET_GLOBAL(Drives.drives[driveid].pchs.heads, buffer[3]);
+ SET_GLOBAL(Drives.drives[driveid].pchs.spt, buffer[6]);
u64 sectors;
if (buffer[83] & (1 << 10)) // word 83 - lba48 support
sectors = *(u64*)&buffer[100]; // word 100-103
else
sectors = *(u32*)&buffer[60]; // word 60 and word 61
- SET_GLOBAL(ATA.devices[driveid].sectors, sectors);
+ SET_GLOBAL(Drives.drives[driveid].sectors, sectors);
// Setup disk geometry translation.
setup_translation(driveid);
// Report drive info to user.
- u8 ataid = GET_GLOBAL(ATA.devices[driveid].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
u8 channel = ataid / 2;
u8 slave = ataid % 2;
- char *model = ATA.devices[driveid].model;
+ char *model = Drives.drives[driveid].model;
printf("ata%d-%d: %s ATA-%d Hard-Disk ", channel, slave, model
, extract_version(buffer));
u64 sizeinmb = sectors >> 11;
@@ -730,7 +628,7 @@ ata_detect()
u8 channel = ataid / 2;
u8 slave = ataid % 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
if (!iobase1)
break;
@@ -758,10 +656,10 @@ ata_detect()
continue;
// Prepare new driveid.
- if (driveid >= ARRAY_SIZE(ATA.devices))
+ if (driveid >= ARRAY_SIZE(Drives.drives))
break;
- memset(&ATA.devices[driveid], 0, sizeof(ATA.devices[0]));
- ATA.devices[driveid].cntl_id = ataid;
+ memset(&Drives.drives[driveid], 0, sizeof(Drives.drives[0]));
+ Drives.drives[driveid].cntl_id = ataid;
// reset the channel
if (slave && ataid == last_reset_ataid + 1) {
@@ -810,27 +708,18 @@ ata_detect()
static void
ata_init()
{
- memset(&ATA, 0, sizeof(ATA));
-
- // hdidmap and cdidmap init.
- u8 device;
- for (device=0; device < CONFIG_MAX_ATA_DEVICES; device++) {
- SET_GLOBAL(ATA.idmap[0][device], CONFIG_MAX_ATA_DEVICES);
- SET_GLOBAL(ATA.idmap[1][device], CONFIG_MAX_ATA_DEVICES);
- }
-
// Scan PCI bus for ATA adapters
int count=0;
int bdf, max;
foreachpci(bdf, max) {
if (pci_config_readw(bdf, PCI_CLASS_DEVICE) != PCI_CLASS_STORAGE_IDE)
continue;
- if (count >= ARRAY_SIZE(ATA.channels))
+ if (count >= ARRAY_SIZE(ATA_channels))
break;
u8 irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
- SET_GLOBAL(ATA.channels[count].irq, irq);
- SET_GLOBAL(ATA.channels[count].pci_bdf, bdf);
+ SET_GLOBAL(ATA_channels[count].irq, irq);
+ SET_GLOBAL(ATA_channels[count].pci_bdf, bdf);
u8 prog_if = pci_config_readb(bdf, PCI_CLASS_PROG);
u32 port1, port2;
@@ -842,8 +731,8 @@ ata_init()
port1 = 0x1f0;
port2 = 0x3f0;
}
- SET_GLOBAL(ATA.channels[count].iobase1, port1);
- SET_GLOBAL(ATA.channels[count].iobase2, port2);
+ SET_GLOBAL(ATA_channels[count].iobase1, port1);
+ SET_GLOBAL(ATA_channels[count].iobase2, port2);
dprintf(1, "ATA controller %d at %x/%x (dev %x prog_if %x)\n"
, count, port1, port2, bdf, prog_if);
count++;
@@ -857,14 +746,14 @@ ata_init()
}
dprintf(1, "ATA controller %d at %x/%x (dev %x prog_if %x)\n"
, count, port1, port2, bdf, prog_if);
- SET_GLOBAL(ATA.channels[count].iobase1, port1);
- SET_GLOBAL(ATA.channels[count].iobase2, port2);
+ SET_GLOBAL(ATA_channels[count].iobase1, port1);
+ SET_GLOBAL(ATA_channels[count].iobase2, port2);
count++;
}
}
void
-hard_drive_setup()
+ata_setup()
{
if (!CONFIG_ATA)
return;
@@ -877,68 +766,3 @@ hard_drive_setup()
enable_hwirq(14, entry_76);
}
-
-
-/****************************************************************
- * Drive mapping
- ****************************************************************/
-
-// Fill in Fixed Disk Parameter Table (located in ebda).
-static void
-fill_fdpt(int driveid)
-{
- if (driveid > 1)
- return;
-
- u16 nlc = GET_GLOBAL(ATA.devices[driveid].lchs.cylinders);
- u16 nlh = GET_GLOBAL(ATA.devices[driveid].lchs.heads);
- u16 nlspt = GET_GLOBAL(ATA.devices[driveid].lchs.spt);
-
- u16 npc = GET_GLOBAL(ATA.devices[driveid].pchs.cylinders);
- u16 nph = GET_GLOBAL(ATA.devices[driveid].pchs.heads);
- u16 npspt = GET_GLOBAL(ATA.devices[driveid].pchs.spt);
-
- struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[driveid];
- fdpt->precompensation = 0xffff;
- fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
- fdpt->landing_zone = npc;
- fdpt->cylinders = nlc;
- fdpt->heads = nlh;
- fdpt->sectors = nlspt;
-
- if (nlc == npc && nlh == nph && nlspt == npspt)
- // no logical CHS mapping used, just physical CHS
- // use Standard Fixed Disk Parameter Table (FDPT)
- return;
-
- // complies with Phoenix style Translated Fixed Disk Parameter
- // Table (FDPT)
- fdpt->phys_cylinders = npc;
- fdpt->phys_heads = nph;
- fdpt->phys_sectors = npspt;
- fdpt->a0h_signature = 0xa0;
-
- // Checksum structure.
- fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
-
- if (driveid == 0)
- SET_IVT(0x41, get_ebda_seg()
- , offsetof(struct extended_bios_data_area_s, fdpt[0]));
- else
- SET_IVT(0x46, get_ebda_seg()
- , offsetof(struct extended_bios_data_area_s, fdpt[1]));
-}
-
-// Map a drive (that was registered via add_bcv_hd)
-void
-map_drive(int driveid)
-{
- // fill hdidmap
- u8 hdcount = GET_BDA(hdcount);
- dprintf(3, "Mapping driveid %d to %d\n", driveid, hdcount);
- SET_GLOBAL(ATA.idmap[0][hdcount], driveid);
- SET_BDA(hdcount, hdcount + 1);
-
- // Fill "fdpt" structure.
- fill_fdpt(hdcount);
-}
diff --git a/src/atabits.h b/src/ata.h
index 84951079..66477e20 100644
--- a/src/atabits.h
+++ b/src/ata.h
@@ -1,3 +1,25 @@
+#ifndef __ATA_H
+#define __ATA_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_MAX_ATA_INTERFACES
+
+struct ata_channel_s {
+ u16 iobase1; // IO Base 1
+ u16 iobase2; // IO Base 2
+ u16 pci_bdf;
+ u8 irq; // IRQ
+};
+
+// ata.c
+extern struct ata_channel_s ATA_channels[CONFIG_MAX_ATA_INTERFACES];
+int cdrom_read(struct disk_op_s *op);
+int ata_cmd_packet(int driveid, u8 *cmdbuf, u8 cmdlen
+ , u32 length, void *buf_fl);
+void ata_setup();
+int process_ata_op(struct disk_op_s *op);
+int process_atapi_op(struct disk_op_s *op);
+
// Global defines -- ATA register and register bits.
// command block & control block regs
#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
@@ -105,3 +127,5 @@
#define ATA_CMD_WRITE_MULTIPLE 0xC5
#define ATA_CMD_WRITE_SECTORS 0x30
#define ATA_CMD_WRITE_VERIFY 0x3C
+
+#endif // ata.h
diff --git a/src/biosvar.h b/src/biosvar.h
index 7eaa07bc..9469c9aa 100644
--- a/src/biosvar.h
+++ b/src/biosvar.h
@@ -228,7 +228,7 @@ struct extended_bios_data_area_s {
struct dpte_s dpte;
// Locks for removable devices
- u8 cdrom_locks[CONFIG_MAX_ATA_DEVICES];
+ u8 cdrom_locks[CONFIG_MAX_DRIVES];
u16 boot_sequence;
diff --git a/src/block.c b/src/block.c
new file mode 100644
index 00000000..2df2cc45
--- /dev/null
+++ b/src/block.c
@@ -0,0 +1,211 @@
+// Disk setup and access
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // struct ata_s
+#include "biosvar.h" // GET_GLOBAL
+#include "cmos.h" // inb_cmos
+#include "util.h" // dprintf
+
+struct drives_s Drives VAR16_32;
+
+
+/****************************************************************
+ * Disk geometry translation
+ ****************************************************************/
+
+static u8
+get_translation(int driveid)
+{
+ u8 type = GET_GLOBAL(Drives.drives[driveid].type);
+ if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
+ // Emulators pass in the translation info via nvram.
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
+ u8 channel = ataid / 2;
+ u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
+ translation >>= 2 * (ataid % 4);
+ translation &= 0x03;
+ return translation;
+ }
+
+ // On COREBOOT, use a heuristic to determine translation type.
+ u16 heads = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
+ u16 cylinders = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
+ u16 spt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
+
+ if (cylinders <= 1024 && heads <= 16 && spt <= 63)
+ return TRANSLATION_NONE;
+ if (cylinders * heads <= 131072)
+ return TRANSLATION_LARGE;
+ return TRANSLATION_LBA;
+}
+
+void
+setup_translation(int driveid)
+{
+ u8 translation = get_translation(driveid);
+ SET_GLOBAL(Drives.drives[driveid].translation, translation);
+
+ u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
+ u8 channel = ataid / 2;
+ u8 slave = ataid % 2;
+ u16 heads = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
+ u16 cylinders = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
+ u16 spt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
+ u64 sectors = GET_GLOBAL(Drives.drives[driveid].sectors);
+
+ dprintf(1, "ata%d-%d: PCHS=%u/%d/%d translation="
+ , channel, slave, cylinders, heads, spt);
+ switch (translation) {
+ case TRANSLATION_NONE:
+ dprintf(1, "none");
+ break;
+ case TRANSLATION_LBA:
+ dprintf(1, "lba");
+ spt = 63;
+ if (sectors > 63*255*1024) {
+ heads = 255;
+ cylinders = 1024;
+ break;
+ }
+ u32 sect = (u32)sectors / 63;
+ heads = sect / 1024;
+ if (heads>128)
+ heads = 255;
+ else if (heads>64)
+ heads = 128;
+ else if (heads>32)
+ heads = 64;
+ else if (heads>16)
+ heads = 32;
+ else
+ heads = 16;
+ cylinders = sect / heads;
+ break;
+ case TRANSLATION_RECHS:
+ dprintf(1, "r-echs");
+ // Take care not to overflow
+ if (heads==16) {
+ if (cylinders>61439)
+ cylinders=61439;
+ heads=15;
+ cylinders = (u16)((u32)(cylinders)*16/15);
+ }
+ // then go through the large bitshift process
+ case TRANSLATION_LARGE:
+ if (translation == TRANSLATION_LARGE)
+ dprintf(1, "large");
+ while (cylinders > 1024) {
+ cylinders >>= 1;
+ heads <<= 1;
+
+ // If we max out the head count
+ if (heads > 127)
+ break;
+ }
+ break;
+ }
+ // clip to 1024 cylinders in lchs
+ if (cylinders > 1024)
+ cylinders = 1024;
+ dprintf(1, " LCHS=%d/%d/%d\n", cylinders, heads, spt);
+
+ SET_GLOBAL(Drives.drives[driveid].lchs.heads, heads);
+ SET_GLOBAL(Drives.drives[driveid].lchs.cylinders, cylinders);
+ SET_GLOBAL(Drives.drives[driveid].lchs.spt, spt);
+}
+
+
+/****************************************************************
+ * Drive mapping
+ ****************************************************************/
+
+// Fill in Fixed Disk Parameter Table (located in ebda).
+static void
+fill_fdpt(int driveid)
+{
+ if (driveid > 1)
+ return;
+
+ u16 nlc = GET_GLOBAL(Drives.drives[driveid].lchs.cylinders);
+ u16 nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads);
+ u16 nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
+
+ u16 npc = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
+ u16 nph = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
+ u16 npspt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
+
+ struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[driveid];
+ fdpt->precompensation = 0xffff;
+ fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
+ fdpt->landing_zone = npc;
+ fdpt->cylinders = nlc;
+ fdpt->heads = nlh;
+ fdpt->sectors = nlspt;
+
+ if (nlc == npc && nlh == nph && nlspt == npspt)
+ // no logical CHS mapping used, just physical CHS
+ // use Standard Fixed Disk Parameter Table (FDPT)
+ return;
+
+ // complies with Phoenix style Translated Fixed Disk Parameter
+ // Table (FDPT)
+ fdpt->phys_cylinders = npc;
+ fdpt->phys_heads = nph;
+ fdpt->phys_sectors = npspt;
+ fdpt->a0h_signature = 0xa0;
+
+ // Checksum structure.
+ fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
+
+ if (driveid == 0)
+ SET_IVT(0x41, get_ebda_seg()
+ , offsetof(struct extended_bios_data_area_s, fdpt[0]));
+ else
+ SET_IVT(0x46, get_ebda_seg()
+ , offsetof(struct extended_bios_data_area_s, fdpt[1]));
+}
+
+// Map a drive (that was registered via add_bcv_hd)
+void
+map_hd_drive(int driveid)
+{
+ // fill hdidmap
+ u8 hdcount = GET_BDA(hdcount);
+ if (hdcount >= ARRAY_SIZE(Drives.idmap[0]))
+ return;
+ dprintf(3, "Mapping hd driveid %d to %d\n", driveid, hdcount);
+ SET_GLOBAL(Drives.idmap[0][hdcount], driveid);
+ SET_BDA(hdcount, hdcount + 1);
+
+ // Fill "fdpt" structure.
+ fill_fdpt(hdcount);
+}
+
+// Map a cd
+void
+map_cd_drive(int driveid)
+{
+ // fill cdidmap
+ u8 cdcount = GET_GLOBAL(Drives.cdcount);
+ if (cdcount >= ARRAY_SIZE(Drives.idmap[1]))
+ return;
+ dprintf(3, "Mapping cd driveid %d to %d\n", driveid, cdcount);
+ SET_GLOBAL(Drives.idmap[1][cdcount], driveid);
+ SET_GLOBAL(Drives.cdcount, cdcount+1);
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+drive_setup()
+{
+ memset(&Drives, 0, sizeof(Drives));
+ memset(&Drives.idmap, 0xff, sizeof(Drives.idmap));
+}
diff --git a/src/boot.c b/src/boot.c
index b1dffefe..b4067bbf 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -168,12 +168,12 @@ static int
menu_show_cdrom(struct ipl_entry_s *ie, int menupos)
{
int i;
- for (i = 0; i < ATA.cdcount; i++) {
- int driveid = ATA.idmap[1][i];
+ for (i = 0; i < Drives.cdcount; i++) {
+ int driveid = Drives.idmap[1][i];
printf("%d. CD-Rom [ata%d-%d %s]\n", menupos + i
- , driveid / 2, driveid % 2, ATA.devices[driveid].model);
+ , driveid / 2, driveid % 2, Drives.drives[driveid].model);
}
- return ATA.cdcount;
+ return Drives.cdcount;
}
// Show coreboot-fs menu item.
@@ -272,7 +272,7 @@ run_bcv(struct ipl_entry_s *ie)
{
switch (ie->type) {
case IPL_TYPE_HARDDISK:
- map_drive(ie->vector);
+ map_hd_drive(ie->vector);
break;
case IPL_TYPE_BEV:
call_bcv(ie->vector >> 16, ie->vector & 0xffff);
diff --git a/src/cdrom.c b/src/cdrom.c
index c62829a4..ca19da07 100644
--- a/src/cdrom.c
+++ b/src/cdrom.c
@@ -1,6 +1,6 @@
// 16bit code to access cdrom drives.
//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -9,7 +9,7 @@
#include "util.h" // memset
#include "bregs.h" // struct bregs
#include "biosvar.h" // GET_EBDA
-#include "atabits.h" // ATA_CMD_REQUEST_SENSE
+#include "ata.h" // ATA_CMD_REQUEST_SENSE
/****************************************************************
@@ -387,7 +387,7 @@ atapi_is_ready(u16 device)
}
}
- if (blksize != GET_GLOBAL(ATA.devices[device].blksize)) {
+ if (blksize != GET_GLOBAL(Drives.drives[device].blksize)) {
printf("Unsupported sector size %u\n", blksize);
return -1;
}
@@ -401,9 +401,9 @@ int
cdrom_boot(int cdid)
{
// Verify device is a cdrom.
- if (cdid >= ATA.cdcount)
+ if (cdid >= Drives.cdcount)
return 1;
- int driveid = GET_GLOBAL(ATA.idmap[1][cdid]);
+ int driveid = GET_GLOBAL(Drives.idmap[1][cdid]);
int ret = atapi_is_ready(driveid);
if (ret)
diff --git a/src/config.h b/src/config.h
index 98b69e82..a81e1ecc 100644
--- a/src/config.h
+++ b/src/config.h
@@ -24,7 +24,9 @@
// Screen writes are also sent to debug ports.
#define CONFIG_SCREEN_AND_DEBUG 1
-// Support for int13 floppy drive access
+// Support int13 disk/floppy drive functions
+#define CONFIG_DRIVES 1
+// Support floppy drive access
#define CONFIG_FLOPPY_SUPPORT 1
// Support for IDE disk code
#define CONFIG_ATA 1
@@ -104,8 +106,12 @@
// Space to reserve in high-memory for tables
#define CONFIG_MAX_HIGHTABLE (64*1024)
+// Maximum number of ATA controllers to support
#define CONFIG_MAX_ATA_INTERFACES 4
-#define CONFIG_MAX_ATA_DEVICES (CONFIG_MAX_ATA_INTERFACES*2)
+// Maximum number of internal drives supported
+#define CONFIG_MAX_DRIVES 8
+// Largest supported externaly facing drive id
+#define CONFIG_MAX_EXTDRIVE 16
#define CONFIG_MODEL_ID 0xFC
#define CONFIG_SUBMODEL_ID 0x00
diff --git a/src/disk.c b/src/disk.c
index 609beaad..263c0d9a 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -12,7 +12,7 @@
#include "pic.h" // eoi_pic2
#include "bregs.h" // struct bregs
#include "pci.h" // pci_bdf_to_bus
-#include "atabits.h" // ATA_CB_DC
+#include "ata.h" // ATA_CB_DC
/****************************************************************
@@ -56,7 +56,7 @@ __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
irq_enable();
int status = 0;
- u8 type = GET_GLOBAL(ATA.devices[dop.driveid].type);
+ u8 type = GET_GLOBAL(Drives.drives[dop.driveid].type);
if (type == DTYPE_ATA)
status = process_ata_op(&dop);
else if (type == DTYPE_ATAPI)
@@ -77,7 +77,7 @@ __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
static int
send_disk_op(struct disk_op_s *op)
{
- if (! CONFIG_ATA)
+ if (! CONFIG_DRIVES)
return -1;
return stack_hop((u32)op, GET_SEG(SS), 0, __send_disk_op);
@@ -124,7 +124,7 @@ basic_access(struct bregs *regs, u8 device, u16 command)
struct disk_op_s dop;
dop.driveid = device;
dop.command = command;
- int lba = legacy_lba(regs, get_global_seg(), &ATA.devices[device].lchs);
+ int lba = legacy_lba(regs, get_global_seg(), &Drives.drives[device].lchs);
if (lba < 0)
return;
dop.lba = lba;
@@ -218,7 +218,7 @@ extended_access(struct bregs *regs, u8 device, u16 command)
dop.lba = GET_INT13EXT(regs, lba);
dop.command = command;
dop.driveid = device;
- if (dop.lba >= GET_GLOBAL(ATA.devices[device].sectors)) {
+ if (dop.lba >= GET_GLOBAL(Drives.drives[device].sectors)) {
dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
, regs->ah);
disk_ret(regs, DISK_RET_EPARAM);
@@ -300,9 +300,9 @@ static void
disk_1308(struct bregs *regs, u8 device)
{
// Get logical geometry from table
- u16 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
- u16 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
- u16 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
+ u16 nlc = GET_GLOBAL(Drives.drives[device].lchs.cylinders);
+ u16 nlh = GET_GLOBAL(Drives.drives[device].lchs.heads);
+ u16 nlspt = GET_GLOBAL(Drives.drives[device].lchs.spt);
u16 count = GET_BDA(hdcount);
nlc = nlc - 2; /* 0 based , last sector not used */
@@ -372,9 +372,9 @@ static void
disk_1315(struct bregs *regs, u8 device)
{
// Get logical geometry from table
- u16 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
- u16 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
- u16 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
+ u16 nlc = GET_GLOBAL(Drives.drives[device].lchs.cylinders);
+ u16 nlh = GET_GLOBAL(Drives.drives[device].lchs.heads);
+ u16 nlspt = GET_GLOBAL(Drives.drives[device].lchs.spt);
// Compute sector count seen by int13
u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
@@ -453,12 +453,12 @@ disk_1348(struct bregs *regs, u8 device)
// EDD 1.x
- u8 type = GET_GLOBAL(ATA.devices[device].type);
- u16 npc = GET_GLOBAL(ATA.devices[device].pchs.cylinders);
- u16 nph = GET_GLOBAL(ATA.devices[device].pchs.heads);
- u16 npspt = GET_GLOBAL(ATA.devices[device].pchs.spt);
- u64 lba = GET_GLOBAL(ATA.devices[device].sectors);
- u16 blksize = GET_GLOBAL(ATA.devices[device].blksize);
+ u8 type = GET_GLOBAL(Drives.drives[device].type);
+ u16 npc = GET_GLOBAL(Drives.drives[device].pchs.cylinders);
+ u16 nph = GET_GLOBAL(Drives.drives[device].pchs.heads);
+ u16 npspt = GET_GLOBAL(Drives.drives[device].pchs.spt);
+ u64 lba = GET_GLOBAL(Drives.drives[device].sectors);
+ u16 blksize = GET_GLOBAL(Drives.drives[device].blksize);
dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
, size, type, npc, nph, npspt, (u32)lba, blksize);
@@ -500,16 +500,16 @@ disk_1348(struct bregs *regs, u8 device)
, offsetof(struct extended_bios_data_area_s, dpte));
// Fill in dpte
- u8 ataid = GET_GLOBAL(ATA.devices[device].cntl_id);
+ u8 ataid = GET_GLOBAL(Drives.drives[device].cntl_id);
u8 channel = ataid / 2;
u8 slave = ataid % 2;
- u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
- u16 iobase2 = GET_GLOBAL(ATA.channels[channel].iobase2);
- u8 irq = GET_GLOBAL(ATA.channels[channel].irq);
+ u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
+ u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
+ u8 irq = GET_GLOBAL(ATA_channels[channel].irq);
u16 options = 0;
if (type == DTYPE_ATA) {
- u8 translation = GET_GLOBAL(ATA.devices[device].translation);
+ u8 translation = GET_GLOBAL(Drives.drives[device].translation);
if (translation != TRANSLATION_NONE) {
options |= 1<<3; // CHS translation
if (translation == TRANSLATION_LBA)
@@ -559,7 +559,7 @@ disk_1348(struct bregs *regs, u8 device)
SET_INT13DPT(regs, host_bus[2], 'I');
SET_INT13DPT(regs, host_bus[3], 0);
- u32 bdf = GET_GLOBAL(ATA.channels[channel].pci_bdf);
+ u32 bdf = GET_GLOBAL(ATA_channels[channel].pci_bdf);
u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
| (pci_bdf_to_fn(bdf) << 16));
SET_INT13DPT(regs, iface_path, path);
@@ -680,25 +680,25 @@ disk_13(struct bregs *regs, u8 device)
* Entry points
****************************************************************/
-static u8
+static int
get_device(struct bregs *regs, u8 iscd, u8 drive)
{
// basic check : device has to be defined
- if (drive >= CONFIG_MAX_ATA_DEVICES) {
+ if (drive >= ARRAY_SIZE(Drives.idmap[0])) {
disk_ret(regs, DISK_RET_EPARAM);
- return CONFIG_MAX_ATA_DEVICES;
+ return -1;
}
// Get the ata channel
- u8 device = GET_GLOBAL(ATA.idmap[iscd][drive]);
+ u8 driveid = GET_GLOBAL(Drives.idmap[iscd][drive]);
// basic check : device has to be valid
- if (device >= CONFIG_MAX_ATA_DEVICES) {
+ if (driveid >= ARRAY_SIZE(Drives.drives)) {
disk_ret(regs, DISK_RET_EPARAM);
- return CONFIG_MAX_ATA_DEVICES;
+ return -1;
}
- return device;
+ return driveid;
}
static void
@@ -709,24 +709,24 @@ handle_legacy_disk(struct bregs *regs, u8 drive)
return;
}
- if (! CONFIG_ATA) {
+ if (! CONFIG_DRIVES) {
// XXX - old code had other disk access method.
disk_ret(regs, DISK_RET_EPARAM);
return;
}
if (drive >= 0xe0) {
- u8 device = get_device(regs, 1, drive - 0xe0);
- if (device >= CONFIG_MAX_ATA_DEVICES)
+ int driveid = get_device(regs, 1, drive - 0xe0);
+ if (driveid < 0)
return;
- cdrom_13(regs, device);
+ cdrom_13(regs, driveid);
return;
}
- u8 device = get_device(regs, 0, drive - 0x80);
- if (device >= CONFIG_MAX_ATA_DEVICES)
+ int driveid = get_device(regs, 0, drive - 0x80);
+ if (driveid < 0)
return;
- disk_13(regs, device);
+ disk_13(regs, driveid);
}
void VISIBLE16
diff --git a/src/disk.h b/src/disk.h
index 9441fe13..384ea2dc 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -167,15 +167,8 @@ struct chs_s {
u16 spt; // # sectors / track
};
-struct ata_channel_s {
- u16 iobase1; // IO Base 1
- u16 iobase2; // IO Base 2
- u16 pci_bdf;
- u8 irq; // IRQ
-};
-
-struct ata_device_s {
- u8 type; // Detected type of ata (ata/atapi/none)
+struct drive_s {
+ u8 type; // Detected type of drive (ata/atapi/none)
u8 removable; // Removable device flag
u16 blksize; // block size
int cntl_id;
@@ -198,16 +191,13 @@ struct ata_device_s {
#define TRANSLATION_LARGE 2
#define TRANSLATION_RECHS 3
-struct ata_s {
- // ATA channels info
- struct ata_channel_s channels[CONFIG_MAX_ATA_INTERFACES];
-
- // ATA devices info
- struct ata_device_s devices[CONFIG_MAX_ATA_DEVICES];
+struct drives_s {
+ // info on each internally handled drive
+ struct drive_s drives[CONFIG_MAX_DRIVES];
//
- // map between bios hd/cd id and ata channels
+ // map between bios hd/cd id and driveid index into drives[]
u8 cdcount;
- u8 idmap[2][CONFIG_MAX_ATA_DEVICES];
+ u8 idmap[2][CONFIG_MAX_EXTDRIVE];
};
@@ -215,20 +205,17 @@ struct ata_s {
* Function defs
****************************************************************/
-// ata.c
-extern struct ata_s ATA;
-int cdrom_read(struct disk_op_s *op);
-int ata_cmd_packet(int driveid, u8 *cmdbuf, u8 cmdlen
- , u32 length, void *buf_fl);
-void hard_drive_setup();
-int process_ata_op(struct disk_op_s *op);
-int process_atapi_op(struct disk_op_s *op);
-void map_drive(int driveid);
+// block.c
+extern struct drives_s Drives;
+void setup_translation(int driveid);
+void map_hd_drive(int driveid);
+void map_cd_drive(int driveid);
+void drive_setup();
// floppy.c
extern u8 FloppyCount;
extern struct floppy_ext_dbt_s diskette_param_table2;
-void floppy_drive_setup();
+void floppy_setup();
void floppy_13(struct bregs *regs, u8 drive);
void floppy_tick();
diff --git a/src/floppy.c b/src/floppy.c
index 12bed1e1..7f236ce4 100644
--- a/src/floppy.c
+++ b/src/floppy.c
@@ -1,6 +1,6 @@
// 16bit code to access floppy drives.
//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -60,7 +60,7 @@ u8 FloppyCount VAR16_32;
u8 FloppyTypes[2] VAR16_32;
void
-floppy_drive_setup()
+floppy_setup()
{
if (! CONFIG_FLOPPY_SUPPORT)
return;
diff --git a/src/post.c b/src/post.c
index 32d22c88..9bb51326 100644
--- a/src/post.c
+++ b/src/post.c
@@ -11,6 +11,7 @@
#include "util.h" // memset
#include "biosvar.h" // struct bios_data_area_s
#include "disk.h" // floppy_drive_setup
+#include "ata.h" // ata_setup
#include "memmap.h" // add_e820
#include "pic.h" // pic_setup
#include "pci.h" // create_pirtable
@@ -185,8 +186,9 @@ post()
boot_setup();
- floppy_drive_setup();
- hard_drive_setup();
+ drive_setup();
+ floppy_setup();
+ ata_setup();
optionrom_setup();