struct vgamode_s *bochsvga_find_mode(int mode) { struct bochsvga_mode *m = bochsvga_modes; if (GET_GLOBAL(dispi_found)) for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++) if (GET_GLOBAL(m->mode) == mode) return &m->info; return stdvga_find_mode(mode); }
static u8 get_translation(struct drive_s *drive_g) { u8 type = GET_GLOBAL(drive_g->type); if (! CONFIG_COREBOOT && type == DTYPE_ATA) { // Emulators pass in the translation info via nvram. u8 ataid = GET_GLOBAL(drive_g->cntl_id); u8 channel = ataid / 2; u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2); translation >>= 2 * (ataid % 4); translation &= 0x03; return translation; }
static void via_155f18(struct bregs *regs) { int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed); if (fbsize < 0 || ramspeed < 0) { set_code_invalid(regs, RET_EUNSUPPORTED); return; } regs->eax = 0x5f; regs->ebx = 0x500 | (ramspeed << 4) | fbsize; regs->ecx = 0x060; set_success(regs); }
// Reset a drive static void ata_reset(struct atadrive_s *adrive_g) { struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); u8 slave = GET_GLOBAL(adrive_g->slave); u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); dprintf(6, "ata_reset drive=%p\n", &adrive_g->drive); // Pulse SRST outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC); udelay(5); outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC); msleep(2); // wait for device to become not busy. int status = await_not_bsy(iobase1); if (status < 0) goto done; if (slave) { // Change device. u64 end = calc_future_tsc(IDE_TIMEOUT); for (;;) { outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH); status = ndelay_await_not_bsy(iobase1); if (status < 0) goto done; if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1) break; // Change drive request failed to take effect - retry. if (check_tsc(end)) { warn_timeout(); goto done; } } } else { // QEMU doesn't reset dh on reset, so set it explicitly. outb(ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH); } // On a user-reset request, wait for RDY if it is an ATA device. u8 type=GET_GLOBAL(adrive_g->drive.type); if (type == DTYPE_ATA) status = await_rdy(iobase1); done: // Enable interrupts outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); dprintf(6, "ata_reset exit status=%x\n", status); }
// read disk drive parameters static void noinline disk_1308(struct bregs *regs, struct drive_s *drive_g) { u16 ebda_seg = get_ebda_seg(); // Get logical geometry from table u16 nlc, nlh, nlspt; fillLCHS(drive_g, &nlc, &nlh, &nlspt); nlc--; nlh--; u8 count; if (regs->dl < EXTSTART_HD) { // Floppy count = GET_GLOBAL(FloppyCount); if (CONFIG_CDROM_EMU && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2; else regs->bx = GET_GLOBAL(drive_g->floppy_type); // set es & di to point to 11 byte diskette param table in ROM regs->es = SEG_BIOS; regs->di = (u32)&diskette_param_table2; } else if (regs->dl < EXTSTART_CD) { // Hard drive count = GET_BDA(hdcount); nlc--; // last sector reserved } else { // Not supported on CDROM disk_ret(regs, DISK_RET_EPARAM); return; } if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) { u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive); if (((emudrive ^ regs->dl) & 0x80) == 0) // Note extra drive due to emulation. count++; if (regs->dl < EXTSTART_HD && count > 2) // Max of two floppy drives. count = 2; } regs->al = 0; regs->ch = nlc & 0xff; regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f); regs->dh = nlh; disk_ret(regs, DISK_RET_SUCCESS); regs->dl = count; }
void bochsvga_list_modes(u16 seg, u16 *dest, u16 *last) { struct bochsvga_mode *m = bochsvga_modes; if (GET_GLOBAL(dispi_found)) { for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)] && dest<last; m++) { u16 mode = GET_GLOBAL(m->mode); if (mode == 0xffff) continue; SET_FARVAR(seg, *dest, mode); dest++; } } stdvga_list_modes(seg, dest, last); }
static void vbe_104f06(struct bregs *regs) { if (regs->bl > 0x02) goto fail; struct vgamode_s *vmode_g = get_current_mode(); if (! vmode_g) goto fail; int bpp = vga_bpp(vmode_g); if (regs->bl == 0x00) { int ret = vgahw_set_linelength(vmode_g, DIV_ROUND_UP(regs->cx * bpp, 8)); if (ret) goto fail; } else if (regs->bl == 0x02) { int ret = vgahw_set_linelength(vmode_g, regs->cx); if (ret) goto fail; } int linelength = vgahw_get_linelength(vmode_g); if (linelength < 0) goto fail; regs->bx = linelength; regs->cx = (linelength * 8) / bpp; regs->dx = GET_GLOBAL(VBE_total_memory) / linelength; regs->ax = 0x004f; return; fail: regs->ax = 0x014f; }
// Send an ata command that does not transfer any further data. int ata_cmd_nondata(struct atadrive_s *adrive_g, struct ata_pio_command *cmd) { struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); // Disable interrupts outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); int ret = send_cmd(adrive_g, cmd); if (ret) goto fail; ret = ndelay_await_not_bsy(iobase1); if (ret < 0) goto fail; if (ret & ATA_CB_STAT_ERR) { dprintf(6, "nondata cmd : read error (status=%02x err=%02x)\n" , ret, inb(iobase1 + ATA_CB_ERR)); ret = -4; goto fail; } if (ret & ATA_CB_STAT_DRQ) { dprintf(6, "nondata cmd : DRQ set (status %02x)\n", ret); ret = -5; goto fail; } fail: // Enable interrupts outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); return ret; }
static void vbe_104f08(struct bregs *regs) { struct vgamode_s *vmode_g = get_current_mode(); if (! vmode_g) goto fail; u8 memmodel = GET_GLOBAL(vmode_g->memmodel); if (memmodel == MM_DIRECT || memmodel == MM_YUV) { regs->ax = 0x034f; return; } if (regs->bl > 1) goto fail; if (regs->bl == 0) { int ret = vgahw_set_dacformat(vmode_g, regs->bh); if (ret < 0) goto fail; } int ret = vgahw_get_dacformat(vmode_g); if (ret < 0) goto fail; regs->bh = ret; regs->ax = 0x004f; return; fail: regs->ax = 0x014f; }
// Test if USB keyboard is active. inline int usb_kbd_active(void) { if (! CONFIG_USB_KEYBOARD) return 0; return GET_GLOBAL(keyboard_pipe) != NULL; }
// Test if USB mouse is active. inline int usb_mouse_active(void) { if (! CONFIG_USB_MOUSE) return 0; return GET_GLOBAL(mouse_pipe) != NULL; }
struct drive_s * getDrive(u8 exttype, u8 extdriveoffset) { if (extdriveoffset >= ARRAY_SIZE(IDMap[0])) return NULL; return GET_GLOBAL(IDMap[exttype][extdriveoffset]); }
// Perform read/write/verify using new-style "int13ext" accesses. static void noinline extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command) { struct disk_op_s dop; // Get lba and check. dop.lba = GET_INT13EXT(regs, lba); dop.command = command; dop.drive_g = drive_g; if (dop.lba >= GET_GLOBAL(drive_g->sectors)) { warn_invalid(regs); disk_ret(regs, DISK_RET_EPARAM); return; } dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data)); dop.count = GET_INT13EXT(regs, count); if (! dop.count) { // Nothing to do. disk_ret(regs, DISK_RET_SUCCESS); return; } int status = send_disk_op(&dop); SET_INT13EXT(regs, count, dop.count); disk_ret(regs, status); }
static void intel_155f40(struct bregs *regs) { regs->ax = 0x005f; regs->cl = GET_GLOBAL(IntelDisplayId); set_success(regs); }
// Route command to low-level handler. static int cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) { u8 type = GET_GLOBAL(op->drive_g->type); switch (type) { case DTYPE_ATA_ATAPI: return atapi_cmd_data(op, cdbcmd, blocksize); case DTYPE_USB: return usb_cmd_data(op, cdbcmd, blocksize); case DTYPE_UAS: return uas_cmd_data(op, cdbcmd, blocksize); case DTYPE_AHCI_ATAPI: return ahci_cmd_data(op, cdbcmd, blocksize); case DTYPE_VIRTIO_SCSI: return virtio_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_LSI_SCSI: return lsi_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_ESP_SCSI: return esp_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_MEGASAS: return megasas_cmd_data(op, cdbcmd, blocksize); default: op->count = 0; return DISK_RET_EPARAM; } }
// INT 13h Fixed Disk Services Entry Point void VISIBLE16 handle_13(struct bregs *regs) { debug_enter(regs, DEBUG_HDL_13); u8 extdrive = regs->dl; if (CONFIG_CDROM_EMU) { if (regs->ah == 0x4b) { cdemu_134b(regs); return; } u16 ebda_seg = get_ebda_seg(); if (GET_EBDA2(ebda_seg, cdemu.active)) { u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive); if (extdrive == emudrive) { // Access to an emulated drive. struct drive_s *cdemu = GET_GLOBAL(cdemu_drive); if (regs->ah > 0x16) { // Only old-style commands supported. disk_13XX(regs, cdemu); return; } disk_13(regs, cdemu); return; } if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0) // Adjust id to make room for emulated drive. extdrive--; } } handle_legacy_disk(regs, extdrive); }
static int ramdisk_copy(struct disk_op_s *op, int iswrite) { u32 offset = GET_GLOBAL(op->drive_g->cntl_id); offset += (u32)op->lba * DISK_SECTOR_SIZE; u64 opd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)op->buf_fl); u64 ramd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE(offset); u64 gdt[6]; if (iswrite) { gdt[2] = opd; gdt[3] = ramd; } else { gdt[2] = ramd; gdt[3] = opd; } // Call int 1587 to copy data. struct bregs br; memset(&br, 0, sizeof(br)); br.flags = F_CF|F_IF; br.ah = 0x87; br.es = GET_SEG(SS); br.si = (u32)gdt; br.cx = op->count * DISK_SECTOR_SIZE / 2; call16_int(0x15, &br); if (br.flags & F_CF) return DISK_RET_EBADTRACK; return DISK_RET_SUCCESS; }
static int cdemu_read(struct disk_op_s *op) { struct drive_s *drive_g; drive_g = GLOBALFLAT2GLOBAL(GET_LOW(CDEmu.emulated_drive_gf)); struct disk_op_s dop; dop.drive_g = drive_g; 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; }
static void smi_157f02(struct bregs *regs) { /* Boot Display Device Override */ regs->ax = 0x007f; regs->bl = GET_GLOBAL(SmiBootDisplay); set_success(regs); }
static void vbe_104f00(struct bregs *regs) { u16 seg = regs->es; struct vbe_info *info = (void*)(regs->di+0); if (GET_FARVAR(seg, info->signature) == VBE2_SIGNATURE) { dprintf(4, "Get VBE Controller: VBE2 Signature found\n"); } else if (GET_FARVAR(seg, info->signature) == VESA_SIGNATURE) { dprintf(4, "Get VBE Controller: VESA Signature found\n"); } else { dprintf(4, "Get VBE Controller: Invalid Signature\n"); } memset_far(seg, info, 0, sizeof(*info)); SET_FARVAR(seg, info->signature, VESA_SIGNATURE); SET_FARVAR(seg, info->version, 0x0300); SET_FARVAR(seg, info->oem_string, SEGOFF(get_global_seg(), (u32)VBE_OEM_STRING)); SET_FARVAR(seg, info->capabilities, GET_GLOBAL(VBE_capabilities)); /* We generate our mode list in the reserved field of the info block */ u16 *destmode = (void*)info->reserved; SET_FARVAR(seg, info->video_mode, SEGOFF(seg, (u32)destmode)); /* Total memory (in 64k blocks) */ SET_FARVAR(seg, info->total_memory , GET_GLOBAL(VBE_total_memory) / (64*1024)); SET_FARVAR(seg, info->oem_vendor_string, SEGOFF(get_global_seg(), (u32)VBE_VENDOR_STRING)); SET_FARVAR(seg, info->oem_product_string, SEGOFF(get_global_seg(), (u32)VBE_PRODUCT_STRING)); SET_FARVAR(seg, info->oem_revision_string, SEGOFF(get_global_seg(), (u32)VBE_REVISION_STRING)); /* Fill list of modes */ u16 *last = (void*)&info->reserved[sizeof(info->reserved)]; vgahw_list_modes(seg, destmode, last - 1); regs->ax = 0x004f; }
// Handle a USB key press/release event. static void procscankey(u8 key, u8 key_release, u8 mods) { if (key >= ARRAY_SIZE(KeyToScanCode)) return; u16 scancode = GET_GLOBAL(KeyToScanCode[key]); if (scancode) prockeys(scancode, key_release, mods); }
static void fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt) { if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive)) { // Emulated drive - get info from ebda. (It's not possible to // populate the geometry directly in the driveid because the // geometry is only known after the bios segment is made // read-only). u16 ebda_seg = get_ebda_seg(); *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders); *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads); *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt); return; } *nlc = GET_GLOBAL(drive_g->lchs.cylinders); *nlh = GET_GLOBAL(drive_g->lchs.heads); *nlspt = GET_GLOBAL(drive_g->lchs.spt); }
// Write sectors. int cdb_write(struct disk_op_s *op) { struct cdb_rwdata_10 cmd; memset(&cmd, 0, sizeof(cmd)); cmd.command = CDB_CMD_WRITE_10; cmd.lba = cpu_to_be32(op->lba); cmd.count = cpu_to_be16(op->count); return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize)); }
static u8 bochsvga_dispi_enabled(void) { if (!GET_GLOBAL(dispi_found)) return 0; u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE); if (!(en & VBE_DISPI_ENABLED)) return 0; return 1; }
// installation check static void handle_1ab101(struct bregs *regs) { regs->al = 0x01; // Flags - "Config Mechanism #1" supported. regs->bx = 0x0210; // PCI version 2.10 regs->cl = GET_GLOBAL(MaxPCIBus); regs->edx = 0x20494350; // "PCI " regs->edi = (u32)entry_pcibios32 + BUILD_BIOS_ADDR; set_code_success(regs); }
struct drive_s * getDrive(u8 exttype, u8 extdriveoffset) { if (extdriveoffset >= ARRAY_SIZE(IDMap[0])) return NULL; struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]); if (!drive_gf) return NULL; return GLOBALFLAT2GLOBAL(drive_gf); }
// Read sectors. int cdb_read(struct disk_op_s *op) { struct cdb_rwdata_10 cmd; memset(&cmd, 0, sizeof(cmd)); cmd.command = CDB_CMD_READ_10; cmd.lba = htonl(op->lba); cmd.count = htons(op->count); return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize)); }
struct vgamode_s * find_vga_entry(u8 mode) { int i; for (i = 0; i < ARRAY_SIZE(vga_modes); i++) { struct vgamode_s *vmode_g = &vga_modes[i]; if (GET_GLOBAL(vmode_g->svgamode) == mode) return vmode_g; } return NULL; }
// Output a string that is in the CS segment. static void puts_cs(struct putcinfo *action, const char *s) { char *vs = (char*)s; for (;; vs++) { char c = GET_GLOBAL(*vs); if (!c) break; putc(action, c); } }
// Check for drive RDY for 16bit interface command. static int isready(struct atadrive_s *adrive_g) { // Read the status from controller struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf); u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); u8 status = inb(iobase1 + ATA_CB_STAT); if ((status & (ATA_CB_STAT_BSY|ATA_CB_STAT_RDY)) == ATA_CB_STAT_RDY) return DISK_RET_SUCCESS; return DISK_RET_ENOTREADY; }