diff options
author | Patrick Rudolph <siro@das-labor.org> | 2017-07-01 16:15:05 +0200 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2017-07-07 21:09:53 +0000 |
commit | 894977b2cda924d7db9e2819c8941e2d4cf6a9a4 (patch) | |
tree | b9b3b626a30e0eefa4c956d586cfb83523cbe0a1 | |
parent | 4eb84cf8784d77d6e5f24daeb04fa727dfbea016 (diff) |
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>
-rw-r--r-- | src/arch/x86/acpigen.c | 53 |
1 files changed, 32 insertions, 21 deletions
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: |