diff options
author | Patrick Rudolph <siro@das-labor.org> | 2018-05-02 19:07:57 +0200 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2018-05-18 12:19:43 +0000 |
commit | 65cbbe77ac8200d391cdb423c756bc93aabb16cc (patch) | |
tree | 3961823bc7b28de33ae5d6f2fb80c98ccc3d232d /src/arch | |
parent | 892e9f6030f2ade15067ec7b51c819130072e91b (diff) | |
download | coreboot-65cbbe77ac8200d391cdb423c756bc93aabb16cc.tar.xz |
arch/x86/acpigen: Fix corner case in _ROM generator
In case the Option ROM isn't a multiple of 4KiB the last buffer was
truncated to prevent a buffer overrun. But tests on nouveau showed
that nouveau expects a buffer that has the requested size and is zero
padded instead.
Always return a buffer with requested size and zero pad the remaining
bytes. Fixes nouveau on Lenovo W520 with Option ROM not being multiple
of 4 KiB.
Change-Id: I3f0ecc42a21945f66eb67f73e511bd516acf0fa9
Signed-off-by: Patrick Rudolph <siro@das-labor.org>
Reviewed-on: https://review.coreboot.org/25999
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Rikken <nico@nicorikken.eu>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Naresh Solanki <naresh.solanki@intel.com>
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/x86/acpigen.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c index 6243d265ce..732f749209 100644 --- a/src/arch/x86/acpigen.c +++ b/src/arch/x86/acpigen.c @@ -1342,6 +1342,10 @@ void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count) * Generate ACPI AML code for _ROM method. * This function takes as input ROM data and ROM length. * + * The ACPI spec isn't clear about what should happen at the end of the + * ROM. Tests showed that it shouldn't truncate, but fill the remaining + * bytes in the returned buffer with zeros. + * * Arguments passed into _DSM method: * Arg0 = Offset in Bytes * Arg1 = Bytes to return @@ -1367,6 +1371,8 @@ void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count) * Store (0x1000, Local1) * } * + * Store (Local1, Local3) + * * If (LGreater (Local0, 0x10000)) * { * Return(Buffer(Local1){0}) @@ -1381,7 +1387,7 @@ void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count) * } * } * - * Name (ROM1, Buffer (Local1) {0}) + * Name (ROM1, Buffer (Local3) {0}) * * Multiply (Local0, 0x08, Local0) * Multiply (Local1, 0x08, Local1) @@ -1443,6 +1449,11 @@ void acpigen_write_rom(void *bios, const size_t length) /* Pop if */ acpigen_pop_len(); + /* Store (Local1, Local3) */ + acpigen_write_store(); + acpigen_emit_byte(LOCAL1_OP); + acpigen_emit_byte(LOCAL3_OP); + /* If (LGreater (Local0, length)) */ acpigen_write_if(); acpigen_emit_byte(LGREATER_OP); @@ -1489,11 +1500,11 @@ void acpigen_write_rom(void *bios, const size_t length) /* Pop if */ acpigen_pop_len(); - /* Name (ROM1, Buffer (Local1) {0}) */ + /* Name (ROM1, Buffer (Local3) {0}) */ acpigen_write_name("ROM1"); acpigen_emit_byte(BUFFER_OP); acpigen_write_len_f(); - acpigen_emit_byte(LOCAL1_OP); + acpigen_emit_byte(LOCAL3_OP); acpigen_emit_byte(0); acpigen_pop_len(); |