diff mbox series

[v3,22/35] acpi: Add support for various misc ACPI opcodes

Message ID 20200614025523.40183-11-sjg@chromium.org
State Superseded
Headers show
Series dm: Add programmatic generation of ACPI tables (part B) | expand

Commit Message

Simon Glass June 14, 2020, 2:55 a.m. UTC
Add more functions to handle some miscellaneous ACPI opcodes.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner at br-automation.com>
---

Changes in v3:
- Fix function name in comment for acpigen_write_not()
- Use #defines for the mask values

 include/acpi/acpigen.h | 117 +++++++++++++++++++++++++++++++++++++++++
 lib/acpi/acpigen.c     |  84 +++++++++++++++++++++++++++++
 test/dm/acpigen.c      |  75 ++++++++++++++++++++++++++
 3 files changed, 276 insertions(+)

Comments

Bin Meng June 29, 2020, 3 a.m. UTC | #1
Hi Simon,

On Sun, Jun 14, 2020 at 10:55 AM Simon Glass <sjg at chromium.org> wrote:
>
> Add more functions to handle some miscellaneous ACPI opcodes.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> Reviewed-by: Wolfgang Wallner <wolfgang.wallner at br-automation.com>
> ---
>
> Changes in v3:
> - Fix function name in comment for acpigen_write_not()
> - Use #defines for the mask values
>
>  include/acpi/acpigen.h | 117 +++++++++++++++++++++++++++++++++++++++++
>  lib/acpi/acpigen.c     |  84 +++++++++++++++++++++++++++++
>  test/dm/acpigen.c      |  75 ++++++++++++++++++++++++++
>  3 files changed, 276 insertions(+)
>
> diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> index 40cd72504a..d640324986 100644
> --- a/include/acpi/acpigen.h
> +++ b/include/acpi/acpigen.h
> @@ -17,6 +17,9 @@ struct acpi_ctx;
>  /* Top 4 bits of the value used to indicate a three-byte length value */
>  #define ACPI_PKG_LEN_3_BYTES   0x80
>
> +#define ACPI_METHOD_NARGS_MASK         0x7
> +#define ACPI_METHOD_SERIALIZED_MASK    BIT(3)
> +
>  /* ACPI Op/Prefix codes */
>  enum {
>         ZERO_OP                 = 0x00,
> @@ -29,9 +32,26 @@ enum {
>         QWORD_PREFIX            = 0x0e,
>         BUFFER_OP               = 0x11,
>         PACKAGE_OP              = 0x12,
> +       METHOD_OP               = 0x14,
> +       SLEEP_OP                = 0x22,
>         DUAL_NAME_PREFIX        = 0x2e,
>         MULTI_NAME_PREFIX       = 0x2f,
> +       DEBUG_OP                = 0x31,
> +       EXT_OP_PREFIX           = 0x5b,
>         ROOT_PREFIX             = 0x5c,
> +       LOCAL0_OP               = 0x60,
> +       LOCAL1_OP               = 0x61,
> +       LOCAL2_OP               = 0x62,
> +       LOCAL3_OP               = 0x63,
> +       LOCAL4_OP               = 0x64,
> +       LOCAL5_OP               = 0x65,
> +       LOCAL6_OP               = 0x66,
> +       LOCAL7_OP               = 0x67,
> +       STORE_OP                = 0x70,
> +       AND_OP                  = 0x7b,
> +       OR_OP                   = 0x7d,
> +       NOT_OP                  = 0x80,
> +       RETURN_OP               = 0xa4,
>  };
>
>  /**
> @@ -201,4 +221,101 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
>   */
>  int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
>
> +/**
> + * acpigen_emit_ext_op() - Emit an extended op with the EXT_OP_PREFIX prefix
> + *
> + * @ctx: ACPI context pointer
> + * @op: Operation code (e.g. SLEEP_OP)
> + */
> +void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op);
> +
> +/**
> + * acpigen_write_method() - Write a method header
> + *
> + * @ctx: ACPI context pointer
> + * @name: Method name (4 characters)
> + * @nargs: Number of method arguments (0 if none)
> + */
> +void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs);
> +
> +/**
> + * acpigen_write_method_serialized() - Write a method header
> + *
> + * This sets the 'serialized' flag so that the method is thread-safe
> + *
> + * @ctx: ACPI context pointer
> + * @name: Method name (4 characters)
> + * @nargs: Number of method arguments (0 if none)
> + */
> +void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
> +                                    int nargs);
> +
> +/**
> + * acpigen_write_sta() - Write a _STA method
> + *
> + * @ctx: ACPI context pointer
> + * @status: Status value to return
> + */
> +void acpigen_write_sta(struct acpi_ctx *ctx, uint status);
> +
> +/**
> + * acpigen_write_sleep() - Write a sleep operation
> + *
> + * @ctx: ACPI context pointer
> + * @sleep_ms: Number of milliseconds to sleep for
> + */
> +void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms);
> +
> +/**
> + * acpigen_write_store() - Write a store operation
> + *
> + * @ctx: ACPI context pointer
> + */
> +void acpigen_write_store(struct acpi_ctx *ctx);
> +
> +/**
> + * acpigen_write_debug_string() - Write a debug string
> + *
> + * This writes a debug operation with an associated string
> + *
> + * @ctx: ACPI context pointer
> + * @str: String to write
> + */
> +void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str);
> +
> +/**
> + * acpigen_write_or() - Write a bitwise OR operation
> + *
> + * res = arg1 | arg2
> + *
> + * @ctx: ACPI context pointer
> + * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
> + * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
> + * @res: ACPI opcode for result (e.g. LOCAL2_OP)
> + */
> +void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
> +
> +/**
> + * acpigen_write_and() - Write a bitwise AND operation
> + *
> + * res = arg1 & arg2
> + *
> + * @ctx: ACPI context pointer
> + * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
> + * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
> + * @res: ACPI opcode for result (e.g. LOCAL2_OP)
> + */
> +void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
> +
> +/**
> + * acpigen_write_not() - Write a bitwise NOT operation
> + *
> + * res = ~arg1
> + *
> + * @ctx: ACPI context pointer
> + * @arg: ACPI opcode for operand (e.g. LOCAL0_OP)
> + * @res: ACPI opcode for result (e.g. LOCAL2_OP)
> + */
> +void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res);
> +
>  #endif
> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> index 0f08d7b8a8..81ecad774c 100644
> --- a/lib/acpi/acpigen.c
> +++ b/lib/acpi/acpigen.c
> @@ -71,6 +71,12 @@ void acpigen_pop_len(struct acpi_ctx *ctx)
>         p[2] = len >> 12 & 0xff;
>  }
>
> +void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op)
> +{
> +       acpigen_emit_byte(ctx, EXT_OP_PREFIX);
> +       acpigen_emit_byte(ctx, op);
> +}
> +
>  char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
>  {
>         char *p;
> @@ -250,6 +256,38 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
>         acpigen_emit_namestring(ctx, namepath);
>  }
>
> +static void acpigen_write_method_(struct acpi_ctx *ctx, const char *name,

I am not sure if this is the naming convention U-Boot uses. I prefer
we name this to acpigen_write_method_internal or
acpigen_write_method_helper

> +                                 uint flags)
> +{
> +       acpigen_emit_byte(ctx, METHOD_OP);
> +       acpigen_write_len_f(ctx);
> +       acpigen_emit_namestring(ctx, name);
> +       acpigen_emit_byte(ctx, flags);
> +}
> +
> +/* Method (name, nargs, NotSerialized) */
> +void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs)
> +{
> +       acpigen_write_method_(ctx, name, nargs & ACPI_METHOD_NARGS_MASK);
> +}
> +
> +/* Method (name, nargs, Serialized) */
> +void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
> +                                    int nargs)
> +{
> +       acpigen_write_method_(ctx, name, (nargs & ACPI_METHOD_NARGS_MASK) |
> +                             ACPI_METHOD_SERIALIZED_MASK);
> +}
> +
> +void acpigen_write_sta(struct acpi_ctx *ctx, uint status)
> +{
> +       /* Method (_STA, 0, NotSerialized) { Return (status) } */
> +       acpigen_write_method(ctx, "_STA", 0);
> +       acpigen_emit_byte(ctx, RETURN_OP);
> +       acpigen_write_byte(ctx, status);
> +       acpigen_pop_len(ctx);
> +}
> +
>  /*
>   * ToUUID(uuid)
>   *
> @@ -286,3 +324,49 @@ int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
>
>         return 0;
>  }
> +
> +/* Sleep (ms) */
> +void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms)
> +{
> +       acpigen_emit_ext_op(ctx, SLEEP_OP);
> +       acpigen_write_integer(ctx, sleep_ms);
> +}
> +
> +void acpigen_write_store(struct acpi_ctx *ctx)
> +{
> +       acpigen_emit_byte(ctx, STORE_OP);
> +}
> +
> +/* Or (arg1, arg2, res) */
> +void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
> +{
> +       acpigen_emit_byte(ctx, OR_OP);
> +       acpigen_emit_byte(ctx, arg1);
> +       acpigen_emit_byte(ctx, arg2);
> +       acpigen_emit_byte(ctx, res);
> +}
> +
> +/* And (arg1, arg2, res) */
> +void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
> +{
> +       acpigen_emit_byte(ctx, AND_OP);
> +       acpigen_emit_byte(ctx, arg1);
> +       acpigen_emit_byte(ctx, arg2);
> +       acpigen_emit_byte(ctx, res);
> +}
> +
> +/* Not (arg, res) */
> +void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res)
> +{
> +       acpigen_emit_byte(ctx, NOT_OP);
> +       acpigen_emit_byte(ctx, arg);
> +       acpigen_emit_byte(ctx, res);
> +}
> +
> +/* Store (str, DEBUG) */
> +void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
> +{
> +       acpigen_write_store(ctx);
> +       acpigen_write_string(ctx, str);
> +       acpigen_emit_ext_op(ctx, DEBUG_OP);
> +}
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index 4f514eb9cc..86c65fbb82 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -625,3 +625,78 @@ static int dm_test_acpi_uuid(struct unit_test_state *uts)
>         return 0;
>  }
>  DM_TEST(dm_test_acpi_uuid, 0);
> +
> +/* Test writing misc ACPI codes */
> +static int dm_test_acpi_misc(struct unit_test_state *uts)
> +{
> +       struct acpi_ctx *ctx;
> +       const int flags = 3;
> +       const int nargs = 4;
> +       u8 *ptr;
> +
> +       ut_assertok(alloc_context(&ctx));
> +
> +       ptr = acpigen_get_current(ctx);
> +       acpigen_write_sleep(ctx, TEST_INT64);
> +       ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 3)));
> +       ptr += 11;
> +
> +       acpigen_write_store(ctx);
> +       ut_asserteq(STORE_OP, *ptr);
> +       ptr++;
> +
> +       acpigen_write_debug_string(ctx, TEST_STRING);
> +       ut_asserteq_str(TEST_STRING, (char *)ptr + 2);
> +       ptr += 2 +  sizeof(TEST_STRING);
> +       ut_asserteq(EXT_OP_PREFIX, ptr[0]);
> +       ut_asserteq(DEBUG_OP, ptr[1]);
> +       ptr += 2;
> +
> +       acpigen_write_sta(ctx, flags);
> +       ut_asserteq(METHOD_OP, ptr[0]);
> +       ut_asserteq(11, get_length(ptr + 1));
> +       ut_asserteq_strn("_STA", (char *)ptr + 4);
> +       ut_asserteq(0, ptr[8]);
> +       ut_asserteq(RETURN_OP, ptr[9]);
> +       ut_asserteq(BYTE_PREFIX, ptr[10]);
> +       ut_asserteq(flags, ptr[11]);
> +       ptr += 12;
> +
> +       acpigen_write_sleep(ctx, TEST_INT16);
> +       ut_asserteq(SLEEP_OP, ptr[1]);
> +       ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 3)));
> +       ptr += 5;
> +
> +       acpigen_write_method_serialized(ctx, "FRED", nargs);
> +       ut_asserteq(METHOD_OP, ptr[0]);
> +       ut_asserteq_strn("FRED", (char *)ptr + 4);
> +       ut_asserteq(1 << 3 | nargs, ptr[8]);
> +       ut_asserteq(1, ctx->ltop);      /* method is unfinished */
> +
> +       ptr += 9;
> +       acpigen_write_or(ctx, LOCAL0_OP, LOCAL1_OP, LOCAL2_OP);
> +       acpigen_write_and(ctx, LOCAL3_OP, LOCAL4_OP, LOCAL5_OP);
> +       acpigen_write_not(ctx, LOCAL6_OP, LOCAL7_OP);
> +       ut_asserteq(OR_OP, ptr[0]);
> +       ut_asserteq(LOCAL0_OP, ptr[1]);
> +       ut_asserteq(LOCAL1_OP, ptr[2]);
> +       ut_asserteq(LOCAL2_OP, ptr[3]);
> +
> +       ptr += 4;
> +       ut_asserteq(AND_OP, ptr[0]);
> +       ut_asserteq(LOCAL3_OP, ptr[1]);
> +       ut_asserteq(LOCAL4_OP, ptr[2]);
> +       ut_asserteq(LOCAL5_OP, ptr[3]);
> +
> +       ptr += 4;
> +       ut_asserteq(NOT_OP, ptr[0]);
> +       ut_asserteq(LOCAL6_OP, ptr[1]);
> +       ut_asserteq(LOCAL7_OP, ptr[2]);
> +       ptr += 3;
> +       ut_asserteq_ptr(ptr, ctx->current);
> +
> +       free_context(&ctx);
> +
> +       return 0;
> +}
> +DM_TEST(dm_test_acpi_misc, 0);
> --

