diff options
author | Achin Gupta <achin.gupta@arm.com> | 2013-10-25 09:08:21 +0100 |
---|---|---|
committer | James Morrissey <james.morrissey@arm.com> | 2013-10-25 09:37:16 +0100 |
commit | 4f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a56 (patch) | |
tree | 475db5d74370cb62b02afab0900774955a59702f /lib/semihosting |
ARMv8 Trusted Firmware release v0.2
Diffstat (limited to 'lib/semihosting')
-rw-r--r-- | lib/semihosting/aarch64/semihosting_call.S | 37 | ||||
-rw-r--r-- | lib/semihosting/semihosting.c | 234 |
2 files changed, 271 insertions, 0 deletions
diff --git a/lib/semihosting/aarch64/semihosting_call.S b/lib/semihosting/aarch64/semihosting_call.S new file mode 100644 index 00000000..cc72ec21 --- /dev/null +++ b/lib/semihosting/aarch64/semihosting_call.S @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + .globl semihosting_call + + .section .text, "ax" + +semihosting_call:; .type semihosting_call, %function + hlt #0xf000 + ret diff --git a/lib/semihosting/semihosting.c b/lib/semihosting/semihosting.c new file mode 100644 index 00000000..558973ac --- /dev/null +++ b/lib/semihosting/semihosting.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2013, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <semihosting.h> + +#ifndef SEMIHOSTING_SUPPORTED +#define SEMIHOSTING_SUPPORTED 1 +#endif + +extern int semihosting_call(unsigned int operation, + void *system_block_address); + +typedef struct { + const char *file_name; + unsigned int mode; + unsigned int name_length; +} smh_file_open_block; + +typedef struct { + int handle; + void *buffer; + unsigned int length; +} smh_file_read_write_block; + +typedef struct { + int handle; + unsigned int location; +} smh_file_seek_block; + +typedef struct { + char *command_line; + unsigned int command_length; +} smh_system_block; + +int semihosting_connection_supported(void) +{ + return SEMIHOSTING_SUPPORTED; +} + +int semihosting_file_open(const char *file_name, unsigned int mode) +{ + smh_file_open_block open_block; + + open_block.file_name = file_name; + open_block.mode = mode; + open_block.name_length = strlen(file_name); + + return semihosting_call(SEMIHOSTING_SYS_OPEN, + (void *) &open_block); +} + +int semihosting_file_seek(int file_handle, unsigned int offset) +{ + smh_file_seek_block seek_block; + int result; + + seek_block.handle = file_handle; + seek_block.location = offset; + + result = semihosting_call(SEMIHOSTING_SYS_SEEK, + (void *) &seek_block); + + if (result) + result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); + + return result; +} + +int semihosting_file_read(int file_handle, int *length, void *buffer) +{ + smh_file_read_write_block read_block; + int result = -EINVAL; + + if ((length == NULL) || (buffer == NULL)) + return result; + + read_block.handle = file_handle; + read_block.buffer = buffer; + read_block.length = *length; + + result = semihosting_call(SEMIHOSTING_SYS_READ, + (void *) &read_block); + + if (result == *length) { + return -EINVAL; + } else if (result < *length) { + *length -= result; + return 0; + } else + return result; +} + +int semihosting_file_write(int file_handle, int *length, void *buffer) +{ + smh_file_read_write_block write_block; + + if ((length == NULL) || (buffer == NULL)) + return -EINVAL; + + write_block.handle = file_handle; + write_block.buffer = buffer; + write_block.length = *length; + + *length = semihosting_call(SEMIHOSTING_SYS_WRITE, + (void *) &write_block); + + return *length; +} + +int semihosting_file_close(int file_handle) +{ + return semihosting_call(SEMIHOSTING_SYS_CLOSE, + (void *) &file_handle); +} + +int semihosting_file_length(int file_handle) +{ + return semihosting_call(SEMIHOSTING_SYS_FLEN, + (void *) &file_handle); +} + +char semihosting_read_char(void) +{ + return semihosting_call(SEMIHOSTING_SYS_READC, NULL); +} + +void semihosting_write_char(char character) +{ + semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); +} + +void semihosting_write_string(char *string) +{ + semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); +} + +int semihosting_system(char *command_line) +{ + smh_system_block system_block; + + system_block.command_line = command_line; + system_block.command_length = strlen(command_line); + + return semihosting_call(SEMIHOSTING_SYS_SYSTEM, + (void *) &system_block); +} + +int semihosting_get_flen(const char *file_name) +{ + int file_handle, length; + + assert(semihosting_connection_supported()); + + file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); + if (file_handle == -1) + return file_handle; + + /* Find the length of the file */ + length = semihosting_file_length(file_handle); + + return semihosting_file_close(file_handle) ? -1 : length; +} + +int semihosting_download_file(const char *file_name, + int buf_size, + void *buf) +{ + int ret = -EINVAL, file_handle, length; + + /* Null pointer check */ + if (!buf) + return ret; + + assert(semihosting_connection_supported()); + + file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); + if (file_handle == -1) + return ret; + + /* Find the actual length of the file */ + length = semihosting_file_length(file_handle); + if (length == -1) + goto semihosting_fail; + + /* Signal error if we do not have enough space for the file */ + if (length > buf_size) + goto semihosting_fail; + + /* + * A successful read will return 0 in which case we pass back + * the actual number of bytes read. Else we pass a negative + * value indicating an error. + */ + ret = semihosting_file_read(file_handle, &length, buf); + if (ret) + goto semihosting_fail; + else + ret = length; + +semihosting_fail: + semihosting_file_close(file_handle); + return ret; +} |