int is_no_emulation(int drive) { struct packet { unsigned char packet_size; unsigned char media_type; unsigned char drive_num; unsigned char ctrlr_index; unsigned long lba; unsigned short device_spec; unsigned short buffer_segment; unsigned short load_segment; unsigned short sector_count; unsigned char cyl_count; unsigned char sec_count; unsigned char head_count; unsigned char reseved; } __attribute__((packed)); static struct packet pkt; bzero(&pkt, sizeof(pkt)); pkt.packet_size = 0x13; bb.intno = 0x13; bb.eax.r.h = 0x4b; bb.eax.r.l = 0x01; // subfunc: get info bb.edx.r.l = drive; bb.esi.rr = NORMALIZED_OFFSET((unsigned)&pkt); bb.ds = NORMALIZED_SEGMENT((unsigned)&pkt); bios(&bb); #if DEBUG printf("el_torito info drive %x\n", drive); printf("--> cf %x, eax %x\n", bb.flags.cf, bb.eax.rr); printf("pkt_size: %x\n", pkt.packet_size); printf("media_type: %x\n", pkt.media_type); printf("drive_num: %x\n", pkt.drive_num); printf("device_spec: %x\n", pkt.device_spec); printf("press a key->\n"); getchar(); #endif /* Some BIOSes erroneously return cf = 1 */ /* Just check to see if the drive number is the same. */ if (pkt.drive_num == drive && (pkt.media_type & 0x0F) == 0) { return 1; // We are in no-emulation mode. } return 0; }
int get_drive_info(int drive, struct driveInfo *dp) { boot_drive_info_t *di = &dp->di; int ret = 0; #if UNUSED if (maxhd == 0) { bb.intno = 0x13; bb.eax.r.h = 0x08; bb.edx.r.l = 0x80; bios(&bb); if (bb.flags.cf == 0) maxhd = 0x7f + bb.edx.r.l; }; if (drive > maxhd) return 0; #endif bzero(dp, sizeof(struct driveInfo)); dp->biosdev = drive; /* Check for El Torito no-emulation mode. */ dp->no_emulation = is_no_emulation(drive); /* Check drive for EBIOS support. */ bb.intno = 0x13; bb.eax.r.h = 0x41; bb.edx.r.l = drive; bb.ebx.rr = 0x55aa; bios(&bb); if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) dp->uses_ebios = bb.ecx.r.l; // Get flags for supported operations. if (dp->uses_ebios & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) { // Get EBIOS drive info. static struct drive_params params; params.buf_size = sizeof(params); bb.intno = 0x13; bb.eax.r.h = 0x48; bb.edx.r.l = drive; bb.esi.rr = NORMALIZED_OFFSET((unsigned)¶ms); bb.ds = NORMALIZED_SEGMENT((unsigned)¶ms); bios(&bb); if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) { dp->uses_ebios = 0; di->params.buf_size = 1; } else { bcopy(¶ms, &di->params, sizeof(params)); if (drive >= BASE_HD_DRIVE && (dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && di->params.buf_size >= 30 && !(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) { void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4)); bcopy(ptr, &di->dpte, sizeof(di->dpte)); } } } if (dp->no_emulation) { /* Some BIOSes give us erroneous EBIOS support information. * Assume that if you're on a CD, then you can use * EBIOS disk calls. */ dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS; } #if DEBUG print_drive_info(di); printf("uses_ebios = 0x%x\n", dp->uses_ebios); printf("result %d\n", ret); printf("press a key->\n");getc(); #endif if (ret == 0) dp->valid = 1; return ret; }
int ebiosread(int dev, unsigned long long sec, int count) { int i; static struct { unsigned char size; unsigned char reserved; unsigned char numblocks; unsigned char reserved2; unsigned short bufferOffset; unsigned short bufferSegment; unsigned long long startblock; } addrpacket __attribute__((aligned(16))) = {0}; addrpacket.size = sizeof(addrpacket); for (i = 0; ;) { bb.intno = 0x13; bb.eax.r.h = 0x42; bb.edx.r.l = dev; bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket); bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket); addrpacket.reserved = addrpacket.reserved2 = 0; addrpacket.numblocks = count; addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR)); addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR)); addrpacket.startblock = sec; bios(&bb); // In case of a successful call, make sure we set AH (return code) to zero. if (bb.flags.cf == 0) { bb.eax.r.h = 0; } // Now we can really check for the return code (AH) value. if ((bb.eax.r.h == 0x00) || (i++ >= 5)) { break; } // Reset disk subsystem and try again. bb.eax.r.h = 0x00; bios(&bb); } return bb.eax.r.h; } //============================================================================== void putc(int ch) { bb.intno = 0x10; bb.ebx.r.h = 0x00; /* background black */ bb.ebx.r.l = 0x0F; /* foreground white */ bb.eax.r.h = 0x0e; bb.eax.r.l = ch; bios(&bb); }
unsigned long getMemoryMap(MemoryRange * rangeArray, unsigned long maxRangeCount, unsigned long * conMemSizePtr, unsigned long * extMemSizePtr) { #define kMemoryMapSignature 'SMAP' #define kDescriptorSizeMin 20 MemoryRange * range = (MemoryRange *)BIOS_ADDR; unsigned long count = 0; unsigned long long conMemSize = 0; unsigned long long extMemSize = 0; // Prepare for the INT15 E820h call. Each call returns a single // memory range. A continuation value is returned that must be // provided on a subsequent call to fetch the next range. // // Certain BIOSes (Award 6.00PG) expect the upper word in EAX // to be cleared on entry, otherwise only a single range will // be reported. // // Some BIOSes will simply ignore the value of ECX on entry. // Probably best to keep its value at 20 to avoid surprises. //printf("Get memory map 0x%x, %d\n", rangeArray);getc(); if (maxRangeCount > (BIOS_LEN / sizeof(MemoryRange))) maxRangeCount = (BIOS_LEN / sizeof(MemoryRange)); bb.ebx.rx = 0; // Initial continuation value must be zero. while (count < maxRangeCount) { bb.intno = 0x15; bb.eax.rx = 0xe820; bb.ecx.rx = kDescriptorSizeMin; bb.edx.rx = kMemoryMapSignature; bb.edi.rr = NORMALIZED_OFFSET( (unsigned long) range ); bb.es = NORMALIZED_SEGMENT( (unsigned long) range ); bios(&bb); // Check for errors. if ( bb.flags.cf || bb.eax.rx != kMemoryMapSignature || bb.ecx.rx != kDescriptorSizeMin ) { //printf("Got an error %x %x %x\n", bb.flags.cf, // bb.eax.rx, bb.ecx.rx); break; } // Tally up the conventional/extended memory sizes. if (range->type == kMemoryRangeUsable || range->type == kMemoryRangeACPI || range->type == kMemoryRangeNVS ) { // Tally the conventional memory ranges. if (range->base + range->length <= 0xa0000) conMemSize += range->length; // Record the top of extended memory. if (range->base >= EXTENDED_ADDR) extMemSize += range->length; } range++; count++; // Is this the last address range? if ( bb.ebx.rx == 0 ) { //printf("last range\n"); break; } } *conMemSizePtr = conMemSize / 1024; // size in KB *extMemSizePtr = extMemSize / 1024; // size in KB // Copy out data bcopy((char *)BIOS_ADDR, rangeArray, ((char *)range - (char *)BIOS_ADDR)); #if DEBUG { int i; printf("%d total ranges\n", count);getc(); for (i=0, range = rangeArray; i<count; i++, range++) { printf("range: type %d, base 0x%x, length 0x%x\n", range->type, (unsigned int)range->base, (unsigned int)range->length); getc(); } } #endif return count; }