// Perform read/write/verify using new-style "int13ext" accesses. static void noinline extended_access(struct bregs *regs, struct drive_s *drive_gf, u16 command) { struct disk_op_s dop; struct int13ext_s *param_far = (struct int13ext_s*)(regs->si+0); // Get lba and check. dop.lba = GET_FARVAR(regs->ds, param_far->lba); dop.command = command; dop.drive_gf = drive_gf; if (dop.lba >= GET_GLOBALFLAT(drive_gf->sectors)) { warn_invalid(regs); disk_ret(regs, DISK_RET_EPARAM); return; } dop.buf_fl = SEGOFF_TO_FLATPTR(GET_FARVAR(regs->ds, param_far->data)); dop.count = GET_FARVAR(regs->ds, param_far->count); if (! dop.count) { // Nothing to do. disk_ret(regs, DISK_RET_SUCCESS); return; } int status = send_disk_op(&dop); SET_FARVAR(regs->ds, param_far->count, dop.count); disk_ret(regs, status); }
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; }
static int bochsvga_restore_state(u16 seg, u16 *info) { u16 en = GET_FARVAR(seg, *info); info++; if (!(en & VBE_DISPI_ENABLED)) { dispi_write(VBE_DISPI_INDEX_ENABLE, en); return 0; } int i; for (i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) if (i == VBE_DISPI_INDEX_ENABLE) { dispi_write(i, en); } else { dispi_write(i, GET_FARVAR(seg, *info)); info++; } return 0; }
static void dequeue_key(struct bregs *regs, int incr, int extended) { yield(); u16 buffer_head; u16 buffer_tail; for (;;) { buffer_head = GET_BDA(kbd_buf_head); buffer_tail = GET_BDA(kbd_buf_tail); if (buffer_head != buffer_tail) break; if (!incr) { regs->flags |= F_ZF; return; } yield_toirq(); } u16 keycode = GET_FARVAR(SEG_BDA, *(u16*)(buffer_head+0)); u8 ascii = keycode & 0xff; if (!extended) { // Translate extended keys if (ascii == 0xe0 && keycode & 0xff00) keycode &= 0xff00; else if (keycode == 0xe00d || keycode == 0xe00a) // Extended enter key keycode = 0x1c00 | ascii; else if (keycode == 0xe02f) // Extended '/' key keycode = 0x352f; // Technically, if the ascii value is 0xf0 or if the // 'scancode' is greater than 0x84 then the key should be // discarded. However, there seems no harm in passing on the // extended values in these cases. } if (ascii == 0xf0 && keycode & 0xff00) keycode &= 0xff00; regs->ax = keycode; if (!incr) { regs->flags &= ~F_ZF; return; } u16 buffer_start = GET_BDA(kbd_buf_start_offset); u16 buffer_end = GET_BDA(kbd_buf_end_offset); buffer_head += 2; if (buffer_head >= buffer_end) buffer_head = buffer_start; SET_BDA(kbd_buf_head, buffer_head); }
static void dequeue_key(struct bregs *regs, int incr, int extended) { yield(); u16 buffer_head; u16 buffer_tail; for (;;) { buffer_head = GET_BDA(kbd_buf_head); buffer_tail = GET_BDA(kbd_buf_tail); if (buffer_head != buffer_tail) break; if (!incr) { regs->flags |= F_ZF; return; } yield_toirq(); } u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0)); u8 scan_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1)); if ((ascii_code == 0xF0 && scan_code != 0) || (ascii_code == 0xE0 && !extended)) ascii_code = 0; regs->ax = (scan_code << 8) | ascii_code; if (!incr) { regs->flags &= ~F_ZF; return; } u16 buffer_start = GET_BDA(kbd_buf_start_offset); u16 buffer_end = GET_BDA(kbd_buf_end_offset); buffer_head += 2; if (buffer_head >= buffer_end) buffer_head = buffer_start; SET_BDA(kbd_buf_head, buffer_head); }
static void gfx_planar(struct gfx_op *op) { if (!CONFIG_VGA_STDVGA_PORTS) return; void *dest_far = (void*)(op->y * op->linelength + op->x / 8); int plane; switch (op->op) { default: case GO_READ8: memset(op->pixels, 0, sizeof(op->pixels)); for (plane = 0; plane < 4; plane++) { stdvga_planar4_plane(plane); u8 data = GET_FARVAR(SEG_GRAPH, *(u8*)dest_far); int pixel; for (pixel=0; pixel<8; pixel++) op->pixels[pixel] |= ((data>>(7-pixel)) & 1) << plane; } break; case GO_WRITE8: for (plane = 0; plane<4; plane++) { stdvga_planar4_plane(plane); u8 data = 0; int pixel; for (pixel=0; pixel<8; pixel++) data |= ((op->pixels[pixel]>>plane) & 1) << (7-pixel); SET_FARVAR(SEG_GRAPH, *(u8*)dest_far, data); } break; case GO_MEMSET: for (plane = 0; plane < 4; plane++) { stdvga_planar4_plane(plane); u8 data = (op->pixels[0] & (1<<plane)) ? 0xff : 0x00; memset_stride(SEG_GRAPH, dest_far, data , op->xlen / 8, op->linelength, op->ylen); } break; case GO_MEMMOVE: ; void *src_far = (void*)(op->srcy * op->linelength + op->x / 8); for (plane = 0; plane < 4; plane++) { stdvga_planar4_plane(plane); memmove_stride(SEG_GRAPH, dest_far, src_far , op->xlen / 8, op->linelength, op->ylen); } break; } stdvga_planar4_plane(-1); }
static void gfx_cga(struct gfx_op *op) { int bpp = GET_GLOBAL(op->vmode_g->depth); void *dest_far = (void*)(op->y / 2 * op->linelength + op->x / 8 * bpp); switch (op->op) { default: case GO_READ8: if (op->y & 1) dest_far += 0x2000; if (bpp == 1) { u8 data = GET_FARVAR(SEG_CTEXT, *(u8*)dest_far); int pixel; for (pixel=0; pixel<8; pixel++) op->pixels[pixel] = (data >> (7-pixel)) & 1; } else {
int cdrom_boot(struct drive_s *drive_g) { ASSERT32FLAT(); struct disk_op_s dop; int cdid = getDriveId(EXTTYPE_CD, drive_g); memset(&dop, 0, sizeof(dop)); dop.drive_g = drive_g; if (!dop.drive_g || cdid < 0) return 1; int ret = scsi_is_ready(&dop); if (ret) dprintf(1, "scsi_is_ready returned %d\n", ret); // Read the Boot Record Volume Descriptor u8 buffer[CDROM_SECTOR_SIZE]; dop.lba = 0x11; dop.count = 1; dop.buf_fl = buffer; ret = cdb_read(&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 = cdb_read(&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 u8 media = buffer[0x21]; CDEmu.media = media; CDEmu.emulated_drive_gf = dop.drive_g; 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; // And we read the image in memory dop.lba = lba; dop.count = DIV_ROUND_UP(nbsectors, 4); dop.buf_fl = MAKE_FLATPTR(boot_segment, 0); ret = cdb_read(&dop); if (ret) return 12; if (media == 0) { // No emulation requested - return success. CDEmu.emulated_extdrive = 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_extdrive = 0x00; // XXX - get and set actual floppy count. set_equipment_flags(0x41, 0x41); switch (media) { case 0x01: // 1.2M floppy CDEmu.lchs.spt = 15; CDEmu.lchs.cylinders = 80; CDEmu.lchs.heads = 2; break; case 0x02: // 1.44M floppy CDEmu.lchs.spt = 18; CDEmu.lchs.cylinders = 80; CDEmu.lchs.heads = 2; break; case 0x03: // 2.88M floppy CDEmu.lchs.spt = 36; CDEmu.lchs.cylinders = 80; CDEmu.lchs.heads = 2; break; } } else { // Harddrive emulation CDEmu.emulated_extdrive = 0x80; SET_BDA(hdcount, GET_BDA(hdcount) + 1); // Peak at partition table to get chs. struct mbr_s *mbr = (void*)0; u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl); u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow); u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads); CDEmu.lchs.spt = sptcyl & 0x3f; CDEmu.lchs.cylinders = ((sptcyl<<2)&0x300) + cyllow + 1; CDEmu.lchs.heads = heads + 1; } // everything is ok, so from now on, the emulation is active CDEmu.active = 0x01; dprintf(6, "cdemu media=%d\n", media); return 0; }
// IBM/MS get drive parameters static void noinline disk_1348(struct bregs *regs, struct drive_s *drive_gf) { u16 seg = regs->ds; struct int13dpt_s *param_far = (struct int13dpt_s*)(regs->si+0); u16 size = GET_FARVAR(seg, param_far->size); u16 t13 = size == 74; // Buffer is too small if (size < 26) { disk_ret(regs, DISK_RET_EPARAM); return; } // EDD 1.x u8 type = GET_GLOBALFLAT(drive_gf->type); u16 npc = GET_GLOBALFLAT(drive_gf->pchs.cylinder); u16 nph = GET_GLOBALFLAT(drive_gf->pchs.head); u16 nps = GET_GLOBALFLAT(drive_gf->pchs.sector); u64 lba = GET_GLOBALFLAT(drive_gf->sectors); u16 blksize = GET_GLOBALFLAT(drive_gf->blksize); dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n" , size, type, npc, nph, nps, (u32)lba, blksize); SET_FARVAR(seg, param_far->size, 26); if (type == DTYPE_ATA_ATAPI) { // 0x74 = removable, media change, lockable, max values SET_FARVAR(seg, param_far->infos, 0x74); SET_FARVAR(seg, param_far->cylinders, 0xffffffff); SET_FARVAR(seg, param_far->heads, 0xffffffff); SET_FARVAR(seg, param_far->spt, 0xffffffff); SET_FARVAR(seg, param_far->sector_count, (u64)-1); } else { if (lba > (u64)nps*nph*0x3fff) { SET_FARVAR(seg, param_far->infos, 0x00); // geometry is invalid SET_FARVAR(seg, param_far->cylinders, 0x3fff); } else { SET_FARVAR(seg, param_far->infos, 0x02); // geometry is valid SET_FARVAR(seg, param_far->cylinders, (u32)npc); } SET_FARVAR(seg, param_far->heads, (u32)nph); SET_FARVAR(seg, param_far->spt, (u32)nps); SET_FARVAR(seg, param_far->sector_count, lba); } SET_FARVAR(seg, param_far->blksize, blksize); if (size < 30 || (type != DTYPE_ATA && type != DTYPE_ATA_ATAPI && type != DTYPE_VIRTIO_BLK && type != DTYPE_VIRTIO_SCSI)) { disk_ret(regs, DISK_RET_SUCCESS); return; } // EDD 2.x int bdf; u16 iobase1 = 0; u64 device_path = 0; u8 channel = 0; SET_FARVAR(seg, param_far->size, 30); if (type == DTYPE_ATA || type == DTYPE_ATA_ATAPI) { SET_FARVAR(seg, param_far->dpte, SEGOFF(SEG_LOW, (u32)&DefaultDPTE)); // Fill in dpte struct atadrive_s *adrive_gf = container_of( drive_gf, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); u8 slave = GET_GLOBALFLAT(adrive_gf->slave); u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); u8 irq = GET_GLOBALFLAT(chan_gf->irq); iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); bdf = GET_GLOBALFLAT(chan_gf->pci_bdf); device_path = slave; channel = GET_GLOBALFLAT(chan_gf->chanid); u16 options = 0; if (type == DTYPE_ATA) { u8 translation = GET_GLOBALFLAT(drive_gf->translation); if (translation != TRANSLATION_NONE) { options |= 1<<3; // CHS translation if (translation == TRANSLATION_LBA) options |= 1<<9; if (translation == TRANSLATION_RECHS) options |= 3<<9; } } else { // ATAPI options |= 1<<5; // removable device options |= 1<<6; // atapi device } options |= 1<<4; // lba translation if (CONFIG_ATA_PIO32) options |= 1<<7; SET_LOW(DefaultDPTE.iobase1, iobase1); SET_LOW(DefaultDPTE.iobase2, iobase2 + ATA_CB_DC); SET_LOW(DefaultDPTE.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | ATA_CB_DH_LBA)); SET_LOW(DefaultDPTE.unused, 0xcb); SET_LOW(DefaultDPTE.irq, irq); SET_LOW(DefaultDPTE.blkcount, 1); SET_LOW(DefaultDPTE.dma, 0); SET_LOW(DefaultDPTE.pio, 0); SET_LOW(DefaultDPTE.options, options); SET_LOW(DefaultDPTE.reserved, 0); SET_LOW(DefaultDPTE.revision, 0x11); u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15); SET_LOW(DefaultDPTE.checksum, -sum); } else {
gfx_cga(struct gfx_op *op) { int bpp = GET_GLOBAL(op->vmode_g->depth); void *dest_far = (void*)(op->y / 2 * op->linelength + op->x / 8 * bpp); switch (op->op) { default: case GO_READ8: if (op->y & 1) dest_far += 0x2000; if (bpp == 1) { u8 data = GET_FARVAR(SEG_CTEXT, *(u8*)dest_far); int pixel; for (pixel=0; pixel<8; pixel++) op->pixels[pixel] = (data >> (7-pixel)) & 1; } else { u16 data = GET_FARVAR(SEG_CTEXT, *(u16*)dest_far); data = be16_to_cpu(data); int pixel; for (pixel=0; pixel<8; pixel++) op->pixels[pixel] = (data >> ((7-pixel)*2)) & 3; } break; case GO_WRITE8: if (op->y & 1) dest_far += 0x2000; if (bpp == 1) { u8 data = 0; int pixel; for (pixel=0; pixel<8; pixel++) data |= (op->pixels[pixel] & 1) << (7-pixel); SET_FARVAR(SEG_CTEXT, *(u8*)dest_far, data);