From 65cbbe77ac8200d391cdb423c756bc93aabb16cc Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Wed, 2 May 2018 19:07:57 +0200 Subject: 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 Reviewed-on: https://review.coreboot.org/25999 Tested-by: build bot (Jenkins) Reviewed-by: Nico Rikken Reviewed-by: Paul Menzel Reviewed-by: Naresh Solanki --- src/arch/x86/acpigen.c | 17 ++++++++++++++--- 1 file 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(); -- cgit v1.2.3