diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/ata.c | 284 | ||||
-rw-r--r-- | src/ata.h (renamed from src/atabits.h) | 24 | ||||
-rw-r--r-- | src/biosvar.h | 2 | ||||
-rw-r--r-- | src/block.c | 211 | ||||
-rw-r--r-- | src/boot.c | 10 | ||||
-rw-r--r-- | src/cdrom.c | 10 | ||||
-rw-r--r-- | src/config.h | 10 | ||||
-rw-r--r-- | src/disk.c | 74 | ||||
-rw-r--r-- | src/disk.h | 41 | ||||
-rw-r--r-- | src/floppy.c | 4 | ||||
-rw-r--r-- | src/post.c | 6 |
12 files changed, 366 insertions, 312 deletions
@@ -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 @@ -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)); +} @@ -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 @@ -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 @@ -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; @@ -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(); |