Exemple #1
0
int envy_bios_parse_mux (struct envy_bios *bios) {
	struct envy_bios_mux *mux = &bios->mux;
	if (!mux->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, mux->offset, &mux->version);
	err |= bios_u8(bios, mux->offset+1, &mux->hlen);
	err |= bios_u8(bios, mux->offset+2, &mux->entriesnum);
	err |= bios_u8(bios, mux->offset+3, &mux->rlen);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, mux->offset, mux->hlen + mux->rlen * mux->entriesnum, "MUX", -1);
	int wanthlen = 0;
	int wantrlen = 0;
	switch (mux->version) {
		case 0x10:
			wanthlen = 4;
			wantrlen = 5;
			break;
		default:
			ENVY_BIOS_ERR("Unknown MUX table version %x.%x\n", mux->version >> 4, mux->version & 0xf);
			return -EINVAL;
	}
	if (mux->hlen < wanthlen) {
		ENVY_BIOS_ERR("MUX table header too short [%d < %d]\n", mux->hlen, wanthlen);
		return -EINVAL;
	}
	if (mux->rlen < wantrlen) {
		ENVY_BIOS_ERR("MUX table record too short [%d < %d]\n", mux->rlen, wantrlen);
		return -EINVAL;
	}
	if (mux->hlen > wanthlen) {
		ENVY_BIOS_WARN("MUX table header longer than expected [%d > %d]\n", mux->hlen, wanthlen);
	}
	if (mux->rlen > wantrlen) {
		ENVY_BIOS_WARN("MUX table record longer than expected [%d > %d]\n", mux->rlen, wantrlen);
	}
	mux->entries = calloc(mux->entriesnum, sizeof *mux->entries);
	if (!mux->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < mux->entriesnum; i++) {
		struct envy_bios_mux_entry *entry = &mux->entries[i];
		entry->offset = mux->offset + mux->hlen + mux->rlen * i;
		uint8_t sub[4];
		err |= bios_u8(bios, entry->offset, &entry->idx);
		int j;
		for (j = 0; j < 4; j++) {
			err |= bios_u8(bios, entry->offset+j+1, &sub[j]);
			entry->sub_loc[j] = sub[j] & 1;
			entry->sub_line[j] = sub[j] >> 1 & 0x1f;
			entry->sub_val[j] = sub[j] >> 6 & 1;
			entry->sub_unk7[j] = sub[j] >> 7 & 1;
		}
		if (err)
			return -EFAULT;
	}
	mux->valid = 1;
	return 0;
}
Exemple #2
0
int envy_bios_parse_iunk21 (struct envy_bios *bios) {
	struct envy_bios_iunk21 *iunk21 = &bios->iunk21;
	if (!iunk21->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, iunk21->offset, &iunk21->version);
	err |= bios_u8(bios, iunk21->offset+1, &iunk21->hlen);
	err |= bios_u8(bios, iunk21->offset+2, &iunk21->rlen);
	err |= bios_u8(bios, iunk21->offset+3, &iunk21->entriesnum);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, iunk21->offset, iunk21->hlen + iunk21->rlen * iunk21->entriesnum, "IUNK21", -1);
	int wanthlen = 0;
	int wantrlen = 0;
	switch (iunk21->version) {
		case 0x10:
			wanthlen = 4;
			wantrlen = 3;
			break;
		default:
			ENVY_BIOS_ERR("Unknown IUNK21 table version %d.%d\n", iunk21->version >> 4, iunk21->version & 0xf);
			return -EINVAL;
	}
	if (iunk21->hlen < wanthlen) {
		ENVY_BIOS_ERR("IUNK21 table header too short [%d < %d]\n", iunk21->hlen, wanthlen);
		return -EINVAL;
	}
	if (iunk21->rlen < wantrlen) {
		ENVY_BIOS_ERR("IUNK21 table record too short [%d < %d]\n", iunk21->rlen, wantrlen);
		return -EINVAL;
	}
	if (iunk21->hlen > wanthlen) {
		ENVY_BIOS_WARN("IUNK21 table header longer than expected [%d > %d]\n", iunk21->hlen, wanthlen);
	}
	if (iunk21->rlen > wantrlen) {
		ENVY_BIOS_WARN("IUNK21 table record longer than expected [%d > %d]\n", iunk21->rlen, wantrlen);
	}
	iunk21->entries = calloc(iunk21->entriesnum, sizeof *iunk21->entries);
	if (!iunk21->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < iunk21->entriesnum; i++) {
		struct envy_bios_iunk21_entry *entry = &iunk21->entries[i];
		entry->offset = iunk21->offset + iunk21->hlen + iunk21->rlen * i;
		/* XXX */
		if (err)
			return -EFAULT;
	}
	iunk21->valid = 1;
	return 0;
}
Exemple #3
0
int envy_bios_parse_bit_empty (struct envy_bios *bios, struct envy_bios_bit_entry *bit) {
	if (bit->t_len) {
		ENVY_BIOS_ERR("BIT table '%c' not empty!\n", bit->type);
		return -EINVAL;
	}
	return 0;
}
Exemple #4
0
int envy_bios_parse_power_unk4c(struct envy_bios *bios) {
	struct envy_bios_power_unk4c *unk4c = &bios->power.unk4c;
	int i, err = 0;

	if (!unk4c->offset)
		return -EINVAL;

	bios_u8(bios, unk4c->offset + 0x0, &unk4c->version);
	switch(unk4c->version) {
	case 0x10:
		err |= bios_u8(bios, unk4c->offset + 0x1, &unk4c->hlen);
		err |= bios_u8(bios, unk4c->offset + 0x2, &unk4c->rlen);
		err |= bios_u8(bios, unk4c->offset + 0x3, &unk4c->entriesnum);
		unk4c->valid = !err;
		break;
	default:
		ENVY_BIOS_ERR("Unknown UNK4c table version 0x%x\n", unk4c->version);
		return -EINVAL;
	};

	err = 0;
	unk4c->entries = malloc(unk4c->entriesnum * sizeof(struct envy_bios_power_unk4c_entry));
	for (i = 0; i < unk4c->entriesnum; i++) {
		uint16_t data = unk4c->offset + unk4c->hlen + i * unk4c->rlen;

		unk4c->entries[i].offset = data;
	}

	return 0;
}
Exemple #5
0
int envy_bios_parse_power_boost(struct envy_bios *bios) {
	struct envy_bios_power_boost *boost = &bios->power.boost;
	int i, j, err = 0;

	if (!boost->offset)
		return -EINVAL;

	bios_u8(bios, boost->offset + 0x0, &boost->version);
	switch(boost->version) {
	case 0x11:
		err |= bios_u8(bios, boost->offset + 0x1, &boost->hlen);
		err |= bios_u8(bios, boost->offset + 0x2, &boost->rlen);
		err |= bios_u8(bios, boost->offset + 0x3, &boost->ssz);
		err |= bios_u8(bios, boost->offset + 0x4, &boost->snr);
		err |= bios_u8(bios, boost->offset + 0x5, &boost->entriesnum);
		boost->valid = !err;
		break;
	default:
		ENVY_BIOS_ERR("Unknown BOOST table version 0x%x\n", boost->version);
		return -EINVAL;
	};

	boost->entries = malloc(boost->entriesnum * sizeof(struct envy_bios_power_boost_entry));

	for (i = 0; i < boost->entriesnum; i++) {
		uint16_t data = boost->offset + boost->hlen + i * (boost->rlen + (boost->snr * boost->ssz));

		uint16_t tmp;
		err |= bios_u16(bios, data + 0x0, &tmp);
		err |= bios_u16(bios, data + 0x2, &boost->entries[i].min);
		err |= bios_u16(bios, data + 0x4, &boost->entries[i].max);

		boost->entries[i].offset = data;
		boost->entries[i].pstate = (tmp & 0x01e0) >> 5;

		boost->entries[i].entries = malloc(boost->snr * sizeof(struct envy_bios_power_boost_subentry));

		for (j = 0; j < boost->snr; j++) {
			struct envy_bios_power_boost_subentry *sub = &boost->entries[i].entries[j];
			uint16_t sdata = data + boost->rlen + j * boost->ssz;

			sub->offset = sdata;
			bios_u8(bios, sdata + 0x0, &sub->domain);
			bios_u8(bios, sdata + 0x1, &sub->percent);
			bios_u16(bios, sdata + 0x2, &sub->min);
			bios_u16(bios, sdata + 0x4, &sub->max);
		}
	}

	return 0;
}
Exemple #6
0
int envy_bios_parse_power_cstep(struct envy_bios *bios) {
	struct envy_bios_power_cstep *cstep = &bios->power.cstep;
	int i, err = 0;

	if (!cstep->offset)
		return -EINVAL;

	bios_u8(bios, cstep->offset + 0x0, &cstep->version);
	switch(cstep->version) {
	case 0x10:
		err |= bios_u8(bios, cstep->offset + 0x1, &cstep->hlen);
		err |= bios_u8(bios, cstep->offset + 0x2, &cstep->rlen);
		err |= bios_u8(bios, cstep->offset + 0x3, &cstep->entriesnum);
		err |= bios_u8(bios, cstep->offset + 0x4, &cstep->ssz);
		err |= bios_u8(bios, cstep->offset + 0x5, &cstep->snr);
		cstep->valid = !err;
		break;
	default:
		ENVY_BIOS_ERR("Unknown CSTEP table version 0x%x\n", cstep->version);
		return -EINVAL;
	};

	assert(cstep->entriesnum <= (sizeof(cstep->ent1) / sizeof(struct envy_bios_power_cstep_entry1)));
	for (i = 0; i < cstep->entriesnum; i++) {
		uint16_t data = cstep->offset + cstep->hlen + i * cstep->rlen;

		uint16_t tmp;
		err |= bios_u16(bios, data + 0x0, &tmp);

		cstep->ent1[i].offset = data;
		cstep->ent1[i].pstate = (tmp & 0x01e0) >> 5;
		bios_u8(bios, data + 0x3, &cstep->ent1[i].index);
	}

	cstep->ent2 = malloc(cstep->snr * sizeof(struct envy_bios_power_cstep_entry2));
	memset(cstep->ent2, 0x0, cstep->snr * sizeof(struct envy_bios_power_cstep_entry2));
	for (i = 0; i < cstep->snr; i++) {
		uint16_t data = cstep->offset + cstep->hlen + (cstep->entriesnum * cstep->rlen) + (i * cstep->ssz);

		cstep->ent2[i].offset = data;
		bios_u16(bios, data + 0x0, &cstep->ent2[i].freq);
		bios_u8(bios, data + 0x2, &cstep->ent2[i].unkn[0]);
		bios_u8(bios, data + 0x3, &cstep->ent2[i].unkn[1]);
		bios_u8(bios, data + 0x4, &cstep->ent2[i].voltage);
		cstep->ent2[i].valid = (cstep->ent2[i].freq > 0);
	}

	return 0;
}
Exemple #7
0
int envy_bios_parse_power_base_clock(struct envy_bios *bios) {
	struct envy_bios_power_base_clock *bc = &bios->power.base_clock;
	int i, j, err = 0;

	if (!bc->offset)
		return -EINVAL;

	bios_u8(bios, bc->offset + 0x0, &bc->version);
	switch(bc->version) {
	case 0x10:
		err |= bios_u8(bios, bc->offset + 0x1, &bc->hlen);
		err |= bios_u8(bios, bc->offset + 0x2, &bc->rlen);
		err |= bios_u8(bios, bc->offset + 0x3, &bc->selen);
		err |= bios_u8(bios, bc->offset + 0x4, &bc->secount);
		err |= bios_u8(bios, bc->offset + 0x5, &bc->entriesnum);
		bc->valid = !err;

		if (bc->valid) {
			bios_u8(bios, bc->offset + 0x0f, &bc->base_entry);
			bios_u8(bios, bc->offset + 0x10, &bc->boost_entry);
			bios_u8(bios, bc->offset + 0x11, &bc->tdp_entry);
		} else {
			return -EINVAL;
		}

		break;
	default:
		ENVY_BIOS_ERR("BASE CLOCKS table version 0x%x\n", bc->version);
		return -EINVAL;
	};

	err = 0;
	bc->entries = malloc(bc->entriesnum * sizeof(struct envy_bios_power_base_clock_entry));
	for (i = 0; i < bc->entriesnum; i++) {
		struct envy_bios_power_base_clock_entry *bce = &bc->entries[i];

		bce->offset = bc->offset + bc->hlen + i * (bc->rlen + (bc->selen * bc->secount));
		bios_u8(bios, bce->offset, &bce->pstate);
		bios_u16(bios, bce->offset + 0x1, &bce->unk0);
		bios_u16(bios, bce->offset + 0x3, &bce->unk1);
		bce->clock = malloc(bc->secount * sizeof(uint16_t));
		for (j = 0; j < bc->secount; j++)
			bios_u16(bios, bce->offset + 0x5 + j, &bce->clock[j]);
	}

	return 0;
}
Exemple #8
0
int envy_bios_parse_bit_2 (struct envy_bios *bios, struct envy_bios_bit_entry *bit) {
	struct envy_bios_i2cscript *i2cscript = &bios->i2cscript;
	i2cscript->bit = bit;
	int wantlen = 4;
	if (bit->t_len < wantlen) {
		ENVY_BIOS_ERR("I2C script table too short: %d < %d\n", bit->t_len, wantlen);
		return -EINVAL;
	}
	if (bit->t_len > wantlen)
		ENVY_BIOS_WARN("I2C script table longer than expected: %d > %d\n", bit->t_len, wantlen);
	int err = 0;
	err |= bios_u16(bios, bit->t_offset+0, &i2cscript->unk00);
	err |= bios_u16(bios, bit->t_offset+2, &i2cscript->script);
	if (err)
		return -EFAULT;
	i2cscript->valid = 1;
	return 0;
}
Exemple #9
0
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;
}
Exemple #10
0
int envy_bios_parse_power_sense(struct envy_bios *bios) {
	struct envy_bios_power_sense *sense = &bios->power.sense;
	int i, err = 0;

	if (!sense->offset)
		return -EINVAL;

	bios_u8(bios, sense->offset + 0x0, &sense->version);
	switch(sense->version) {
	case 0x10:
	case 0x20:
		err |= bios_u8(bios, sense->offset + 0x1, &sense->hlen);
		err |= bios_u8(bios, sense->offset + 0x2, &sense->rlen);
		err |= bios_u8(bios, sense->offset + 0x3, &sense->entriesnum);
		sense->valid = !err;
		break;
	default:
		ENVY_BIOS_ERR("Unknown SENSE table version 0x%x\n", sense->version);
		return -EINVAL;
	};

	err = 0;
	sense->entries = malloc(sense->entriesnum * sizeof(struct envy_bios_power_sense_entry));
	for (i = 0; i < sense->entriesnum; i++) {
		uint16_t data = sense->offset + sense->hlen + i * sense->rlen;

		sense->entries[i].offset = data;

		switch(sense->version) {
		case 0x10:
			err |= bios_u8(bios, data + 0x2, &sense->entries[i].extdev_id);
			err |= bios_u8(bios, data + 0x3, &sense->entries[i].resistor_mohm);
			break;
		case 0x20:
			err |= bios_u8(bios, data + 0x1, &sense->entries[i].extdev_id);
			err |= bios_u8(bios, data + 0x5, &sense->entries[i].resistor_mohm);
			break;
		};
	}

	return 0;
}
Exemple #11
0
int
envy_bios_parse_mem_train (struct envy_bios *bios) {
	struct envy_bios_mem_train *mt = &bios->mem.train;
	if (!mt->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, mt->offset, &mt->version);
	err |= bios_u8(bios, mt->offset+1, &mt->hlen);
	err |= bios_u8(bios, mt->offset+2, &mt->rlen);
	err |= bios_u8(bios, mt->offset+3, &mt->subentrylen);
	err |= bios_u8(bios, mt->offset+4, &mt->subentries);
	err |= bios_u8(bios, mt->offset+5, &mt->entriesnum);
	if (err)
		return -EFAULT;
	bios_u16(bios, mt->offset+6, &mt->mclk);

	envy_bios_block(bios, mt->offset, mt->hlen + mt->rlen * mt->entriesnum, "MEM TRAIN", -1);
	mt->entries = calloc(mt->entriesnum, sizeof *mt->entries);
	if (!mt->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < mt->entriesnum; i++) {
		struct envy_bios_mem_train_entry *entry = &mt->entries[i];
		entry->offset = mt->offset + mt->hlen + ((mt->rlen + mt->subentries * mt->subentrylen) * i);
		err |= bios_u8(bios, entry->offset, &entry->u00);
		if (mt->subentries > sizeof(entry->subentry)) {
			mt->subentries = sizeof(entry->subentry);
			ENVY_BIOS_ERR("Error when parsing mem train: subentries = %d > %zu\n", mt->subentries, sizeof(entry->subentry));
			return -EFAULT;
		}
		int j;
		for (j = 0; j < mt->subentries; j++) {
			err |= bios_u8(bios, entry->offset+j+1, &entry->subentry[j]);
		}
		if (err)
			return -EFAULT;
	}
	mt->valid = 1;
	return 0;
}
Exemple #12
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;
}
Exemple #13
0
int envy_bios_parse_power_unk44(struct envy_bios *bios) {
	struct envy_bios_power_unk44 *unk44 = &bios->power.unk44;
	int err = 0;

	if (!unk44->offset)
		return -EINVAL;

	bios_u8(bios, unk44->offset + 0x0, &unk44->version);
	switch(unk44->version) {
	case 0x10:
		err |= bios_u8(bios, unk44->offset + 0x1, &unk44->hlen);

		/* it doesn't appear as if this table has entries at all */
		unk44->valid = !err;
		break;
	default:
		ENVY_BIOS_ERR("Unknown UNK44 table version 0x%x\n", unk44->version);
		return -EINVAL;
	};

	return 0;
}
Exemple #14
0
int envy_bios_parse_bit (struct envy_bios *bios) {
	struct envy_bios_bit *bit = &bios->bit;
	if (!bit->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, bit->offset+7, &bit->version);
	err |= bios_u8(bios, bit->offset+8, &bit->hlen);
	err |= bios_u8(bios, bit->offset+9, &bit->rlen);
	err |= bios_u8(bios, bit->offset+10, &bit->entriesnum);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, bit->offset, bit->hlen + bit->rlen * bit->entriesnum, "BIT", -1);
	uint8_t checksum = 0;
	int i;
	for (i = 0; i < bit->hlen; i++) {
		uint8_t byte;
		err |= bios_u8(bios, bit->offset+i, &byte);
		if (err)
			return -EFAULT;
		checksum += byte;
	}
	if (checksum) {
		ENVY_BIOS_ERR("BIT table checksum mismatch\n");
		return -EINVAL;
	}
	int wanthlen = 12;
	int wantrlen = 6;
	switch (bit->version) {
		case 1:
			break;
		default:
			ENVY_BIOS_ERR("Unknown BIT table version %d\n", bit->version);
			return -EINVAL;
	}
	if (bit->hlen < wanthlen) {
		ENVY_BIOS_ERR("BIT table header too short [%d < %d]\n", bit->hlen, wanthlen);
		return -EINVAL;
	}
	if (bit->rlen < wantrlen) {
		ENVY_BIOS_ERR("BIT table record too short [%d < %d]\n", bit->rlen, wantrlen);
		return -EINVAL;
	}
	if (bit->hlen > wanthlen) {
		ENVY_BIOS_WARN("BIT table header longer than expected [%d > %d]\n", bit->hlen, wanthlen);
	}
	if (bit->rlen > wantrlen) {
		ENVY_BIOS_WARN("BIT table record longer than expected [%d > %d]\n", bit->rlen, wantrlen);
	}
	bit->entries = calloc(bit->entriesnum, sizeof *bit->entries);
	if (!bit->entries)
		return -ENOMEM;
	for (i = 0; i < bit->entriesnum; i++) {
		struct envy_bios_bit_entry *entry = &bit->entries[i];
		entry->offset = bit->offset + bit->hlen + bit->rlen * i;
		err |= bios_u8(bios, entry->offset+0, &entry->type);
		err |= bios_u8(bios, entry->offset+1, &entry->version);
		err |= bios_u16(bios, entry->offset+2, &entry->t_len);
		err |= bios_u16(bios, entry->offset+4, &entry->t_offset);
		if (err)
			return -EFAULT;
		entry->is_unk = 1;
		if (entry->type != 'b' && entry->t_len)
			envy_bios_block(bios, entry->t_offset, entry->t_len, "BIT", entry->type);
	}
	int j;
	/* iterate over BIT tables by type first - some types of tables have to be parsed before others, notably 'i'. */
	for (j = 0; bit_types[j].parse; j++) {
		for (i = 0; i < bit->entriesnum; i++) {
			struct envy_bios_bit_entry *entry = &bit->entries[i];
			if (entry->type == bit_types[j].type && entry->version == bit_types[j].version) {
				if (bit_types[j].parse(bios, entry))
					ENVY_BIOS_ERR("Failed to parse BIT table '%c' at 0x%04x version %d\n", entry->type, entry->t_offset, entry->version);
				else
					entry->is_unk = 0;
			}
		}
	}
	bit->valid = 1;
	return 0;
}
Exemple #15
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;
	}
}
Exemple #16
0
int envy_bios_parse_conn (struct envy_bios *bios) {
	struct envy_bios_conn *conn = &bios->conn;
	if (!conn->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, conn->offset, &conn->version);
	err |= bios_u8(bios, conn->offset+1, &conn->hlen);
	err |= bios_u8(bios, conn->offset+2, &conn->entriesnum);
	err |= bios_u8(bios, conn->offset+3, &conn->rlen);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, conn->offset, conn->hlen + conn->rlen * conn->entriesnum, "CONN", -1);
	int wanthlen = 5;
	int wantrlen = 4;
	if (conn->rlen < 4)
		wantrlen = 2;
	switch (conn->version) {
		case 0x30:
		case 0x40:
			break;
		default:
			ENVY_BIOS_ERR("Unknown CONN table version %d.%d\n", conn->version >> 4, conn->version & 0xf);
			return -EINVAL;
	}
	if (conn->hlen < wanthlen) {
		ENVY_BIOS_ERR("CONN table header too short [%d < %d]\n", conn->hlen, wanthlen);
		return -EINVAL;
	}
	if (conn->rlen < wantrlen) {
		ENVY_BIOS_ERR("CONN table record too short [%d < %d]\n", conn->rlen, wantrlen);
		return -EINVAL;
	}
	if (conn->hlen > wanthlen) {
		ENVY_BIOS_WARN("CONN table header longer than expected [%d > %d]\n", conn->hlen, wanthlen);
	}
	if (conn->rlen > wantrlen) {
		ENVY_BIOS_WARN("CONN table record longer than expected [%d > %d]\n", conn->rlen, wantrlen);
	}
	conn->entries = calloc(conn->entriesnum, sizeof *conn->entries);
	if (!conn->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < conn->entriesnum; i++) {
		struct envy_bios_conn_entry *entry = &conn->entries[i];
		entry->offset = conn->offset + conn->hlen + conn->rlen * i;
		uint8_t bytes[4] = { 0 };
		uint32_t val = 0;
		int j;
		static const int hpds[7] = { 12, 13, 16, 17, 24, 25, 26 };
		entry->hpd = -1;
		entry->dp_ext = -1;
		for (j = 0; j < 4 && j < conn->rlen; j++) {
			err |= bios_u8(bios, entry->offset+j, &bytes[j]);
			if (err)
				return -EFAULT;
			val |= bytes[j] << j * 8;
		}
		entry->type = bytes[0];
		entry->tag = bytes[1] & 0xf;
		for (j = 0; j < 7; j++) {
			if (val & 1 << hpds[j]) {
				if (entry->hpd == -1)
					entry->hpd = j;
				else
					ENVY_BIOS_ERR("CONN %d: duplicate HPD bits\n", i);
			}
		}
		for (j = 0; j < 2; j++) {
			if (val & 1 << (j+14)) {
				if (entry->dp_ext == -1)
					entry->dp_ext = j;
				else
					ENVY_BIOS_ERR("CONN %d: duplicate DP_AUX bits\n", i);
			}
		}
		entry->unk02_2 = bytes[2] >> 2 & 3;
		entry->unk02_4 = bytes[2] >> 4 & 7;
		entry->unk02_7 = bytes[2] >> 7 & 1;
		entry->unk03_3 = bytes[3] >> 3 & 0x1f;
	}
	conn->valid = 1;
	return 0;
}