seabios/src/cdrom.c

323 lines
8.2 KiB
C
Raw Permalink Normal View History

// Support for booting from cdroms (the "El Torito" spec).
//
// 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 "biosvar.h" // GET_GLOBAL
#include "block.h" // struct drive_s
#include "bregs.h" // struct bregs
#include "hw/ata.h" // ATA_CMD_REQUEST_SENSE
#include "hw/blockcmd.h" // CDB_CMD_REQUEST_SENSE
#include "malloc.h" // free
#include "output.h" // dprintf
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
#include "util.h" // cdrom_prepboot
Add 'measurement' code to the BIOS This patch adds invocations of functions that measure various parts of the code and data through various parts of the BIOS code. It follows TCG specifications on what needs to be measured. It also adds the implementation of the called functions. Reference for what needs to be measured can be found in specs found here: http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios The first measurements are done once the ACPI tables have been initialized. Once booted into Linux, the current measurements produce the following logs which can be found in /sys/kernel/security/tpm0/ascii_bios_measurements. The below log also shows measurements from trusted grub. 1 3fb240d2a04085a4e84f81e4398e070ed5a18163 06 [SMBIOS] 2 cc812353fc277c1fab99e0b721752a1392984566 06 [Option ROM] 2 9dbd87163112e5670378abe4510491259a61f411 05 [Start Option ROM Scan] 2 6f74e357331b8dee11bbad85f27bc66cb873106c 06 [Option ROM] 2 5626eb7ac05c7231e46d7461e7d3839b03ae9fad 06 [Option ROM] 4 c1e25c3f6b0dc78d57296aa2870ca6f782ccf80f 05 [Calling INT 19h] 0 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 1 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 2 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 3 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 4 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 5 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 6 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 7 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 4 8cf2fe6c87d4d0b2998a43da630292e6d85ee8b6 05 [Booting BCV device 80h (HDD)] 4 5dff94459a3e2d13a433ef94afdc306144565bf7 0d [IPL] 5 d1b33afde65ad47502332af957c60f20c84c1edc 0e [IPL Partition Data] 4 487ce764b527ccad17f1d04243d0136fa981e6c4 0d [IPL] 4 91d285e4dead566324c8938a3cc75803f462d9a1 0d [IPL] 4 8ba79ac98bb491524fef29defc724daaf6263d35 0d [IPL] 4 c591c15b82e4ff30e7383a4ff1ef3b41b38521ac 06 [] 4 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator] 5 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator] 5 e8673b9e14b02dc12d8ccfd0176bca7a3de7fc3c 0e [IPL Partition Data] 5 0163e375a0af7525c5dac1a8e74b277359e40d1d 1105 [] 8 4be30f67c3d48ab7f04d9c0fd07f06d4c68379be 1205 [] 8 54c83965978de9708d026016ecb0e70660e04388 1305 [] 5 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator] 8 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator] 8 f3973cae05d6e2055062119d6e6e1e077b7df876 1005 [] Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
2015-05-26 21:48:33 +02:00
#include "tcgbios.h" // tpm_*
/****************************************************************
* CD emulation
****************************************************************/
struct eltorito_s CDEmu VARLOW = { .size=sizeof(CDEmu) };
struct drive_s *emulated_drive_gf VARLOW;
struct drive_s *cdemu_drive_gf VARFSEG;
static int
cdemu_read(struct disk_op_s *op)
{
struct drive_s *drive_gf = GET_LOW(emulated_drive_gf);
struct disk_op_s dop;
dop.drive_fl = drive_gf;
dop.command = op->command;
dop.lba = GET_LOW(CDEmu.ilba) + op->lba / 4;
int count = op->count;
op->count = 0;
u8 *cdbuf_fl = GET_GLOBAL(bounce_buf_fl);
if (op->lba & 3) {
// Partial read of first block.
dop.count = 1;
dop.buf_fl = cdbuf_fl;
int ret = process_op(&dop);
if (ret)
return ret;
u8 thiscount = 4 - (op->lba & 3);
if (thiscount > count)
thiscount = count;
count -= thiscount;
memcpy_fl(op->buf_fl, cdbuf_fl + (op->lba & 3) * 512, thiscount * 512);
op->buf_fl += thiscount * 512;
op->count += thiscount;
dop.lba++;
}
if (count > 3) {
// Read n number of regular blocks.
dop.count = count / 4;
dop.buf_fl = op->buf_fl;
int ret = process_op(&dop);
op->count += dop.count * 4;
if (ret)
return ret;
u8 thiscount = count & ~3;
count &= 3;
op->buf_fl += thiscount * 512;
dop.lba += thiscount / 4;
}
if (count) {
// Partial read on last block.
dop.count = 1;
dop.buf_fl = cdbuf_fl;
int ret = process_op(&dop);
if (ret)
return ret;
u8 thiscount = count;
memcpy_fl(op->buf_fl, cdbuf_fl, thiscount * 512);
op->count += thiscount;
}
return DISK_RET_SUCCESS;
}
int
cdemu_process_op(struct disk_op_s *op)
{
if (!CONFIG_CDROM_EMU)
return 0;
switch (op->command) {
case CMD_READ:
return cdemu_read(op);
case CMD_WRITE:
case CMD_FORMAT:
return DISK_RET_EWRITEPROTECT;
default:
return default_process_op(op);
}
}
void
cdrom_prepboot(void)
{
if (!CONFIG_CDROM_EMU)
return;
if (!CDCount)
return;
if (create_bounce_buf() < 0)
return;
struct drive_s *drive = malloc_fseg(sizeof(*drive));
if (!drive) {
warn_noalloc();
return;
}
cdemu_drive_gf = drive;
memset(drive, 0, sizeof(*drive));
drive->type = DTYPE_CDEMU;
drive->blksize = DISK_SECTOR_SIZE;
drive->sectors = (u64)-1;
}
/****************************************************************
* CD booting
****************************************************************/
int
cdrom_boot(struct drive_s *drive)
{
ASSERT32FLAT();
struct disk_op_s dop;
int cdid = getDriveId(EXTTYPE_CD, drive);
memset(&dop, 0, sizeof(dop));
dop.drive_fl = drive;
if (!dop.drive_fl || cdid < 0)
return 1;
int ret = scsi_is_ready(&dop);
if (ret)
dprintf(5, "scsi_is_ready returned %d\n", ret);
// Read the Boot Record Volume Descriptor
u8 buffer[CDROM_SECTOR_SIZE];
dop.command = CMD_READ;
dop.lba = 0x11;
dop.count = 1;
dop.buf_fl = buffer;
ret = process_op(&dop);
if (ret)
return 3;
// Validity checks
if (buffer[0])
return 4;
if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
return 5;
// ok, now we calculate the Boot catalog address
u32 lba = *(u32*)&buffer[0x47];
// And we read the Boot Catalog
dop.lba = lba;
dop.count = 1;
ret = process_op(&dop);
if (ret)
return 7;
// Validation entry
if (buffer[0x00] != 0x01)
return 8; // Header
if (buffer[0x01] != 0x00)
return 9; // Platform
if (buffer[0x1E] != 0x55)
return 10; // key 1
if (buffer[0x1F] != 0xAA)
return 10; // key 2
// Initial/Default Entry
if (buffer[0x20] != 0x88)
return 11; // Bootable
Add 'measurement' code to the BIOS This patch adds invocations of functions that measure various parts of the code and data through various parts of the BIOS code. It follows TCG specifications on what needs to be measured. It also adds the implementation of the called functions. Reference for what needs to be measured can be found in specs found here: http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios The first measurements are done once the ACPI tables have been initialized. Once booted into Linux, the current measurements produce the following logs which can be found in /sys/kernel/security/tpm0/ascii_bios_measurements. The below log also shows measurements from trusted grub. 1 3fb240d2a04085a4e84f81e4398e070ed5a18163 06 [SMBIOS] 2 cc812353fc277c1fab99e0b721752a1392984566 06 [Option ROM] 2 9dbd87163112e5670378abe4510491259a61f411 05 [Start Option ROM Scan] 2 6f74e357331b8dee11bbad85f27bc66cb873106c 06 [Option ROM] 2 5626eb7ac05c7231e46d7461e7d3839b03ae9fad 06 [Option ROM] 4 c1e25c3f6b0dc78d57296aa2870ca6f782ccf80f 05 [Calling INT 19h] 0 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 1 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 2 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 3 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 4 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 5 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 6 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 7 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 4 8cf2fe6c87d4d0b2998a43da630292e6d85ee8b6 05 [Booting BCV device 80h (HDD)] 4 5dff94459a3e2d13a433ef94afdc306144565bf7 0d [IPL] 5 d1b33afde65ad47502332af957c60f20c84c1edc 0e [IPL Partition Data] 4 487ce764b527ccad17f1d04243d0136fa981e6c4 0d [IPL] 4 91d285e4dead566324c8938a3cc75803f462d9a1 0d [IPL] 4 8ba79ac98bb491524fef29defc724daaf6263d35 0d [IPL] 4 c591c15b82e4ff30e7383a4ff1ef3b41b38521ac 06 [] 4 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator] 5 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator] 5 e8673b9e14b02dc12d8ccfd0176bca7a3de7fc3c 0e [IPL Partition Data] 5 0163e375a0af7525c5dac1a8e74b277359e40d1d 1105 [] 8 4be30f67c3d48ab7f04d9c0fd07f06d4c68379be 1205 [] 8 54c83965978de9708d026016ecb0e70660e04388 1305 [] 5 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator] 8 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator] 8 f3973cae05d6e2055062119d6e6e1e077b7df876 1005 [] Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
2015-05-26 21:48:33 +02:00
/* measure 2048 bytes (one sector) */
tpm_add_cdrom_catalog(MAKE_FLATPTR(GET_SEG(SS), buffer), sizeof(buffer));
// Fill in el-torito cdrom emulation fields.
emulated_drive_gf = drive;
u8 media = buffer[0x21];
u16 boot_segment = *(u16*)&buffer[0x22];
if (!boot_segment)
boot_segment = 0x07C0;
CDEmu.load_segment = boot_segment;
CDEmu.buffer_segment = 0x0000;
u16 nbsectors = *(u16*)&buffer[0x26];
CDEmu.sector_count = nbsectors;
lba = *(u32*)&buffer[0x28];
CDEmu.ilba = lba;
CDEmu.controller_index = drive->cntl_id / 2;
CDEmu.device_spec = drive->cntl_id % 2;
// And we read the image in memory
nbsectors = DIV_ROUND_UP(nbsectors, 4);
dop.lba = lba;
dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
while (nbsectors) {
int count = nbsectors;
if (count > 64*1024/CDROM_SECTOR_SIZE)
count = 64*1024/CDROM_SECTOR_SIZE;
dop.count = count;
ret = process_op(&dop);
if (ret)
return 12;
nbsectors -= count;
dop.lba += count;
dop.buf_fl += count*CDROM_SECTOR_SIZE;
}
if (media == 0) {
// No emulation requested - return success.
CDEmu.emulated_drive = EXTSTART_CD + cdid;
return 0;
}
// Emulation of a floppy/harddisk requested
if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
return 13;
// Set emulated drive id and increase bios installed hardware
// number of devices
if (media < 4) {
// Floppy emulation
CDEmu.emulated_drive = 0x00;
// XXX - get and set actual floppy count.
set_equipment_flags(0x41, 0x41);
switch (media) {
case 0x01: // 1.2M floppy
CDEmu.chs.sptcyl = 15;
CDEmu.chs.cyllow = 79;
CDEmu.chs.heads = 1;
break;
case 0x02: // 1.44M floppy
CDEmu.chs.sptcyl = 18;
CDEmu.chs.cyllow = 79;
CDEmu.chs.heads = 1;
break;
case 0x03: // 2.88M floppy
CDEmu.chs.sptcyl = 36;
CDEmu.chs.cyllow = 79;
CDEmu.chs.heads = 1;
break;
}
} else {
// Harddrive emulation
CDEmu.emulated_drive = 0x80;
SET_BDA(hdcount, GET_BDA(hdcount) + 1);
// Peak at partition table to get chs.
struct mbr_s *mbr = MAKE_FLATPTR(boot_segment, 0);
CDEmu.chs = mbr->partitions[0].last;
}
// everything is ok, so from now on, the emulation is active
CDEmu.media = media;
dprintf(6, "cdemu media=%d\n", media);
return 0;
}
// check if media is present and the drive is bootable.
// in case it is return the volume label.
char*
cdrom_media_info(struct drive_s *drive)
{
ASSERT32FLAT();
struct disk_op_s dop;
memset(&dop, 0, sizeof(dop));
dop.drive_fl = drive;
int ret = scsi_is_ready(&dop);
if (ret)
return NULL;
// Read the Boot Record Volume Descriptor
u8 buffer[CDROM_SECTOR_SIZE];
dop.command = CMD_READ;
dop.lba = 0x11;
dop.count = 1;
dop.buf_fl = buffer;
ret = process_op(&dop);
if (ret)
return NULL;
// Is it bootable?
if (buffer[0])
return NULL;
if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
return NULL;
// Read the Primary Volume Descriptor
dop.command = CMD_READ;
dop.lba = 0x10;
dop.count = 1;
dop.buf_fl = buffer;
ret = process_op(&dop);
if (ret)
return NULL;
// Read volume id, trim trailing spaces
char *volume = znprintf(30, "%s", buffer + 40);
nullTrailingSpace(volume);
return volume;
}