Example program
QNX SDP8.0SMMUMAN User's GuideAPIConfigurationUtilities
The following is an example program that connects to the smmuman service and monitors IOMMU/SMMU transgressions reported by the service.
This program is taken from a system that maps all DMA devices in the
smmuman startup configuration
(see
Startup mappings). It monitors transgressions reported by the smmuman service, but doesn't create SMMU objects or memory mappings:
#ifdef __USAGE
%C - SMMU violations monitor
Syntax:
%C
Options:
-v verbosity
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <smmu.h>
#include <inttypes.h>
#include <sys/neutrino.h>
#include <sys/siginfo.h>
#include <sys/slogcodes.h>
#include <sys/procmgr.h>
#define PULSE_CODE_SMMU_VIOLATION 0
#define _SLOGC_SMMUMON (_SLOGC_PRIVATE_END - 6)
static int verbosity_level = 0;
static int smmumon_slogf(int severity, int verbosity, int vlevel, const char *fmt, ...)
{
int ret;
va_list arglist;
ret = 0;
if (severity <= _SLOG_ERROR || verbosity > 5) {
va_start(arglist, fmt);
vfprintf(stderr, fmt, arglist);
va_end(arglist);
fprintf(stderr, "\n");
}
if (vlevel <= 4 || verbosity >= vlevel) {
va_start(arglist, fmt);
ret = vslogf(_SLOGC_SMMUMON, severity, fmt, arglist);
va_end(arglist);
}
return (ret);
}
static void options(int argc, char **argv)
{
int opt;
while (optind < argc)
{
while ((opt = getopt(argc, argv, "v")) != -1)
{
switch (opt)
{
case 'v':
if (verbosity_level < 20) {
verbosity_level++;
}
break;
default:
smmumon_slogf(
_SLOG_ERROR, 1, 0,
"options: unexpected parameter\n");
exit(-1);
}
}
}
}
static int process_all_violations(void)
{
int result;
for(;;) {
struct smmu_status status;
result = smmu_xfer_status(&status);
if (result == -1) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"process_all_violations: smmu_xfer_status failed, errno=%d\n",
errno);
return -1;
}
if (result == 0)
{
return 0;
}
if (result != 1) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"process_all_violations: unexpected result from smmu_xfer_status,"
" result=%d\n", result);
return -1;
}
switch(status.devid.type) {
case SDT_PCI: {
smmumon_slogf(
_SLOG_CRITICAL, verbosity_level, 0,
"pci device violation detected : "
"fault_addr=0x%" PRIx64 " "
"hw_specific=0x%" PRIx64 " "
"flags=0x%x "
"pci bdf=%d:%d:%d"
"\n",
status.fault_addr,
status.hw_specific,
status.flags,
status.devid.pci.bus,
status.devid.pci.dev,
status.devid.pci.func);
break;
}
case SDT_MMIO: {
smmumon_slogf(
_SLOG_CRITICAL, verbosity_level, 0,
"mmio device violation detected : "
"fault_addr=0x%" PRIx64 " "
"hw_specific=0x%" PRIx64 " "
"flags=0x%x "
"mmio.phys=0x%" PRIx64 " "
"mmio.length=0x%x"
"\n",
status.fault_addr,
status.hw_specific,
status.flags,
status.devid.mmio.phys,
status.devid.mmio.length);
break;
}
default:
{
smmumon_slogf(
_SLOG_CRITICAL, verbosity_level, 0,
"unknown device type violation detected, "
"type=%d : "
"fault_addr=0x%" PRIx64 " "
"hw_specific=0x%" PRIx64 " "
"flags=0x%x "
"\n",
status.devid.type,
status.fault_addr,
status.hw_specific,
status.flags);
break;
}
}
}
return -1;
}
static int wait_for_violations(int channel, int coid)
{
int result;
struct sigevent event;
SIGEV_PULSE_INIT(&event, coid, -1, PULSE_CODE_SMMU_VIOLATION, NULL);
result = MsgRegisterEvent(&event,-1);
if (result!=0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"wait_for_violations: MsgRegisteredEvent failed , errno=%d\n",
errno);
return -1;
}
result = smmu_xfer_notify(&event);
if (result!=0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"wait_for_violations: smmu_xfer_notify-1 failed , errno=%d\n",
errno);
return -1;
}
for(;;) {
struct _pulse pulse;
result = MsgReceivePulse(channel, &pulse, sizeof(pulse), NULL);
if (result != 0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"wait_for_violations: MsgReceivePulse failed, errno=%d\n",
errno);
return -1;
}
if (pulse.code != PULSE_CODE_SMMU_VIOLATION) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"wait_for_violations: unexpected pulse.code=%d\n",
pulse.code);
return -1;
}
result = smmu_xfer_notify(&event);
if (result!=0) {
process_all_violations();
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"wait_for_violations: smmu_xfer_notify-2 failed , errno=%d\n",
errno);
return -1;
}
result = process_all_violations();
if (result != 0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"wait_for_violations: process_all_violations failed, errno=%d\n",
errno);
return -1;
}
}
return -1;
}
static int connect_attach_channel_and_process(int channel)
{
int coid;
coid = ConnectAttach_r(0, 0, channel, _NTO_SIDE_CHANNEL, 0);
if(coid < 0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"connect_attach_channel_and_process : ConnectAttach_r %d\n",
-coid);
return -1;
}
int result;
result = wait_for_violations(channel,coid);
ConnectDetach_r(coid);
return result;
}
static int open_channel_and_process(void)
{
int channel;
channel = ChannelCreate_r(0);
if(channel < 0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"open_channel_and_process: ChannelCreate_r failed: %d\n",
-channel);
return -1;
}
int result;
result = connect_attach_channel_and_process(channel);
ChannelDestroy_r(channel);
return result;
}
int main(int argc, char *argv[])
{
int result;
options(argc,argv);
result = procmgr_daemon( 0,
PROCMGR_DAEMON_NODEVNULL | PROCMGR_DAEMON_NOCLOSE);
if (result < 0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"main: procmgr_daemon failed : %s\n", strerror(errno));
return -1;
}
result = smmu_init(0);
if (result != 0) {
smmumon_slogf(
_SLOG_ERROR, verbosity_level, 0,
"main: smmu_init failed, errno=%d\n",errno);
return -1;
}
result = open_channel_and_process();
smmu_fini();
return result;
}
Page updated: