Skip to content

Commit

Permalink
Introduce support for IPMI opregions
Browse files Browse the repository at this point in the history
This also serves as the foundation for supporting other write-then-read
and serial address space types.

Signed-off-by: Daniil Tatianin <99danilt@gmail.com>
  • Loading branch information
d-tatianin committed Jan 6, 2025
1 parent 777187b commit ac6c2f3
Show file tree
Hide file tree
Showing 7 changed files with 383 additions and 144 deletions.
14 changes: 12 additions & 2 deletions include/uacpi/internal/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,21 @@ void uacpi_write_buffer_field(
uacpi_buffer_field *field, const void *src, uacpi_size size
);

uacpi_status uacpi_field_unit_get_read_type(
struct uacpi_field_unit *field, uacpi_object_type *out_type
);

uacpi_status uacpi_field_unit_get_bit_length(
struct uacpi_field_unit *field, uacpi_size *out_length
);

uacpi_status uacpi_read_field_unit(
uacpi_field_unit *field, void *dst, uacpi_size size
uacpi_field_unit *field, void *dst, uacpi_size size,
uacpi_data_view *wtr_response
);
uacpi_status uacpi_write_field_unit(
uacpi_field_unit *field, const void *src, uacpi_size size
uacpi_field_unit *field, const void *src, uacpi_size size,
uacpi_data_view *wtr_response
);

