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>
diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c
index 6243d26..732f749 100644
--- a/src/arch/x86/acpigen.c
+++ b/src/arch/x86/acpigen.c
@@ -1342,6 +1342,10 @@
  * 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 @@
  *		Store (0x1000, Local1)
  *	}
  *
+ *	Store (Local1, Local3)
+ *
  *	If (LGreater (Local0, 0x10000))
  *	{
  *		Return(Buffer(Local1){0})
@@ -1381,7 +1387,7 @@
  *		}
  *	}
  *
- *	Name (ROM1, Buffer (Local1) {0})
+ *	Name (ROM1, Buffer (Local3) {0})
  *
  *	Multiply (Local0, 0x08, Local0)
  *	Multiply (Local1, 0x08, Local1)
@@ -1443,6 +1449,11 @@
 	/* 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 @@
 	/* 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();