int envy_bios_parse_power_budget(struct envy_bios *bios) { struct envy_bios_power_budget *budget = &bios->power.budget; int i, err = 0; if (!budget->offset) return -EINVAL; bios_u8(bios, budget->offset + 0x0, &budget->version); switch(budget->version) { case 0x10: case 0x20: case 0x30: err |= bios_u8(bios, budget->offset + 0x1, &budget->hlen); err |= bios_u8(bios, budget->offset + 0x2, &budget->rlen); err |= bios_u8(bios, budget->offset + 0x3, &budget->entriesnum); budget->valid = !err; break; default: ENVY_BIOS_ERR("Unknown POWER BUDGET table version 0x%x\n", budget->version); return -EINVAL; }; err = 0; budget->entries = malloc(budget->entriesnum * sizeof(struct envy_bios_power_budget_entry)); memset(budget->entries, 0x0, budget->entriesnum * sizeof(struct envy_bios_power_budget_entry)); for (i = 0; i < budget->entriesnum; i++) { uint16_t data = budget->offset + budget->hlen + i * budget->rlen; budget->entries[i].offset = data; if (budget->rlen == 0x6) { err |= bios_u32(bios, data + 0x02, &budget->entries[i].avg); } else { err |= bios_u32(bios, data + 0x02, &budget->entries[i].min); err |= bios_u32(bios, data + 0x06, &budget->entries[i].avg); err |= bios_u32(bios, data + 0x0a, &budget->entries[i].peak); err |= bios_u32(bios, data + 0x12, &budget->entries[i].unkn12); } budget->entries[i].valid = !err; } return 0; }
int envy_bios_parse_power_fan(struct envy_bios *bios) { struct envy_bios_power_fan *fan = &bios->power.fan; uint16_t data; int err = 0; if (!fan->offset) return -EINVAL; bios_u8(bios, fan->offset + 0x0, &fan->version); switch(fan->version) { case 0x10: err |= bios_u8(bios, fan->offset + 0x1, &fan->hlen); err |= bios_u8(bios, fan->offset + 0x2, &fan->rlen); err |= bios_u8(bios, fan->offset + 0x3, &fan->entriesnum); fan->valid = !err; break; default: ENVY_BIOS_ERR("Unknown FAN table version 0x%x\n", fan->version); return -EINVAL; }; /* go to the first entry */ data = fan->offset + fan->hlen; bios_u8(bios, data + 0x00, &fan->type); bios_u8(bios, data + 0x02, &fan->duty_min); bios_u8(bios, data + 0x03, &fan->duty_max); /* 0x10 == constant to 9? */ bios_u32(bios, data + 0x0b, &fan->divisor); fan->divisor &= 0xffffff; bios_u16(bios, data + 0x0e, &fan->unk0e); /* looks like the fan bump delay */ bios_u16(bios, data + 0x10, &fan->unk10); /* looks like the fan slow down delay */ bios_u16(bios, data + 0x14, &fan->unboost_unboost_ms); bios_u8(bios, data + 0x17, &fan->duty_boosted); /* threshold = 96 °C */ /* temp fan bump min = 45°C */ /* temp fan max = 95°C */ return 0; }
static void print_nv01_init_script(struct envy_bios *bios, FILE *out, unsigned offset, unsigned mask) { unsigned len; uint8_t op; uint8_t arg8_0, arg8_1, arg8_2; uint16_t arg16_0; uint32_t arg32_0, arg32_1, arg32_2; int err = 0; if (!(mask & ENVY_BIOS_PRINT_SCRIPTS)) return; fprintf(out, "Init script at 0x%x:\n", offset); while (1) { if (bios_u8(bios, offset, &op)) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } switch (op) { case 0x6e: /* NV01+ */ len = 13; err |= bios_u32(bios, offset+1, &arg32_0); err |= bios_u32(bios, offset+5, &arg32_1); err |= bios_u32(bios, offset+9, &arg32_2); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tMMIO_MASK 0x%06x &= 0x%08x |= 0x%08x\n", arg32_0, arg32_1, arg32_2); break; case 0x7a: /* NV03+ */ len = 9; err |= bios_u32(bios, offset+1, &arg32_0); err |= bios_u32(bios, offset+5, &arg32_1); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tMMIO_WR 0x%06x <= 0x%08x\n", arg32_0, arg32_1); break; case 0x77: /* NV03+ */ len = 7; err |= bios_u32(bios, offset+1, &arg32_0); err |= bios_u16(bios, offset+5, &arg16_0); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tMMIO_WR16 0x%06x <= 0x%04x\n", arg32_0, arg16_0); break; case 0x79: /* NV03+ */ len = 13; err |= bios_u32(bios, offset+1, &arg32_0); err |= bios_u32(bios, offset+5, &arg32_1); err |= bios_u32(bios, offset+9, &arg32_2); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tMMIO_WR_CRYSTAL 0x%06x <= 0x%08x / 0x%08x\n", arg32_0, arg32_1, arg32_2); break; case 0x74: /* NV03+ */ len = 3; err |= bios_u16(bios, offset+1, &arg16_0); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tUSLEEP %d\n", arg16_0); break; case 0x69: /* NV03+ */ len = 5; err |= bios_u16(bios, offset+1, &arg16_0); err |= bios_u8(bios, offset+3, &arg8_0); err |= bios_u8(bios, offset+4, &arg8_1); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tIO_MASK 0x%04x &= 0x%02x |= 0x%02x\n", arg16_0, arg8_0, arg8_1); break; case 0x78: /* NV03+ */ len = 6; err |= bios_u16(bios, offset+1, &arg16_0); err |= bios_u8(bios, offset+3, &arg8_0); err |= bios_u8(bios, offset+4, &arg8_1); err |= bios_u8(bios, offset+5, &arg8_2); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tIOIDX_MASK 0x%04x[0x%02x] &= 0x%02x |= 0x%02x\n", arg16_0, arg8_0, arg8_1, arg8_2); break; case 0x6d: /* NV03+ */ len = 2; err |= bios_u8(bios, offset+1, &arg8_0); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tIF_MEM_SIZE 0x%02x\n", arg8_0); break; case 0x73: /* NV03+ */ len = 9; err |= bios_u32(bios, offset+1, &arg32_0); err |= bios_u32(bios, offset+5, &arg32_1); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tIF_STRAPS & 0x%08x == 0x%08x\n", arg32_0, arg32_1); break; case 0x72: /* NV03+ */ len = 1; dump_hex_script(bios, out, offset, len); fprintf(out, "\tRESUME\n"); break; case 0x63: /* NV03+ */ len = 1; dump_hex_script(bios, out, offset, len); fprintf(out, "\tCOMPUTE_MEM\n"); break; case 0x71: /* NV01+ */ len = 1; dump_hex_script(bios, out, offset, len); fprintf(out, "\tQUIT\n"); fprintf(out, "\n"); return; case 0x70: /* NV01:NV03 */ len = 7; err |= bios_u16(bios, offset+1, &arg16_0); err |= bios_u32(bios, offset+3, &arg32_0); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tDAC_PLL 0x%04x <= 0x%08x\n", arg16_0, arg32_0); break; case 0x64: /* NV01:NV03 */ len = 5; err |= bios_u16(bios, offset+1, &arg16_0); err |= bios_u8(bios, offset+3, &arg8_0); err |= bios_u8(bios, offset+4, &arg8_1); if (err) { ENVY_BIOS_ERR("Init script out of bounds!\n"); return; } dump_hex_script(bios, out, offset, len); fprintf(out, "\tDAC_MASK 0x%04x &= 0x%02x |= 0x%02x\n", arg16_0, arg8_0, arg8_1); break; case 0xff: /* NV01:NV03 */ len = 1; dump_hex_script(bios, out, offset, len); fprintf(out, "\tQUIT\n"); fprintf(out, "\n"); return; default: len = 1; dump_hex_script(bios, out, offset, len); fprintf(out, "\n"); ENVY_BIOS_ERR("Unknown op 0x%02x in init script!\n", op); return; } offset += len; } }
void envy_bios_print_mem_train_ptrn(struct envy_bios *bios, FILE *out, unsigned mask) { struct envy_bios_mem_train_ptrn *mtp = &bios->mem.train_ptrn; int i, j; uint32_t data, idx; uint16_t data_off; uint8_t bits; if (!mtp->offset || !(mask & ENVY_BIOS_PRINT_MEM)) return; fprintf(out, "MEM TRAIN PATTERN table at 0x%x, version %x\n", mtp->offset, mtp->version); envy_bios_dump_hex(bios, out, mtp->offset, mtp->hlen, mask); if (mask & ENVY_BIOS_PRINT_VERBOSE) fprintf(out, "\n"); for (i = 0; i < mtp->entriesnum; i++) { data_off = mtp->entries[i].offset; bits = mtp->entries[i].bits; fprintf(out, "Set %2i: %u bits, modulo %u", i, mtp->entries[i].bits, mtp->entries[i].modulo); if (mtp->entries[i].indirect) { data_off = mtp->entries[mtp->entries[i].indirect_entry].offset; bits = mtp->entries[mtp->entries[i].indirect_entry].bits; fprintf(out, ". indirect(%2d)\n", mtp->entries[i].indirect_entry); } else { data_off = mtp->entries[i].offset; bits = mtp->entries[i].bits; fprintf(out, ". direct(%2d)\n", mtp->entries[i].indirect_entry); } envy_bios_dump_hex(bios, out, mtp->entries[i].offset, mtp->rlen, mask); if (mask & ENVY_BIOS_PRINT_VERBOSE) fprintf(out, "\n"); for (j = 0; j < mtp->entries[i].modulo; j++) { uint32_t p_bits; uint32_t mask; uint16_t off; uint8_t mod; if (mtp->entries[i].indirect) { p_bits = j * mtp->entries[i].bits; mask = (1ULL << mtp->entries[i].bits) - 1; off = p_bits / 8; mod = p_bits % 8; bios_u32(bios, mtp->entries[i].offset + mtp->rlen + off, &idx); idx = idx >> mod; idx = idx & mask; } else { idx = j; } p_bits = idx * bits; mask = (1ULL << bits) - 1; off = p_bits / 8; mod = p_bits % 8; bios_u32(bios, data_off + mtp->rlen + off, &data); data = data >> mod; data = data & mask; fprintf(out, " %2u: [%08x]\n", idx, data); }