uacpi_status uacpi_system_io_read(
Expand Down
3 changes: 2 additions & 1 deletion include/uacpi/internal/opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,9 +665,10 @@ UACPI_OP( \
StoreOp, 0x70, \
{ \
UACPI_PARSE_OP_TERM_ARG, \
UACPI_PARSE_OP_OBJECT_COPY_TO_PREV, \
UACPI_PARSE_OP_SUPERNAME, \
UACPI_PARSE_OP_INVOKE_HANDLER, \
UACPI_PARSE_OP_ITEM_POP, \
UACPI_PARSE_OP_OBJECT_COPY_TO_PREV, \
}, \
UACPI_OP_PROPERTY_TERM_ARG \
) \
Expand Down
13 changes: 8 additions & 5 deletions include/uacpi/internal/opregion.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ void uacpi_deinitialize_opregion(void);
void uacpi_trace_region_error(
uacpi_namespace_node *node, uacpi_char *message, uacpi_status ret
);
void uacpi_trace_region_io(
uacpi_namespace_node *node, uacpi_address_space space, uacpi_region_op op,
uacpi_u64 offset, uacpi_u8 byte_size, uacpi_u64 ret
);

uacpi_status uacpi_install_address_space_handler_with_flags(
uacpi_namespace_node *device_node, enum uacpi_address_space space,
Expand All @@ -36,7 +32,14 @@ uacpi_status uacpi_opregion_attach(uacpi_namespace_node *node);

void uacpi_install_default_address_space_handlers(void);

uacpi_bool uacpi_is_buffer_access_address_space(uacpi_address_space space);

union uacpi_opregion_io_data {
uacpi_u64 *integer;
uacpi_data_view buffer;
};

uacpi_status uacpi_dispatch_opregion_io(
uacpi_field_unit *field, uacpi_u32 offset,
uacpi_region_op op, uacpi_u64 *in_out
uacpi_region_op op, union uacpi_opregion_io_data data
);
10 changes: 10 additions & 0 deletions include/uacpi/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ typedef enum uacpi_region_op {
UACPI_REGION_OP_PCC_SEND,
UACPI_REGION_OP_GPIO_READ,
UACPI_REGION_OP_GPIO_WRITE,

UACPI_REGION_OP_IPMI_COMMAND,
} uacpi_region_op;

typedef struct uacpi_generic_region_info {
Expand Down Expand Up @@ -422,6 +424,14 @@ typedef struct uacpi_region_gpio_rw_data
uacpi_u64 value;
} uacpi_region_gpio_rw_data;

typedef struct uacpi_region_ipmi_rw_data
{
void *handler_context;
void *region_context;
uacpi_data_view in_out_message;
uacpi_u64 command;
} uacpi_region_ipmi_rw_data;

typedef struct uacpi_region_detach_data {
void *handler_context;
void *region_context;
Expand Down
172 changes: 125 additions & 47 deletions source/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,18 +867,6 @@ static uacpi_status handle_package(struct execution_context *ctx)
return UACPI_STATUS_OK;
}

static uacpi_size field_byte_size(uacpi_object *obj)
{
uacpi_size bit_length;

if (obj->type == UACPI_OBJECT_BUFFER_FIELD)
bit_length = obj->buffer_field.bit_length;
else
bit_length = obj->field_unit->bit_length;

return uacpi_round_up_bits_to_bytes(bit_length);
}

static uacpi_size sizeof_int(void)
{
return g_uacpi_rt_ctx.is_rev1 ? 4 : 8;
Expand Down Expand Up @@ -941,8 +929,9 @@ static void write_buffer_index(uacpi_buffer_index *buf_idx,
* the specification. In reality, we just copy one buffer to another
* because that's what NT does.
*/
static uacpi_status object_assign_with_implicit_cast(uacpi_object *dst,
uacpi_object *src)
static uacpi_status object_assign_with_implicit_cast(
uacpi_object *dst, uacpi_object *src, uacpi_data_view *wtr_response
)
{
uacpi_status ret;
uacpi_data_view src_buf;
Expand Down Expand Up @@ -975,7 +964,8 @@ static uacpi_status object_assign_with_implicit_cast(uacpi_object *dst,

case UACPI_OBJECT_FIELD_UNIT:
return uacpi_write_field_unit(
dst->field_unit, src_buf.bytes, src_buf.length
dst->field_unit, src_buf.bytes, src_buf.length,
wtr_response
);

case UACPI_OBJECT_BUFFER_INDEX:
Expand Down Expand Up @@ -2279,8 +2269,9 @@ static void object_replace_child(uacpi_object *parent, uacpi_object *new_child)
* 3. NAME -> Store with implicit cast.
* 4. RefOf -> Not allowed here.
*/
static uacpi_status store_to_reference(uacpi_object *dst,
uacpi_object *src)
static uacpi_status store_to_reference(
uacpi_object *dst, uacpi_object *src, uacpi_data_view *wtr_response
)
{
uacpi_object *src_obj;
uacpi_bool overwrite = UACPI_FALSE;
Expand Down Expand Up @@ -2335,7 +2326,9 @@ static uacpi_status store_to_reference(uacpi_object *dst,
return UACPI_STATUS_OK;
}

return object_assign_with_implicit_cast(dst->inner_object, src_obj);
return object_assign_with_implicit_cast(
dst->inner_object, src_obj, wtr_response
);
}

static uacpi_status handle_ref_or_deref_of(struct execution_context *ctx)
Expand Down Expand Up @@ -3769,48 +3762,69 @@ static uacpi_object_type buffer_field_get_read_type(
return UACPI_OBJECT_INTEGER;
}

static uacpi_object_type field_unit_get_read_type(
struct uacpi_field_unit *field
static uacpi_status field_get_read_type(
uacpi_object *obj, uacpi_object_type *out_type
)
{
if (field->bit_length > (g_uacpi_rt_ctx.is_rev1 ? 32u : 64u))
return UACPI_OBJECT_BUFFER;
if (obj->type == UACPI_OBJECT_BUFFER_FIELD) {
*out_type = buffer_field_get_read_type(&obj->buffer_field);
return UACPI_STATUS_OK;
}

return UACPI_OBJECT_INTEGER;
return uacpi_field_unit_get_read_type(obj->field_unit, out_type);
}

static uacpi_object_type field_get_read_type(uacpi_object *obj)
static uacpi_status field_byte_size(
uacpi_object *obj, uacpi_size *out_size
)
{
if (obj->type == UACPI_OBJECT_BUFFER_FIELD)
return buffer_field_get_read_type(&obj->buffer_field);
uacpi_size bit_length;

return field_unit_get_read_type(obj->field_unit);
if (obj->type == UACPI_OBJECT_BUFFER_FIELD) {
bit_length = obj->buffer_field.bit_length;
} else {
uacpi_status ret;

ret = uacpi_field_unit_get_bit_length(obj->field_unit, &bit_length);
if (uacpi_unlikely_error(ret))
return ret;
}

*out_size = uacpi_round_up_bits_to_bytes(bit_length);
return UACPI_STATUS_OK;
}

static uacpi_status handle_field_read(struct execution_context *ctx)
{
uacpi_status ret;
struct op_context *op_ctx = ctx->cur_op_ctx;
struct uacpi_namespace_node *node;
uacpi_object *src_obj, *dst_obj;
uacpi_size dst_size;
void *dst;
void *dst = UACPI_NULL;
uacpi_data_view wtr_response = { 0 };

node = item_array_at(&op_ctx->items, 0)->node;
src_obj = uacpi_namespace_node_get_object(node);
dst_obj = item_array_at(&op_ctx->items, 1)->obj;

if (field_get_read_type(src_obj) == UACPI_OBJECT_BUFFER) {
if (op_ctx->op->code == UACPI_AML_OP_InternalOpReadFieldAsBuffer) {
uacpi_buffer *buf;

buf = dst_obj->buffer;
dst_size = field_byte_size(src_obj);
ret = field_byte_size(src_obj, &dst_size);
if (uacpi_unlikely_error(ret))
return ret;

dst = uacpi_kernel_alloc_zeroed(dst_size);
if (dst == UACPI_NULL)
return UACPI_STATUS_OUT_OF_MEMORY;
if (dst_size != 0) {
buf = dst_obj->buffer;

dst = uacpi_kernel_alloc_zeroed(dst_size);
if (dst == UACPI_NULL)
return UACPI_STATUS_OUT_OF_MEMORY;

buf->data = dst;
buf->size = dst_size;
buf->data = dst;
buf->size = dst_size;
}
} else {
dst = &dst_obj->integer;
dst_size = sizeof(uacpi_u64);
Expand All @@ -3821,7 +3835,21 @@ static uacpi_status handle_field_read(struct execution_context *ctx)
return UACPI_STATUS_OK;
}

return uacpi_read_field_unit(src_obj->field_unit, dst, dst_size);
ret = uacpi_read_field_unit(
src_obj->field_unit, dst, dst_size, &wtr_response
);
if (uacpi_unlikely_error(ret))
return ret;

if (wtr_response.data != UACPI_NULL) {
uacpi_buffer *buf;

buf = dst_obj->buffer;
buf->data = wtr_response.data;
buf->size = wtr_response.length;
}

return ret;
}

static uacpi_status handle_create_buffer_field(struct execution_context *ctx)
Expand Down Expand Up @@ -4192,7 +4220,9 @@ static uacpi_bool maybe_end_block(struct execution_context *ctx)
return UACPI_TRUE;
}

static uacpi_status store_to_target(uacpi_object *dst, uacpi_object *src)
static uacpi_status store_to_target(
uacpi_object *dst, uacpi_object *src, uacpi_data_view *wtr_response
)
{
uacpi_status ret;

Expand All @@ -4201,12 +4231,12 @@ static uacpi_status store_to_target(uacpi_object *dst, uacpi_object *src)
ret = debug_store(src);
break;
case UACPI_OBJECT_REFERENCE:
ret = store_to_reference(dst, src);
ret = store_to_reference(dst, src, wtr_response);
break;

case UACPI_OBJECT_BUFFER_INDEX:
src = uacpi_unwrap_internal_reference(src);
ret = object_assign_with_implicit_cast(dst, src);
ret = object_assign_with_implicit_cast(dst, src, wtr_response);
break;

case UACPI_OBJECT_INTEGER:
Expand All @@ -4233,8 +4263,35 @@ static uacpi_status handle_copy_object_or_store(struct execution_context *ctx)
src = item_array_at(&op_ctx->items, 0)->obj;
dst = item_array_at(&op_ctx->items, 1)->obj;

if (op_ctx->op->code == UACPI_AML_OP_StoreOp)
return store_to_target(dst, src);
if (op_ctx->op->code == UACPI_AML_OP_StoreOp) {
uacpi_status ret;
uacpi_data_view wtr_response = { 0 };

ret = store_to_target(dst, src, &wtr_response);
if (uacpi_unlikely_error(ret))
return ret;

/*
* This was a write-then-read field access since we got a response
* buffer back from this store. Now we have to return this buffer
* as a prvalue from the StoreOp so that it can be used by AML to
* retrieve the response.
*/
if (wtr_response.data != UACPI_NULL) {
uacpi_object *wtr_response_obj;

wtr_response_obj = uacpi_object_create_buffer(wtr_response);
if (wtr_response_obj == UACPI_NULL) {
uacpi_free(wtr_response.data, wtr_response.length);
return UACPI_STATUS_OUT_OF_MEMORY;
}

uacpi_object_unref(src);
item_array_at(&op_ctx->items, 0)->obj = wtr_response_obj;
}

return ret;
}

if (dst->type != UACPI_OBJECT_REFERENCE)
return UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE;
Expand Down Expand Up @@ -4279,13 +4336,16 @@ static uacpi_status handle_inc_dec(struct execution_context *ctx)
if (uacpi_unlikely(!field_allowed))
goto out_bad_type;

true_src_type = field_get_read_type(src);
ret = field_get_read_type(src, &true_src_type);
if (uacpi_unlikely_error(ret))
goto out_bad_type;
if (true_src_type != UACPI_OBJECT_INTEGER)
goto out_bad_type;

if (src->type == UACPI_OBJECT_FIELD_UNIT) {
ret = uacpi_read_field_unit(
src->field_unit, &dst->integer, sizeof_int()
src->field_unit, &dst->integer, sizeof_int(),
UACPI_NULL
);
if (uacpi_unlikely_error(ret))
return ret;
Expand Down Expand Up @@ -5497,7 +5557,7 @@ static uacpi_status exec_op(struct execution_context *ctx)
src = item->obj;
}

ret = store_to_target(dst, src);
ret = store_to_target(dst, src, UACPI_NULL);
break;
}

Expand Down Expand Up @@ -5589,11 +5649,28 @@ static uacpi_status exec_op(struct execution_context *ctx)
}

case UACPI_OBJECT_BUFFER_FIELD:
case UACPI_OBJECT_FIELD_UNIT:
case UACPI_OBJECT_FIELD_UNIT: {
uacpi_object_type type;

if (!op_wants_term_arg_or_operand(prev_op))
break;

switch (field_get_read_type(obj)) {
ret = field_get_read_type(obj, &type);
if (uacpi_unlikely_error(ret)) {
const uacpi_char *field_path;

field_path = uacpi_namespace_node_generate_absolute_path(
item->node
);

uacpi_error(
"unable to perform a read from field %s: "
"parent opregion gone\n", field_path
);
uacpi_free_absolute_path(field_path);
}

switch (type) {
case UACPI_OBJECT_BUFFER:
new_op = UACPI_AML_OP_InternalOpReadFieldAsBuffer;
break;
Expand All @@ -5605,6 +5682,7 @@ static uacpi_status exec_op(struct execution_context *ctx)
continue;
}
break;
}
default:
break;
}
Expand Down
Loading

0 comments on commit ac6c2f3

Please sign in to comment.