mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 20:18:18 +00: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);
 | 
						|
}
 |