DBT-RISE-TGC/src/iss/semihosting/semihosting.cpp

681 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "semihosting.h"
#include <iss/vm_types.h>
#include <stdexcept>
template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter) {
switch(call_number) {
case SEMIHOSTING_ENTER_SVC: {
throw std::runtime_error("Semihosting Call not Implemented");
} /* DEPRECATED */
case SEMIHOSTING_SYS_CLOCK: {
/*
* Returns the number of centiseconds (hundredths of a second)
* since the execution started.
*
* Values returned can be of limited use for some benchmarking
* purposes because of communication overhead or other
* agent-specific factors. For example, with a debug hardware
* unit the request is passed back to the host for execution.
* This can lead to unpredictable delays in transmission and
* process scheduling.
*
* Use this function to calculate time intervals, by calculating
* differences between intervals with and without the code
* sequence to be timed.
*
* Entry
* The PARAMETER REGISTER must contain 0. There are no other
* parameters.
*
* Return
* On exit, the RETURN REGISTER contains:
* - The number of centiseconds since some arbitrary start
* point, if the call is successful.
* - 1 if the call is not successful. For example, because
* of a communications error.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_CLOSE: {
/*
* Closes a file on the host system. The handle must reference
* a file that was opened with SYS_OPEN.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* one-field argument block:
* - field 1 Contains a handle for an open file.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the call is successful
* - 1 if the call is not successful.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_ELAPSED: {
/*
* Returns the number of elapsed target ticks since execution
* started.
* Use SYS_TICKFREQ to determine the tick frequency.
*
* Entry (32-bit)
* On entry, the PARAMETER REGISTER points to a two-field data
* block to be used for returning the number of elapsed ticks:
* - field 1 The least significant field and is at the low address.
* - field 2 The most significant field and is at the high address.
*
* Entry (64-bit)
* On entry the PARAMETER REGISTER points to a one-field data
* block to be used for returning the number of elapsed ticks:
* - field 1 The number of elapsed ticks as a 64-bit value.
*
* Return
* On exit:
* - On success, the RETURN REGISTER contains 0, the PARAMETER
* REGISTER is unchanged, and the data block pointed to by the
* PARAMETER REGISTER is filled in with the number of elapsed
* ticks.
* - On failure, the RETURN REGISTER contains -1, and the
* PARAMETER REGISTER contains -1.
*
* Note: Some semihosting implementations might not support this
* semihosting operation, and they always return -1 in the
* RETURN REGISTER.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_ERRNO: {
/*
* Returns the value of the C library errno variable that is
* associated with the semihosting implementation. The errno
* variable can be set by a number of C library semihosted
* functions, including:
* - SYS_REMOVE
* - SYS_OPEN
* - SYS_CLOSE
* - SYS_READ
* - SYS_WRITE
* - SYS_SEEK.
*
* Whether errno is set or not, and to what value, is entirely
* host-specific, except where the ISO C standard defines the
* behavior.
*
* Entry
* There are no parameters. The PARAMETER REGISTER must be 0.
*
* Return
* On exit, the RETURN REGISTER contains the value of the C
* library errno variable.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_EXIT: {
/*
* Note: SYS_EXIT was called angel_SWIreason_ReportException in
* previous versions of the documentation.
*
* An application calls this operation to report an exception
* to the debugger directly. The most common use is to report
* that execution has completed, using ADP_Stopped_ApplicationExit.
*
* Note: This semihosting operation provides no means for 32-bit
* callers to indicate an application exit with a specified exit
* code. Semihosting callers may prefer to check for the presence
* of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use
* the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it
* is available.
*
* Entry (32-bit)
* On entry, the PARAMETER register is set to a reason code
* describing the cause of the trap. Not all semihosting client
* implementations will necessarily trap every corresponding
* event. Important reason codes are:
*
* - ADP_Stopped_ApplicationExit 0x20026
* - ADP_Stopped_RunTimeErrorUnknown 0x20023
*
* Entry (64-bit)
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field argument block:
* - field 1 The exception type, which is one of the set of
* reason codes in the above tables.
* - field 2 A subcode, whose meaning depends on the reason
* code in field 1.
* In particular, if field 1 is ADP_Stopped_ApplicationExit
* then field 2 is an exit status code, as passed to the C
* standard library exit() function. A simulator receiving
* this request must notify a connected debugger, if present,
* and then exit with the specified status.
*
* Return
* No return is expected from these calls. However, it is
* possible for the debugger to request that the application
* continues by performing an RDI_Execute request or equivalent.
* In this case, execution continues with the registers as they
* were on entry to the operation, or as subsequently modified
* by the debugger.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_EXIT_EXTENDED: {
/*
* This operation is only supported if the semihosting extension
* SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is
* reported using feature byte 0, bit 0. If this extension is
* supported, then the implementation provides a means to
* report a normal exit with a nonzero exit status in both 32-bit
* and 64-bit semihosting APIs.
*
* The implementation must provide the semihosting call
* SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs.
*
* SYS_EXIT_EXTENDED is used by an application to report an
* exception or exit to the debugger directly. The most common
* use is to report that execution has completed, using
* ADP_Stopped_ApplicationExit.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field argument block:
* - field 1 The exception type, which should be one of the set
* of reason codes that are documented for the SYS_EXIT
* (0x18) call. For example, ADP_Stopped_ApplicationExit.
* - field 2 A subcode, whose meaning depends on the reason
* code in field 1. In particular, if field 1 is
* ADP_Stopped_ApplicationExit then field 2 is an exit status
* code, as passed to the C standard library exit() function.
* A simulator receiving this request must notify a connected
* debugger, if present, and then exit with the specified status.
*
* Return
* No return is expected from these calls.
*
* For the A64 API, this call is identical to the behavior of
* the mandatory SYS_EXIT (0x18) call. If this extension is
* supported, then both calls must be implemented.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_FLEN: {
/*
* Returns the length of a specified file.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* one-field argument block:
* - field 1 A handle for a previously opened, seekable file
* object.
*
* Return
* On exit, the RETURN REGISTER contains:
* - The current length of the file object, if the call is
* successful.
* - 1 if an error occurs.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_GET_CMDLINE: {
/*
* Returns the command line that is used for the call to the
* executable, that is, argc and argv.
*
* Entry
* On entry, the PARAMETER REGISTER points to a two-field data
* block to be used for returning the command string and its length:
* - field 1 A pointer to a buffer of at least the size that is
* specified in field 2.
* - field 2 The length of the buffer in bytes.
*
* Return
* On exit:
* If the call is successful, then the RETURN REGISTER contains 0,
* the PARAMETER REGISTER is unchanged, and the data block is
* updated as follows:
* - field 1 A pointer to a null-terminated string of the command
* line.
* - field 2 The length of the string in bytes.
* If the call is not successful, then the RETURN REGISTER
* contains -1.
*
* Note: The semihosting implementation might impose limits on
* the maximum length of the string that can be transferred.
* However, the implementation must be able to support a
* command-line length of at least 80 bytes.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_HEAPINFO: {
/*
* Returns the system stack and heap parameters.
*
* Entry
* On entry, the PARAMETER REGISTER contains the address of a
* pointer to a four-field data block. The contents of the data
* block are filled by the function. The following C-like
* pseudocode describes the layout of the block:
* struct block {
* void* heap_base;
* void* heap_limit;
* void* stack_base;
* void* stack_limit;
* };
*
* Return
* On exit, the PARAMETER REGISTER is unchanged and the data
* block has been updated.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_ISERROR: {
/*
* Determines whether the return code from another semihosting
* call is an error status or not.
*
* This call is passed a parameter block containing the error
* code to examine.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* one-field data block:
* - field 1 The required status word to check.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the status field is not an error indication
* - A nonzero value if the status field is an error indication.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_ISTTY: {
/*
* Checks whether a file is connected to an interactive device.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* one-field argument block:
* field 1 A handle for a previously opened file object.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 1 if the handle identifies an interactive device.
* - 0 if the handle identifies a file.
* - A value other than 1 or 0 if an error occurs.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_OPEN: {
/*
* Opens a file on the host system.
*
* The file path is specified either as relative to the current
* directory of the host process, or absolute, using the path
* conventions of the host operating system.
*
* Semihosting implementations must support opening the special
* path name :semihosting-features as part of the semihosting
* extensions reporting mechanism.
*
* ARM targets interpret the special path name :tt as meaning
* the console input stream, for an open-read or the console
* output stream, for an open-write. Opening these streams is
* performed as part of the standard startup code for those
* applications that reference the C stdio streams. The
* semihosting extension SH_EXT_STDOUT_STDERR allows the
* semihosting caller to open separate output streams
* corresponding to stdout and stderr. This extension is
* reported using feature byte 0, bit 1. Use SYS_OPEN with
* the special path name :semihosting-features to access the
* feature bits.
*
* If this extension is supported, the implementation must
* support the following additional semantics to SYS_OPEN:
* - If the special path name :tt is opened with an fopen
* mode requesting write access (w, wb, w+, or w+b), then
* this is a request to open stdout.
* - If the special path name :tt is opened with a mode
* requesting append access (a, ab, a+, or a+b), then this is
* a request to open stderr.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* three-field argument block:
* - field 1 A pointer to a null-terminated string containing
* a file or device name.
* - field 2 An integer that specifies the file opening mode.
* - field 3 An integer that gives the length of the string
* pointed to by field 1.
*
* The length does not include the terminating null character
* that must be present.
*
* Return
* On exit, the RETURN REGISTER contains:
* - A nonzero handle if the call is successful.
* - 1 if the call is not successful.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_READ: {
/*
* Reads the contents of a file into a buffer. The file position
* is specified either:
* - Explicitly by a SYS_SEEK.
* - Implicitly one byte beyond the previous SYS_READ or
* SYS_WRITE request.
*
* The file position is at the start of the file when it is
* opened, and is lost when the file is closed. Perform the
* file operation as a single action whenever possible. For
* example, do not split a read of 16KB into four 4KB chunks
* unless there is no alternative.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* three-field data block:
* - field 1 Contains a handle for a file previously opened
* with SYS_OPEN.
* - field 2 Points to a buffer.
* - field 3 Contains the number of bytes to read to the buffer
* from the file.
*
* Return
* On exit, the RETURN REGISTER contains the number of bytes not
* filled in the buffer (buffer_length - bytes_read) as follows:
* - If the RETURN REGISTER is 0, the entire buffer was
* successfully filled.
* - If the RETURN REGISTER is the same as field 3, no bytes
* were read (EOF can be assumed).
* - If the RETURN REGISTER contains a value smaller than
* field 3, the read succeeded but the buffer was only partly
* filled. For interactive devices, this is the most common
* return value.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_READC: {
/*
* Reads a byte from the console.
*
* Entry
* The PARAMETER REGISTER must contain 0. There are no other
* parameters or values possible.
*
* Return
* On exit, the RETURN REGISTER contains the byte read from
* the console.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_REMOVE: {
/*
* Deletes a specified file on the host filing system.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field argument block:
* - field 1 Points to a null-terminated string that gives the
* path name of the file to be deleted.
* - field 2 The length of the string.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the delete is successful
* - A nonzero, host-specific error code if the delete fails.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_RENAME: {
/*
* Renames a specified file.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* four-field data block:
* - field 1 A pointer to the name of the old file.
* - field 2 The length of the old filename.
* - field 3 A pointer to the new filename.
* - field 4 The length of the new filename. Both strings are
* null-terminated.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the rename is successful.
* - A nonzero, host-specific error code if the rename fails.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_SEEK: {
/*
* Seeks to a specified position in a file using an offset
* specified from the start of the file. The file is assumed
* to be a byte array and the offset is given in bytes.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field data block:
* - field 1 A handle for a seekable file object.
* - field 2 The absolute byte position to seek to.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the request is successful.
* - A negative value if the request is not successful.
* Use SYS_ERRNO to read the value of the host errno variable
* describing the error.
*
* Note: The effect of seeking outside the current extent of
* the file object is undefined.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_SYSTEM: {
/*
* Passes a command to the host command-line interpreter.
* This enables you to execute a system command such as dir,
* ls, or pwd. The terminal I/O is on the host, and is not
* visible to the target.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field argument block:
* - field 1 Points to a string to be passed to the host
* command-line interpreter.
* - field 2 The length of the string.
*
* Return
* On exit, the RETURN REGISTER contains the return status.
*/
/* Provide SYS_SYSTEM functionality. Uses the
* libc system command, there may be a reason *NOT*
* to use this, but as I can't think of one, I
* implemented it this way.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_TICKFREQ: {
/*
* Returns the tick frequency.
*
* Entry
* The PARAMETER REGISTER must contain 0 on entry to this routine.
*
* Return
* On exit, the RETURN REGISTER contains either:
* - The number of ticks per second.
* - 1 if the target does not know the value of one tick.
*
* Note: Some semihosting implementations might not support
* this semihosting operation, and they always return -1 in the
* RETURN REGISTER.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_TIME: {
/*
* Returns the number of seconds since 00:00 January 1, 1970.
* This value is real-world time, regardless of any debug agent
* configuration.
*
* Entry
* There are no parameters.
*
* Return
* On exit, the RETURN REGISTER contains the number of seconds.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_TMPNAM: {
/*
* Returns a temporary name for a file identified by a system
* file identifier.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* three-word argument block:
* - field 1 A pointer to a buffer.
* - field 2 A target identifier for this filename. Its value
* must be an integer in the range 0-255.
* - field 3 Contains the length of the buffer. The length must
* be at least the value of L_tmpnam on the host system.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the call is successful.
* - 1 if an error occurs.
*
* The buffer pointed to by the PARAMETER REGISTER contains
* the filename, prefixed with a suitable directory name.
* If you use the same target identifier again, the same
* filename is returned.
*
* Note: The returned string must be null-terminated.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_WRITE: {
/*
* Writes the contents of a buffer to a specified file at the
* current file position. The file position is specified either:
* - Explicitly, by a SYS_SEEK.
* - Implicitly as one byte beyond the previous SYS_READ or
* SYS_WRITE request.
*
* The file position is at the start of the file when the file
* is opened, and is lost when the file is closed.
*
* Perform the file operation as a single action whenever
* possible. For example, do not split a write of 16KB into
* four 4KB chunks unless there is no alternative.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* three-field data block:
* - field 1 Contains a handle for a file previously opened
* with SYS_OPEN.
* - field 2 Points to the memory containing the data to be written.
* - field 3 Contains the number of bytes to be written from
* the buffer to the file.
*
* Return
* On exit, the RETURN REGISTER contains:
* - 0 if the call is successful.
* - The number of bytes that are not written, if there is an error.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_WRITEC: {
/*
* Writes a character byte, pointed to by the PARAMETER REGISTER,
* to the debug channel. When executed under a semihosting
* debugger, the character appears on the host debugger console.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to the
* character.
*
* Return
* None. The RETURN REGISTER is corrupted.
*/
throw std::runtime_error("Semihosting Call not Implemented");
}
case SEMIHOSTING_SYS_WRITE0: {
/*
* Writes a null-terminated string to the debug channel.
* When executed under a semihosting debugger, the characters
* appear on the host debugger console.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to the
* first byte of the string.
*
* Return
* None. The RETURN REGISTER is corrupted.
*/
uint8_t character;
while(1) {
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character);
if(res != iss::Ok)
return;
if(character == 0)
break;
putchar(character);
parameter++;
}
}
case SEMIHOSTING_USER_CMD_0x100: {
/**
*
* This is a user defined operation (while user cmds 0x100-0x1ff
* are possible, none are currently implemented).
*
* Reads the user operation parameters from target, then fires the
* corresponding target event. When the target callbacks returned,
* cleans up the command parameter buffer.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field data block:
* - field 1 Contains a pointer to the bound command parameter
* string
* - field 2 Contains the command parameter string length
*
* Return
* On exit, the RETURN REGISTER contains the return status.
*/
throw std::runtime_error("Semihosting Call not Implemented");
} /* First user cmd op code */
case SEMIHOSTING_USER_CMD_0x1FF: {
/**
*
* This is a user defined operation (while user cmds 0x100-0x1ff
* are possible, none are currently implemented).
*
* Reads the user operation parameters from target, then fires the
* corresponding target event. When the target callbacks returned,
* cleans up the command parameter buffer.
*
* Entry
* On entry, the PARAMETER REGISTER contains a pointer to a
* two-field data block:
* - field 1 Contains a pointer to the bound command parameter
* string
* - field 2 Contains the command parameter string length
*
* Return
* On exit, the RETURN REGISTER contains the return status.
*/
throw std::runtime_error("Semihosting Call not Implemented");
} /* Last user cmd op code */
default:
throw std::runtime_error("Semihosting Call not Implemented");
}
}
template void semihosting_callback<uint32_t>(iss::arch_if* arch_if_ptr, uint32_t call_number, uint32_t parameter);
template void semihosting_callback<uint64_t>(iss::arch_if* arch_if_ptr, uint64_t call_number, uint64_t parameter);