Skip to content
Open
38 changes: 33 additions & 5 deletions src/audio/module_adapter/module_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ static void module_adapter_mem_free(struct processing_module *mod)
* \brief Create a module adapter component.
* \param[in] drv - component driver pointer.
* \param[in] config - component ipc descriptor pointer.
* \param[in] spec - passdowned data from driver.
* \param[in] const_spec - passdowned data from driver.
* \param[in] mod_priv - Pointer to private data for processing module.
*
* \return: a pointer to newly created module adapter component on success. NULL on error.
Expand All @@ -167,20 +167,32 @@ static void module_adapter_mem_free(struct processing_module *mod)
* the create method.
*/
struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
const struct comp_ipc_config *config, const void *spec,
void *mod_priv, struct userspace_context *user_ctx)
const struct comp_ipc_config *config,
const void *const_spec, void *mod_priv,
struct userspace_context *user_ctx)
{
int ret;
struct module_config *dst;
const struct module_interface *const interface = drv->adapter_ops;

struct ipc_config_process spec =
*((const struct ipc_config_process *) const_spec);
#if CONFIG_IPC_MAJOR_4
struct module_ext_init_data ext_data = { 0 };
#endif
comp_cl_dbg(drv, "start");

if (!config) {
comp_cl_err(drv, "wrong input params! drv = %zx config = %zx",
(size_t)drv, (size_t)config);
return NULL;
}
#if CONFIG_IPC_MAJOR_4
if (config->ipc_extended_init) {
ret = module_ext_init_decode(drv, &ext_data, &spec);
if (ret != 0)
return NULL;
}
#endif

struct processing_module *mod = module_adapter_mem_alloc(drv, config);

Expand All @@ -204,7 +216,17 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
#endif /* CONFIG_USERSPACE */

dst = &mod->priv.cfg;
ret = module_adapter_init_data(dev, dst, config, spec);
/*
* NOTE: dst->ext_data points to stack variable and contains
* pointers to IPC payload mailbox, so its only valid in
* functions that called from this function. This why
* the pointer is set NULL before the this function
* exits.
*/
#if CONFIG_IPC_MAJOR_4
dst->ext_data = &ext_data;
#endif
ret = module_adapter_init_data(dev, dst, config, &spec);
if (ret) {
comp_err(dev, "%d: module init data failed",
ret);
Expand Down Expand Up @@ -270,6 +292,9 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
component_set_nearest_period_frames(dev, params.rate);
#endif

#if CONFIG_IPC_MAJOR_4
dst->ext_data = NULL;
#endif
comp_dbg(dev, "done");
return dev;

Expand All @@ -279,6 +304,9 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
schedule_task_free(dev->task);
#endif
module_adapter_mem_free(mod);
#if CONFIG_IPC_MAJOR_4
dst->ext_data = NULL;
#endif

return NULL;
}
Expand Down
67 changes: 33 additions & 34 deletions src/audio/module_adapter/module_adapter_ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@

LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL);

static const struct ipc4_base_module_extended_cfg *
module_ext_init_decode(struct comp_dev *dev, struct module_config *dst,
const unsigned char *data, size_t *size)
int module_ext_init_decode(const struct comp_driver *drv, struct module_ext_init_data *ext_data,
struct ipc_config_process *spec)
{
const struct ipc4_module_init_ext_init *ext_init =
(const struct ipc4_module_init_ext_init *)data;
(const struct ipc4_module_init_ext_init *)spec->data;
bool last_object = !ext_init->data_obj_array;
const struct ipc4_module_init_ext_object *obj;

if (*size < sizeof(ext_init)) {
comp_err(dev, "Size too small for ext init %u < %u",
*size, sizeof(ext_init));
return NULL;
assert(drv->type == SOF_COMP_MODULE_ADAPTER);
if (spec->size < sizeof(ext_init)) {
comp_cl_err(drv, "Size too small for ext init %zu < %zu",
spec->size, sizeof(ext_init));
return -EINVAL;
}
/* TODO: Handle ext_init->gna_used and ext_init->rtos_domain here */
/* Get the first obj struct right after ext_init struct */
Expand All @@ -46,18 +46,18 @@ module_ext_init_decode(struct comp_dev *dev, struct module_config *dst,
const struct ipc4_module_init_ext_object *next_obj;

/* Check if there is space for the object header */
if ((unsigned char *)(obj + 1) - data > *size) {
comp_err(dev, "ext init obj overflow, %u > %u",
(unsigned char *)(obj + 1) - data, *size);
return NULL;
if ((unsigned char *)(obj + 1) - spec->data > spec->size) {
comp_cl_err(drv, "ext init obj overflow, %u > %zu",
(unsigned char *)(obj + 1) - spec->data, spec->size);
return -EINVAL;
}
/* Calculate would be next object position and check if current object fits */
next_obj = (const struct ipc4_module_init_ext_object *)
(((uint32_t *) (obj + 1)) + obj->object_words);
if ((unsigned char *)next_obj - data > *size) {
comp_err(dev, "ext init object array overflow, %u > %u",
(unsigned char *)obj - data, *size);
return NULL;
if ((unsigned char *)next_obj - spec->data > spec->size) {
comp_cl_err(drv, "ext init object array overflow, %u > %zu",
(unsigned char *)obj - spec->data, spec->size);
return -EINVAL;
}
switch (obj->object_id) {
case IPC4_MOD_INIT_DATA_ID_DP_DATA:
Expand All @@ -67,32 +67,34 @@ module_ext_init_decode(struct comp_dev *dev, struct module_config *dst,
(const struct ipc4_module_init_ext_obj_dp_data *)(obj + 1);

if (obj->object_words * sizeof(uint32_t) < sizeof(*dp_data)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to the commit message, I understand by "released" you mean it's already a part of the ABI? Maybe better use that wording, since I first thought "released" meant "freed" which was confusing. (unrelated to this commit) just noticing, that module_ext_init_decode() returns a pointer of type struct ipc4_base_module_extended_cfg which should only be appropriate for the base module? Strange

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix the commit message.

The reason is that the base config follows ext_init in the payload, and if there is anything left aftere ext_init, it should be base config. Anyway, this is going way when I move module_ext_init_decode()-call to module_adapter_new_ext().

comp_err(dev, "dp_data object too small %u < %u",
obj->object_words * sizeof(uint32_t), sizeof(*dp_data));
return NULL;
comp_cl_warn(drv, "dp_data object too small %zu < %zu",
obj->object_words * sizeof(uint32_t),
sizeof(*dp_data));
break;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this not fatal any more? Also break only takes you out of switch, not out of the loop, is that correct?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks a bit suspicious, this goes on to access "dp_data->interim_heap_bytes" from the too small object. This does not look correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mandatory if we go and redefine "struct ipc4_module_init_ext_obj_dp_data". Otherwise payloads sent by an older linux version would always fail dp module creation.

But fear not, non of the data in the too short data object is used. Its all ignored as all of that code accessing the data is within the case block. And we need to continue the decoding loop in case there is some other objects there that we can decode correctly.

}
dst->domain_id = dp_data->domain_id;
dst->stack_bytes = dp_data->stack_bytes;
dst->heap_bytes = dp_data->heap_bytes;
comp_info(dev, "init_ext_obj_dp_data domain %u stack %u heap %u",
dp_data->domain_id, dp_data->stack_bytes, dp_data->heap_bytes);
ext_data->dp_data = dp_data;
comp_cl_info(drv,
"init_ext_obj_dp_data domain %u stack %u interim %u lifetime %u shared %u",
dp_data->domain_id, dp_data->stack_bytes,
dp_data->interim_heap_bytes, dp_data->lifetime_heap_bytes,
dp_data->shared_bytes);
break;
}
default:
comp_info(dev, "Unknown ext init object id %u of %u words",
obj->object_id, obj->object_words);
comp_cl_info(drv, "Unknown ext init object id %u of %u words",
obj->object_id, obj->object_words);
}
/* Read the last object flag from obj header */
last_object = obj->last_object;
/* Move to next object */
obj = next_obj;
}

/* Remove decoded ext_init payload from the size */
*size -= (unsigned char *) obj - data;
/* Remove decoded ext_init payload from spec */
spec->size -= (unsigned char *)obj - spec->data;
spec->data = (const unsigned char *)obj;

/* return remaining payload */
return (const struct ipc4_base_module_extended_cfg *)obj;
return 0;
}

/*
Expand All @@ -114,10 +116,7 @@ int module_adapter_init_data(struct comp_dev *dev,
size_t cfgsz = args->size;

assert(dev->drv->type == SOF_COMP_MODULE_ADAPTER);
if (config->ipc_extended_init)
cfg = module_ext_init_decode(dev, dst, args->data, &cfgsz);
else
cfg = (const struct ipc4_base_module_extended_cfg *)args->data;
cfg = (const struct ipc4_base_module_extended_cfg *)args->data;

if (cfg == NULL)
return -EINVAL;
Expand Down
3 changes: 2 additions & 1 deletion src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ void pipeline_posn_init(struct sof *sof)
}

/* create new pipeline - returns pipeline id or negative error */
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id)
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id,
struct create_pipeline_params *pparams)
{
struct sof_ipc_stream_posn posn;
struct pipeline *p;
Expand Down
8 changes: 5 additions & 3 deletions src/include/ipc4/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,11 @@ struct ipc4_module_init_ext_object {

/* Ext init array data object for Data Processing module memory requirements */
struct ipc4_module_init_ext_obj_dp_data {
uint32_t domain_id; /* userspace domain ID */
uint32_t stack_bytes; /* required stack size in bytes, 0 means default size */
uint32_t heap_bytes; /* required heap size in bytes, 0 means default size */
uint32_t domain_id; /* userspace domain ID */
uint32_t stack_bytes; /* required stack size in bytes */
uint32_t interim_heap_bytes; /* required interim heap size in bytes */
uint32_t lifetime_heap_bytes; /* required lifetime heap size in bytes */
uint32_t shared_bytes; /* required shared memory size in bytes */
} __attribute__((packed, aligned(4)));

/*
Expand Down
38 changes: 37 additions & 1 deletion src/include/ipc4/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,41 @@ enum ipc4_pipeline_state {
SOF_IPC4_PIPELINE_STATE_SAVED
};

/* IDs for all pipeline ext data types in struct ipc4_pipeline_init_ext_object */
enum ipc4_pipeline_ext_obj_id {
IPC4_GLB_PIPE_EXT_OBJ_ID_INVALID = 0,
IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA = 1,
IPC4_GLB_PIPE_EXT_OBJ_ID_MAX = IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA,
};

/* data object for vendor bespoke data with ABI growth and backwards compat */
struct ipc4_pipeline_ext_object {
uint32_t last_object : 1; /* object is last in array if 1 else object follows. */
uint32_t object_id : 15; /* unique ID for this object or globally */
uint32_t object_words : 16; /* size in dwords (excluding this structure) */
} __packed __aligned(4);
/* the object data will be placed in memory here and will have size "object_words" */

/* Ext array data object for pipeline instance's memory requirements */
struct ipc4_pipeline_ext_obj_mem_data {
uint32_t domain_id; /* userspace domain ID */
uint32_t stack_bytes; /* required stack size in bytes */
uint32_t interim_heap_bytes; /* required interim heap size in bytes */
uint32_t lifetime_heap_bytes; /* required lifetime heap size in bytes */
uint32_t shared_bytes; /* required shared memory in bytes */
} __packed __aligned(4);

/*
* Host Driver sends this message to create a new pipeline instance.
*/
struct ipc4_pipeline_ext_payload {
uint32_t payload_words : 24; /* size in dwords (excluding this structure) */
uint32_t data_obj_array : 1; /* struct ipc4_pipeline_ext_object data */
uint32_t rsvd0 : 7;
uint32_t rsvd1;
uint32_t rsvd2;
} __packed __aligned(4);

/*!
* lp - indicates whether the pipeline should be kept on running in low power
* mode. On BXT the driver should set this flag to 1 for WoV pipeline.
Expand Down Expand Up @@ -106,7 +141,8 @@ struct ipc4_pipeline_create {
uint32_t rsvd1 : 3;
uint32_t attributes : 16;
uint32_t core_id : 4;
uint32_t rsvd2 : 6;
uint32_t rsvd2 : 5;
uint32_t payload : 1;
uint32_t _reserved_2 : 2;
} r;
} extension;
Expand Down
16 changes: 13 additions & 3 deletions src/include/module/module/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@
#define module_get_private_data(mod) ((mod)->priv.private)
#define module_set_private_data(mod, data) ((mod)->priv.private = data)

/**
* \struct module_ext_init_data
* \brief Container for found ext init object pointers
* This struct contains pointers that point to IPC payload directly. The
* module should store what it needs in its init() callback as the data
* is not valid after that.
*/
struct ipc4_module_init_ext_obj_dp_data;
struct module_ext_init_data {
const struct ipc4_module_init_ext_obj_dp_data *dp_data;
};

/**
* \struct module_config
* \brief Module config container, used for both config types.
Expand All @@ -38,9 +50,7 @@ struct module_config {
uint8_t nb_output_pins;
struct ipc4_input_pin_format *input_pins;
struct ipc4_output_pin_format *output_pins;
uint32_t domain_id; /* userspace domain ID */
uint32_t stack_bytes; /* stack size in bytes, 0 means default value */
uint32_t heap_bytes; /* max heap size in bytes, 0 means default value */
struct module_ext_init_data *ext_data; /**< IPC payload pointers, NULL after init() */
#endif
};

Expand Down
13 changes: 12 additions & 1 deletion src/include/sof/audio/module_adapter/module/generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,18 @@ int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd);
void module_update_buffer_position(struct input_stream_buffer *input_buffers,
struct output_stream_buffer *output_buffers,
uint32_t frames);

struct module_ext_init_data;
#if CONFIG_IPC_MAJOR_4
int module_ext_init_decode(const struct comp_driver *drv, struct module_ext_init_data *ext_data,
struct ipc_config_process *spec);
#else
static inline
int module_ext_init_decode(const struct comp_driver *drv, struct module_ext_init_data *ext_data,
struct ipc_config_process *spec)
{
return 0;
}
#endif
int module_adapter_init_data(struct comp_dev *dev,
struct module_config *dst,
const struct comp_ipc_config *config,
Expand Down
11 changes: 10 additions & 1 deletion src/include/sof/audio/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ struct pipeline_task {
struct comp_dev *sched_comp; /**< pipeline scheduling component */
};

struct ipc4_pipeline_ext_obj_mem_data;

/** \brief For storing IPC payload data. */
struct create_pipeline_params {
const struct ipc4_pipeline_ext_obj_mem_data *mem_data;
};

#define pipeline_task_get(t) container_of(t, struct pipeline_task, task)

/*
Expand All @@ -148,9 +155,11 @@ struct pipeline_task {
* \param[in] pipeline_id Pipeline ID number.
* \param[in] priority Pipeline scheduling priority.
* \param[in] comp_id Pipeline component ID number.
* \param[in] pparams Pipeline parameters from IPC payload, maybe NULL.
* \return New pipeline pointer or NULL.
*/
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id);
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id,
struct create_pipeline_params *pparams);

/**
* \brief Free's a pipeline.
Expand Down
2 changes: 1 addition & 1 deletion src/ipc/ipc3/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc)

/* create the pipeline */
pipe = pipeline_new(pipe_desc->pipeline_id, pipe_desc->priority,
pipe_desc->comp_id);
pipe_desc->comp_id, NULL);
if (!pipe) {
tr_err(&ipc_tr, "pipeline_new() failed");
return -ENOMEM;
Expand Down
Loading
Loading