aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rudolph <siro@das-labor.org>2017-04-28 16:34:26 +0200
committerPatrick Rudolph <siro@das-labor.org>2018-01-31 08:36:42 +0000
commit6be6df00144402cdc5ace0489d7255186609537c (patch)
tree019426c1469c3c084d56b2ff7ce0d806a073f436
parenta8733e381d587e51266275f3b96aec2059a3e03c (diff)
arch/x86/acpigen: Add generator for _ROM
Generate ACPI AML code for _ROM method. This function takes as input ROM data and ROM length. Arguments passed into _DSM method: Arg0 = Offset in Bytes Arg1 = Bytes to return Example: acpigen_write_rom(0xdeadbeef, 0x10000) AML code generated would look like: Method (_ROM, 2, NotSerialized) // _ROM: Read-Only Memory { OperationRegion (ROMS, SystemMemory, 0xdeadbeef, 0x00010000) Field (ROMS, AnyAcc, NoLock, Preserve) { Offset (0x00), RBF0, 524288 } Local0 = Arg0 Local1 = Arg1 If (Local1 > 0x1000) { Local1 = 0x1000 } If (Local0 > 0x00010000) { Return (Buffer (Local1) { 0x00 }) } If (Local0 > 0x0f000) { Local2 = 0x10000 - Local0 If (Local1 > Local2) { Local1 = Local2 } } Name (ROM1, Buffer (Local1) { 0x00 }) Local1 *= 0x08 Local0 *= 0x08 CreateField (RBF0, Local0, Local1, TMPB) ROM1 = TMPB /* \_SB_.PCI0.GFX0._ROM.TMPB */ Return (ROM1) /* \_SB_.PCI0.GFX0._ROM.ROM1 */ } Change-Id: Ie118b15257295b7133c8e585c0fd5218249dec8d Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/20547 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
-rw-r--r--src/arch/x86/acpigen.c192
-rw-r--r--src/arch/x86/include/arch/acpigen.h8
2 files changed, 200 insertions, 0 deletions
diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c
index 9637b7de96..bdb73bfac6 100644
--- a/src/arch/x86/acpigen.c
+++ b/src/arch/x86/acpigen.c
@@ -1311,6 +1311,198 @@ void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count)
acpigen_pop_len(); /* Method _DSM */
}
+/*
+ * Generate ACPI AML code for _ROM method.
+ * This function takes as input ROM data and ROM length.
+ *
+ * Arguments passed into _DSM method:
+ * Arg0 = Offset in Bytes
+ * Arg1 = Bytes to return
+ *
+ * Example:
+ * acpigen_write_rom(0xdeadbeef, 0x10000)
+ *
+ * AML code generated would look like:
+ * Method (_ROM, 2, NotSerialized) {
+ *
+ * OperationRegion("ROMS", SYSTEMMEMORY, 0xdeadbeef, 0x10000)
+ * Field (ROMS, AnyAcc, NoLock, Preserve)
+ * {
+ * Offset (0),
+ * RBF0, 0x80000
+ * }
+ *
+ * Store (Arg0, Local0)
+ * Store (Arg1, Local1)
+ *
+ * If (LGreater (Local1, 0x1000))
+ * {
+ * Store (0x1000, Local1)
+ * }
+ *
+ * If (LGreater (Local0, 0x10000))
+ * {
+ * Return(Buffer(Local1){0})
+ * }
+ *
+ * If (LGreater (Local0, 0x0f000))
+ * {
+ * Subtract (0x10000, Local0, Local2)
+ * If (LGreater (Local1, Local2))
+ * {
+ * Store (Local2, Local1)
+ * }
+ * }
+ *
+ * Name (ROM1, Buffer (Local1) {0})
+ *
+ * Multiply (Local0, 0x08, Local0)
+ * Multiply (Local1, 0x08, Local1)
+ *
+ * CreateField (RBF0, Local0, Local1, TMPB)
+ * Store (TMPB, ROM1)
+ * Return (ROM1)
+ * }
+ */
+
+void acpigen_write_rom(void *bios, const size_t length)
+{
+ ASSERT(bios)
+ ASSERT(length)
+
+ /* Method (_ROM, 2, NotSerialized) */
+ acpigen_write_method("_ROM", 2);
+
+ /* OperationRegion("ROMS", SYSTEMMEMORY, current, length) */
+ struct opregion opreg = OPREGION("ROMS", SYSTEMMEMORY,
+ (uintptr_t)bios, length);
+ acpigen_write_opregion(&opreg);
+
+ struct fieldlist l[] = {
+ FIELDLIST_OFFSET(0),
+ FIELDLIST_NAMESTR("RBF0", 8 * length),
+ };
+
+ /* Field (ROMS, AnyAcc, NoLock, Preserve)
+ * {
+ * Offset (0),
+ * RBF0, 0x80000
+ * } */
+ acpigen_write_field(opreg.name, l, 2, FIELD_ANYACC |
+ FIELD_NOLOCK | FIELD_PRESERVE);
+
+ /* Store (Arg0, Local0) */
+ acpigen_write_store();
+ acpigen_emit_byte(ARG0_OP);
+ acpigen_emit_byte(LOCAL0_OP);
+
+ /* Store (Arg1, Local1) */
+ acpigen_write_store();
+ acpigen_emit_byte(ARG1_OP);
+ acpigen_emit_byte(LOCAL1_OP);
+
+ /* ACPI SPEC requires to return at maximum 4KiB */
+ /* If (LGreater (Local1, 0x1000)) */
+ acpigen_write_if();
+ acpigen_emit_byte(LGREATER_OP);
+ acpigen_emit_byte(LOCAL1_OP);
+ acpigen_write_integer(0x1000);
+
+ /* Store (0x1000, Local1) */
+ acpigen_write_store();
+ acpigen_write_integer(0x1000);
+ acpigen_emit_byte(LOCAL1_OP);
+
+ /* Pop if */
+ acpigen_pop_len();
+
+ /* If (LGreater (Local0, length)) */
+ acpigen_write_if();
+ acpigen_emit_byte(LGREATER_OP);
+ acpigen_emit_byte(LOCAL0_OP);
+ acpigen_write_integer(length);
+
+ /* Return(Buffer(Local1){0}) */
+ acpigen_emit_byte(RETURN_OP);
+ acpigen_emit_byte(BUFFER_OP);
+ acpigen_write_len_f();
+ acpigen_emit_byte(LOCAL1_OP);
+ acpigen_emit_byte(0);
+ acpigen_pop_len();
+
+ /* Pop if */
+ acpigen_pop_len();
+
+ /* If (LGreater (Local0, length - 4096)) */
+ acpigen_write_if();
+ acpigen_emit_byte(LGREATER_OP);
+ acpigen_emit_byte(LOCAL0_OP);
+ acpigen_write_integer(length - 4096);
+
+ /* Subtract (length, Local0, Local2) */
+ acpigen_emit_byte(SUBTRACT_OP);
+ acpigen_write_integer(length);
+ acpigen_emit_byte(LOCAL0_OP);
+ acpigen_emit_byte(LOCAL2_OP);
+
+ /* If (LGreater (Local1, Local2)) */
+ acpigen_write_if();
+ acpigen_emit_byte(LGREATER_OP);
+ acpigen_emit_byte(LOCAL1_OP);
+ acpigen_emit_byte(LOCAL2_OP);
+
+ /* Store (Local2, Local1) */
+ acpigen_write_store();
+ acpigen_emit_byte(LOCAL2_OP);
+ acpigen_emit_byte(LOCAL1_OP);
+
+ /* Pop if */
+ acpigen_pop_len();
+
+ /* Pop if */
+ acpigen_pop_len();
+
+ /* Name (ROM1, Buffer (Local1) {0}) */
+ acpigen_write_name("ROM1");
+ acpigen_emit_byte(BUFFER_OP);
+ acpigen_write_len_f();
+ acpigen_emit_byte(LOCAL1_OP);
+ acpigen_emit_byte(0);
+ acpigen_pop_len();
+
+ /* Multiply (Local1, 0x08, Local1) */
+ acpigen_emit_byte(MULTIPLY_OP);
+ acpigen_emit_byte(LOCAL1_OP);
+ acpigen_write_integer(0x08);
+ acpigen_emit_byte(LOCAL1_OP);
+
+ /* Multiply (Local0, 0x08, Local0) */
+ acpigen_emit_byte(MULTIPLY_OP);
+ acpigen_emit_byte(LOCAL0_OP);
+ acpigen_write_integer(0x08);
+ acpigen_emit_byte(LOCAL0_OP);
+
+ /* CreateField (RBF0, Local0, Local1, TMPB) */
+ acpigen_emit_ext_op(CREATEFIELD_OP);
+ acpigen_emit_namestring("RBF0");
+ acpigen_emit_byte(LOCAL0_OP);
+ acpigen_emit_byte(LOCAL1_OP);
+ acpigen_emit_namestring("TMPB");
+
+ /* Store (TMPB, ROM1) */
+ acpigen_write_store();
+ acpigen_emit_namestring("TMPB");
+ acpigen_emit_namestring("ROM1");
+
+ /* Return (ROM1) */
+ acpigen_emit_byte(RETURN_OP);
+ acpigen_emit_namestring("ROM1");
+
+ /* Pop method */
+ acpigen_pop_len();
+}
+
+
/* Soc-implemented functions -- weak definitions. */
int __attribute__((weak)) acpigen_soc_read_rx_gpio(unsigned int gpio_num)
{
diff --git a/src/arch/x86/include/arch/acpigen.h b/src/arch/x86/include/arch/acpigen.h
index a50a9004f6..216e75fce6 100644
--- a/src/arch/x86/include/arch/acpigen.h
+++ b/src/arch/x86/include/arch/acpigen.h
@@ -264,6 +264,14 @@ void acpigen_write_return_byte(uint8_t arg);
void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *),
size_t count, void *arg);
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 ROM length has to be multiple of 4096 and has to be less
+ * than the current implementation limit of 0x40000.
+ */
+void acpigen_write_rom(void *bios, const size_t length);
/*
* Generate ACPI AML code for OperationRegion
* This function takes input region name, region space, region offset & region