Apex Universal Library and Kernel Module Reporting Information
In this discussion we will go over the lib_report demo application which will provide significant detail regarding the library and kernel module as listed below. This discussion assumes that you have the kernel module installed (insmod) and the demo_basic source ready for compilation. We are also assuming that the Eclipse workspace is all setup and is in its original form; if this is not the case, simply extract a new copy to another folder of your choice. We will discuss each one of these in detail as well as indicate why we provide these features.
- Library name and revision
- Human readable summary list of all modules within the library "aul_module_list.csv".
- Human readable list of all IOCTL commands within the library and driver space "aul_command_list.csv".
- Enumerated list of all IOCTL commands "aul_command_enum.h" which can be used by applications.
- Enumerated list of all error/status codes "aul_status_enum.h" which can be used by applications.
- List of all logical devices available "aul_device_logical_enum.h" which can be used by applications.
- List of all internal revision information "aul_integrity.c".
There are several ways we can compile run and exercise this demo code: (i) at the terminal and (ii) using Eclipse using debugger. In this discussion will stick with the terminal mode as it is the most basic way to bring up and run this application. Here are the general steps:
- move to the folder "~/aes_eclipse/lib_report/_Out_Debug_Out_Debug" (without quotes)
- execute the make file: "make clean" (without quotes)
- execute the make file: "make all" (without quotes)
- now run the program: "./Demo_Basic" (without quotes)
Here is an illustration:
user@Ubuntu32vb:~/aes_eclipse/lib_report/_Out_Debug$ make clean <-- remove prior build.
user@Ubuntu32vb:~/aes_eclipse/lib_report/_Out_Debug$ make all <-- compile the code.
user@Ubuntu32vb:~/aes_eclipse/lib_report/_Out_Debug$ ./lib_report <-- run the code.
Please refer to lib_report.c and acgr.h files as we move through this discussion. I would suggest having the lib_report.c file on one screen while reading this blog on a second screen or similar setup.
Library Name and Revision
There are two functions shown below that can be used to return the static library name and its revision. These can be used together at run time to verify that the correct library revision has been compiled up with the application; if the revision or library name does not match the correct values or ranges expected by the user application, then the application can error out and report this issue. This offers a great mechanism to enforce revisions between user application and the AUL static or dynamic library (depending on compilation and target).
The first printf() statement on line 135 reports the library that is statically compiled to the lib_report application. The library name is retrieved using the function AUL_Library_Name(). It is used to aid the developer in determining which library, auldebug.a (debug) or aul.a (release) is statically compiled into the application. Refer to demo_basic for further information.
const char * AUL_Library_Name( void );
The function AUL_Library_Revision() on line 136 retrieves the revision of the library.
int AUL_Library_Revision( unsigned long * revision );
The revision is reported in a "YYMMDDHHmm" format; where "YY" is the year, "MM" is the month, "DD" is the day, "HH" is the hour (in 24 hour) and "mm" is the time in minutes. This revision time stamp is auto-created at time of library compilation.
The library has been design with the notion of software modules. What we mean by modules is that major functional sections are broken into separate modules that can be added or removed. The concept is that it offers additional structures for managing the code base. The function ACGR_Report_CSV_Module() will produce a CSV file with a list of all the software modules within the library and kernel driver.
int ACGR_Report_CSV_Module( size_t column_names_include, const char * file_name );
Line 167 of the lib_reports.c the function ACGR_Report_CSV_Module() runs this report and delivers it to the file "aul_module_list.csv". If an error is encountered, the code will jump to the end. A sample of the output can be found here: aul_module_list.csv. The column_names_include parameter, if TRUE will produce the column header in the first row; else no column header row will be produced.
The generated file will contain 6-columns of information: name, ID, type, module_ts, command_ts, and status_ts. The name and ID columns describe the name and ID of the module. Module type column describes what kind of module it is. There are three types of modules: device, component and module. A device module defines a top level device such as an STX104 or Tracer board. A device is composed of one or more components. Modules of type module are software modules that provide internal support. The columns module_ts, command_ts and status_ts define the revision date codes of the module and its associated command and status source files. Every module will have a set of commands and status (or error codes); and so all columns with a "_TS" suffix indicate a time stamp of a module, commands or status. The time stamp is another way for the application to further verify library and driver revision. This is primarily for the software developer and maintainer in module revision verification.
Line 153 AUL_Initialization() initializes the library and opens the underlying kernel driver. Further details can be found in the demo_basic tutorial. At this point, the underlying kernel driver has been intialized and opened.
The library and driver have a list of commands that can grow and shrink with as the number of modules is added or removed. Therefore, there needs to be a way for the user to retrieve the latest list of commands that will be used by the users application to communicate with the library. This information can be output in two forms: CSV file or as a standard C header file which can be subsequently used within the user application. The commands are contained within the majority of the upper layer library functions, it is when you wish to use the lower level functions that will require a command and for the driver you will need to send an IOCTL command. For example, the CMD_AULDRV_ID command is used in a driver IOCTL call to retrieve the kernel module ID.
Within the lib_report.c line 183, the function ACGR_Report_CSV_Command() performs the generation of the command CSV file. If parameter column_names_include is set to TRUE, then the column header names are created on the first row of the file. Here is an example of the the file aul_command_list.csv.
int ACGR_Report_CSV_Command( size_t column_names_include, const char * file_name );
Within the lib_report.c line 217, the function ACGR_Source_File_Command_Enumeration() performs the generation of the command header file which is simply an enumerated list along with a date and time stamp at the top of the file.
int ACGR_Source_File_Command_Enumeration( const char * file_name );
Here is an example of the aul_command_enum.h output file. This file can be used within an application. You will notice that all commands have a "CMD_" so that the enumeration remains unique.
Enumerated Error List
All enumerated error codes have symbol names with an "EC_" prefix to maintain uniqueness. You can produce a human readable form of any error code by simply passing the error code to AUL_Error_String().
Within the lib_report.c line 199 contains the ACGR_Report_CSV_Status() function and line 235 contains the ACGR_Source_File_Status_Enumeration() function, both produce a complete list of error codes used within the library and kernel module. All error code values are determined by adding an offset EC_OFFSET found in the status_macros.h file in the shared folder. The purpose of this offset is to keep the error codes outside of any OS related error codes. In the event that we wish to return OS kinds of error codes within the kernel module it will be easily possible to support that.
The ACGR_Report_CSV_Status() function will produce a CSV report. If column_names_include is TRUE, then the first row will contain column names. The report will have a SYMBOL, MODULE_NAME, VALUE and MESSAGE columns. The SYMBOL column indicates the enumerated symbol name; in other words this symbol represents the number shown in the VALUE column. The MESSAGE column is the human readable format of the error code. The MODULE_NAME column is the module name from which the error codes are created. Here is an example file aul_status_list.csv.
int ACGR_Report_CSV_Status( size_t column_names_include, const char * file_name );
The ACGR_Source_File_Status_Enumeration() function produces a header file with all the same status (error codes) found in the CSV report. Here is an example file aul_status_enum.h. An auto-generated date and file name is added to the top of the file. Any functions returning an error code will return one of these error codes. A no fail or success error code is always zero and the enumerated symbol SUCCESS is used.
int ACGR_Source_File_Status_Enumeration( const char * file_name );
Logical Device ID
The function ACGR_Source_File_Device_Logical_Enumeration() shown in lib_report line 259 will generate an enumerated list of devices and the output file is a header file. This enumeration contains a unique ID for each device. This is not currently used by any top layer functions, but in the future that may change. It finds use primarily in the functions with the "Device_" prefix in the name. The file aul_device_logical_enum.h is an example.
int ACGR_Source_File_Device_Logical_Enumeration( const char * file_name );
The function produces a C file, for example aul_integrity.c, which contains an array of aul_integrity_type type data structures that contain module IDs and time stamps very similar to file generated by the ACGR_Report_CSV_Module(). In fact, the output of the ACGR_Source_File_Integrity() can be used by user application to quickly confirm that the application and library and kernel module match up exactly as expected.
int ACGR_Source_File_Integrity( const char * file_name );
The aul_integrity_list of data structures generated by ACGR_Source_File_Integrity() can then be passed into the ACGR_Integrity_Test() by the application for a quick finger print match test.
int ACGR_Integrity_Test( const aul_integrity_type * integrity_list );
where the integrity_list is found within the C file output by the ACGR_Source_File_Integrity()
End Of Application
Finally, it is time to close the kernel driver, line 302 of the lib_report.c, and the library. Here we use the function AUL_Termination() to perform this task and is defined as:
int AUL_Termination( void );
The AUL_Termination() function only needs to be called if the AUL_Initialization() function was completed successfully. If an error occurs we can use the same AUL_Error_String() function to retrieve a human readable form of the error code.
The lib_report program provides detailed information to support the user application both in terms of commands and errors, as well as verifying/finger-print Apex provided software to existing customer application. There are several functions that auto-generate source and header files for use within the user application. Thus, if a revision occurs, one can quickly regenerate the enumerated lists and constant library integrity test data structures.