Other than above,
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>

Regards,
Bin
diff mbox series

Patch

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 40cd72504a..d640324986 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -17,6 +17,9 @@  struct acpi_ctx;
 /* Top 4 bits of the value used to indicate a three-byte length value */
 #define ACPI_PKG_LEN_3_BYTES	0x80
 
+#define ACPI_METHOD_NARGS_MASK		0x7
+#define ACPI_METHOD_SERIALIZED_MASK	BIT(3)
+
 /* ACPI Op/Prefix codes */
 enum {
 	ZERO_OP			= 0x00,
@@ -29,9 +32,26 @@  enum {
 	QWORD_PREFIX		= 0x0e,
 	BUFFER_OP		= 0x11,
 	PACKAGE_OP		= 0x12,
+	METHOD_OP		= 0x14,
+	SLEEP_OP		= 0x22,
 	DUAL_NAME_PREFIX	= 0x2e,
 	MULTI_NAME_PREFIX	= 0x2f,
+	DEBUG_OP		= 0x31,
+	EXT_OP_PREFIX		= 0x5b,
 	ROOT_PREFIX		= 0x5c,
+	LOCAL0_OP		= 0x60,
+	LOCAL1_OP		= 0x61,
+	LOCAL2_OP		= 0x62,
+	LOCAL3_OP		= 0x63,
+	LOCAL4_OP		= 0x64,
+	LOCAL5_OP		= 0x65,
+	LOCAL6_OP		= 0x66,
+	LOCAL7_OP		= 0x67,
+	STORE_OP		= 0x70,
+	AND_OP			= 0x7b,
+	OR_OP			= 0x7d,
+	NOT_OP			= 0x80,
+	RETURN_OP		= 0xa4,
 };
 
 /**
@@ -201,4 +221,101 @@  void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
  */
 int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
 
+/**
+ * acpigen_emit_ext_op() - Emit an extended op with the EXT_OP_PREFIX prefix
+ *
+ * @ctx: ACPI context pointer
+ * @op: Operation code (e.g. SLEEP_OP)
+ */
+void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op);
+
+/**
+ * acpigen_write_method() - Write a method header
+ *
+ * @ctx: ACPI context pointer
+ * @name: Method name (4 characters)
+ * @nargs: Number of method arguments (0 if none)
+ */
+void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs);
+
+/**
+ * acpigen_write_method_serialized() - Write a method header
+ *
+ * This sets the 'serialized' flag so that the method is thread-safe
+ *
+ * @ctx: ACPI context pointer
+ * @name: Method name (4 characters)
+ * @nargs: Number of method arguments (0 if none)
+ */
+void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
+				     int nargs);
+
+/**
+ * acpigen_write_sta() - Write a _STA method
+ *
+ * @ctx: ACPI context pointer
+ * @status: Status value to return
+ */
+void acpigen_write_sta(struct acpi_ctx *ctx, uint status);
+
+/**
+ * acpigen_write_sleep() - Write a sleep operation
+ *
+ * @ctx: ACPI context pointer
+ * @sleep_ms: Number of milliseconds to sleep for
+ */
+void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms);
+
+/**
+ * acpigen_write_store() - Write a store operation
+ *
+ * @ctx: ACPI context pointer
+ */
+void acpigen_write_store(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_write_debug_string() - Write a debug string
+ *
+ * This writes a debug operation with an associated string
+ *
+ * @ctx: ACPI context pointer
+ * @str: String to write
+ */
+void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str);
+
+/**
+ * acpigen_write_or() - Write a bitwise OR operation
+ *
+ * res = arg1 | arg2
+ *
+ * @ctx: ACPI context pointer
+ * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
+ * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
+ * @res: ACPI opcode for result (e.g. LOCAL2_OP)
+ */
+void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
+
+/**
+ * acpigen_write_and() - Write a bitwise AND operation
+ *
+ * res = arg1 & arg2
+ *
+ * @ctx: ACPI context pointer
+ * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
+ * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
+ * @res: ACPI opcode for result (e.g. LOCAL2_OP)
+ */
+void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
+
+/**
+ * acpigen_write_not() - Write a bitwise NOT operation
+ *
+ * res = ~arg1
+ *
+ * @ctx: ACPI context pointer
+ * @arg: ACPI opcode for operand (e.g. LOCAL0_OP)
+ * @res: ACPI opcode for result (e.g. LOCAL2_OP)
+ */
+void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 0f08d7b8a8..81ecad774c 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -71,6 +71,12 @@  void acpigen_pop_len(struct acpi_ctx *ctx)
 	p[2] = len >> 12 & 0xff;
 }
 
