x86/acpigen: Fix acpigen_write_field

The current code doesn't work for field with size > 0x3f.
Fix that by using the correct syntax, reverse engineered using iasl.

Refactor to reuse existing code.

Tested on GNU Linux 4.9 and iasl.

Change-Id: Iac3600f184e6bd36a2bcb85753110692fbcbe4b6
Signed-off-by: Patrick Rudolph <siro@das-labor.org>
Reviewed-on: https://review.coreboot.org/19435
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Sumeet R Pawnikar <sumeet.r.pawnikar@intel.com>
This commit is contained in:
Patrick Rudolph 2017-07-01 16:15:05 +02:00 committed by Stefan Reinauer
parent 4eb84cf878
commit 894977b2cd
1 changed files with 32 additions and 21 deletions

View File

@ -373,12 +373,34 @@ void acpigen_write_opregion(struct opregion *opreg)
acpigen_write_integer(opreg->regionlen); acpigen_write_integer(opreg->regionlen);
} }
static void acpigen_write_field_length(uint32_t len)
{
uint8_t i, j;
uint8_t emit[4];
i = 1;
if (len < 0x40) {
emit[0] = len & 0x3F;
} else {
emit[0] = len & 0xF;
len >>= 4;
while (len) {
emit[i] = len & 0xFF;
i++;
len >>= 8;
}
}
/* Update bit 7:6 : Number of bytes followed by emit[0] */
emit[0] |= (i - 1) << 6;
for (j = 0; j < i; j++)
acpigen_emit_byte(emit[j]);
}
static void acpigen_write_field_offset(uint32_t offset, static void acpigen_write_field_offset(uint32_t offset,
uint32_t current_bit_pos) uint32_t current_bit_pos)
{ {
uint32_t diff_bits; uint32_t diff_bits;
uint8_t i, j;
uint8_t emit[4];
if (offset < current_bit_pos) { if (offset < current_bit_pos) {
printk(BIOS_WARNING, "%s: Cannot move offset backward", printk(BIOS_WARNING, "%s: Cannot move offset backward",
@ -394,24 +416,14 @@ static void acpigen_write_field_offset(uint32_t offset,
return; return;
} }
i = 1;
if (diff_bits < 0x40) {
emit[0] = diff_bits & 0x3F;
} else {
emit[0] = diff_bits & 0xF;
diff_bits >>= 4;
while (diff_bits) {
emit[i] = diff_bits & 0xFF;
i++;
diff_bits >>= 8;
}
}
/* Update bit 7:6 : Number of bytes followed by emit[0] */
emit[0] |= (i - 1) << 6;
acpigen_emit_byte(0); acpigen_emit_byte(0);
for (j = 0; j < i; j++) acpigen_write_field_length(diff_bits);
acpigen_emit_byte(emit[j]); }
static void acpigen_write_field_name(const char *name, uint32_t size)
{
acpigen_emit_simple_namestring(name);
acpigen_write_field_length(size);
} }
/* /*
@ -452,8 +464,7 @@ void acpigen_write_field(const char *name, struct fieldlist *l, size_t count,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
switch (l[i].type) { switch (l[i].type) {
case NAME_STRING: case NAME_STRING:
acpigen_emit_simple_namestring(l[i].name); acpigen_write_field_name(l[i].name, l[i].bits);
acpigen_emit_byte(l[i].bits);
current_bit_pos += l[i].bits; current_bit_pos += l[i].bits;
break; break;
case OFFSET: case OFFSET: