This commit implements the necessary operations required to establish a connection with the MCD server:
* query information about the server * connect to " * disconnect from " Signed-off-by: Mario Fleischmann <mario.fleischm...@lauterbach.com> --- mcd/mcd_qapi.c | 13 +++ mcd/mcd_qapi.h | 2 + mcd/mcd_server.c | 110 +++++++++++++++++++++- mcd/mcd_stub.c | 98 ++++++++++++++++++++ qapi/mcd.json | 205 +++++++++++++++++++++++++++++++++++++++++ tests/qtest/mcd-test.c | 96 +++++++++++++++++++ tests/qtest/mcd-util.c | 60 ++++++++++++ tests/qtest/mcd-util.h | 9 ++ 8 files changed, 588 insertions(+), 5 deletions(-) diff --git a/mcd/mcd_qapi.c b/mcd/mcd_qapi.c index 9a99866..d2a2926 100644 --- a/mcd/mcd_qapi.c +++ b/mcd/mcd_qapi.c @@ -64,3 +64,16 @@ MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info) return marshal; } + +MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info) +{ + MCDServerInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDServerInfo) { + .server = g_strdup(server_info->server), + .system_instance = g_strdup(server_info->system_instance), + .acc_hw = g_strdup(server_info->acc_hw), + }; + + return marshal; +} diff --git a/mcd/mcd_qapi.h b/mcd/mcd_qapi.h index 47f4e16..e515a37 100644 --- a/mcd/mcd_qapi.h +++ b/mcd/mcd_qapi.h @@ -21,6 +21,8 @@ MCDImplVersionInfo *marshal_mcd_impl_version_info( MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info); +MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); #endif /* MCD_QAPI_H */ diff --git a/mcd/mcd_server.c b/mcd/mcd_server.c index 6e941f0..4d06c25 100644 --- a/mcd/mcd_server.c +++ b/mcd/mcd_server.c @@ -38,14 +38,17 @@ static mcd_error_info_st custom_mcd_error; /** * struct mcdserver_state - State of the MCD server * - * @last_error: Error info of most recent executed function. + * @last_error: Error info of most recent executed function. + * @open_server: Open server instance as allocated in mcd_open_server_f(). */ typedef struct mcdserver_state { const mcd_error_info_st *last_error; + mcd_server_st *open_server; } mcdserver_state; static mcdserver_state g_server_state = { .last_error = &MCD_ERROR_NONE, + .open_server = NULL, }; mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, @@ -87,7 +90,10 @@ mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, void mcd_exit_f(void) { - g_server_state.last_error = &MCD_ERROR_NONE; + if (g_server_state.open_server) { + mcd_close_server_f(g_server_state.open_server); + } + return; } @@ -95,7 +101,51 @@ mcd_return_et mcd_qry_servers_f(const char *host, bool running, uint32_t start_index, uint32_t *num_servers, mcd_server_info_st *server_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (start_index >= 1) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "QEMU only has one MCD server", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (!num_servers) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + if (!running) { + /* MCD server is always running */ + *num_servers = 0; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + if (*num_servers == 0) { + *num_servers = 1; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + /* num_servers != 0 => return server information */ + + if (!server_info) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + *server_info = (mcd_server_info_st) { + .server = "QEMU" + }; + snprintf(server_info->system_instance, MCD_UNIQUE_NAME_LEN, + "Process ID: %d", (int) getpid()); + + *num_servers = 1; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -103,13 +153,63 @@ mcd_return_et mcd_open_server_f(const char *system_key, const char *config_string, mcd_server_st **server) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (g_server_state.open_server) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "server already open", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (!server) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + g_server_state.open_server = g_malloc(sizeof(mcd_server_st)); + *g_server_state.open_server = (mcd_server_st) { + .instance = NULL, + .host = "QEMU", + .config_string = "", + }; + + *server = g_server_state.open_server; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } mcd_return_et mcd_close_server_f(const mcd_server_st *server) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (!g_server_state.open_server) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "server not open", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (server != g_server_state.open_server) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown server", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + g_free(g_server_state.open_server); + g_server_state.open_server = NULL; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } diff --git a/mcd/mcd_stub.c b/mcd/mcd_stub.c index 23db1cf..b237f9a 100644 --- a/mcd/mcd_stub.c +++ b/mcd/mcd_stub.c @@ -13,6 +13,39 @@ #include "mcd_qapi.h" #include "mcd/mcd-qapi-commands.h" +/** + * struct mcdstub_state - State of the MCD server stub + * + * @open_server: Open server instance as allocated in mcd_open_server_f(). + * @open_server_uid: Unique identifier of the open server. + */ +typedef struct mcdstub_state { + mcd_server_st *open_server; + uint32_t open_server_uid; +} mcdstub_state; + + +static mcdstub_state g_stub_state = { + .open_server = NULL, + .open_server_uid = 0, +}; + +static uint32_t store_open_server(mcd_server_st *server) +{ + g_stub_state.open_server = server; + g_stub_state.open_server_uid++; + return g_stub_state.open_server_uid; +} + +static mcd_server_st *retrieve_open_server(uint32_t server_uid) +{ + if (server_uid == g_stub_state.open_server_uid) { + return g_stub_state.open_server; + } else { + return NULL; + } +} + MCDInitializeResult *qmp_mcd_initialize(MCDAPIVersion *version_req, Error **errp) { @@ -36,6 +69,71 @@ void qmp_mcd_exit(Error **errp) mcd_exit_f(); } +MCDQryServersResult *qmp_mcd_qry_servers(const char *host, bool running, + uint32_t start_index, + uint32_t num_servers, Error **errp) +{ + MCDServerInfoList **tailp; + MCDServerInfo *info; + mcd_server_info_st *server_info = NULL; + bool query_num_only = num_servers == 0; + MCDQryServersResult *result = g_malloc0(sizeof(*result)); + + if (!query_num_only) { + server_info = g_malloc0(num_servers * sizeof(*server_info)); + } + + result->return_status = mcd_qry_servers_f(host, running, start_index, + &num_servers, server_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_servers = true; + result->num_servers = num_servers; + if (!query_num_only) { + result->has_server_info = true; + tailp = &(result->server_info); + for (uint32_t i = 0; i < num_servers; i++) { + info = marshal_mcd_server_info(server_info + i); + QAPI_LIST_APPEND(tailp, info); + } + } + } + + if (!query_num_only) { + g_free(server_info); + } + + return result; +} + +MCDOpenServerResult *qmp_mcd_open_server(const char *system_key, + const char *config_string, + Error **errp) +{ + MCDOpenServerResult *result = g_malloc0(sizeof(*result)); + mcd_server_st *server; + + result->return_status = mcd_open_server_f(system_key, config_string, + &server); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_server_uid = true; + result->server_uid = store_open_server(server); + result->host = g_strdup(server->host); + result->config_string = g_strdup(server->config_string); + } + + return result; +} + +MCDCloseServerResult *qmp_mcd_close_server(uint32_t server_uid, Error **errp) +{ + MCDCloseServerResult *result = g_malloc0(sizeof(*result)); + mcd_server_st *server = retrieve_open_server(server_uid); + result->return_status = mcd_close_server_f(server); + return result; +} + MCDErrorInfo *qmp_mcd_qry_error_info(Error **errp) { MCDErrorInfo *result; diff --git a/qapi/mcd.json b/qapi/mcd.json index 7b42a74..3cdfd5d 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -73,6 +73,24 @@ 'error-str' : 'str' }} +## +# @MCDServerInfo: +# +# Structure type containing the server information. +# +# @server: String containing the server name. +# @system-instance: String containing the unique system instance identifier. +# @acc-hw: String containing the unique device access hardware name. +# +# Since: 9.1 +## +{ 'struct': 'MCDServerInfo', + 'data': { + 'server' : 'str', + 'system-instance': 'str', + 'acc-hw' : 'str' } } + + ## # == Target Initialization API ## @@ -148,6 +166,193 @@ { 'command': 'mcd-exit' } +## +# == Server Connection API +## + + +## +# @MCDQryServersResult: +# +# Return value of @mcd-qry-servers. +# +# @return-status: Return code. +# @num-servers: The number of returned servers. In case the input value of +# @num-servers is '0', this is the number of all available +# servers. +# @server-info: Server information. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryServersResult', + 'data': { + 'return-status': 'uint32', + '*num-servers' : 'uint32', + '*server-info' : [ 'MCDServerInfo' ] }} + + +## +# @mcd-qry-servers: +# +# Function returning a list of available servers. +# +# @host: String containing the host name. +# @running: Selects between running and installed servers. +# @start-index: Start index of the queried servers. This refers to an +# internal list of the target side implementation. +# @num-servers: The number of queried servers starting from the defined +# @start-index. If it is set to '0', no server descriptions are +# returned but the number of all available servers. +# +# Returns: @MCDQryServersResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-qry-servers", +# "arguments": { "host": "", +# "running": true, +# "start-index": 0, +# "num-servers": 0 } } +# <- { +# "return": { +# "num-servers": 1, +# "return-status": 0 +# } +# } +# +# -> { "execute": "mcd-qry-servers", +# "arguments": { "host": "", +# "running": true, +# "start-index": 0, +# "num-servers": 1 } } +# <- { +# "return": { +# "num-servers": 1, +# "server-info": [ +# { +# "system-instance": "Process ID: 44801", +# "acc-hw": "", +# "server": "QEMU" +# } +# ], +# "return-status": 0 +# } +# } +## +{ 'command': 'mcd-qry-servers', + 'data': { + 'host' : 'str', + 'running' : 'bool', + 'start-index': 'uint32', + 'num-servers': 'uint32' }, + 'returns': 'MCDQryServersResult' } + + +## +# @MCDOpenServerResult: +# +# Return value of @mcd-open-server. +# +# @return-status: Return code. +# @server-uid: Unique identifier of the server instance. +# @host: String containing the host name. +# @config-string: Server configuration information. +# +# Since: 9.1 +## +{ 'struct': 'MCDOpenServerResult', + 'data': { + 'return-status' : 'uint32', + '*server-uid' : 'uint32', + '*host' : 'str', + '*config-string': 'str' } } + + +## +# @mcd-open-server: +# +# Function opening the connection to a server on a host computer. +# +# @system-key: A server is claimed by this key when being opened. +# @config-string: Allows the configuration of the server connection by a +# character string. Delimiters are blanks, tabs and line +# breaks. Value strings are always enclosed with "double +# quotes". Bool values can be "TRUE" or "FALSE" (both in +# small letters). +# +# Returns: @MCDOpenServerResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-open-server", +# "arguments": { "system-key": "", +# "config-string": "" } } +# <- { +# "return": { +# "config-string": "", +# "host": "QEMU", +# "server-uid": 1, +# "return-status": 0 +# } +# } +# -> { "execute": "mcd-open-server", +# "arguments": { "system-key": "", +# "config-string": "" } } +# <- { +# "return": { +# "return-status": 3 +# } +# } +# -> { "execute": "mcd-qry-error-info" } +# <- { +# "return": { +# "error-str": "server already open", +# "error-code": 512, +# "error-events": 0, +# "return-status": 3 +# } +# } +## +{ 'command': 'mcd-open-server', + 'data': { + 'system-key' : 'str', + 'config-string': 'str' }, + 'returns': 'MCDOpenServerResult' } + + +## +# @MCDCloseServerResult: +# +# Return value of @mcd-close-server. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDCloseServerResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-close-server: +# +# Function closing the connection to a debug server on a host computer. +# +# @server-uid: Unique identifier of the open server as returned by +# @mcd-open-server. +# +# Returns: @MCDCloseServerResult. +# +# Since: 9.1 +## +{ 'command': 'mcd-close-server', + 'data': { 'server-uid': 'uint32' }, + 'returns': 'MCDCloseServerResult' } + + ## # == Core Connection API ## diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index 9911804..708a474 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -132,6 +132,100 @@ static void test_initialize(void) mcdtest_quit(&qts); } +static void test_qry_servers(void) +{ + QTestStateMCD qts = mcdtest_init(QEMU_EXTRA_ARGS); + + char host[] = ""; + + q_obj_mcd_qry_servers_arg qapi_args = { + .host = host, + .running = true, + .start_index = 0, + .num_servers = 0, + }; + + MCDQryServersResult *result = qtest_mcd_qry_servers(&qts, &qapi_args); + g_assert(result->return_status == MCD_RET_ACT_NONE); + g_assert(result->has_num_servers); + g_assert(result->num_servers == 1); + g_assert(result->has_server_info == false); + + qapi_args.num_servers = result->num_servers; + qapi_free_MCDQryServersResult(result); + + result = qtest_mcd_qry_servers(&qts, &qapi_args); + + g_assert(result->return_status == MCD_RET_ACT_NONE); + g_assert(result->has_num_servers); + g_assert(result->num_servers == 1); + g_assert(result->has_server_info); + + if (verbose) { + MCDServerInfo *server_info = result->server_info->value; + fprintf(stderr, "[INFO]\tServer info: %s (%s)\n", + server_info->server, + server_info->system_instance); + } + + qapi_free_MCDQryServersResult(result); + mcdtest_quit(&qts); +} + +static void test_open_server(void) +{ + QTestStateMCD qts = mcdtest_init(QEMU_EXTRA_ARGS); + + char empty_string[] = ""; + + q_obj_mcd_open_server_arg open_server_args = { + .system_key = empty_string, + .config_string = empty_string, + }; + + q_obj_mcd_close_server_arg close_server_args; + + MCDOpenServerResult *open_server_result; + MCDCloseServerResult *close_server_result; + + open_server_result = qtest_mcd_open_server(&qts, &open_server_args); + g_assert(open_server_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_server_result->has_server_uid); + + close_server_args.server_uid = open_server_result->server_uid; + qapi_free_MCDOpenServerResult(open_server_result); + + /* Check that server cannot be opened twice */ + open_server_result = qtest_mcd_open_server(&qts, &open_server_args); + g_assert(open_server_result->return_status != MCD_RET_ACT_NONE); + + if (verbose) { + MCDErrorInfo *error_info = qtest_mcd_qry_error_info(&qts); + fprintf(stderr, "[INFO]\tServer cannot be opened twice: %s\n", + error_info->error_str); + qapi_free_MCDErrorInfo(error_info); + } + + qapi_free_MCDOpenServerResult(open_server_result); + close_server_result = qtest_mcd_close_server(&qts, &close_server_args); + g_assert(close_server_result->return_status == MCD_RET_ACT_NONE); + qapi_free_MCDCloseServerResult(close_server_result); + + /* Check that server cannot be closed twice */ + close_server_result = qtest_mcd_close_server(&qts, &close_server_args); + g_assert(close_server_result->return_status != MCD_RET_ACT_NONE); + + if (verbose) { + MCDErrorInfo *error_info = qtest_mcd_qry_error_info(&qts); + fprintf(stderr, "[INFO]\tServer cannot be closed twice: %s\n", + error_info->error_str); + qapi_free_MCDErrorInfo(error_info); + } + + qapi_free_MCDCloseServerResult(close_server_result); + mcdtest_quit(&qts); +} + int main(int argc, char *argv[]) { char *v_env = getenv("V"); @@ -140,5 +234,7 @@ int main(int argc, char *argv[]) qtest_add_func("mcd/initialize-mcdtest", test_initialize_mcdtest); qtest_add_func("mcd/initialize", test_initialize); + qtest_add_func("mcd/qry-servers", test_qry_servers); + qtest_add_func("mcd/open-server", test_open_server); return g_test_run(); } diff --git a/tests/qtest/mcd-util.c b/tests/qtest/mcd-util.c index 50c5d4e..3926b33 100644 --- a/tests/qtest/mcd-util.c +++ b/tests/qtest/mcd-util.c @@ -97,3 +97,63 @@ MCDErrorInfo *qtest_mcd_qry_error_info(QTestStateMCD *qts) return unmarshal; } + +MCDQryServersResult *qtest_mcd_qry_servers(QTestStateMCD *qts, + q_obj_mcd_qry_servers_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryServersResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_servers_arg); + + resp = qtest_mcd(qts, "{'execute': 'mcd-qry-servers'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryServersResult); + + return unmarshal; +} + +MCDOpenServerResult *qtest_mcd_open_server(QTestStateMCD *qts, + q_obj_mcd_open_server_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDOpenServerResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_open_server_arg); + + resp = qtest_mcd(qts, "{'execute': 'mcd-open-server'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDOpenServerResult); + + return unmarshal; +} + +MCDCloseServerResult *qtest_mcd_close_server(QTestStateMCD *qts, + q_obj_mcd_close_server_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDCloseServerResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_close_server_arg); + + resp = qtest_mcd(qts, "{'execute': 'mcd-close-server'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDCloseServerResult); + + return unmarshal; +} diff --git a/tests/qtest/mcd-util.h b/tests/qtest/mcd-util.h index 2cff29c..8ffafaa 100644 --- a/tests/qtest/mcd-util.h +++ b/tests/qtest/mcd-util.h @@ -24,4 +24,13 @@ MCDInitializeResult *qtest_mcd_initialize(QTestStateMCD *qts, MCDErrorInfo *qtest_mcd_qry_error_info(QTestStateMCD *qts); +MCDQryServersResult *qtest_mcd_qry_servers(QTestStateMCD *qts, + q_obj_mcd_qry_servers_arg *args); + +MCDOpenServerResult *qtest_mcd_open_server(QTestStateMCD *qts, + q_obj_mcd_open_server_arg *args); + +MCDCloseServerResult *qtest_mcd_close_server(QTestStateMCD *qts, + q_obj_mcd_close_server_arg *args); + #endif /* TEST_MCD_UTILS_H */ -- 2.34.1