From 894977b2cda924d7db9e2819c8941e2d4cf6a9a4 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Sat, 1 Jul 2017 16:15:05 +0200 Subject: 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 Reviewed-on: https://review.coreboot.org/19435 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel Reviewed-by: Stefan Reinauer Reviewed-by: Sumeet R Pawnikar --- src/arch/x86/acpigen.c | 53 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c index 59bfee314b..f9690b3368 100644 --- a/src/arch/x86/acpigen.c +++ b/src/arch/x86/acpigen.c @@ -373,12 +373,34 @@ void acpigen_write_opregion(struct opregion *opreg) 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, uint32_t current_bit_pos) { uint32_t diff_bits; - uint8_t i, j; - uint8_t emit[4]; if (offset < current_bit_pos) { printk(BIOS_WARNING, "%s: Cannot move offset backward", @@ -394,24 +416,14 @@ static void acpigen_write_field_offset(uint32_t offset, 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); - for (j = 0; j < i; j++) - acpigen_emit_byte(emit[j]); + acpigen_write_field_length(diff_bits); +} + +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++) { switch (l[i].type) { case NAME_STRING: - acpigen_emit_simple_namestring(l[i].name); - acpigen_emit_byte(l[i].bits); + acpigen_write_field_name(l[i].name, l[i].bits); current_bit_pos += l[i].bits; break; case OFFSET: -- cgit v1.2.3