+void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op)
+{
+	acpigen_emit_byte(ctx, EXT_OP_PREFIX);
+	acpigen_emit_byte(ctx, op);
+}
+
 char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
 {
 	char *p;
@@ -250,6 +256,38 @@  void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
 	acpigen_emit_namestring(ctx, namepath);
 }
 
+static void acpigen_write_method_(struct acpi_ctx *ctx, const char *name,
+				  uint flags)
+{
+	acpigen_emit_byte(ctx, METHOD_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_namestring(ctx, name);
+	acpigen_emit_byte(ctx, flags);
+}
+
+/* Method (name, nargs, NotSerialized) */
+void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs)
+{
+	acpigen_write_method_(ctx, name, nargs & ACPI_METHOD_NARGS_MASK);
+}
+
+/* Method (name, nargs, Serialized) */
+void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
+				     int nargs)
+{
+	acpigen_write_method_(ctx, name, (nargs & ACPI_METHOD_NARGS_MASK) |
+			      ACPI_METHOD_SERIALIZED_MASK);
+}
+
+void acpigen_write_sta(struct acpi_ctx *ctx, uint status)
+{
+	/* Method (_STA, 0, NotSerialized) { Return (status) } */
+	acpigen_write_method(ctx, "_STA", 0);
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_write_byte(ctx, status);
+	acpigen_pop_len(ctx);
+}
+
 /*
  * ToUUID(uuid)
  *
@@ -286,3 +324,49 @@  int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
 
 	return 0;
 }
+
+/* Sleep (ms) */
+void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms)
+{
+	acpigen_emit_ext_op(ctx, SLEEP_OP);
+	acpigen_write_integer(ctx, sleep_ms);
+}
+
+void acpigen_write_store(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, STORE_OP);
+}
+
+/* Or (arg1, arg2, res) */
+void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
+{
+	acpigen_emit_byte(ctx, OR_OP);
+	acpigen_emit_byte(ctx, arg1);
+	acpigen_emit_byte(ctx, arg2);
+	acpigen_emit_byte(ctx, res);
+}
+
+/* And (arg1, arg2, res) */
+void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
+{
+	acpigen_emit_byte(ctx, AND_OP);
+	acpigen_emit_byte(ctx, arg1);
+	acpigen_emit_byte(ctx, arg2);
+	acpigen_emit_byte(ctx, res);
+}
+
+/* Not (arg, res) */
+void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res)
+{
+	acpigen_emit_byte(ctx, NOT_OP);
+	acpigen_emit_byte(ctx, arg);
+	acpigen_emit_byte(ctx, res);
+}
+
+/* Store (str, DEBUG) */
+void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
+{
+	acpigen_write_store(ctx);
+	acpigen_write_string(ctx, str);
+	acpigen_emit_ext_op(ctx, DEBUG_OP);
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 4f514eb9cc..86c65fbb82 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -625,3 +625,78 @@  static int dm_test_acpi_uuid(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_uuid, 0);
+
+/* Test writing misc ACPI codes */
+static int dm_test_acpi_misc(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	const int flags = 3;
+	const int nargs = 4;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+	acpigen_write_sleep(ctx, TEST_INT64);
+	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 3)));
+	ptr += 11;
+
+	acpigen_write_store(ctx);
+	ut_asserteq(STORE_OP, *ptr);
+	ptr++;
+
+	acpigen_write_debug_string(ctx, TEST_STRING);
+	ut_asserteq_str(TEST_STRING, (char *)ptr + 2);
+	ptr += 2 +  sizeof(TEST_STRING);
+	ut_asserteq(EXT_OP_PREFIX, ptr[0]);
+	ut_asserteq(DEBUG_OP, ptr[1]);
+	ptr += 2;
+
+	acpigen_write_sta(ctx, flags);
+	ut_asserteq(METHOD_OP, ptr[0]);
+	ut_asserteq(11, get_length(ptr + 1));
+	ut_asserteq_strn("_STA", (char *)ptr + 4);
+	ut_asserteq(0, ptr[8]);
+	ut_asserteq(RETURN_OP, ptr[9]);
+	ut_asserteq(BYTE_PREFIX, ptr[10]);
+	ut_asserteq(flags, ptr[11]);
+	ptr += 12;
+
+	acpigen_write_sleep(ctx, TEST_INT16);
+	ut_asserteq(SLEEP_OP, ptr[1]);
+	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 3)));
+	ptr += 5;
+
+	acpigen_write_method_serialized(ctx, "FRED", nargs);
+	ut_asserteq(METHOD_OP, ptr[0]);
+	ut_asserteq_strn("FRED", (char *)ptr + 4);
+	ut_asserteq(1 << 3 | nargs, ptr[8]);
+	ut_asserteq(1, ctx->ltop);	/* method is unfinished */
+
+	ptr += 9;
+	acpigen_write_or(ctx, LOCAL0_OP, LOCAL1_OP, LOCAL2_OP);
+	acpigen_write_and(ctx, LOCAL3_OP, LOCAL4_OP, LOCAL5_OP);
+	acpigen_write_not(ctx, LOCAL6_OP, LOCAL7_OP);
+	ut_asserteq(OR_OP, ptr[0]);
+	ut_asserteq(LOCAL0_OP, ptr[1]);
+	ut_asserteq(LOCAL1_OP, ptr[2]);
+	ut_asserteq(LOCAL2_OP, ptr[3]);
+
+	ptr += 4;
+	ut_asserteq(AND_OP, ptr[0]);
+	ut_asserteq(LOCAL3_OP, ptr[1]);
+	ut_asserteq(LOCAL4_OP, ptr[2]);
+	ut_asserteq(LOCAL5_OP, ptr[3]);
+
+	ptr += 4;
+	ut_asserteq(NOT_OP, ptr[0]);
+	ut_asserteq(LOCAL6_OP, ptr[1]);
+	ut_asserteq(LOCAL7_OP, ptr[2]);
+	ptr += 3;
+	ut_asserteq_ptr(ptr, ctx->current);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_misc, 0);