mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 00:11:51 +01:00 
			
		
		
		
	We factor out the arch-independent parts of the ARM semihosting implementation as a common library so that it can be shared with RISC-V. Signed-off-by: Kautuk Consul <kconsul@ventanamicro.com> Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
		
			
				
	
	
		
			187 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
 | |
|  * Copyright 2014 Broadcom Corporation
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <log.h>
 | |
| #include <semihosting.h>
 | |
| 
 | |
| #define SYSOPEN		0x01
 | |
| #define SYSCLOSE	0x02
 | |
| #define SYSWRITEC	0x03
 | |
| #define SYSWRITE0	0x04
 | |
| #define SYSWRITE	0x05
 | |
| #define SYSREAD		0x06
 | |
| #define SYSREADC	0x07
 | |
| #define SYSISERROR	0x08
 | |
| #define SYSSEEK		0x0A
 | |
| #define SYSFLEN		0x0C
 | |
| #define SYSERRNO	0x13
 | |
| 
 | |
| #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
 | |
| static bool _semihosting_enabled = true;
 | |
| static bool try_semihosting = true;
 | |
| 
 | |
| bool semihosting_enabled(void)
 | |
| {
 | |
| 	if (try_semihosting) {
 | |
| 		smh_trap(SYSERRNO, NULL);
 | |
| 		try_semihosting = false;
 | |
| 	}
 | |
| 
 | |
| 	return _semihosting_enabled;
 | |
| }
 | |
| 
 | |
| void disable_semihosting(void)
 | |
| {
 | |
| 	_semihosting_enabled = false;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /**
 | |
|  * smh_errno() - Read the host's errno
 | |
|  *
 | |
|  * This gets the value of the host's errno and negates it. The host's errno may
 | |
|  * or may not be set, so only call this function if a previous semihosting call
 | |
|  * has failed.
 | |
|  *
 | |
|  * Return: a negative error value
 | |
|  */
 | |
| static int smh_errno(void)
 | |
| {
 | |
| 	long ret = smh_trap(SYSERRNO, NULL);
 | |
| 
 | |
| 	if (ret > 0 && ret < INT_MAX)
 | |
| 		return -ret;
 | |
| 	return -EIO;
 | |
| }
 | |
| 
 | |
| long smh_open(const char *fname, enum smh_open_mode mode)
 | |
| {
 | |
| 	long fd;
 | |
| 	struct smh_open_s {
 | |
| 		const char *fname;
 | |
| 		unsigned long mode;
 | |
| 		size_t len;
 | |
| 	} open;
 | |
| 
 | |
| 	debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
 | |
| 
 | |
| 	open.fname = fname;
 | |
| 	open.len = strlen(fname);
 | |
| 	open.mode = mode;
 | |
| 
 | |
| 	/* Open the file on the host */
 | |
| 	fd = smh_trap(SYSOPEN, &open);
 | |
| 	if (fd == -1)
 | |
| 		return smh_errno();
 | |
| 	return fd;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * struct smg_rdwr_s - Arguments for read and write
 | |
|  * @fd: A file descriptor returned from smh_open()
 | |
|  * @memp: Pointer to a buffer of memory of at least @len bytes
 | |
|  * @len: The number of bytes to read or write
 | |
|  */
 | |
| struct smh_rdwr_s {
 | |
| 	long fd;
 | |
| 	void *memp;
 | |
| 	size_t len;
 | |
| };
 | |
| 
 | |
| long smh_read(long fd, void *memp, size_t len)
 | |
| {
 | |
| 	long ret;
 | |
| 	struct smh_rdwr_s read;
 | |
| 
 | |
| 	debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
 | |
| 
 | |
| 	read.fd = fd;
 | |
| 	read.memp = memp;
 | |
| 	read.len = len;
 | |
| 
 | |
| 	ret = smh_trap(SYSREAD, &read);
 | |
| 	if (ret < 0)
 | |
| 		return smh_errno();
 | |
| 	return len - ret;
 | |
| }
 | |
| 
 | |
| long smh_write(long fd, const void *memp, size_t len, ulong *written)
 | |
| {
 | |
| 	long ret;
 | |
| 	struct smh_rdwr_s write;
 | |
| 
 | |
| 	debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
 | |
| 
 | |
| 	write.fd = fd;
 | |
| 	write.memp = (void *)memp;
 | |
| 	write.len = len;
 | |
| 
 | |
| 	ret = smh_trap(SYSWRITE, &write);
 | |
| 	*written = len - ret;
 | |
| 	if (ret)
 | |
| 		return smh_errno();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| long smh_close(long fd)
 | |
| {
 | |
| 	long ret;
 | |
| 
 | |
| 	debug("%s: fd %ld\n", __func__, fd);
 | |
| 
 | |
| 	ret = smh_trap(SYSCLOSE, &fd);
 | |
| 	if (ret == -1)
 | |
| 		return smh_errno();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| long smh_flen(long fd)
 | |
| {
 | |
| 	long ret;
 | |
| 
 | |
| 	debug("%s: fd %ld\n", __func__, fd);
 | |
| 
 | |
| 	ret = smh_trap(SYSFLEN, &fd);
 | |
| 	if (ret == -1)
 | |
| 		return smh_errno();
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| long smh_seek(long fd, long pos)
 | |
| {
 | |
| 	long ret;
 | |
| 	struct smh_seek_s {
 | |
| 		long fd;
 | |
| 		long pos;
 | |
| 	} seek;
 | |
| 
 | |
| 	debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
 | |
| 
 | |
| 	seek.fd = fd;
 | |
| 	seek.pos = pos;
 | |
| 
 | |
| 	ret = smh_trap(SYSSEEK, &seek);
 | |
| 	if (ret)
 | |
| 		return smh_errno();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int smh_getc(void)
 | |
| {
 | |
| 	return smh_trap(SYSREADC, NULL);
 | |
| }
 | |
| 
 | |
| void smh_putc(char ch)
 | |
| {
 | |
| 	smh_trap(SYSWRITEC, &ch);
 | |
| }
 | |
| 
 | |
| void smh_puts(const char *s)
 | |
| {
 | |
| 	smh_trap(SYSWRITE0, (char *)s);
 | |
| }
 |