diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /cpu | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'cpu')
80 files changed, 8381 insertions, 0 deletions
diff --git a/cpu/Makefile.am b/cpu/Makefile.am new file mode 100644 index 0000000..c3a3eab --- /dev/null +++ b/cpu/Makefile.am @@ -0,0 +1,162 @@ + +sysnames = @sysnames@ + +vpath %.c $(addprefix $(top_srcdir)/, $(sysnames)) + +lib_LTLIBRARIES = libmcpu.la + +libmcpu_la_SOURCES = cpu-context.c cpu-context.h cpu-registers.c cpu-registers.h cpu-byteorder.c cpu-instruction.c cpu-instruction.h cpu-syscalls.c cpu-syscalls.h cpu-sysdeps.h cpu-errno.h + +nodist_libmcpu_la_SOURCES = sys-errno.c sys-open.c sys-creat.c sys-close.c sys-dup.c sys-read.c sys-write.c sys-lseek.c \ + sys-link.c sys-unlink.c sys-chdir.c sys-mkdir.c sys-chmod.c sys-chown.c sys-access.c sys-rename.c sys-rmdir.c \ + sys-symlink.c sys-readlink.c sys-stat.c sys-fstat.c sys-lstat.c sys-fcntl.c sys-pipe2.c sys-getdents.c sys-select.c sys-fsync.c sys-truncate.c sys-ftruncate.c sys-fchmod.c sys-fchown.c sys-fchdir.c sys-clock_gettime.c sys-clock_getres.c sys-clock_nanosleep.c + +libmcpu_la_CPPFLAGS = -I$(top_srcdir)/include $(LIBMPU_CPPFLAGS) +libmcpu_la_CFLAGS = $(LIBMPU_CFLAGS) +libmcpu_la_LIBADD = $(LIBMPU_LIBS) +libmcpu_la_LDFLAGS = -version-info @LIBMCPU_LT_VERSION_INFO@ $(LIBMPU_LDFLAGS) + +# Automake's generated libtool compile rules rebuild a source pathname from +# $(srcdir) and therefore lose the pathname selected by GNU make vpath. +# These explicit rules compile the prerequisite path resolved by vpath ($<). + +libmcpu_la-sys-errno.lo: sys-errno.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-errno.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-errno.Tpo $(DEPDIR)/libmcpu_la-sys-errno.Plo + +libmcpu_la-sys-open.lo: sys-open.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-open.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-open.Tpo $(DEPDIR)/libmcpu_la-sys-open.Plo + +libmcpu_la-sys-creat.lo: sys-creat.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-creat.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-creat.Tpo $(DEPDIR)/libmcpu_la-sys-creat.Plo + +libmcpu_la-sys-close.lo: sys-close.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-close.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-close.Tpo $(DEPDIR)/libmcpu_la-sys-close.Plo + +libmcpu_la-sys-dup.lo: sys-dup.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-dup.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-dup.Tpo $(DEPDIR)/libmcpu_la-sys-dup.Plo + +libmcpu_la-sys-read.lo: sys-read.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-read.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-read.Tpo $(DEPDIR)/libmcpu_la-sys-read.Plo + +libmcpu_la-sys-write.lo: sys-write.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-write.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-write.Tpo $(DEPDIR)/libmcpu_la-sys-write.Plo + +libmcpu_la-sys-lseek.lo: sys-lseek.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-lseek.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-lseek.Tpo $(DEPDIR)/libmcpu_la-sys-lseek.Plo + +libmcpu_la-sys-link.lo: sys-link.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-link.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-link.Tpo $(DEPDIR)/libmcpu_la-sys-link.Plo + +libmcpu_la-sys-unlink.lo: sys-unlink.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-unlink.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-unlink.Tpo $(DEPDIR)/libmcpu_la-sys-unlink.Plo + +libmcpu_la-sys-chdir.lo: sys-chdir.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-chdir.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-chdir.Tpo $(DEPDIR)/libmcpu_la-sys-chdir.Plo + +libmcpu_la-sys-mkdir.lo: sys-mkdir.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-mkdir.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-mkdir.Tpo $(DEPDIR)/libmcpu_la-sys-mkdir.Plo + +libmcpu_la-sys-access.lo: sys-access.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-access.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-access.Tpo $(DEPDIR)/libmcpu_la-sys-access.Plo + +libmcpu_la-sys-rename.lo: sys-rename.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-rename.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-rename.Tpo $(DEPDIR)/libmcpu_la-sys-rename.Plo + +libmcpu_la-sys-rmdir.lo: sys-rmdir.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-rmdir.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-rmdir.Tpo $(DEPDIR)/libmcpu_la-sys-rmdir.Plo + +libmcpu_la-sys-symlink.lo: sys-symlink.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-symlink.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-symlink.Tpo $(DEPDIR)/libmcpu_la-sys-symlink.Plo + +libmcpu_la-sys-readlink.lo: sys-readlink.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-readlink.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-readlink.Tpo $(DEPDIR)/libmcpu_la-sys-readlink.Plo + +libmcpu_la-sys-stat.lo: sys-stat.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-stat.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-stat.Tpo $(DEPDIR)/libmcpu_la-sys-stat.Plo + +libmcpu_la-sys-fstat.lo: sys-fstat.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-fstat.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-fstat.Tpo $(DEPDIR)/libmcpu_la-sys-fstat.Plo + +libmcpu_la-sys-lstat.lo: sys-lstat.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-lstat.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-lstat.Tpo $(DEPDIR)/libmcpu_la-sys-lstat.Plo + +libmcpu_la-sys-chmod.lo: sys-chmod.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-chmod.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-chmod.Tpo $(DEPDIR)/libmcpu_la-sys-chmod.Plo + +libmcpu_la-sys-chown.lo: sys-chown.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-chown.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-chown.Tpo $(DEPDIR)/libmcpu_la-sys-chown.Plo + +libmcpu_la-sys-fcntl.lo: sys-fcntl.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-fcntl.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-fcntl.Tpo $(DEPDIR)/libmcpu_la-sys-fcntl.Plo + +libmcpu_la-sys-pipe2.lo: sys-pipe2.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-pipe2.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-pipe2.Tpo $(DEPDIR)/libmcpu_la-sys-pipe2.Plo + +libmcpu_la-sys-getdents.lo: sys-getdents.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-getdents.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-getdents.Tpo $(DEPDIR)/libmcpu_la-sys-getdents.Plo + + +libmcpu_la-sys-select.lo: sys-select.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-select.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-select.Tpo $(DEPDIR)/libmcpu_la-sys-select.Plo + +libmcpu_la-sys-fsync.lo: sys-fsync.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-fsync.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-fsync.Tpo $(DEPDIR)/libmcpu_la-sys-fsync.Plo + +libmcpu_la-sys-truncate.lo: sys-truncate.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-truncate.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-truncate.Tpo $(DEPDIR)/libmcpu_la-sys-truncate.Plo + +libmcpu_la-sys-ftruncate.lo: sys-ftruncate.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-ftruncate.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-ftruncate.Tpo $(DEPDIR)/libmcpu_la-sys-ftruncate.Plo + +libmcpu_la-sys-fchmod.lo: sys-fchmod.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-fchmod.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-fchmod.Tpo $(DEPDIR)/libmcpu_la-sys-fchmod.Plo + +libmcpu_la-sys-fchown.lo: sys-fchown.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-fchown.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-fchown.Tpo $(DEPDIR)/libmcpu_la-sys-fchown.Plo + +libmcpu_la-sys-fchdir.lo: sys-fchdir.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-fchdir.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-fchdir.Tpo $(DEPDIR)/libmcpu_la-sys-fchdir.Plo + +libmcpu_la-sys-clock_gettime.lo: sys-clock_gettime.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-clock_gettime.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-clock_gettime.Tpo $(DEPDIR)/libmcpu_la-sys-clock_gettime.Plo + +libmcpu_la-sys-clock_getres.lo: sys-clock_getres.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-clock_getres.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-clock_getres.Tpo $(DEPDIR)/libmcpu_la-sys-clock_getres.Plo + +libmcpu_la-sys-clock_nanosleep.lo: sys-clock_nanosleep.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmcpu_la_CPPFLAGS) $(CPPFLAGS) $(libmcpu_la_CFLAGS) $(CFLAGS) -MT $@ -MD -MP -MF $(DEPDIR)/libmcpu_la-sys-clock_nanosleep.Tpo -c -o $@ $< + $(AM_V_at)$(am__mv) $(DEPDIR)/libmcpu_la-sys-clock_nanosleep.Tpo $(DEPDIR)/libmcpu_la-sys-clock_nanosleep.Plo diff --git a/cpu/cpu-byteorder.c b/cpu/cpu-byteorder.c new file mode 100644 index 0000000..ebc612a --- /dev/null +++ b/cpu/cpu-byteorder.c @@ -0,0 +1,116 @@ +/*************************************************************** + __CPU_BYTEORDER.C + + Byte-order accessors for canonical PROGRAM fields and + architectural data-object representation. + + PART OF : CPU - library . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#include <string.h> +#include <libmcpu.h> + +__mpu_uint16_t +__cpu_data_get_u16( const __mpu_UNIT_t *p ) +{ + __mpu_uint16_t v = 0; + if( p ) memcpy( &v, p, sizeof(v) ); + return( v ); +} + +__mpu_uint32_t +__cpu_data_get_u32( const __mpu_UNIT_t *p ) +{ + __mpu_uint32_t v = 0; + if( p ) memcpy( &v, p, sizeof(v) ); + return( v ); +} + +__mpu_uint64_t +__cpu_data_get_u64( const __mpu_UNIT_t *p ) +{ + __mpu_uint64_t v = 0; + if( p ) memcpy( &v, p, sizeof(v) ); + return( v ); +} + +void +__cpu_data_put_u16( __mpu_UNIT_t *p, __mpu_uint16_t v ) +{ + if( p ) memcpy( p, &v, sizeof(v) ); +} + +void +__cpu_data_put_u32( __mpu_UNIT_t *p, __mpu_uint32_t v ) +{ + if( p ) memcpy( p, &v, sizeof(v) ); +} + +void +__cpu_data_put_u64( __mpu_UNIT_t *p, __mpu_uint64_t v ) +{ + if( p ) memcpy( p, &v, sizeof(v) ); +} + +__mpu_uint16_t +__cpu_code_get_u16( const __mpu_UNIT_t *p ) +{ + if( !p ) return( 0 ); + return (__mpu_uint16_t)(((__mpu_uint16_t)p[0] << 8) | + (__mpu_uint16_t)p[1]); +} + +__mpu_uint32_t +__cpu_code_get_u32( const __mpu_UNIT_t *p ) +{ + __mpu_uint32_t v; + if( !p ) return( 0 ); + v = ((__mpu_uint32_t)p[0] << 24); + v |= ((__mpu_uint32_t)p[1] << 16); + v |= ((__mpu_uint32_t)p[2] << 8); + v |= (__mpu_uint32_t)p[3]; + return( v ); +} + +__mpu_uint64_t +__cpu_code_get_u64( const __mpu_UNIT_t *p ) +{ + __mpu_uint64_t v = 0; + int k; + if( !p ) return( 0 ); + for( k = 0; k < 8; ++k ) v = ( v << 8 ) | p[k]; + return( v ); +} + +void +__cpu_code_put_u16( __mpu_UNIT_t *p, __mpu_uint16_t v ) +{ + if( !p ) return; + p[0] = (__mpu_UNIT_t)(v >> 8); + p[1] = (__mpu_UNIT_t)v; +} + +void +__cpu_code_put_u32( __mpu_UNIT_t *p, __mpu_uint32_t v ) +{ + if( !p ) return; + p[0] = (__mpu_UNIT_t)(v >> 24); + p[1] = (__mpu_UNIT_t)(v >> 16); + p[2] = (__mpu_UNIT_t)(v >> 8); + p[3] = (__mpu_UNIT_t)v; +} + +void +__cpu_code_put_u64( __mpu_UNIT_t *p, __mpu_uint64_t v ) +{ + int k; + if( !p ) return; + for( k = 7; k >= 0; --k ) + { + p[k] = (__mpu_UNIT_t)( v & __mpu_UINT64_C( 0xff ) ); + v >>= 8; + } +} diff --git a/cpu/cpu-context.c b/cpu/cpu-context.c new file mode 100644 index 0000000..e77d93a --- /dev/null +++ b/cpu/cpu-context.c @@ -0,0 +1,589 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> +#include <libmcpu.h> +#include <cpu-context.h> +#include <cpu-syscalls.h> + +__thread struct __cpu_context cctx; +__thread struct __cpu_context *pcctx; + +static __mpu_uint32_t +__cpu_get_mpu_psw( void ) +{ + __mpu_uint32_t psw = 0; + if( __mpu_gta() ) psw |= PSW_AF_MASK; + if( __mpu_gtc() ) psw |= PSW_CF_MASK; + if( __mpu_gto() ) psw |= PSW_OF_MASK; + if( __mpu_gts() ) psw |= PSW_SF_MASK; + if( __mpu_gtp() ) psw |= PSW_PF_MASK; + if( __mpu_gtz() ) psw |= PSW_ZF_MASK; + if( __mpu_gtr() ) psw |= PSW_RF_MASK; + if( __mpu_gtv() ) psw |= PSW_VF_MASK; + if( __mpu_gtdom() ) psw |= PSW_DOMF_MASK; + if( __mpu_gtsng() ) psw |= PSW_SNGF_MASK; + if( __mpu_gtovf() ) psw |= PSW_OVFF_MASK; + if( __mpu_gtudf() ) psw |= PSW_UDFF_MASK; + if( __mpu_gttls() ) psw |= PSW_TLSF_MASK; + if( __mpu_gtpls() ) psw |= PSW_PLSF_MASK; + if( __mpu_gtind() ) psw |= PSW_INDF_MASK; + if( __mpu_gtinx() ) psw |= PSW_INXF_MASK; + return( psw ); +} + +static void +__cpu_set_mpu_psw( __mpu_uint32_t p ) +{ +#define SF(mask,st,cl) do{if(p&(mask)) st(); else cl();}while(0) + SF( PSW_AF_MASK, __mpu_sta, __mpu_cla ); + SF( PSW_CF_MASK, __mpu_stc, __mpu_clc ); + SF( PSW_OF_MASK, __mpu_sto, __mpu_clo ); + SF( PSW_SF_MASK, __mpu_sts, __mpu_cls ); + SF( PSW_PF_MASK, __mpu_stp, __mpu_clp ); + SF( PSW_ZF_MASK, __mpu_stz, __mpu_clz ); + SF( PSW_RF_MASK, __mpu_str, __mpu_clr ); + SF( PSW_VF_MASK, __mpu_stv, __mpu_clv ); + SF( PSW_DOMF_MASK, __mpu_stdom, __mpu_cldom ); + SF( PSW_SNGF_MASK, __mpu_stsng, __mpu_clsng ); + SF( PSW_OVFF_MASK, __mpu_stovf, __mpu_clovf ); + SF( PSW_UDFF_MASK, __mpu_studf, __mpu_cludf ); + SF( PSW_TLSF_MASK, __mpu_sttls, __mpu_cltls ); + SF( PSW_PLSF_MASK, __mpu_stpls, __mpu_clpls ); + SF( PSW_INDF_MASK, __mpu_stind, __mpu_clind ); + SF( PSW_INXF_MASK, __mpu_stinx, __mpu_clinx ); +#undef SF +} + +/* + * Host backing store. Architectural size and host mapping capacity are kept + * separate deliberately: the latter is rounded to the host page size only so + * mmap()/mprotect()/munmap() can operate on complete pages. CPU bounds checks + * must always use the architectural size fields. + */ +static size_t +host_page_size( void ) +{ + static size_t page; + long n; + if( page ) return( page ); + n = sysconf( _SC_PAGESIZE ); + if( n <= 0 ) return( 0 ); + page = (size_t)n; + return( page ); +} + +static void +mem_unmap( __mpu_UNIT_t **p, __mpu_uint64_t *sz, __mpu_uint64_t *cap ) +{ + if( *p && *cap && (__mpu_uint64_t)(size_t)*cap == *cap ) + (void)munmap( (void *)*p, (size_t)*cap ); + *p = 0; + *sz = 0; + *cap = 0; +} + +static int mem_alloc( __mpu_UNIT_t **p, __mpu_uint64_t *sz, __mpu_uint64_t *cap, + __mpu_uint64_t n) +{ + size_t page, need, mapped, max = (size_t)-1; + void *q; + + mem_unmap( p, sz, cap ); + if( !n ) return( 0 ); + if( (__mpu_uint64_t)(size_t)n != n ) return( -1 ); + + page = host_page_size(); + if( !page ) return( -1 ); + need = (size_t)n; + if( need > max - ( page - 1U ) ) return( -1 ); + mapped = ( ( need + page - 1U ) / page ) * page; + if( !mapped ) return( -1 ); + + q = mmap( (void *)0, mapped, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if( q == MAP_FAILED ) return( -1 ); + + /* Anonymous mappings are zero-filled by the host kernel. */ + *p = (__mpu_UNIT_t *)q; + *sz = n; + *cap = (__mpu_uint64_t)mapped; + return( 0 ); +} + +void +__cpu_init( void ) +{ + pcctx = &cctx; + __cpu_cwd_context_free(); + __cpu_fd_context_free(); + mem_unmap( &cctx._program, &cctx._program_size, &cctx._program_capacity ); + mem_unmap( &cctx._data, &cctx._data_size, &cctx._data_capacity ); + mem_unmap( &cctx._stack, &cctx._stack_size, &cctx._stack_capacity ); + mem_unmap( &cctx._control, &cctx._control_size, &cctx._control_capacity ); + mem_unmap( &cctx._input, &cctx._input_size, &cctx._input_capacity ); + mem_unmap( &cctx._output, &cctx._output_size, &cctx._output_capacity ); + mem_unmap( &cctx._trace, &cctx._trace_size, &cctx._trace_capacity ); + mem_unmap( &cctx._heap, &cctx._heap_size, &cctx._heap_capacity ); + memset( &cctx, 0, sizeof( cctx ) ); + pcctx = &cctx; + __cpu_fd_context_init(); + __cpu_cwd_context_init(); + __mpu_init(); +} + +void +__cpu_free_context( void ) +{ + if( !pcctx ) pcctx = &cctx; + __cpu_cwd_context_free(); + __cpu_fd_context_free(); + mem_unmap( &pcctx->_program, &pcctx->_program_size, &pcctx->_program_capacity ); + mem_unmap( &pcctx->_data, &pcctx->_data_size, &pcctx->_data_capacity ); + mem_unmap( &pcctx->_stack, &pcctx->_stack_size, &pcctx->_stack_capacity ); + mem_unmap( &pcctx->_control, &pcctx->_control_size, &pcctx->_control_capacity ); + mem_unmap( &pcctx->_input, &pcctx->_input_size, &pcctx->_input_capacity ); + mem_unmap( &pcctx->_output, &pcctx->_output_size, &pcctx->_output_capacity ); + mem_unmap( &pcctx->_trace, &pcctx->_trace_size, &pcctx->_trace_capacity ); + mem_unmap( &pcctx->_heap, &pcctx->_heap_size, &pcctx->_heap_capacity ); + pcctx->_heap_brk = 0; + pcctx->_heap_limit = 0; + pcctx->_pc = 0; + pcctx->_sp = 0; + pcctx->_fp = 0; + pcctx->_psw = 0; + pcctx->_stop_reason = CPU_STOP_NONE; + pcctx->_exit_status = 0; + __mpu_free_context(); +} + +__mpu_uint64_t * +__ptr_cpu_pc( void ) +{ + return( &cctx._pc ); +} + +__mpu_uint64_t * +__ptr_cpu_sp( void ) +{ + return( &cctx._sp ); +} + +__mpu_uint64_t * +__ptr_cpu_fp( void ) +{ + return( &cctx._fp ); +} + +__mpu_UNIT_t * +__ptr_cpu_registers( void ) +{ + return( &cctx._regs[0] ); +} + +int +__cpu_program_alloc( __mpu_uint64_t n ) +{ + return( mem_alloc( &cctx._program, &cctx._program_size, &cctx._program_capacity, n ) ); +} + +void +__cpu_program_free( void ) +{ + mem_unmap( &cctx._program, &cctx._program_size, &cctx._program_capacity ); + cctx._pc = 0; +} + +int +__cpu_program_protect( void ) +{ + if( !cctx._program ) return( cctx._program_size == 0 ? 0 : -1 ); + if( !cctx._program_capacity || + (__mpu_uint64_t)(size_t)cctx._program_capacity != cctx._program_capacity) + return( -1 ); + return( mprotect( (void *)cctx._program, (size_t)cctx._program_capacity, PROT_READ ) == 0 ? 0 : -1 ); +} + +__mpu_UNIT_t * +__cpu_program_ptr( void ) +{ + return( cctx._program ); +} + +__mpu_uint64_t +__cpu_program_size( void ) +{ + return( cctx._program_size ); +} + +int +__cpu_program_set( const __mpu_UNIT_t *d, __mpu_uint64_t n ) +{ + if( __cpu_program_alloc( n ) ) return( -1 ); + if( n && d ) memcpy( cctx._program, d, (size_t)n ); + if( __cpu_program_protect() ) + { + __cpu_program_free(); + return( -1 ); + } + return( 0 ); +} + +int +__cpu_data_alloc( __mpu_uint64_t n ) +{ + return( mem_alloc( &cctx._data, &cctx._data_size, &cctx._data_capacity, n ) ); +} + +void +__cpu_data_free( void ) +{ + mem_unmap( &cctx._data, &cctx._data_size, &cctx._data_capacity ); +} + +__mpu_UNIT_t * +__cpu_data_ptr( void ) +{ + return( cctx._data ); +} + +__mpu_uint64_t +__cpu_data_size( void ) +{ + return( cctx._data_size ); +} + +int +__cpu_data_set( const __mpu_UNIT_t *d, __mpu_uint64_t n ) +{ + if( __cpu_data_alloc( n ) ) return( -1 ); + if( n && d ) memcpy( cctx._data, d, (size_t)n ); + return( 0 ); +} + +int +__cpu_stack_alloc( __mpu_uint64_t n ) +{ + int rc = mem_alloc( &cctx._stack, &cctx._stack_size, &cctx._stack_capacity, n ); + cctx._sp = ( rc == 0 ) ? n : 0; + cctx._fp = ( rc == 0 ) ? n : 0; + return( rc ); +} + +void +__cpu_stack_free( void ) +{ + mem_unmap( &cctx._stack, &cctx._stack_size, &cctx._stack_capacity ); + cctx._sp = 0; + cctx._fp = 0; +} + +__mpu_UNIT_t * +__cpu_stack_ptr( void ) +{ + return( cctx._stack ); +} + +__mpu_uint64_t +__cpu_stack_size( void ) +{ + return( cctx._stack_size ); +} + +#define DEFINE_SEGMENT_API(name,field) \ +int __cpu_##name##_alloc(__mpu_uint64_t n){return mem_alloc(&cctx._##field,&cctx._##field##_size,&cctx._##field##_capacity,n);} \ +void __cpu_##name##_free(void){mem_unmap(&cctx._##field,&cctx._##field##_size,&cctx._##field##_capacity);} \ +__mpu_UNIT_t *__cpu_##name##_ptr(void){return cctx._##field;} \ +__mpu_uint64_t __cpu_##name##_size(void){return cctx._##field##_size;} \ +int __cpu_##name##_set(const __mpu_UNIT_t *d,__mpu_uint64_t n){if(__cpu_##name##_alloc(n))return -1;if(n&&d)memcpy(cctx._##field,d,(size_t)n);return 0;} + +DEFINE_SEGMENT_API( control, control ) +DEFINE_SEGMENT_API( input, input ) +DEFINE_SEGMENT_API( output, output ) +DEFINE_SEGMENT_API( trace, trace ) +#undef DEFINE_SEGMENT_API + +static int +__cpu_heap_grow( __mpu_uint64_t new_size ) +{ + size_t page, need, mapped, max = (size_t)-1; + __mpu_UNIT_t *p; + + if( new_size <= cctx._heap_capacity ) return( 0 ); + if( (__mpu_uint64_t)(size_t)new_size != new_size ) return( -1 ); + + page = host_page_size(); + if( !page ) return( -1 ); + + need = (size_t)new_size; + if( need > max - (page - 1U) ) return( -1 ); + + mapped = ((need + page - 1U) / page) * page; + if( !mapped ) return( -1 ); + + p = (__mpu_UNIT_t *)mmap( (void *)0, mapped, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ); + if( p == (__mpu_UNIT_t *)MAP_FAILED ) return( -1 ); + + if( cctx._heap && cctx._heap_size ) + memcpy( p, cctx._heap, (size_t)cctx._heap_size ); + + if( cctx._heap && cctx._heap_capacity ) + (void)munmap( (void *)cctx._heap, (size_t)cctx._heap_capacity ); + + cctx._heap = p; + cctx._heap_capacity = (__mpu_uint64_t)mapped; + + return( 0 ); + +} /* End of __cpu_heap_grow() */ + + +int +__cpu_heap_alloc( __mpu_uint64_t initial_size, __mpu_uint64_t maximum_size ) +{ + int rc; + + if( maximum_size < initial_size || + maximum_size < CPU_HEAP_BEGIN || initial_size < CPU_HEAP_BEGIN ) + return( -1 ); + + rc = mem_alloc( &cctx._heap, &cctx._heap_size, + &cctx._heap_capacity, initial_size ); + if( rc ) + { + cctx._heap_brk = 0; + cctx._heap_limit = 0; + return( rc ); + } + + cctx._heap_brk = CPU_HEAP_BEGIN; + cctx._heap_limit = maximum_size; + + return( 0 ); + +} /* End of __cpu_heap_alloc() */ + + +void +__cpu_heap_free( void ) +{ + mem_unmap( &cctx._heap, &cctx._heap_size, &cctx._heap_capacity ); + cctx._heap_brk = 0; + cctx._heap_limit = 0; + +} /* End of __cpu_heap_free() */ + + +__mpu_uint64_t +__cpu_heap_brk( __mpu_uint64_t new_brk ) +{ + __mpu_uint64_t old_brk = cctx._heap_brk; + + if( !cctx._heap || cctx._heap_limit < CPU_HEAP_BEGIN ) + return( old_brk ); + + if( new_brk < CPU_HEAP_BEGIN || new_brk > cctx._heap_limit ) + return( old_brk ); + + if( new_brk == old_brk ) return( old_brk ); + + if( new_brk < old_brk ) + { + memset( cctx._heap + (size_t)new_brk, 0, + (size_t)(old_brk - new_brk) ); + cctx._heap_brk = new_brk; + return( new_brk ); + } + + if( new_brk <= cctx._heap_size ) + { + cctx._heap_brk = new_brk; + return( new_brk ); + } + + if( new_brk <= cctx._heap_capacity ) + { + memset( cctx._heap + (size_t)cctx._heap_size, 0, + (size_t)(new_brk - cctx._heap_size) ); + cctx._heap_size = new_brk; + cctx._heap_brk = new_brk; + return( new_brk ); + } + + if( __cpu_heap_grow( new_brk ) != 0 ) return( old_brk ); + + cctx._heap_size = new_brk; + cctx._heap_brk = new_brk; + + return( new_brk ); + +} /* End of __cpu_heap_brk() */ + + +__mpu_UNIT_t * +__cpu_heap_ptr( void ) +{ + return( cctx._heap ); +} + +__mpu_uint64_t +__cpu_heap_size( void ) +{ + return( cctx._heap_size ); +} + +__mpu_uint64_t +__cpu_heap_limit( void ) +{ + return( cctx._heap_limit ); +} + +cpu_stop_reason +__cpu_get_stop_reason( void ) +{ + return( cctx._stop_reason ); +} + +__mpu_int32_t +__cpu_get_exit_status( void ) +{ + return( cctx._exit_status ); +} + +void +__cpu_clear_stop_reason( void ) +{ + cctx._stop_reason = CPU_STOP_NONE; + cctx._exit_status = 0; +} + +__mpu_uint32_t +__cpu_get_psw( void ) +{ + return( ( __cpu_get_mpu_psw() & PSW_MPU_MASK ) | ( cctx._psw & PSW_CPU_MASK ) ); +} + +void +__cpu_set_psw( __mpu_uint32_t p ) +{ + __cpu_set_mpu_psw( p & PSW_MPU_MASK ); + cctx._psw = p & PSW_CPU_MASK; +} + +void +__cpu_clear_psw( void ) +{ + __mpu_clear_mflags(); + cctx._psw = 0; +} + +int +__cpu_gth( void ) +{ + return( (int)__CFLAG( PSW_HF_MASK, PSW_HF_SHIFT ) ); +} + +int +__cpu_gtt( void ) +{ + return( (int)__CFLAG( PSW_TF_MASK, PSW_TF_SHIFT ) ); +} + +int +__cpu_gti( void ) +{ + return( (int)__CFLAG( PSW_IF_MASK, PSW_IF_SHIFT ) ); +} + +void +__cpu_sth( void ) +{ + __SET_CFLAG( PSW_HF_MASK ); +} + +void +__cpu_stt( void ) +{ + __SET_CFLAG( PSW_TF_MASK ); +} + +void +__cpu_sti( void ) +{ + __SET_CFLAG( PSW_IF_MASK ); +} + +void +__cpu_clh( void ) +{ + __CLEAR_CFLAG( PSW_HF_MASK ); +} + +void +__cpu_clt( void ) +{ + __CLEAR_CFLAG( PSW_TF_MASK ); +} + +void +__cpu_cli( void ) +{ + __CLEAR_CFLAG( PSW_IF_MASK ); +} + +void +__cpu_cmh( void ) +{ + __INVERT_CFLAG( PSW_HF_MASK ); +} + +void +__cpu_cmt( void ) +{ + __INVERT_CFLAG( PSW_TF_MASK ); +} + +void +__cpu_cmi( void ) +{ + __INVERT_CFLAG( PSW_IF_MASK ); +} + +int +__cpu_gtmode( void ) +{ + return( (int)( ( cctx._psw & PSW_MODE_MASK ) >> PSW_MODE_SHIFT ) ); +} + +int +__cpu_stmode( unsigned int m ) +{ + if( m > 3 ) return( -1 ); + cctx._psw &= ~PSW_MODE_MASK; + cctx._psw |= ( (__mpu_uint32_t)m << PSW_MODE_SHIFT ) & PSW_MODE_MASK; + return( 0 ); +} + +int +__cpu_ptr_make( __mpu_uint64_t *ptr, unsigned int segment, __mpu_uint64_t offset ) +{ + if( !ptr || segment > CPU_PTR_SEG_MAX || offset > CPU_PTR_OFFSET_MASK ) return( -1 ); + *ptr = ( (__mpu_uint64_t)segment << CPU_PTR_SEG_SHIFT ) | offset; + return( 0 ); +} + +unsigned int +__cpu_ptr_segment( __mpu_uint64_t ptr ) +{ + return( (unsigned int)( ( ptr & CPU_PTR_SEG_MASK ) >> CPU_PTR_SEG_SHIFT ) ); +} + +__mpu_uint64_t +__cpu_ptr_offset( __mpu_uint64_t ptr ) +{ + return( ptr & CPU_PTR_OFFSET_MASK ); +} diff --git a/cpu/cpu-context.h b/cpu/cpu-context.h new file mode 100644 index 0000000..1957df9 --- /dev/null +++ b/cpu/cpu-context.h @@ -0,0 +1,120 @@ +/*************************************************************** + __CPU_CONTEXT.H + + This file contains CPU CONTEXT operation functions & data + declarations. + + PART OF : CPU - library . + USAGE : Internal only . + NOTE : Include "libcpu.h" before this FILE . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ +#ifndef __CPU_CONTEXT_H +#define __CPU_CONTEXT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define CPU_GUEST_FD_MAX 256 + +typedef struct __cpu_fd_entry +{ + int host_fd; + unsigned int owned; + unsigned int flags; +} __cpu_fd_entry; + +typedef struct __cpu_context cpu_context; +struct __cpu_context +{ + __mpu_uint64_t _pc; + __mpu_uint64_t _sp; + __mpu_uint64_t _fp; + __mpu_uint32_t _psw; + cpu_stop_reason _stop_reason; + __mpu_int32_t _exit_status; + + __mpu_UNIT_t *_program; + __mpu_uint64_t _program_size; + __mpu_uint64_t _program_capacity; + __mpu_UNIT_t *_data; + __mpu_uint64_t _data_size; + __mpu_uint64_t _data_capacity; + __mpu_UNIT_t *_stack; + __mpu_uint64_t _stack_size; + __mpu_uint64_t _stack_capacity; + __mpu_UNIT_t *_control; + __mpu_uint64_t _control_size; + __mpu_uint64_t _control_capacity; + __mpu_UNIT_t *_input; + __mpu_uint64_t _input_size; + __mpu_uint64_t _input_capacity; + __mpu_UNIT_t *_output; + __mpu_uint64_t _output_size; + __mpu_uint64_t _output_capacity; + __mpu_UNIT_t *_trace; + __mpu_uint64_t _trace_size; + __mpu_uint64_t _trace_capacity; + __mpu_UNIT_t *_heap; + __mpu_uint64_t _heap_brk; + __mpu_uint64_t _heap_size; + __mpu_uint64_t _heap_capacity; + __mpu_uint64_t _heap_limit; + + int _fd_initialized; + __cpu_fd_entry _fd[CPU_GUEST_FD_MAX]; + + int _cwd_initialized; + int _cwd_fd; + + __mpu_UNIT_t _regs[CPU_REGISTERS_MEM_SIZE_IN_UNITS]; +}; + +extern __thread struct __cpu_context *pcctx; + +#define __PC (pcctx->_pc) +#define __SP (pcctx->_sp) +#define __FP (pcctx->_fp) +#define __REGS ((__mpu_UNIT_t *)&pcctx->_regs[0]) +#define __PROGRAM (pcctx->_program) +#define __PSIZE (pcctx->_program_size) +#define __PCAP (pcctx->_program_capacity) +#define __DATA (pcctx->_data) +#define __DSIZE (pcctx->_data_size) +#define __DCAP (pcctx->_data_capacity) +#define __STACK (pcctx->_stack) +#define __SSIZE (pcctx->_stack_size) +#define __SCAP (pcctx->_stack_capacity) +#define __CONTROL (pcctx->_control) +#define __CSIZE (pcctx->_control_size) +#define __CCAP (pcctx->_control_capacity) +#define __INPUT (pcctx->_input) +#define __ISIZE (pcctx->_input_size) +#define __ICAP (pcctx->_input_capacity) +#define __OUTPUT (pcctx->_output) +#define __OSIZE (pcctx->_output_size) +#define __OCAP (pcctx->_output_capacity) +#define __TRACE (pcctx->_trace) +#define __TSIZE (pcctx->_trace_size) +#define __TCAP (pcctx->_trace_capacity) +#define __HEAP (pcctx->_heap) +#define __HBRK (pcctx->_heap_brk) +#define __HSIZE (pcctx->_heap_size) +#define __HCAP (pcctx->_heap_capacity) +#define __HLIMIT (pcctx->_heap_limit) +#define __STOP_REASON (pcctx->_stop_reason) +#define __EXIT_STATUS (pcctx->_exit_status) +#define __CPU_PSW (pcctx->_psw) +#define __SET_CFLAG(mask) (pcctx->_psw |= (mask)) +#define __CLEAR_CFLAG(mask) (pcctx->_psw &= ~(mask)) +#define __INVERT_CFLAG(mask) (pcctx->_psw ^= (mask)) +#define __CFLAG(mask,shift) ((pcctx->_psw & (mask)) >> (shift)) + +extern __mpu_uint64_t __cpu_heap_brk( __mpu_uint64_t new_brk ); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpu/cpu-errno.h b/cpu/cpu-errno.h new file mode 100644 index 0000000..20fb4c9 --- /dev/null +++ b/cpu/cpu-errno.h @@ -0,0 +1,160 @@ +/*************************************************************** + __CPU_ERRNO.H + + This file contains stable MCPU system-call error numbers. + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_ERRNO_H +#define __CPU_ERRNO_H + +#define __MCPU_EPERM 1 /* Operation not permitted */ +#define __MCPU_ENOENT 2 /* No such file or directory */ +#define __MCPU_ESRCH 3 /* No such process */ +#define __MCPU_EINTR 4 /* Interrupted system call */ +#define __MCPU_EIO 5 /* I/O error */ +#define __MCPU_ENXIO 6 /* No such device or address */ +#define __MCPU_E2BIG 7 /* Argument list too long */ +#define __MCPU_ENOEXEC 8 /* Exec format error */ +#define __MCPU_EBADF 9 /* Bad file number */ +#define __MCPU_ECHILD 10 /* No child processes */ +#define __MCPU_EAGAIN 11 /* Try again */ +#define __MCPU_ENOMEM 12 /* Out of memory */ +#define __MCPU_EACCES 13 /* Permission denied */ +#define __MCPU_EFAULT 14 /* Bad address */ +#define __MCPU_ENOTBLK 15 /* Block device required */ +#define __MCPU_EBUSY 16 /* Device or resource busy */ +#define __MCPU_EEXIST 17 /* File exists */ +#define __MCPU_EXDEV 18 /* Cross-device link */ +#define __MCPU_ENODEV 19 /* No such device */ +#define __MCPU_ENOTDIR 20 /* Not a directory */ +#define __MCPU_EISDIR 21 /* Is a directory */ +#define __MCPU_EINVAL 22 /* Invalid argument */ +#define __MCPU_ENFILE 23 /* File table overflow */ +#define __MCPU_EMFILE 24 /* Too many open files */ +#define __MCPU_ENOTTY 25 /* Not a typewriter */ +#define __MCPU_ETXTBSY 26 /* Text file busy */ +#define __MCPU_EFBIG 27 /* File too large */ +#define __MCPU_ENOSPC 28 /* No space left on device */ +#define __MCPU_ESPIPE 29 /* Illegal seek */ +#define __MCPU_EROFS 30 /* Read-only file system */ +#define __MCPU_EMLINK 31 /* Too many links */ +#define __MCPU_EPIPE 32 /* Broken pipe */ +#define __MCPU_EDOM 33 /* Math argument out of domain */ +#define __MCPU_ERANGE 34 /* Math result not representable */ +#define __MCPU_EDEADLK 35 /* Resource deadlock would occur */ +#define __MCPU_ENAMETOOLONG 36 /* File name too long */ +#define __MCPU_ENOLCK 37 /* No record locks available */ +#define __MCPU_ENOSYS 38 /* Invalid system call number */ +#define __MCPU_ENOTEMPTY 39 /* Directory not empty */ +#define __MCPU_ELOOP 40 /* Too many symbolic links encountered */ + +#define __MCPU_EWOULDBLOCK __MCPU_EAGAIN + +#define __MCPU_ENOMSG 42 /* No message of desired type */ +#define __MCPU_EIDRM 43 /* Identifier removed */ +#define __MCPU_ECHRNG 44 /* Channel number out of range */ +#define __MCPU_EL2NSYNC 45 /* Level 2 not synchronized */ +#define __MCPU_EL3HLT 46 /* Level 3 halted */ +#define __MCPU_EL3RST 47 /* Level 3 reset */ +#define __MCPU_ELNRNG 48 /* Link number out of range */ +#define __MCPU_EUNATCH 49 /* Protocol driver not attached */ +#define __MCPU_ENOCSI 50 /* No CSI structure available */ +#define __MCPU_EL2HLT 51 /* Level 2 halted */ +#define __MCPU_EBADE 52 /* Invalid exchange */ +#define __MCPU_EBADR 53 /* Invalid request descriptor */ +#define __MCPU_EXFULL 54 /* Exchange full */ +#define __MCPU_ENOANO 55 /* No anode */ +#define __MCPU_EBADRQC 56 /* Invalid request code */ +#define __MCPU_EBADSLT 57 /* Invalid slot */ + +#define __MCPU_EDEADLOCK __MCPU_EDEADLK + +#define __MCPU_EBFONT 59 /* Bad font file format */ +#define __MCPU_ENOSTR 60 /* Device not a stream */ +#define __MCPU_ENODATA 61 /* No data available */ +#define __MCPU_ETIME 62 /* Timer expired */ +#define __MCPU_ENOSR 63 /* Out of streams resources */ +#define __MCPU_ENONET 64 /* Machine is not on the network */ +#define __MCPU_ENOPKG 65 /* Package not installed */ +#define __MCPU_EREMOTE 66 /* Object is remote */ +#define __MCPU_ENOLINK 67 /* Link has been severed */ +#define __MCPU_EADV 68 /* Advertise error */ +#define __MCPU_ESRMNT 69 /* Srmount error */ +#define __MCPU_ECOMM 70 /* Communication error on send */ +#define __MCPU_EPROTO 71 /* Protocol error */ +#define __MCPU_EMULTIHOP 72 /* Multihop attempted */ +#define __MCPU_EDOTDOT 73 /* RFS specific error */ +#define __MCPU_EBADMSG 74 /* Not a data message */ +#define __MCPU_EOVERFLOW 75 /* Value too large for defined data type */ +#define __MCPU_ENOTUNIQ 76 /* Name not unique on network */ +#define __MCPU_EBADFD 77 /* File descriptor in bad state */ +#define __MCPU_EREMCHG 78 /* Remote address changed */ +#define __MCPU_ELIBACC 79 /* Cannot access a needed shared library */ +#define __MCPU_ELIBBAD 80 /* Accessing a corrupted shared library */ +#define __MCPU_ELIBSCN 81 /* .lib section in a.out corrupted */ +#define __MCPU_ELIBMAX 82 /* Too many shared libraries */ +#define __MCPU_ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define __MCPU_EILSEQ 84 /* Illegal byte sequence */ +#define __MCPU_ERESTART 85 /* Interrupted syscall should be restarted */ +#define __MCPU_ESTRPIPE 86 /* Streams pipe error */ +#define __MCPU_EUSERS 87 /* Too many users */ +#define __MCPU_ENOTSOCK 88 /* Socket operation on non-socket */ +#define __MCPU_EDESTADDRREQ 89 /* Destination address required */ +#define __MCPU_EMSGSIZE 90 /* Message too long */ +#define __MCPU_EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define __MCPU_ENOPROTOOPT 92 /* Protocol not available */ +#define __MCPU_EPROTONOSUPPORT 93 /* Protocol not supported */ +#define __MCPU_ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define __MCPU_EOPNOTSUPP 95 /* Operation not supported */ +#define __MCPU_EPFNOSUPPORT 96 /* Protocol family not supported */ +#define __MCPU_EAFNOSUPPORT 97 /* Address family not supported */ +#define __MCPU_EADDRINUSE 98 /* Address already in use */ +#define __MCPU_EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define __MCPU_ENETDOWN 100 /* Network is down */ +#define __MCPU_ENETUNREACH 101 /* Network is unreachable */ +#define __MCPU_ENETRESET 102 /* Network dropped connection because of reset */ +#define __MCPU_ECONNABORTED 103 /* Software caused connection abort */ +#define __MCPU_ECONNRESET 104 /* Connection reset by peer */ +#define __MCPU_ENOBUFS 105 /* No buffer space available */ +#define __MCPU_EISCONN 106 /* Transport endpoint is already connected */ +#define __MCPU_ENOTCONN 107 /* Transport endpoint is not connected */ +#define __MCPU_ESHUTDOWN 108 /* Cannot send after endpoint shutdown */ +#define __MCPU_ETOOMANYREFS 109 /* Too many references */ +#define __MCPU_ETIMEDOUT 110 /* Connection timed out */ +#define __MCPU_ECONNREFUSED 111 /* Connection refused */ +#define __MCPU_EHOSTDOWN 112 /* Host is down */ +#define __MCPU_EHOSTUNREACH 113 /* No route to host */ +#define __MCPU_EALREADY 114 /* Operation already in progress */ +#define __MCPU_EINPROGRESS 115 /* Operation now in progress */ +#define __MCPU_ESTALE 116 /* Stale file handle */ +#define __MCPU_EUCLEAN 117 /* Structure needs cleaning */ +#define __MCPU_ENOTNAM 118 /* Not a XENIX named type file */ +#define __MCPU_ENAVAIL 119 /* No XENIX semaphores available */ +#define __MCPU_EISNAM 120 /* Is a named type file */ +#define __MCPU_EREMOTEIO 121 /* Remote I/O error */ +#define __MCPU_EDQUOT 122 /* Quota exceeded */ +#define __MCPU_ENOMEDIUM 123 /* No medium found */ +#define __MCPU_EMEDIUMTYPE 124 /* Wrong medium type */ +#define __MCPU_ECANCELED 125 /* Operation canceled */ +#define __MCPU_ENOKEY 126 /* Required key not available */ +#define __MCPU_EKEYEXPIRED 127 /* Key has expired */ +#define __MCPU_EKEYREVOKED 128 /* Key has been revoked */ +#define __MCPU_EKEYREJECTED 129 /* Key was rejected by service */ +#define __MCPU_EOWNERDEAD 130 /* Owner died */ +#define __MCPU_ENOTRECOVERABLE 131 /* State not recoverable */ +#define __MCPU_ERFKILL 132 /* Operation not possible due to RF-kill */ +#define __MCPU_EHWPOISON 133 /* Memory page has hardware error */ +#define __MCPU_EFTYPE 134 /* Wrong file type for intended operation */ + +#define __MCPU_ENOTSUP __MCPU_EOPNOTSUPP + +#define __MCPU_EUNKNOWN 4095 /* Unknown or unmapped HOST error */ + +#endif /* __CPU_ERRNO_H */ diff --git a/cpu/cpu-instruction.c b/cpu/cpu-instruction.c new file mode 100644 index 0000000..4a6b59e --- /dev/null +++ b/cpu/cpu-instruction.c @@ -0,0 +1,1649 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <string.h> +#include <libmcpu.h> +#include <cpu-context.h> +#include <cpu-registers.h> +#include <cpu-instruction.h> +#include <cpu-syscalls.h> + +static int +getreg( const cpu_operand *o, __mpu_UNIT_t **p, __mpu_size_t *n ) +{ + if( !o || o->type != CPU_OPERAND_REGISTER ) return( CPU_EXEC_OPERAND_FAULT ); + *n = __cpu_reg_size( o->value.reg.bits ); + if( !*n ) return( CPU_EXEC_REGISTER_FAULT ); + *p = __cpu_reg_ptr( o->value.reg.bits, o->value.reg.address ); + return( *p ? 0 : CPU_EXEC_REGISTER_FAULT ); +} + +static int +reg2( const cpu_instruction *i, __mpu_UNIT_t **d, __mpu_UNIT_t **a, __mpu_size_t *n ) +{ + __mpu_size_t nd, na; + int rc = getreg( &i->operand[0], d, &nd ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], a, &na ); + if( rc ) return( rc ); + if( nd != na ) return( CPU_EXEC_WIDTH_FAULT ); + *n = nd; + return( 0 ); +} + +static int +reg3( const cpu_instruction *i, __mpu_UNIT_t **d, __mpu_UNIT_t **a, __mpu_UNIT_t **b, __mpu_size_t *n ) +{ + __mpu_size_t nd, na, nb; + int rc = getreg( &i->operand[0], d, &nd ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], a, &na ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], b, &nb ); + if( rc ) return( rc ); + if( nd != na || nd != nb ) return( CPU_EXEC_WIDTH_FAULT ); + *n = nd; + return( 0 ); +} + +static int +valid_real( __mpu_size_t n ) +{ + return( n >= NB_R32 && n <= NB_R_MAX && ( n & ( n - 1 ) ) == 0 ); +} + +static int +valid_complex( __mpu_size_t n ) +{ + return( n >= 8 && n <= NB_C_MAX && ( n & ( n - 1 ) ) == 0 && valid_real( n / 2 ) ); +} + +/* + * LibMPU conversion helpers such as icvt()/r_cvt() may modify the LibMPU + * flag register as an implementation side effect. LibCPU conversion-class + * instructions are architecturally PSW-neutral, so preserve PSW[15:0]. + * + * Do this through the public LibCPU/LibMPU flag facade instead of depending + * on LibMPU's private __MPU_FLAGS/context implementation detail. + */ +static __mpu_uint32_t +cpu_status_flags_save( void ) +{ + return( __cpu_get_psw() & PSW_MPU_MASK ); +} + +static void +cpu_status_flags_restore( __mpu_uint32_t flags ) +{ + __mpu_uint32_t psw = __cpu_get_psw(); + __cpu_set_psw( ( psw & PSW_CPU_MASK ) | ( flags & PSW_MPU_MASK ) ); +} + +static int +stack_offset( __mpu_int64_t off, __mpu_uint64_t width, __mpu_uint64_t *pos ) +{ + __mpu_uint64_t p; + if( !__STACK || !__SSIZE || __SP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); + if( off < 0 ) + { + __mpu_uint64_t mag = (__mpu_uint64_t)( - ( off + 1 ) ) + 1U; + if( mag > __SP ) return( CPU_EXEC_STACK_FAULT ); + p = __SP - mag; + } + else + { + __mpu_uint64_t add = (__mpu_uint64_t)off; + if( add > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); + p = __SP + add; + } + if( p > __SSIZE || width > __SSIZE - p ) return( CPU_EXEC_STACK_FAULT ); + *pos = p; + return( CPU_EXEC_SUCCESS ); +} + +static int +frame_offset( __mpu_int64_t off, __mpu_uint64_t width, __mpu_uint64_t *pos ) +{ + __mpu_uint64_t p; + if( !__STACK || !__SSIZE || __FP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); + if( off < 0 ) + { + __mpu_uint64_t mag = (__mpu_uint64_t)( - ( off + 1 ) ) + 1U; + if( mag > __FP ) return( CPU_EXEC_STACK_FAULT ); + p = __FP - mag; + } + else + { + __mpu_uint64_t add = (__mpu_uint64_t)off; + if( add > __SSIZE - __FP ) return( CPU_EXEC_STACK_FAULT ); + p = __FP + add; + } + if( p > __SSIZE || width > __SSIZE - p ) return( CPU_EXEC_STACK_FAULT ); + *pos = p; + return( CPU_EXEC_SUCCESS ); +} + +static int +pointer_register( const cpu_operand *o, __mpu_UNIT_t **p ) +{ + __mpu_size_t n; + int rc = getreg( o, p, &n ); + if( rc ) return( rc ); + return( n == CPU_PTR64_SIZE ? CPU_EXEC_SUCCESS : CPU_EXEC_WIDTH_FAULT ); +} + +static int pointer_resolve( __mpu_uint64_t ptr, __mpu_uint64_t width, int write, + __mpu_UNIT_t **base, __mpu_uint64_t *offset) +{ + unsigned int seg; + + /* ABI NULL is the all-zero PTR64. It is never dereferenceable even + though its bit fields would otherwise decode as DATA offset zero. */ + if( ptr == CPU_NULL_PTR ) return( CPU_EXEC_POINTER_FAULT ); + seg = __cpu_ptr_segment( ptr ); + __mpu_uint64_t off = __cpu_ptr_offset( ptr ), size = 0; + __mpu_UNIT_t *mem = 0; + + switch( seg ) + { + case CPU_PTR_SEG_DATA: + mem = __DATA; + size = __DSIZE; + break; + case CPU_PTR_SEG_STACK: + mem = __STACK; + size = __SSIZE; + break; + case CPU_PTR_SEG_PROGRAM: + if( write ) return( CPU_EXEC_MEMORY_FAULT ); + mem = __PROGRAM; + size = __PSIZE; + break; + case CPU_PTR_SEG_CONTROL: + if( write ) return( CPU_EXEC_MEMORY_FAULT ); + mem = __CONTROL; + size = __CSIZE; + break; + case CPU_PTR_SEG_INPUT: + if( write ) return( CPU_EXEC_MEMORY_FAULT ); + mem = __INPUT; + size = __ISIZE; + break; + case CPU_PTR_SEG_OUTPUT: + mem = __OUTPUT; + size = __OSIZE; + break; + case CPU_PTR_SEG_TRACE: + mem = __TRACE; + size = __TSIZE; + break; + case CPU_PTR_SEG_HEAP: + mem = __HEAP; + size = __HBRK; + if( off < CPU_HEAP_BEGIN ) return( CPU_EXEC_MEMORY_FAULT ); + break; + default: + return( CPU_EXEC_POINTER_FAULT ); + } + + if( !mem || off > size || width > size - off ) return( CPU_EXEC_MEMORY_FAULT ); + *base = mem; + *offset = off; + return( CPU_EXEC_SUCCESS ); +} + +/* + * Apply a signed byte displacement to a PTR64 offset while preserving the + * four-bit segment selector. The arithmetic is deliberately performed on + * the 60-bit offset field only; carry/borrow is never allowed to enter SEG. + * `subtract' selects PTR - delta instead of PTR + delta. + */ +static int pointer_arith( __mpu_uint64_t ptr, __mpu_int64_t delta, int subtract, + __mpu_uint64_t *result) +{ + __mpu_uint64_t off = __cpu_ptr_offset( ptr ); + __mpu_uint64_t mag; + unsigned int seg = __cpu_ptr_segment( ptr ); + int positive = ( delta >= 0 ); + + if( !result ) return( CPU_EXEC_POINTER_FAULT ); + + if( positive ) + mag = (__mpu_uint64_t)delta; + else + mag = (__mpu_uint64_t)( - ( delta + 1 ) ) + __mpu_UINT64_C( 1 ); + + /* PTR - negative_delta is addition; PTR + negative_delta is subtraction. */ + if( ( !subtract && positive ) || ( subtract && !positive ) ) + { + if( mag > CPU_PTR_OFFSET_MASK - off ) return( CPU_EXEC_POINTER_FAULT ); + off+=mag; + } + else + { + if( mag > off ) return( CPU_EXEC_POINTER_FAULT ); + off -= mag; + } + + if( __cpu_ptr_make( result, seg, off ) ) return( CPU_EXEC_POINTER_FAULT ); + return( CPU_EXEC_SUCCESS ); +} + +static int +reg_i64( const cpu_operand *o, __mpu_int64_t *v ) +{ + __mpu_UNIT_t *p; + __mpu_uint64_t bits; + int rc = pointer_register( o, &p ); + if( rc ) return( rc ); + bits = __cpu_data_get_u64( p ); + memcpy( v, &bits, sizeof( *v ) ); + return( CPU_EXEC_SUCCESS ); +} + +static int +reg_ptr64( const cpu_operand *o, __mpu_uint64_t *v ) +{ + __mpu_UNIT_t *p; + int rc = pointer_register( o, &p ); + if( rc ) return( rc ); + *v = __cpu_data_get_u64( p ); + return( CPU_EXEC_SUCCESS ); +} + +static int +reg_u64( const cpu_operand *o, __mpu_uint64_t *v ) +{ + __mpu_UNIT_t *p; + int rc = pointer_register( o, &p ); + if( rc ) return( rc ); + *v = __cpu_data_get_u64( p ); + return( CPU_EXEC_SUCCESS ); +} + +static int +put_i64_result( const cpu_operand *o, __mpu_int64_t v ) +{ + __mpu_UNIT_t *p; + __mpu_uint64_t bits; + int rc = pointer_register( o, &p ); + if( rc ) return( rc ); + memcpy( &bits, &v, sizeof( bits ) ); + __cpu_data_put_u64( p, bits ); + return( CPU_EXEC_SUCCESS ); +} + +static int +put_u64_result( const cpu_operand *o, __mpu_uint64_t v ) +{ + __mpu_UNIT_t *p; + int rc = pointer_register( o, &p ); + if( rc ) return( rc ); + __cpu_data_put_u64( p, v ); + return( CPU_EXEC_SUCCESS ); +} + +static int +reg_count32( const cpu_operand *o, unsigned int *count ) +{ + __mpu_uint64_t v; + int rc = reg_u64( o, &v ); + if( rc ) return( rc ); + if( v > __mpu_UINT64_C( 0xffffffff ) ) return( CPU_EXEC_OPERAND_FAULT ); + *count = (unsigned int)(__mpu_uint32_t)v; + return( CPU_EXEC_SUCCESS ); +} + +/* Resolve an indirect control-flow operand. The register must be a physical + r64/PTR64 value selecting PROGRAM, and the byte offset must address the + current architectural PROGRAM size. No host pointer is ever accepted. */ +static int +code_pointer_target( const cpu_operand *o, __mpu_uint64_t *target ) +{ + __mpu_uint64_t ptr, off; + int rc; + + if( !target ) return( CPU_EXEC_POINTER_FAULT ); + rc = reg_ptr64( o, &ptr ); + if( rc ) return( rc ); + if( ptr == CPU_NULL_PTR || __cpu_ptr_segment( ptr ) != CPU_PTR_SEG_PROGRAM ) + return( CPU_EXEC_POINTER_FAULT ); + off = __cpu_ptr_offset( ptr ); + if( !__PROGRAM || off >= __PSIZE ) return( CPU_EXEC_POINTER_FAULT ); + *target = off; + return( CPU_EXEC_SUCCESS ); +} + +static int +rconst( mpu_real *d, int nb, __mpu_uint8_t k ) +{ + switch( k ) + { +#define K(x,f) case x: f(d,nb); return 0 + K( CPU_RCONST_ZERO, _m_zero ); + K( CPU_RCONST_HALF, _m_half ); + K( CPU_RCONST_ONE, _m_one ); + K( CPU_RCONST_TWO, _m_two ); + K( CPU_RCONST_TEN, _m_ten ); + K( CPU_RCONST_MTEN, _m_mten ); + K( CPU_RCONST_32, _m_32 ); + K( CPU_RCONST_PI, _m_PI ); + K( CPU_RCONST_E, _m_E ); + K( CPU_RCONST_1_LN2, _m_1_ln2 ); + K( CPU_RCONST_LN2, _m_ln2 ); + K( CPU_RCONST_1_LN10, _m_1_ln10 ); + K( CPU_RCONST_LN10, _m_ln10 ); + K( CPU_RCONST_1_LG2, _m_1_lg2 ); + K( CPU_RCONST_LG2, _m_lg2 ); + K( CPU_RCONST_PI_2, _m_PI_2 ); + K( CPU_RCONST_PI_3, _m_PI_3 ); + K( CPU_RCONST_PI_4, _m_PI_4 ); + K( CPU_RCONST_PI_5, _m_PI_5 ); + K( CPU_RCONST_PI_6, _m_PI_6 ); + K( CPU_RCONST_1_PI, _m_1_PI ); + K( CPU_RCONST_2_PI, _m_2_PI ); + K( CPU_RCONST_3_PI, _m_3_PI ); + K( CPU_RCONST_4_PI, _m_4_PI ); + K( CPU_RCONST_5_PI, _m_5_PI ); + K( CPU_RCONST_2PI, _m_2PI ); + K( CPU_RCONST_3PI, _m_3PI ); + K( CPU_RCONST_1_2PI, _m_1_2PI ); + K( CPU_RCONST_1_3PI, _m_1_3PI ); + K( CPU_RCONST_1_4PI, _m_1_4PI ); + K( CPU_RCONST_1_5PI, _m_1_5PI ); + K( CPU_RCONST_1_6PI, _m_1_6PI ); + K( CPU_RCONST_3PI_4, _m_3PI_4 ); + K( CPU_RCONST_SQRTPI, _m_SQRTPI ); + K( CPU_RCONST_1_SQRTPI, _m_1_SQRTPI ); + K( CPU_RCONST_2_SQRTPI, _m_2_SQRTPI ); + K( CPU_RCONST_SQRT2, _m_SQRT2 ); + K( CPU_RCONST_1_SQRT2, _m_1_SQRT2 ); + K( CPU_RCONST_SQRT3, _m_SQRT3 ); + K( CPU_RCONST_1_SQRT3, _m_1_SQRT3 ); + K( CPU_RCONST_DEGREE, _m_DEGREE ); + K( CPU_RCONST_1_DEGREE, _m_1_DEGREE ); + K( CPU_RCONST_GOLDENRATIO, _m_GOLDENRATIO ); + K( CPU_RCONST_EULERGAMMA, _m_EULERGAMMA ); + K( CPU_RCONST_CATALAN, _m_CATALAN ); + K( CPU_RCONST_EPSILON, _real_epsilon ); + K( CPU_RCONST_IND, _ind ); + case CPU_RCONST_PNAN: _nan( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NNAN: _nan( d, 1, nb ); + return( 0 ); + case CPU_RCONST_PNANMAX: _nan_max( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NNANMAX: _nan_max( d, 1, nb ); + return( 0 ); + case CPU_RCONST_PNANMIN: _nan_min( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NNANMIN: _nan_min( d, 1, nb ); + return( 0 ); + case CPU_RCONST_PINF: _inf( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NINF: _inf( d, 1, nb ); + return( 0 ); + case CPU_RCONST_PREALMIN: _real_min( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NREALMIN: _real_min( d, 1, nb ); + return( 0 ); + case CPU_RCONST_PREALMAX: _real_max( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NREALMAX: _real_max( d, 1, nb ); + return( 0 ); + case CPU_RCONST_PZERO: _signull( d, 0, nb ); + return( 0 ); + case CPU_RCONST_NZERO: _signull( d, 1, nb ); + return( 0 ); +#undef K + default: return( CPU_EXEC_OPERAND_FAULT ); + } +} + +int +__cpu_exec( const cpu_instruction *i ) +{ + __mpu_UNIT_t *d, *a, *b; + __mpu_size_t n; + int rc; + if( !i ) return( CPU_EXEC_INSTRUCTION_FAULT ); + switch( i->opcode ) + { + case CPU_OP_NOP: return( 0 ); + case CPU_OP_HALT: __cpu_sth(); + return( 0 ); + case CPU_OP_END: return( CPU_EXEC_END ); + case CPU_OP_SETF: + case CPU_OP_CLRF: + { + __mpu_uint32_t psw, mask; + if( i->operand[0].type != CPU_OPERAND_PSWBIT8 ) + return( CPU_EXEC_OPERAND_FAULT ); + if( i->operand[0].value.pswbit8 > CPU_PSWBIT_WRITE_MAX ) + return( CPU_EXEC_OPERAND_FAULT ); + psw = __cpu_get_psw(); + mask = (__mpu_uint32_t)1U << i->operand[0].value.pswbit8; + if( i->opcode == CPU_OP_SETF ) psw |= mask; + else psw &= ~mask; + __cpu_set_psw( psw ); + return( CPU_EXEC_SUCCESS ); + } + case CPU_OP_CLRCPUF: + __cpu_set_psw( __cpu_get_psw() & ~PSW_CPUF_MASK ); + return( CPU_EXEC_SUCCESS ); + case CPU_OP_CLRMPUF: + __cpu_set_psw( __cpu_get_psw() & ~PSW_MPUF_MASK ); + return( CPU_EXEC_SUCCESS ); + case CPU_OP_SYSCALL: + __cpu_data_put_u64( __cpu_reg_ptr( 64, CPU_SYSCALL_RET_ADDR ), + __cpu_syscall_dispatch() ); + return( CPU_EXEC_SUCCESS ); + case CPU_OP_EXIT: + { + __mpu_UNIT_t *p; + __mpu_size_t z; + __mpu_uint32_t u; + __mpu_int32_t status; + rc = getreg( &i->operand[0], &p, &z ); + if( rc ) return( rc ); + if( z != 4U ) return( CPU_EXEC_WIDTH_FAULT ); + u = __cpu_data_get_u32( p ); + memcpy( &status, &u, sizeof( status ) ); + __EXIT_STATUS = status; + return( CPU_EXEC_EXIT ); + } + case CPU_OP_CLR: rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + memset( d, 0, n ); + return( 0 ); + case CPU_OP_MOV: rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + memmove( d, a, n ); + return( 0 ); + case CPU_OP_SWAP: rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + { + __mpu_size_t k; + for( k = 0; k < n; k++ ) + { + __mpu_UNIT_t t = d[k]; + d[k] = a[k]; + a[k] = t; + } + } + return( 0 ); + case CPU_OP_BSWAP: + rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + { + __mpu_size_t k; + /* Equal-width naturally aligned register views are either identical or + disjoint. These two paths are therefore exactly equivalent to the + architectural source-snapshot semantics without an 8 KiB temp. */ + if( d == a ) + { + for( k = 0; k < n / 2U; k++ ) + { + __mpu_UNIT_t t = d[k]; + d[k] = d[n - 1U - k]; + d[n - 1U - k] = t; + } + } + else + { + for( k = 0; k < n; k++ ) d[k] = a[n - 1U - k]; + } + } + return( 0 ); + case CPU_OP_LDI: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( i->operand[1].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + mpu_int64_t s; + __mpu_int64_t v = (__mpu_int64_t)i->operand[1].value.imm64; + __mpu_uint32_t flags = cpu_status_flags_save(); + memcpy( s, &v, 8 ); + icvt( ( mpu_int * ) d, ( mpu_int * ) s, (int)n, NB_I64 ); + cpu_status_flags_restore( flags ); + } + return( 0 ); + case CPU_OP_LDR: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->operand[1].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + mpu_real64_t s; + __mpu_uint64_t u = i->operand[1].value.imm64; + __mpu_real64_t v; + __mpu_uint32_t flags = cpu_status_flags_save(); + memcpy( &v, &u, 8 ); + memcpy( s, &v, 8 ); + r_cvt( ( mpu_real * ) d, ( mpu_real * ) s, (int)n, NB_R64 ); + cpu_status_flags_restore( flags ); + } + return( 0 ); + case CPU_OP_LDC: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( !valid_complex( n ) ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->operand[1].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + mpu_real32_t sr, si; + mpu_wide_real_t rr, ri; + __mpu_uint32_t ur = (__mpu_uint32_t)( i->operand[1].value.imm64 >> 32 ), ui = (__mpu_uint32_t)i->operand[1].value.imm64; + __mpu_real32_t fr, fi; + int cn = (int)( n / 2 ); + __mpu_uint32_t flags = cpu_status_flags_save(); + memcpy( &fr, &ur, 4 ); + memcpy( &fi, &ui, 4 ); + memcpy( sr, &fr, 4 ); + memcpy( si, &fi, 4 ); + r_cvt( ( mpu_real * ) rr, ( mpu_real * ) sr, cn, NB_R32 ); + r_cvt( ( mpu_real * ) ri, ( mpu_real * ) si, cn, NB_R32 ); + c_gen_complex( ( mpu_complex * ) d, ( mpu_real * ) rr, ( mpu_real * ) ri, cn ); + cpu_status_flags_restore( flags ); + } + return( 0 ); + case CPU_OP_LOAD: + case CPU_OP_STORE: + { + const cpu_operand *ro = ( i->opcode == CPU_OP_LOAD ) ? &i->operand[0] : &i->operand[1]; + const cpu_operand *ao = ( i->opcode == CPU_OP_LOAD ) ? &i->operand[1] : &i->operand[0]; + rc = getreg( ro, &d, &n ); + if( rc ) return( rc ); + if( ao->type != CPU_OPERAND_ADDR64 ) return( CPU_EXEC_OPERAND_FAULT ); + if( ao->value.addr64 > __DSIZE || (__mpu_uint64_t)n > __DSIZE - ao->value.addr64 ) return( CPU_EXEC_MEMORY_FAULT ); + if( i->opcode == CPU_OP_LOAD ) memmove( d, __DATA + ao->value.addr64, n ); + else memmove( __DATA + ao->value.addr64, d, n ); + return( 0 ); + } + + case CPU_OP_LEA: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( n != CPU_PTR64_SIZE ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->operand[1].type != CPU_OPERAND_PTR64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint64_t ptr = i->operand[1].value.ptr64, off = __cpu_ptr_offset( ptr ), size = 0; + unsigned int seg = __cpu_ptr_segment( ptr ); + switch( seg ) + { + case CPU_PTR_SEG_DATA: size = __DSIZE; + break; + case CPU_PTR_SEG_STACK: size = __SSIZE; + break; + case CPU_PTR_SEG_PROGRAM: size = __PSIZE; + break; + case CPU_PTR_SEG_CONTROL: size = __CSIZE; + break; + case CPU_PTR_SEG_INPUT: size = __ISIZE; + break; + case CPU_PTR_SEG_OUTPUT: size = __OSIZE; + break; + case CPU_PTR_SEG_TRACE: size = __TSIZE; + break; + case CPU_PTR_SEG_HEAP: size = __HBRK; + if( off < CPU_HEAP_BEGIN ) return( CPU_EXEC_MEMORY_FAULT ); + break; + default: return( CPU_EXEC_POINTER_FAULT ); + } + if( off > size ) return( CPU_EXEC_MEMORY_FAULT ); + __cpu_data_put_u64( d, ptr ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_LEASP: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( n != CPU_PTR64_SIZE ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint64_t pos, ptr; + rc = stack_offset( i->operand[1].value.off64, 0, &pos ); + if( rc ) return( rc ); + if( pos > CPU_PTR_OFFSET_MASK ) return( CPU_EXEC_POINTER_FAULT ); + if( __cpu_ptr_make( &ptr, CPU_PTR_SEG_STACK, pos ) ) return( CPU_EXEC_POINTER_FAULT ); + __cpu_data_put_u64( d, ptr ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_LOADP: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + rc = pointer_register( &i->operand[1], &a ); + if( rc ) return( rc ); + { + __mpu_uint64_t ptr, off; + __mpu_UNIT_t *base; + ptr = __cpu_data_get_u64( a ); + rc = pointer_resolve( ptr, (__mpu_uint64_t)n, 0, &base, &off ); + if( rc ) return( rc ); + memmove( d, base + off, n ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_STOREP: + rc = pointer_register( &i->operand[0], &a ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &d, &n ); + if( rc ) return( rc ); + { + __mpu_uint64_t ptr, off; + __mpu_UNIT_t *base; + ptr = __cpu_data_get_u64( a ); + rc = pointer_resolve( ptr, (__mpu_uint64_t)n, 1, &base, &off ); + if( rc ) return( rc ); + memmove( base + off, d, n ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_BMOV: + case CPU_OP_BMOVI: + { + __mpu_uint64_t dstptr, srcptr, count, dstoff, srcoff; + __mpu_UNIT_t *dstbase, *srcbase; + rc = reg_ptr64( &i->operand[0], &dstptr ); + if( rc ) return( rc ); + rc = reg_ptr64( &i->operand[1], &srcptr ); + if( rc ) return( rc ); + if( i->opcode == CPU_OP_BMOV ) + { + rc = reg_u64( &i->operand[2], &count ); + if( rc ) return( rc ); + } + else + { + if( i->operand[2].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); + count = i->operand[2].value.imm64; + } + /* Resolve and validate both complete ranges before modifying memory. */ + rc = pointer_resolve( srcptr, count, 0, &srcbase, &srcoff ); + if( rc ) return( rc ); + rc = pointer_resolve( dstptr, count, 1, &dstbase, &dstoff ); + if( rc ) return( rc ); + if( (__mpu_uint64_t)(size_t)count != count ) return( CPU_EXEC_MEMORY_FAULT ); + memmove( dstbase + dstoff, srcbase + srcoff, (size_t)count ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_PADD: + case CPU_OP_PSUB: + { + __mpu_uint64_t ptr, out; + __mpu_int64_t delta; + rc = pointer_register( &i->operand[0], &d ); + if( rc ) return( rc ); + rc = reg_ptr64( &i->operand[1], &ptr ); + if( rc ) return( rc ); + rc = reg_i64( &i->operand[2], &delta ); + if( rc ) return( rc ); + rc = pointer_arith( ptr, delta, i->opcode == CPU_OP_PSUB, &out ); + if( rc ) return( rc ); + __cpu_data_put_u64( d, out ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_PADDI: + case CPU_OP_PSUBI: + { + __mpu_uint64_t ptr, out; + __mpu_int64_t delta; + rc = pointer_register( &i->operand[0], &d ); + if( rc ) return( rc ); + rc = reg_ptr64( &i->operand[1], &ptr ); + if( rc ) return( rc ); + if( i->operand[2].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + delta = i->operand[2].value.off64; + rc = pointer_arith( ptr, delta, i->opcode == CPU_OP_PSUBI, &out ); + if( rc ) return( rc ); + __cpu_data_put_u64( d, out ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_PDIFF: + { + __mpu_uint64_t left, right; + __mpu_int64_t diff; + rc = pointer_register( &i->operand[0], &d ); + if( rc ) return( rc ); + rc = reg_ptr64( &i->operand[1], &left ); + if( rc ) return( rc ); + rc = reg_ptr64( &i->operand[2], &right ); + if( rc ) return( rc ); + if( __cpu_ptr_segment( left ) != __cpu_ptr_segment( right ) ) + return( CPU_EXEC_POINTER_FAULT ); + diff = (__mpu_int64_t)__cpu_ptr_offset( left ) - + (__mpu_int64_t)__cpu_ptr_offset( right ); + { + __mpu_uint64_t bits; + memcpy( &bits, &diff, sizeof( bits ) ); + __cpu_data_put_u64( d, bits ); + } + } + return( CPU_EXEC_SUCCESS ); + +#define I3(op,fn) case op: rc=reg3(i,&d,&a,&b,&n);if(rc)return rc;fn((mpu_int*)d,(mpu_int*)a,(mpu_int*)b,(int)n);return 0 + I3( CPU_OP_IADD, iadd ); + I3( CPU_OP_IADC, iadc ); + I3( CPU_OP_ISUB, isub ); + I3( CPU_OP_ISBB, isbb ); + I3( CPU_OP_IAND, iand ); + I3( CPU_OP_IOR, ior ); + I3( CPU_OP_IXOR, ixor ); +#undef I3 +#define I2(op,fn) case op: rc=reg2(i,&d,&a,&n);if(rc)return rc;fn((mpu_int*)d,(mpu_int*)a,(int)n);return 0 + I2( CPU_OP_INOT, inot ); + I2( CPU_OP_INEG, ineg ); + I2( CPU_OP_ISHL, ishl ); + I2( CPU_OP_ISHR, ishr ); + I2( CPU_OP_ISAL, isal ); + I2( CPU_OP_ISAR, isar ); + I2( CPU_OP_IROL, irol ); + I2( CPU_OP_IROR, iror ); + I2( CPU_OP_IRCL, ircl ); + I2( CPU_OP_IRCR, ircr ); + I2( CPU_OP_IINC, iinc ); + I2( CPU_OP_IDEC, idec ); +#undef I2 + case CPU_OP_IXCHG: + rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + ixchg( ( mpu_int * ) d, ( mpu_int * ) a, (int)n ); + return( 0 ); + case CPU_OP_ICPY: + case CPU_OP_ICVT: + { + __mpu_size_t nd, na; + rc = getreg( &i->operand[0], &d, &nd ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + if( i->opcode == CPU_OP_ICPY ) icpy( ( mpu_int * ) d, ( mpu_int * ) a, (int)nd, (int)na ); + else + { + __mpu_uint32_t flags = cpu_status_flags_save(); + icvt( ( mpu_int * ) d, ( mpu_int * ) a, (int)nd, (int)na ); + cpu_status_flags_restore( flags ); + } + } + return( 0 ); + case CPU_OP_ISHLN: case CPU_OP_ISHRN: case CPU_OP_ISALN: case CPU_OP_ISARN: + case CPU_OP_IROLN: case CPU_OP_IRORN: case CPU_OP_IRCLN: case CPU_OP_IRCRN: + { + __mpu_size_t nd, na; + unsigned int count; + rc = getreg( &i->operand[0], &d, &nd ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + if( nd != na ) return( CPU_EXEC_WIDTH_FAULT ); + rc = reg_count32( &i->operand[2], &count ); + if( rc ) return( rc ); + switch( i->opcode ) + { + case CPU_OP_ISHLN: ishln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + case CPU_OP_ISHRN: ishrn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + case CPU_OP_ISALN: isaln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + case CPU_OP_ISARN: isarn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + case CPU_OP_IROLN: iroln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + case CPU_OP_IRORN: irorn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + case CPU_OP_IRCLN: ircln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + default: ircrn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); + break; + } + } + return( 0 ); + case CPU_OP_IMUL: + case CPU_OP_ISMUL: + { + __mpu_size_t np, na, nb; + rc = getreg( &i->operand[0], &d, &np ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &b, &nb ); + if( rc ) return( rc ); + if( na != nb || np < 2U * na ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->opcode == CPU_OP_IMUL ) imul( ( mpu_int * ) d, ( mpu_int * ) a, ( mpu_int * ) b, (int)np, (int)na ); + else ismul( ( mpu_int * ) d, ( mpu_int * ) a, ( mpu_int * ) b, (int)np, (int)na ); + } + return( 0 ); + case CPU_OP_IDIV: + case CPU_OP_ISDIV: + { + __mpu_UNIT_t *q, *r, *num, *den; + __mpu_size_t nq, nr, nn, nd; + rc = getreg( &i->operand[0], &q, &nq ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &r, &nr ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &num, &nn ); + if( rc ) return( rc ); + rc = getreg( &i->operand[3], &den, &nd ); + if( rc ) return( rc ); + if( nq != nr || nq != nn || nq != nd ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->opcode == CPU_OP_IDIV ) idiv( ( mpu_int * ) q, ( mpu_int * ) r, ( mpu_int * ) num, ( mpu_int * ) den, (int)nq ); + else isdiv( ( mpu_int * ) q, ( mpu_int * ) r, ( mpu_int * ) num, ( mpu_int * ) den, (int)nq ); + } + return( 0 ); + case CPU_OP_IBITSLEN: + { + __mpu_size_t na; + int v; + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + v = ibits_len( ( mpu_int * ) a, (int)na ); + return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); + } + case CPU_OP_ICMP: case CPU_OP_ITEST: + rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + if( i->opcode == CPU_OP_ICMP ) icmp( ( mpu_int * ) d, ( mpu_int * ) a, (int)n ); + else itest( ( mpu_int * ) d, ( mpu_int * ) a, (int)n ); + return( 0 ); + +#define R3(op,fn,limit) case op: rc=reg3(i,&d,&a,&b,&n);if(rc)return rc;if(!valid_real(n)||n>(limit))return CPU_EXEC_WIDTH_FAULT;fn((mpu_real*)d,(mpu_real*)a,(mpu_real*)b,(int)n);return 0 + R3( CPU_OP_RADD, r_add, NB_R_MAX ); + R3( CPU_OP_RSUB, r_sub, NB_R_MAX ); + R3( CPU_OP_RMUL, r_mul, NB_R_MAX ); + R3( CPU_OP_RDIV, r_div, NB_R_MAX ); + R3( CPU_OP_RPOW, r_pow, NB_R16384 ); + R3( CPU_OP_RHYPOT, r_hypot, NB_R16384 ); + R3( CPU_OP_RATAN2, r_atan2, NB_R16384 ); + R3( CPU_OP_RREMAIN, r_remain, NB_R_MAX ); +#undef R3 +#define R2(op,fn,limit) case op: rc=reg2(i,&d,&a,&n);if(rc)return rc;if(!valid_real(n)||n>(limit))return CPU_EXEC_WIDTH_FAULT;fn((mpu_real*)d,(mpu_real*)a,(int)n);return 0 + R2( CPU_OP_RSQRT, r_sqrt, NB_R16384 ); + R2( CPU_OP_RSIN, r_sin, NB_R16384 ); + R2( CPU_OP_RCOS, r_cos, NB_R16384 ); + R2( CPU_OP_RTAN, r_tan, NB_R16384 ); + R2( CPU_OP_RASIN, r_asin, NB_R16384 ); + R2( CPU_OP_RACOS, r_acos, NB_R16384 ); + R2( CPU_OP_RATAN, r_atan, NB_R16384 ); + R2( CPU_OP_RLOG, r_log, NB_R16384 ); + R2( CPU_OP_RLOG10, r_log10, NB_R16384 ); + R2( CPU_OP_RLOG2, r_log2, NB_R16384 ); + R2( CPU_OP_REXP, r_exp, NB_R16384 ); + R2( CPU_OP_RSINH, r_sinh, NB_R16384 ); + R2( CPU_OP_RCOSH, r_cosh, NB_R16384 ); + R2( CPU_OP_RTANH, r_tanh, NB_R16384 ); + R2( CPU_OP_RFLOOR, r_floor, NB_R_MAX ); + R2( CPU_OP_RCEIL, r_ceil, NB_R_MAX ); + R2( CPU_OP_RROUND, r_round, NB_R_MAX ); + R2( CPU_OP_RLOG1P, r_log1p, NB_R16384 ); + R2( CPU_OP_REXPM1, r_expm1, NB_R16384 ); + R2( CPU_OP_RASINH, r_asinh, NB_R16384 ); + R2( CPU_OP_RACOSH, r_acosh, NB_R16384 ); + R2( CPU_OP_RATANH, r_atanh, NB_R16384 ); +#undef R2 + case CPU_OP_RNEG: + case CPU_OP_RABS: + rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); + if( d != a ) r_cpy( ( mpu_real * ) d, ( mpu_real * ) a, (int)n ); + if( i->opcode == CPU_OP_RNEG ) r_neg( ( mpu_real * ) d, (int)n ); + else r_abs( ( mpu_real * ) d, (int)n ); + return( 0 ); + case CPU_OP_RCPY: + rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); + r_cpy( ( mpu_real * ) d, ( mpu_real * ) a, (int)n ); + return( 0 ); + case CPU_OP_RCVT: + { + __mpu_size_t nd, na; + rc = getreg( &i->operand[0], &d, &nd ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + if( !valid_real( nd ) || !valid_real( na ) ) return( CPU_EXEC_WIDTH_FAULT ); + { + __mpu_uint32_t flags = cpu_status_flags_save(); + r_cvt( ( mpu_real * ) d, ( mpu_real * ) a, (int)nd, (int)na ); + cpu_status_flags_restore( flags ); + } + } + return( 0 ); + case CPU_OP_RCMP: + { + __mpu_size_t na, nb; + int v; + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &b, &nb ); + if( rc ) return( rc ); + if( na != nb || !valid_real( na ) ) return( CPU_EXEC_WIDTH_FAULT ); + v = r_cmp( ( mpu_real * ) a, ( mpu_real * ) b, (int)na ); + return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); + } + case CPU_OP_RFREXP: + { + __mpu_UNIT_t *sig, *exp, *src; + __mpu_size_t nsig, nexp, nsrc; + rc = getreg( &i->operand[0], &sig, &nsig ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &exp, &nexp ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &src, &nsrc ); + if( rc ) return( rc ); + if( nsig != nsrc || !valid_real( nsig ) ) return( CPU_EXEC_WIDTH_FAULT ); + r_frexp( ( mpu_real * ) sig, ( mpu_int * ) exp, ( mpu_real * ) src, (int)nexp, (int)nsrc ); + } + return( 0 ); + case CPU_OP_RLDEXP: + { + __mpu_UNIT_t *dst, *src, *exp; + __mpu_size_t ndst, nsrc, nexp; + rc = getreg( &i->operand[0], &dst, &ndst ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &src, &nsrc ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &exp, &nexp ); + if( rc ) return( rc ); + if( ndst != nsrc || !valid_real( ndst ) ) return( CPU_EXEC_WIDTH_FAULT ); + r_ldexp( ( mpu_real * ) dst, ( mpu_real * ) src, ( mpu_int * ) exp, (int)ndst, (int)nexp ); + } + return( 0 ); + case CPU_OP_RLOGB: + { + __mpu_UNIT_t *dst, *src; + __mpu_size_t ndst, nsrc; + rc = getreg( &i->operand[0], &dst, &ndst ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &src, &nsrc ); + if( rc ) return( rc ); + if( !valid_real( nsrc ) ) return( CPU_EXEC_WIDTH_FAULT ); + r_logb( ( mpu_int * ) dst, ( mpu_real * ) src, (int)ndst, (int)nsrc ); + } + return( 0 ); + case CPU_OP_RMODF: + { + __mpu_UNIT_t *frac, *integ, *src; + __mpu_size_t nf, ni, ns; + rc = getreg( &i->operand[0], &frac, &nf ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &integ, &ni ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &src, &ns ); + if( rc ) return( rc ); + if( nf != ni || nf != ns || !valid_real( nf ) ) return( CPU_EXEC_WIDTH_FAULT ); + r_modf( ( mpu_real * ) frac, ( mpu_real * ) integ, ( mpu_real * ) src, (int)nf ); + } + return( 0 ); + case CPU_OP_ITOR: + case CPU_OP_UITOR: + { + __mpu_UNIT_t *rdst, *isrc; + __mpu_size_t nr, ni; + rc = getreg( &i->operand[0], &rdst, &nr ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &isrc, &ni ); + if( rc ) return( rc ); + if( !valid_real( nr ) ) return( CPU_EXEC_WIDTH_FAULT ); + { + __mpu_uint32_t flags = cpu_status_flags_save(); + if( i->opcode == CPU_OP_ITOR ) ltor( ( mpu_real * ) rdst, ( mpu_int * ) isrc, (int)nr, (int)ni ); + else ultor( ( mpu_real * ) rdst, ( mpu_int * ) isrc, (int)nr, (int)ni ); + cpu_status_flags_restore( flags ); + } + } + return( 0 ); + case CPU_OP_RTOI: + case CPU_OP_RTOUI: + { + __mpu_UNIT_t *idst, *frac, *src; + __mpu_size_t ni, nf, ns; + rc = getreg( &i->operand[0], &idst, &ni ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &frac, &nf ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &src, &ns ); + if( rc ) return( rc ); + if( nf != ns || !valid_real( nf ) ) return( CPU_EXEC_WIDTH_FAULT ); + { + __mpu_uint32_t flags = cpu_status_flags_save(); + if( i->opcode == CPU_OP_RTOI ) rtol_frac( ( mpu_int * ) idst, ( mpu_real * ) frac, ( mpu_real * ) src, (int)ni, (int)ns ); + else rtoul_frac( ( mpu_int * ) idst, ( mpu_real * ) frac, ( mpu_real * ) src, (int)ni, (int)ns ); + cpu_status_flags_restore( flags ); + } + } + return( 0 ); + case CPU_OP_RISNEG: + case CPU_OP_RSIGN: + case CPU_OP_RISIND: + case CPU_OP_RISNAN: + case CPU_OP_RISNANMAX: + case CPU_OP_RISNANMIN: + case CPU_OP_RISINF: + case CPU_OP_RISSIGNULL: + { + __mpu_size_t ns; + int v; + rc = getreg( &i->operand[1], &a, &ns ); + if( rc ) return( rc ); + if( !valid_real( ns ) ) return( CPU_EXEC_WIDTH_FAULT ); + switch( i->opcode ) + { + case CPU_OP_RISNEG: v = r_is_neg( ( mpu_real * ) a, (int)ns ); + break; + case CPU_OP_RSIGN: v = r_sign( ( mpu_real * ) a, (int)ns ); + break; + case CPU_OP_RISIND: v = _is_ind( ( mpu_real * ) a, (int)ns ); + break; + case CPU_OP_RISNAN: v = _is_nans( ( mpu_real * ) a, (int)ns ); + break; + case CPU_OP_RISNANMAX: v = _is_nan_max( ( mpu_real * ) a, (int)ns ); + break; + case CPU_OP_RISNANMIN: v = _is_nan_min( ( mpu_real * ) a, (int)ns ); + break; + case CPU_OP_RISINF: v = _is_inf( ( mpu_real * ) a, (int)ns ); + break; + default: v = _is_signull( ( mpu_real * ) a, (int)ns ); + break; + } + return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); + } + case CPU_OP_RCONST: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->operand[1].type != CPU_OPERAND_CONST8 ) return( CPU_EXEC_OPERAND_FAULT ); + return( rconst( ( mpu_real * ) d, (int)n, i->operand[1].value.const8 ) ); + +#define C3(op,fn,limit) case op: rc=reg3(i,&d,&a,&b,&n);if(rc)return rc;if(!valid_complex(n)||n>(limit))return CPU_EXEC_WIDTH_FAULT;fn((mpu_complex*)d,(mpu_complex*)a,(mpu_complex*)b,(int)(n/2));return 0 + C3( CPU_OP_CADD, c_add, NB_C_MAX ); + C3( CPU_OP_CSUB, c_sub, NB_C_MAX ); + C3( CPU_OP_CMUL, c_mul, NB_C_MAX ); + C3( CPU_OP_CDIV, c_div, NB_C_MAX ); + C3( CPU_OP_CPOW, c_pow, NB_C32768 ); +#undef C3 +#define C2(op,fn) case op: rc=reg2(i,&d,&a,&n);if(rc)return rc;if(!valid_complex(n)||n>NB_C32768)return CPU_EXEC_WIDTH_FAULT;fn((mpu_complex*)d,(mpu_complex*)a,(int)(n/2));return 0 + C2( CPU_OP_CEXP, c_exp ); + C2( CPU_OP_CSIN, c_sin ); + C2( CPU_OP_CCOS, c_cos ); + C2( CPU_OP_CSINH, c_sinh ); + C2( CPU_OP_CCOSH, c_cosh ); + C2( CPU_OP_CLOG, c_log ); + C2( CPU_OP_CSQRT, c_sqrt ); +#undef C2 + case CPU_OP_CCONJ: + case CPU_OP_CCPY: + rc = reg2( i, &d, &a, &n ); + if( rc ) return( rc ); + if( !valid_complex( n ) ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->opcode == CPU_OP_CCONJ ) c_conj( ( mpu_complex * ) d, ( mpu_complex * ) a, (int)( n / 2 ) ); + else c_cpy( ( mpu_complex * ) d, ( mpu_complex * ) a, (int)( n / 2 ) ); + return( 0 ); + case CPU_OP_CCVT: + { + __mpu_size_t nd, ns; + rc = getreg( &i->operand[0], &d, &nd ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &ns ); + if( rc ) return( rc ); + if( !valid_complex( nd ) || !valid_complex( ns ) ) return( CPU_EXEC_WIDTH_FAULT ); + { + __mpu_uint32_t flags = cpu_status_flags_save(); + c_cvt( ( mpu_complex * ) d, ( mpu_complex * ) a, (int)( nd / 2 ), (int)( ns / 2 ) ); + cpu_status_flags_restore( flags ); + } + } + return( 0 ); + case CPU_OP_CREAL: + case CPU_OP_CIMAG: + case CPU_OP_CABS: + case CPU_OP_CNORM: + case CPU_OP_CARG: + { + __mpu_size_t nr, nc; + rc = getreg( &i->operand[0], &d, &nr ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &nc ); + if( rc ) return( rc ); + if( !valid_real( nr ) || !valid_complex( nc ) || nc != 2U * nr ) return( CPU_EXEC_WIDTH_FAULT ); + if( ( i->opcode == CPU_OP_CABS || i->opcode == CPU_OP_CARG ) && nr > NB_R16384 ) + return( CPU_EXEC_WIDTH_FAULT ); + switch( i->opcode ) + { + case CPU_OP_CREAL: c_real_part( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); + break; + case CPU_OP_CIMAG: c_imaginary( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); + break; + case CPU_OP_CABS: c_abs( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); + break; + case CPU_OP_CNORM: c_norm( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); + break; + default: c_arg( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); + break; + } + } + return( 0 ); + case CPU_OP_CRTOC: + { + __mpu_size_t nc, nr; + rc = getreg( &i->operand[0], &d, &nc ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &nr ); + if( rc ) return( rc ); + if( !valid_complex( nc ) || !valid_real( nr ) || nc != 2U * nr ) return( CPU_EXEC_WIDTH_FAULT ); + { + __mpu_uint32_t flags = cpu_status_flags_save(); + c_real_to_complex( ( mpu_complex * ) d, ( mpu_real * ) a, (int)nr ); + cpu_status_flags_restore( flags ); + } + } + return( 0 ); + case CPU_OP_CGEN: + case CPU_OP_CPOLAR: + { + __mpu_size_t nc, nr, ni; + rc = getreg( &i->operand[0], &d, &nc ); + if( rc ) return( rc ); + rc = getreg( &i->operand[1], &a, &nr ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &b, &ni ); + if( rc ) return( rc ); + if( nr != ni || !valid_real( nr ) || !valid_complex( nc ) || nc != 2U * nr ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->opcode == CPU_OP_CPOLAR && nr > NB_R16384 ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->opcode == CPU_OP_CGEN ) c_gen_complex( ( mpu_complex * ) d, ( mpu_real * ) a, ( mpu_real * ) b, (int)nr ); + else c_polar( ( mpu_complex * ) d, ( mpu_real * ) a, ( mpu_real * ) b, (int)nr ); + } + return( 0 ); + case CPU_OP_CISEQ: + case CPU_OP_CISNE: + { + __mpu_size_t na, nb; + int v; + rc = getreg( &i->operand[1], &a, &na ); + if( rc ) return( rc ); + rc = getreg( &i->operand[2], &b, &nb ); + if( rc ) return( rc ); + if( na != nb || !valid_complex( na ) ) return( CPU_EXEC_WIDTH_FAULT ); + v = ( i->opcode == CPU_OP_CISEQ ) ? + c_is_equal( ( mpu_complex * ) a, ( mpu_complex * ) b, (int)( na / 2 ) ): + c_is_nequal( ( mpu_complex * ) a, ( mpu_complex * ) b, (int)( na / 2 ) ); + return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); + } + + case CPU_OP_JMP: + if( i->operand[0].type != CPU_OPERAND_CODE64 ) return( CPU_EXEC_OPERAND_FAULT ); + if( i->operand[0].value.code64 >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); + __PC = i->operand[0].value.code64; + return( CPU_EXEC_BRANCH ); + + case CPU_OP_JMPP: + { + __mpu_uint64_t target; + rc = code_pointer_target( &i->operand[0], &target ); + if( rc ) return( rc ); + __PC = target; + } + return( CPU_EXEC_BRANCH ); + + case CPU_OP_JSET: + case CPU_OP_JCLR: + if( i->operand[0].type != CPU_OPERAND_PSWBIT8 || + i->operand[1].type != CPU_OPERAND_CODE64) + return( CPU_EXEC_OPERAND_FAULT ); + if( i->operand[0].value.pswbit8 > CPU_PSWBIT_MAX ) + return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint32_t mask = (__mpu_uint32_t)1U << i->operand[0].value.pswbit8; + int set = ( ( __cpu_get_psw() & mask ) != 0 ); + int take = ( i->opcode == CPU_OP_JSET ) ? set : !set; + if( take ) + { + if( i->operand[1].value.code64 >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); + __PC = i->operand[1].value.code64; + return( CPU_EXEC_BRANCH ); + } + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_CALL: + if( i->operand[0].type != CPU_OPERAND_CODE64 ) return( CPU_EXEC_OPERAND_FAULT ); + if( i->operand[0].value.code64 >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); + if( __PC > __PSIZE || ( CPU_OPCODE_SIZE + CPU_CODE64_SIZE ) > __PSIZE - __PC ) return( CPU_EXEC_MEMORY_FAULT ); + { + __mpu_uint64_t ret = __PC + CPU_OPCODE_SIZE + CPU_CODE64_SIZE; + __mpu_uint64_t p; + if( ret >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); + if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_CODE64_SIZE > __SP ) return( CPU_EXEC_STACK_FAULT ); + p = __SP - CPU_CODE64_SIZE; + __cpu_data_put_u64( __STACK + p, ret ); + __SP = p; + __PC = i->operand[0].value.code64; + } + return( CPU_EXEC_BRANCH ); + + case CPU_OP_CALLP: + { + const __mpu_uint64_t ilen = CPU_OPCODE_SIZE + CPU_REG24_SIZE; + __mpu_uint64_t target, ret, p; + + /* Validate every source of failure before touching STACK, SP or PC. */ + rc = code_pointer_target( &i->operand[0], &target ); + if( rc ) return( rc ); + if( __PC > __PSIZE || ilen > __PSIZE - __PC ) return( CPU_EXEC_MEMORY_FAULT ); + ret = __PC + ilen; + if( ret >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); + if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_CODE64_SIZE > __SP ) + return( CPU_EXEC_STACK_FAULT ); + + p = __SP - CPU_CODE64_SIZE; + __cpu_data_put_u64( __STACK + p, ret ); + __SP = p; + __PC = target; + } + return( CPU_EXEC_BRANCH ); + + case CPU_OP_RET: + { + __mpu_uint64_t target; + if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_CODE64_SIZE > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); + target = __cpu_data_get_u64( __STACK + __SP ); + if( target >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); + __SP+=CPU_CODE64_SIZE; + __PC = target; + } + return( CPU_EXEC_BRANCH ); + + case CPU_OP_PUSH: + rc = getreg( &i->operand[0], &a, &n ); + if( rc ) return( rc ); + if( !__STACK || !__SSIZE || __SP > __SSIZE || (__mpu_uint64_t)n > __SP ) return( CPU_EXEC_STACK_FAULT ); + { + __mpu_uint64_t p = __SP - (__mpu_uint64_t)n; + memmove( __STACK + p, a, n ); + __SP = p; + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_POP: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( !__STACK || !__SSIZE || __SP > __SSIZE || (__mpu_uint64_t)n > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); + memmove( d, __STACK + __SP, n ); + __SP += (__mpu_uint64_t)n; + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_LDSP: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint64_t p; + rc = stack_offset( i->operand[1].value.off64, (__mpu_uint64_t)n, &p ); + if( rc ) return( rc ); + memmove( d, __STACK + p, n ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_STSP: + if( i->operand[0].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + rc = getreg( &i->operand[1], &a, &n ); + if( rc ) return( rc ); + { + __mpu_uint64_t p; + rc = stack_offset( i->operand[0].value.off64, (__mpu_uint64_t)n, &p ); + if( rc ) return( rc ); + memmove( __STACK + p, a, n ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_ADJSP: + if( i->operand[0].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint64_t p; + rc = stack_offset( i->operand[0].value.off64, 0, &p ); + if( rc ) return( rc ); + __SP = p; + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_PUSHFP: + if( !__STACK || !__SSIZE || __SP > __SSIZE || __FP > __SSIZE || CPU_PTR64_SIZE > __SP ) + return( CPU_EXEC_STACK_FAULT ); + { + __mpu_uint64_t p = __SP - CPU_PTR64_SIZE; + __cpu_data_put_u64( __STACK + p, __FP ); + __SP = p; + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_SETFP: + if( !__STACK || !__SSIZE || __SP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); + __FP = __SP; + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_RESTSP: + if( !__STACK || !__SSIZE || __FP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); + __SP = __FP; + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_POPFP: + { + __mpu_uint64_t oldfp; + if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_PTR64_SIZE > __SSIZE - __SP ) + return( CPU_EXEC_STACK_FAULT ); + oldfp = __cpu_data_get_u64( __STACK + __SP ); + if( oldfp > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); + __FP = oldfp; + __SP+=CPU_PTR64_SIZE; + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_LDFP: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint64_t p; + rc = frame_offset( i->operand[1].value.off64, (__mpu_uint64_t)n, &p ); + if( rc ) return( rc ); + memmove( d, __STACK + p, n ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_STFP: + if( i->operand[0].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + rc = getreg( &i->operand[1], &a, &n ); + if( rc ) return( rc ); + { + __mpu_uint64_t p; + rc = frame_offset( i->operand[0].value.off64, (__mpu_uint64_t)n, &p ); + if( rc ) return( rc ); + memmove( __STACK + p, a, n ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_LEAFP: + rc = getreg( &i->operand[0], &d, &n ); + if( rc ) return( rc ); + if( n != CPU_PTR64_SIZE ) return( CPU_EXEC_WIDTH_FAULT ); + if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); + { + __mpu_uint64_t pos, ptr; + rc = frame_offset( i->operand[1].value.off64, 0, &pos ); + if( rc ) return( rc ); + if( pos > CPU_PTR_OFFSET_MASK ) return( CPU_EXEC_POINTER_FAULT ); + if( __cpu_ptr_make( &ptr, CPU_PTR_SEG_STACK, pos ) ) return( CPU_EXEC_POINTER_FAULT ); + __cpu_data_put_u64( d, ptr ); + } + return( CPU_EXEC_SUCCESS ); + + case CPU_OP_SETSP: + rc = pointer_register( &i->operand[0], &a ); + if( rc ) return( rc ); + { + __mpu_uint64_t ptr, off; + unsigned int seg; + ptr = __cpu_data_get_u64( a ); + seg = __cpu_ptr_segment( ptr ); + off = __cpu_ptr_offset( ptr ); + if( seg != CPU_PTR_SEG_STACK ) return( CPU_EXEC_POINTER_FAULT ); + if( !__STACK || !__SSIZE || off > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); + __SP = off; + } + return( CPU_EXEC_SUCCESS ); + + default: return( CPU_EXEC_OPCODE_FAULT ); + } +} + +static int +decode_need( __mpu_uint64_t program_size, __mpu_uint64_t pos, + __mpu_uint64_t n ) +{ + return( pos <= program_size && n <= program_size - pos ); +} + +static int +decode_reg( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, + cpu_operand *o, __mpu_uint64_t *p ) +{ + if( !decode_need( program_size, *p, 3 ) || __cpu_decode_reg24( &o->value.reg, program + *p ) ) return( -1 ); + o->type = CPU_OPERAND_REGISTER; + *p += 3; + return( 0 ); +} + +static int +decode_u64( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, + cpu_operand *o, __mpu_uint64_t *p, cpu_operand_type t ) +{ + __mpu_uint64_t v; + if( !decode_need( program_size, *p, 8 ) ) return( -1 ); + v = __cpu_code_get_u64( program + *p ); + *p += 8; + o->type = t; + if( t == CPU_OPERAND_IMM64 ) o->value.imm64 = v; + else if( t == CPU_OPERAND_ADDR64 ) o->value.addr64 = v; + else if( t == CPU_OPERAND_CODE64 ) o->value.code64 = v; + else if( t == CPU_OPERAND_OFF64 ) memcpy( &o->value.off64, &v, sizeof( v ) ); + else if( t == CPU_OPERAND_PTR64 ) o->value.ptr64 = v; + else return( -1 ); + return( 0 ); +} + +static int +decode_u8( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, + cpu_operand *o, __mpu_uint64_t *p, cpu_operand_type t ) +{ + __mpu_uint8_t v; + if( !decode_need( program_size, *p, 1 ) ) return( -1 ); + v = program[ ( *p )++]; + o->type = t; + if( t == CPU_OPERAND_CONST8 ) o->value.const8 = v; + else if( t == CPU_OPERAND_PSWBIT8 ) o->value.pswbit8 = v; + else return( -1 ); + return( 0 ); +} + +int +__cpu_decode_at( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, + __mpu_uint64_t pc, cpu_instruction *i ) +{ + __mpu_uint64_t p = pc, start = p; + __mpu_uint16_t op; + int k; + if( !i || !program || !decode_need( program_size, p, 2 ) ) return( CPU_EXEC_DECODE_FAULT ); + memset( i, 0, sizeof( *i ) ); + op = __cpu_code_get_u16( program + p ); + p += 2; + i->opcode = (cpu_opcode)op; +#define DR(n) do{for(k=0;k<(n);k++)if(decode_reg(program,program_size,&i->operand[k],&p))return CPU_EXEC_DECODE_FAULT;}while(0) + switch( op ) + { + case CPU_OP_NOP:case CPU_OP_HALT:case CPU_OP_END:case CPU_OP_SYSCALL:case CPU_OP_RET: + case CPU_OP_CLRCPUF:case CPU_OP_CLRMPUF: + case CPU_OP_PUSHFP:case CPU_OP_SETFP:case CPU_OP_RESTSP:case CPU_OP_POPFP:break; + case CPU_OP_SETF:case CPU_OP_CLRF: + if( decode_u8( program, program_size, &i->operand[0], &p, CPU_OPERAND_PSWBIT8 ) ) return( CPU_EXEC_DECODE_FAULT ); + if( i->operand[0].value.pswbit8 > CPU_PSWBIT_WRITE_MAX ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_CLR: case CPU_OP_EXIT: DR( 1 ); + break; + case CPU_OP_MOV:case CPU_OP_SWAP:case CPU_OP_BSWAP: + case CPU_OP_INOT:case CPU_OP_INEG:case CPU_OP_ICMP:case CPU_OP_ITEST: + case CPU_OP_ISHL:case CPU_OP_ISHR:case CPU_OP_ISAL:case CPU_OP_ISAR: + case CPU_OP_IROL:case CPU_OP_IROR:case CPU_OP_IRCL:case CPU_OP_IRCR: + case CPU_OP_IINC:case CPU_OP_IDEC:case CPU_OP_IXCHG:case CPU_OP_ICPY: + case CPU_OP_ICVT:case CPU_OP_IBITSLEN: + case CPU_OP_RSQRT:case CPU_OP_RSIN:case CPU_OP_RCOS:case CPU_OP_RTAN: + case CPU_OP_RASIN:case CPU_OP_RACOS:case CPU_OP_RATAN: + case CPU_OP_RLOG:case CPU_OP_RLOG10:case CPU_OP_RLOG2:case CPU_OP_REXP: + case CPU_OP_RSINH:case CPU_OP_RCOSH:case CPU_OP_RTANH: + case CPU_OP_RNEG:case CPU_OP_RABS:case CPU_OP_RCPY:case CPU_OP_RCVT: + case CPU_OP_RFLOOR:case CPU_OP_RCEIL:case CPU_OP_RROUND:case CPU_OP_RLOGB: + case CPU_OP_RLOG1P:case CPU_OP_REXPM1:case CPU_OP_RASINH:case CPU_OP_RACOSH:case CPU_OP_RATANH: + case CPU_OP_ITOR:case CPU_OP_UITOR: + case CPU_OP_RISNEG:case CPU_OP_RSIGN:case CPU_OP_RISIND:case CPU_OP_RISNAN: + case CPU_OP_RISNANMAX:case CPU_OP_RISNANMIN:case CPU_OP_RISINF:case CPU_OP_RISSIGNULL: + case CPU_OP_CEXP:case CPU_OP_CSIN:case CPU_OP_CCOS:case CPU_OP_CSINH: + case CPU_OP_CCOSH:case CPU_OP_CLOG:case CPU_OP_CSQRT: + case CPU_OP_CREAL:case CPU_OP_CIMAG:case CPU_OP_CRTOC:case CPU_OP_CCONJ: + case CPU_OP_CABS:case CPU_OP_CNORM:case CPU_OP_CARG:case CPU_OP_CCPY:case CPU_OP_CCVT: + DR( 2 ); + break; + case CPU_OP_IADD:case CPU_OP_IADC:case CPU_OP_ISUB:case CPU_OP_ISBB: + case CPU_OP_IAND:case CPU_OP_IOR:case CPU_OP_IXOR: + case CPU_OP_ISHLN:case CPU_OP_ISHRN:case CPU_OP_ISALN:case CPU_OP_ISARN: + case CPU_OP_IROLN:case CPU_OP_IRORN:case CPU_OP_IRCLN:case CPU_OP_IRCRN: + case CPU_OP_IMUL:case CPU_OP_ISMUL: + case CPU_OP_RADD:case CPU_OP_RSUB:case CPU_OP_RMUL:case CPU_OP_RDIV: + case CPU_OP_RPOW:case CPU_OP_RHYPOT:case CPU_OP_RATAN2:case CPU_OP_RCMP: + case CPU_OP_RFREXP:case CPU_OP_RLDEXP:case CPU_OP_RMODF:case CPU_OP_RREMAIN: + case CPU_OP_RTOI:case CPU_OP_RTOUI: + case CPU_OP_CADD:case CPU_OP_CSUB:case CPU_OP_CMUL:case CPU_OP_CDIV:case CPU_OP_CPOW: + case CPU_OP_CGEN:case CPU_OP_CPOLAR:case CPU_OP_CISEQ:case CPU_OP_CISNE: + DR( 3 ); + break; + case CPU_OP_IDIV: case CPU_OP_ISDIV: DR( 4 ); + break; + case CPU_OP_LDI: case CPU_OP_LDR: case CPU_OP_LDC: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_IMM64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_LOAD: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_ADDR64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_STORE: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_ADDR64 ) ) return( CPU_EXEC_DECODE_FAULT ); + if( decode_reg( program, program_size, &i->operand[1], &p ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_LEA: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_PTR64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_LEASP: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_LOADP: case CPU_OP_STOREP: DR( 2 ); + break; + case CPU_OP_PADD: case CPU_OP_PSUB: case CPU_OP_PDIFF: case CPU_OP_BMOV: DR( 3 ); + break; + case CPU_OP_BMOVI: + DR( 2 ); + if( decode_u64( program, program_size, &i->operand[2], &p, CPU_OPERAND_IMM64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_PADDI:case CPU_OP_PSUBI: + DR( 2 ); + if( decode_u64( program, program_size, &i->operand[2], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_RCONST: DR( 1 ); + if( decode_u8( program, program_size, &i->operand[1], &p, CPU_OPERAND_CONST8 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_JMP: case CPU_OP_CALL: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_CODE64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_JMPP: case CPU_OP_CALLP: DR( 1 ); + break; + case CPU_OP_JSET:case CPU_OP_JCLR: + if( decode_u8( program, program_size, &i->operand[0], &p, CPU_OPERAND_PSWBIT8 ) ) return( CPU_EXEC_DECODE_FAULT ); + if( i->operand[0].value.pswbit8 > CPU_PSWBIT_MAX ) return( CPU_EXEC_DECODE_FAULT ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_CODE64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_PUSH: case CPU_OP_POP: DR( 1 ); + break; + case CPU_OP_LDSP: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_STSP: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + if( decode_reg( program, program_size, &i->operand[1], &p ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_ADJSP: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_LDFP: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_STFP: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + if( decode_reg( program, program_size, &i->operand[1], &p ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_LEAFP: DR( 1 ); + if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); + break; + case CPU_OP_SETSP: DR( 1 ); + break; + default: return( CPU_EXEC_OPCODE_FAULT ); + } +#undef DR + i->length = p - start; + return( 0 ); +} + + +int +__cpu_decode( cpu_instruction *i ) +{ + return( __cpu_decode_at( __PROGRAM, __PSIZE, __PC, i ) ); + +} /* End of __cpu_decode() */ + +int +__cpu_step( void ) +{ + cpu_instruction i; + int rc = __cpu_decode( &i ); + if( rc ) + { + __STOP_REASON = CPU_STOP_FAULT; + return( rc ); + } + rc = __cpu_exec( &i ); + if( rc == CPU_EXEC_BRANCH ) + { + if( __cpu_gth() ) + { + __STOP_REASON = CPU_STOP_HALT; + return( CPU_EXEC_HALT ); + } + return( CPU_EXEC_SUCCESS ); + } + if( rc == CPU_EXEC_END ) + { + __PC += i.length; + __STOP_REASON = CPU_STOP_END; + return( rc ); + } + if( rc == CPU_EXEC_EXIT ) + { + __PC += i.length; + __STOP_REASON = CPU_STOP_EXIT; + return( rc ); + } + if( rc < 0 ) + { + __STOP_REASON = CPU_STOP_FAULT; + return( rc ); + } + if( rc ) return( rc ); + __PC+=i.length; + if( __cpu_gth() ) + { + __STOP_REASON = CPU_STOP_HALT; + return( CPU_EXEC_HALT ); + } + return( CPU_EXEC_SUCCESS ); +} + +int +__cpu_run( void ) +{ + int rc; + __cpu_clh(); + __cpu_clear_stop_reason(); + for( ; ; ) + { + rc = __cpu_step(); + if( rc == CPU_EXEC_HALT ) return( CPU_EXEC_SUCCESS ); + if( rc != CPU_EXEC_SUCCESS ) return( rc ); + } +} diff --git a/cpu/cpu-instruction.h b/cpu/cpu-instruction.h new file mode 100644 index 0000000..d787b43 --- /dev/null +++ b/cpu/cpu-instruction.h @@ -0,0 +1,32 @@ +/*************************************************************** + __CPU_INSTRUCTION.H + + This file contains CPU INSTRUCTION operation functions & + data declarations. + + PART OF : CPU - library . + + USAGE : Internal only . + + NOTE : Include "libcpu.h" before this FILE . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_INSTRUCTION_H +#define __CPU_INSTRUCTION_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define __CPU_MAX_OPERANDS 4 + + +#ifdef __cplusplus +} /* ... extern "C" */ +#endif + +#endif /* __CPU_INSTRUCTION_H */ diff --git a/cpu/cpu-registers.c b/cpu/cpu-registers.c new file mode 100644 index 0000000..7cd7dee --- /dev/null +++ b/cpu/cpu-registers.c @@ -0,0 +1,74 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <libmcpu.h> +#include <cpu-context.h> +#include <cpu-registers.h> + +__mpu_size_t +__cpu_reg_size( unsigned int bits ) +{ + if( bits < 8 || bits > 65536 || ( bits & ( bits - 1 ) ) ) return( 0 ); + return( (__mpu_size_t)( bits >> 3 ) ); +} + +int +__cpu_reg_valid( unsigned int bits, __mpu_uint32_t a ) +{ + __mpu_size_t n = __cpu_reg_size( bits ); + if( !n ) return( 0 ); + if( ( a & ( n - 1 ) ) != 0 ) return( 0 ); + if( a > CPU_REGISTER_ADDRESS_MAX ) return( 0 ); + if( (__mpu_uint64_t)a + n > CPU_REGISTERS_MEM_SIZE_IN_UNITS ) return( 0 ); + return( 1 ); +} + +__mpu_UNIT_t * +__cpu_reg_ptr( unsigned int bits, __mpu_uint32_t a ) +{ + return( __cpu_reg_valid( bits, a ) ? &__REGS[a] : (__mpu_UNIT_t *)0 ); +} + +int +__cpu_encode_reg24( __mpu_UNIT_t out[3], const cpu_register *r ) +{ + unsigned int code = 0, b; + if( !out || !r || !__cpu_reg_valid( r->bits, r->address ) ) return( -1 ); + b = r->bits; + while( b > 8 ) + { + b >>= 1; + ++code; + } + if( code > 13 ) return( -1 ); + out[0] = (__mpu_UNIT_t)( ( code << 4 ) | ( ( r->address >> 16 ) & 0x0f ) ); + out[1] = (__mpu_UNIT_t)( ( r->address >> 8 ) & 0xff ); + out[2] = (__mpu_UNIT_t)( r->address & 0xff ); + return( 0 ); +} + +int +__cpu_decode_reg24( cpu_register *r, const __mpu_UNIT_t in[3] ) +{ + unsigned int code; + __mpu_uint32_t a; + if( !r || !in ) return( -1 ); + code = ( in[0] >> 4 ) & 0x0f; + if( code > 13 ) return( -1 ); + a = ( (__mpu_uint32_t)( in[0] & 0x0f ) << 16 ) | ( (__mpu_uint32_t)in[1] << 8 ) | in[2]; + r->bits = 8U << code; + r->address = a; + return( __cpu_reg_valid( r->bits, a ) ? 0 : -1 ); +} + +int +__cpu_return_reg( cpu_register *r, unsigned int bits ) +{ + __mpu_size_t n; + if( !r ) return( -1 ); + n = __cpu_reg_size( bits ); + if( !n || (__mpu_uint64_t)n > CPU_RETURN_AREA_SIZE ) return( -1 ); + r->bits = bits; + r->address = (__mpu_uint32_t)( CPU_RETURN_AREA_END - (__mpu_uint32_t)n ); + return( __cpu_reg_valid( r->bits, r->address ) ? 0 : -1 ); +} diff --git a/cpu/cpu-registers.h b/cpu/cpu-registers.h new file mode 100644 index 0000000..f9bf9cb --- /dev/null +++ b/cpu/cpu-registers.h @@ -0,0 +1,33 @@ +/*************************************************************** + __CPU_REGISTERS.H + + This file contains CPU REGISTER operation functions & data + declarations. + + PART OF : CPU - library . + + USAGE : Internal only . + + NOTE : Include "libcpu.h" before this FILE . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_REGISTERS_H +#define __CPU_REGISTERS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define __CPU_REGISTER_MIN_BITS 8 +#define __CPU_REGISTER_MAX_BITS 65536 + + +#ifdef __cplusplus +} /* ... extern "C" */ +#endif + +#endif /* __CPU_REGISTERS_H */ diff --git a/cpu/cpu-syscalls.c b/cpu/cpu-syscalls.c new file mode 100644 index 0000000..f12e729 --- /dev/null +++ b/cpu/cpu-syscalls.c @@ -0,0 +1,2174 @@ +/*************************************************************** + __CPU_SYSCALLS.C + + This file contains source code of MCPU system calls. + + PART OF : CPU - library . + + USAGE : Internal only . + + NOTE : NONE . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#include <libmcpu.h> +#include <cpu-context.h> +#include <cpu-syscalls.h> +#include <cpu-sysdeps.h> + + +#define __NR_brk 10 +#define __NR_gettimeofday 0x01c +#define __NR_clock_getres 0x021 +#define __NR_clock_gettime 0x022 +#define __NR_nanosleep 0x030 +#define __NR_clock_nanosleep 0x031 + +#define __NR_read 0x100 +#define __NR_write 0x101 +#define __NR_lseek 0x102 +#define __NR_open 0x103 +#define __NR_creat 0x104 +#define __NR_close 0x105 +#define __NR_link 0x106 +#define __NR_unlink 0x107 +#define __NR_chdir 0x108 +#define __NR_mkdir 0x109 +#define __NR_chmod 0x10b +#define __NR_chown 0x10c +#define __NR_access 0x10f +#define __NR_rename 0x111 +#define __NR_rmdir 0x112 +#define __NR_symlink 0x113 +#define __NR_readlink 0x114 +#define __NR_stat 0x115 +#define __NR_fstat 0x116 +#define __NR_lstat 0x117 +#define __NR_fcntl 0x119 +#define __NR_pipe2 0x11a +#define __NR_getdents 0x11d +#define __NR_select 0x11e +#define __NR_fsync 0x120 +#define __NR_truncate 0x121 +#define __NR_ftruncate 0x122 +#define __NR_fchmod 0x123 +#define __NR_fchown 0x124 +#define __NR_fchdir 0x125 +#define __NR_dup 0x126 +#define __NR_dup2 0x127 + +#define CPU_PATH_MAX 4096U + + +static __mpu_uint64_t +__cpu_syscall_error( int error ) +{ + __mpu_int64_t ret = -(__mpu_int64_t)error; + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_syscall_error() */ + + +static __mpu_uint32_t +__cpu_syscall_nargs( void ) +{ + return( __cpu_data_get_u32( __cpu_reg_ptr( 32, CPU_SYSCALL_NARGS_ADDR ) ) ); + +} /* End of __cpu_syscall_nargs() */ + + +static __mpu_uint64_t +__cpu_syscall_arg( unsigned int n ) +{ + static const __mpu_uint32_t address[CPU_SYSCALL_MAX_ARGS] = + { + CPU_SYSCALL_ARG0_ADDR, + CPU_SYSCALL_ARG1_ADDR, + CPU_SYSCALL_ARG2_ADDR, + CPU_SYSCALL_ARG3_ADDR, + CPU_SYSCALL_ARG4_ADDR, + CPU_SYSCALL_ARG5_ADDR + }; + + if( n >= CPU_SYSCALL_MAX_ARGS ) return( 0 ); + + return( __cpu_data_get_u64( __cpu_reg_ptr( 64, address[n] ) ) ); + +} /* End of __cpu_syscall_arg() */ + + +static int +__cpu_memory_resolve( __mpu_uint64_t ptr, __mpu_uint64_t size, int write, + __mpu_UNIT_t **memory ) +{ + __mpu_UNIT_t *base = (__mpu_UNIT_t *)0; + __mpu_uint64_t limit = 0; + __mpu_uint64_t offset; + unsigned int segment; + + if( !memory ) return( __MCPU_EFAULT ); + *memory = (__mpu_UNIT_t *)0; + + if( ptr == CPU_NULL_PTR ) return( __MCPU_EFAULT ); + + segment = __cpu_ptr_segment( ptr ); + offset = __cpu_ptr_offset( ptr ); + + switch( segment ) + { + case CPU_PTR_SEG_DATA: + base = __DATA; + limit = __DSIZE; + break; + case CPU_PTR_SEG_STACK: + base = __STACK; + limit = __SSIZE; + break; + case CPU_PTR_SEG_PROGRAM: + if( write ) return( __MCPU_EFAULT ); + base = __PROGRAM; + limit = __PSIZE; + break; + case CPU_PTR_SEG_CONTROL: + if( write ) return( __MCPU_EFAULT ); + base = __CONTROL; + limit = __CSIZE; + break; + case CPU_PTR_SEG_INPUT: + if( write ) return( __MCPU_EFAULT ); + base = __INPUT; + limit = __ISIZE; + break; + case CPU_PTR_SEG_OUTPUT: + base = __OUTPUT; + limit = __OSIZE; + break; + case CPU_PTR_SEG_TRACE: + base = __TRACE; + limit = __TSIZE; + break; + case CPU_PTR_SEG_HEAP: + base = __HEAP; + limit = __HBRK; + if( offset < CPU_HEAP_BEGIN ) return( __MCPU_EFAULT ); + break; + default: + return( __MCPU_EFAULT ); + } + + if( !base || offset > limit || size > limit - offset ) return( __MCPU_EFAULT ); + + *memory = base + offset; + return( 0 ); + +} /* End of __cpu_memory_resolve() */ + + +static int +__cpu_copyin( void *dst, __mpu_uint64_t src, __mpu_uint64_t size ) +{ + __mpu_UNIT_t *memory; + int error; + + if( !size ) return( 0 ); + if( !dst ) return( __MCPU_EFAULT ); + + error = __cpu_memory_resolve( src, size, 0, &memory ); + if( error ) return( error ); + + memcpy( dst, memory, (size_t)size ); + return( 0 ); + +} /* End of __cpu_copyin() */ + + +static int +__cpu_copyout( __mpu_uint64_t dst, const void *src, __mpu_uint64_t size ) +{ + __mpu_UNIT_t *memory; + int error; + + if( !size ) return( 0 ); + if( !src ) return( __MCPU_EFAULT ); + + error = __cpu_memory_resolve( dst, size, 1, &memory ); + if( error ) return( error ); + + memcpy( memory, src, (size_t)size ); + return( 0 ); + +} /* End of __cpu_copyout() */ + + +static int +__cpu_utf8_valid( const unsigned char *s, size_t n ) +{ + size_t i = 0; + + while( i < n ) + { + unsigned int c = s[i++]; + + if( c < 0x80U ) continue; + + if( c >= 0xc2U && c <= 0xdfU ) + { + if( i >= n || ( s[i] & 0xc0U ) != 0x80U ) return( 0 ); + ++i; + continue; + } + + if( c == 0xe0U ) + { + if( i + 1 >= n || s[i] < 0xa0U || s[i] > 0xbfU || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; + continue; + } + + if( c >= 0xe1U && c <= 0xecU ) + { + if( i + 1 >= n || ( s[i] & 0xc0U ) != 0x80U || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; + continue; + } + + if( c == 0xedU ) + { + if( i + 1 >= n || s[i] < 0x80U || s[i] > 0x9fU || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; + continue; + } + + if( c >= 0xeeU && c <= 0xefU ) + { + if( i + 1 >= n || ( s[i] & 0xc0U ) != 0x80U || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; + continue; + } + + if( c == 0xf0U ) + { + if( i + 2 >= n || s[i] < 0x90U || s[i] > 0xbfU || + ( s[i + 1] & 0xc0U ) != 0x80U || + ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); + i += 3; + continue; + } + + if( c >= 0xf1U && c <= 0xf3U ) + { + if( i + 2 >= n || ( s[i] & 0xc0U ) != 0x80U || + ( s[i + 1] & 0xc0U ) != 0x80U || + ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); + i += 3; + continue; + } + + if( c == 0xf4U ) + { + if( i + 2 >= n || s[i] < 0x80U || s[i] > 0x8fU || + ( s[i + 1] & 0xc0U ) != 0x80U || + ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); + i += 3; + continue; + } + + return( 0 ); + } + + return( 1 ); + +} /* End of __cpu_utf8_valid() */ + + +static int +__cpu_copyinstr( char **dst, __mpu_uint64_t src ) +{ + __mpu_UNIT_t *memory; + __mpu_uint64_t offset; + __mpu_uint64_t limit; + __mpu_uint64_t n; + unsigned int segment; + char *s; + + if( !dst ) return( __MCPU_EFAULT ); + *dst = (char *)0; + + if( src == CPU_NULL_PTR ) return( __MCPU_EFAULT ); + + segment = __cpu_ptr_segment( src ); + offset = __cpu_ptr_offset( src ); + + if( __cpu_memory_resolve( src, 1, 0, &memory ) != 0 ) return( __MCPU_EFAULT ); + + switch( segment ) + { + case CPU_PTR_SEG_DATA: limit = __DSIZE; break; + case CPU_PTR_SEG_STACK: limit = __SSIZE; break; + case CPU_PTR_SEG_PROGRAM: limit = __PSIZE; break; + case CPU_PTR_SEG_CONTROL: limit = __CSIZE; break; + case CPU_PTR_SEG_INPUT: limit = __ISIZE; break; + case CPU_PTR_SEG_OUTPUT: limit = __OSIZE; break; + case CPU_PTR_SEG_TRACE: limit = __TSIZE; break; + case CPU_PTR_SEG_HEAP: limit = __HBRK; break; + default: return( __MCPU_EFAULT ); + } + + n = 0; + while( offset + n < limit && n < CPU_PATH_MAX ) + { + if( memory[n] == 0 ) break; + ++n; + } + + if( offset + n >= limit || n >= CPU_PATH_MAX ) return( __MCPU_ENAMETOOLONG ); + if( !__cpu_utf8_valid( memory, (size_t)n ) ) return( __MCPU_EILSEQ ); + + s = (char *)malloc( (size_t)n + 1U ); + if( !s ) return( __MCPU_ENOMEM ); + memcpy( s, memory, (size_t)n ); + s[n] = '\0'; + *dst = s; + + return( 0 ); + +} /* End of __cpu_copyinstr() */ + + +void +__cpu_fd_context_init( void ) +{ + unsigned int i; + + if( !pcctx ) return; + + for( i = 0; i < CPU_GUEST_FD_MAX; ++i ) + { + pcctx->_fd[i].host_fd = -1; + pcctx->_fd[i].owned = 0; + pcctx->_fd[i].flags = 0; + } + + pcctx->_fd[0].host_fd = 0; + pcctx->_fd[1].host_fd = 1; + pcctx->_fd[2].host_fd = 2; + pcctx->_fd[0].flags = 0; + pcctx->_fd[1].flags = 0; + pcctx->_fd[2].flags = 0; + pcctx->_fd_initialized = 1; + +} /* End of __cpu_fd_context_init() */ + + +void +__cpu_fd_context_free( void ) +{ + unsigned int i; + + if( !pcctx || !pcctx->_fd_initialized ) return; + + for( i = 0; i < CPU_GUEST_FD_MAX; ++i ) + { + if( pcctx->_fd[i].host_fd >= 0 && pcctx->_fd[i].owned ) + (void)__cpu_sys_close( pcctx->_fd[i].host_fd ); + + pcctx->_fd[i].host_fd = -1; + pcctx->_fd[i].owned = 0; + pcctx->_fd[i].flags = 0; + } + + pcctx->_fd_initialized = 0; + +} /* End of __cpu_fd_context_free() */ + + +void +__cpu_cwd_context_init( void ) +{ + __mpu_int64_t ret; + + if( !pcctx ) return; + + pcctx->_cwd_fd = -1; + pcctx->_cwd_initialized = 0; + + ret = __cpu_sys_cwd_init(); + if( ret < 0 ) return; + + pcctx->_cwd_fd = (int)ret; + pcctx->_cwd_initialized = 1; + +} /* End of __cpu_cwd_context_init() */ + + +void +__cpu_cwd_context_free( void ) +{ + if( !pcctx || !pcctx->_cwd_initialized ) return; + + if( pcctx->_cwd_fd >= 0 ) + (void)__cpu_sys_close( pcctx->_cwd_fd ); + + pcctx->_cwd_fd = -1; + pcctx->_cwd_initialized = 0; + +} /* End of __cpu_cwd_context_free() */ + + +static int +__cpu_fd_get( __mpu_uint64_t fd, int *host_fd ) +{ + if( !pcctx || !pcctx->_fd_initialized || fd >= CPU_GUEST_FD_MAX || + pcctx->_fd[fd].host_fd < 0 ) return( __MCPU_EBADF ); + + if( host_fd ) *host_fd = pcctx->_fd[fd].host_fd; + return( 0 ); + +} /* End of __cpu_fd_get() */ + + +static int +__cpu_fd_find_from( __mpu_uint64_t minimum ) +{ + unsigned int fd; + + if( !pcctx || !pcctx->_fd_initialized || minimum >= CPU_GUEST_FD_MAX ) + return( -1 ); + + for( fd = (unsigned int)minimum; fd < CPU_GUEST_FD_MAX; ++fd ) + if( pcctx->_fd[fd].host_fd < 0 ) return( (int)fd ); + + return( -1 ); + +} /* End of __cpu_fd_find_from() */ + + +static int +__cpu_fd_install_from( int host_fd, __mpu_uint64_t minimum, unsigned int flags ) +{ + int fd; + + if( host_fd < 0 ) return( -1 ); + + fd = __cpu_fd_find_from( minimum ); + if( fd < 0 ) return( -1 ); + + pcctx->_fd[fd].host_fd = host_fd; + pcctx->_fd[fd].owned = 1; + pcctx->_fd[fd].flags = flags; + + return( fd ); + +} /* End of __cpu_fd_install_from() */ + + +static int +__cpu_fd_install( int host_fd ) +{ + return( __cpu_fd_install_from( host_fd, 3, 0 ) ); + +} /* End of __cpu_fd_install() */ + + + + +static __mpu_uint64_t +__cpu_stat_i64_bits( __mpu_int64_t value ) +{ + __mpu_uint64_t bits; + + memcpy( &bits, &value, sizeof( bits ) ); + return( bits ); + +} /* End of __cpu_stat_i64_bits() */ + + +static int +__cpu_stat_copyout( __mpu_uint64_t ptr, const struct __cpu_stat *st ) +{ + __mpu_UNIT_t data[__CPU_STAT_SIZE]; + + if( !st ) return( __MCPU_EFAULT ); + + memset( data, 0, sizeof( data ) ); + + __cpu_data_put_u64( data + __CPU_STAT_ST_DEV, st->st_dev ); + __cpu_data_put_u64( data + __CPU_STAT_ST_INO, st->st_ino ); + __cpu_data_put_u64( data + __CPU_STAT_ST_MODE, st->st_mode ); + __cpu_data_put_u64( data + __CPU_STAT_ST_NLINK, st->st_nlink ); + __cpu_data_put_u64( data + __CPU_STAT_ST_UID, st->st_uid ); + __cpu_data_put_u64( data + __CPU_STAT_ST_GID, st->st_gid ); + __cpu_data_put_u64( data + __CPU_STAT_ST_RDEV, st->st_rdev ); + __cpu_data_put_u64( data + __CPU_STAT_ST_SIZE, __cpu_stat_i64_bits( st->st_size ) ); + __cpu_data_put_u64( data + __CPU_STAT_ST_BLKSIZE, __cpu_stat_i64_bits( st->st_blksize ) ); + __cpu_data_put_u64( data + __CPU_STAT_ST_BLOCKS, __cpu_stat_i64_bits( st->st_blocks ) ); + __cpu_data_put_u64( data + __CPU_STAT_ST_ATIME_SEC, __cpu_stat_i64_bits( st->st_atime_sec ) ); + __cpu_data_put_u64( data + __CPU_STAT_ST_ATIME_NSEC, st->st_atime_nsec ); + __cpu_data_put_u64( data + __CPU_STAT_ST_MTIME_SEC, __cpu_stat_i64_bits( st->st_mtime_sec ) ); + __cpu_data_put_u64( data + __CPU_STAT_ST_MTIME_NSEC, st->st_mtime_nsec ); + __cpu_data_put_u64( data + __CPU_STAT_ST_CTIME_SEC, __cpu_stat_i64_bits( st->st_ctime_sec ) ); + __cpu_data_put_u64( data + __CPU_STAT_ST_CTIME_NSEC, st->st_ctime_nsec ); + + return( __cpu_copyout( ptr, data, sizeof( data ) ) ); + +} /* End of __cpu_stat_copyout() */ + + +static __mpu_uint64_t +__cpu_dirent_i64_bits( __mpu_int64_t value ) +{ + __mpu_uint64_t bits; + + memcpy( &bits, &value, sizeof( bits ) ); + return( bits ); + +} /* End of __cpu_dirent_i64_bits() */ + + +static int +__cpu_dirent_copyout( __mpu_uint64_t ptr, const struct __cpu_dirent *de, + __mpu_uint64_t count ) +{ + __mpu_UNIT_t *data; + __mpu_uint64_t nrecords; + __mpu_uint64_t i; + int error; + + if( !de && count ) return( __MCPU_EFAULT ); + if( count % __CPU_DIRENT_SIZE != 0 ) return( __MCPU_EINVAL ); + if( count > (__mpu_uint64_t)(size_t)-1 ) return( __MCPU_EINVAL ); + + if( !count ) return( 0 ); + data = (__mpu_UNIT_t *)calloc( 1, (size_t)count ); + if( !data ) return( __MCPU_ENOMEM ); + + nrecords = count / __CPU_DIRENT_SIZE; + for( i = 0; i < nrecords; ++i ) + { + __mpu_UNIT_t *record = data + i * __CPU_DIRENT_SIZE; + + __cpu_data_put_u64( record + __CPU_DIRENT_D_INO, de[i].d_ino ); + __cpu_data_put_u64( record + __CPU_DIRENT_D_OFF, + __cpu_dirent_i64_bits( de[i].d_off ) ); + __cpu_data_put_u64( record + __CPU_DIRENT_D_RECLEN, de[i].d_reclen ); + __cpu_data_put_u64( record + __CPU_DIRENT_D_TYPE, de[i].d_type ); + memcpy( record + __CPU_DIRENT_D_NAME, de[i].d_name, + __CPU_DIRENT_NAME_SIZE ); + } + + error = __cpu_copyout( ptr, data, count ); + free( data ); + return( error ); + +} /* End of __cpu_dirent_copyout() */ + + +static __mpu_int64_t +__cpu_select_i64_from_bits( __mpu_uint64_t bits ) +{ + __mpu_int64_t value; + + memcpy( &value, &bits, sizeof( value ) ); + return( value ); + +} /* End of __cpu_select_i64_from_bits() */ + + +static int +__cpu_fdset_load( __mpu_uint64_t ptr, __mpu_uint64_t words[__CPU_FD_SET_WORDS] ) +{ + __mpu_UNIT_t data[__CPU_FD_SET_SIZE]; + __mpu_UNIT_t *memory; + unsigned int i; + int error; + + error = __cpu_memory_resolve( ptr, __CPU_FD_SET_SIZE, 1, &memory ); + if( error ) return( error ); + (void)memory; + + error = __cpu_copyin( data, ptr, sizeof( data ) ); + if( error ) return( error ); + + for( i = 0; i < __CPU_FD_SET_WORDS; ++i ) + words[i] = __cpu_data_get_u64( data + i * 8U ); + + return( 0 ); + +} /* End of __cpu_fdset_load() */ + + +static int +__cpu_fdset_store( __mpu_uint64_t ptr, + const __mpu_uint64_t words[__CPU_FD_SET_WORDS] ) +{ + __mpu_UNIT_t data[__CPU_FD_SET_SIZE]; + unsigned int i; + + memset( data, 0, sizeof( data ) ); + for( i = 0; i < __CPU_FD_SET_WORDS; ++i ) + __cpu_data_put_u64( data + i * 8U, words[i] ); + + return( __cpu_copyout( ptr, data, sizeof( data ) ) ); + +} /* End of __cpu_fdset_store() */ + + +static int +__cpu_fdset_isset( const __mpu_uint64_t words[__CPU_FD_SET_WORDS], + unsigned int fd ) +{ + unsigned int word = fd / 64U; + unsigned int bit = fd % 64U; + + return( ( words[word] & ( (__mpu_uint64_t)1U << bit ) ) != 0 ); + +} /* End of __cpu_fdset_isset() */ + + +static void +__cpu_fdset_set( __mpu_uint64_t words[__CPU_FD_SET_WORDS], unsigned int fd ) +{ + unsigned int word = fd / 64U; + unsigned int bit = fd % 64U; + + words[word] |= ( (__mpu_uint64_t)1U << bit ); + +} /* End of __cpu_fdset_set() */ + + +static int +__cpu_timeval_load( __mpu_uint64_t ptr, struct __cpu_timeval *timeout ) +{ + __mpu_UNIT_t data[__CPU_TIMEVAL_SIZE]; + int error; + + if( !timeout ) return( __MCPU_EFAULT ); + + error = __cpu_copyin( data, ptr, sizeof( data ) ); + if( error ) return( error ); + + timeout->tv_sec = __cpu_select_i64_from_bits( + __cpu_data_get_u64( data + __CPU_TIMEVAL_TV_SEC ) ); + timeout->tv_usec = __cpu_select_i64_from_bits( + __cpu_data_get_u64( data + __CPU_TIMEVAL_TV_USEC ) ); + + if( timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999 ) + return( __MCPU_EINVAL ); + + return( 0 ); + +} /* End of __cpu_timeval_load() */ + + +static int +__cpu_timespec_load( __mpu_uint64_t ptr, struct __cpu_timespec *ts ) +{ + __mpu_UNIT_t data[__CPU_TIMESPEC_SIZE]; + int error; + + if( !ts ) return( __MCPU_EFAULT ); + + error = __cpu_copyin( data, ptr, sizeof( data ) ); + if( error ) return( error ); + + ts->tv_sec = __cpu_select_i64_from_bits( + __cpu_data_get_u64( data + __CPU_TIMESPEC_TV_SEC ) ); + ts->tv_nsec = __cpu_select_i64_from_bits( + __cpu_data_get_u64( data + __CPU_TIMESPEC_TV_NSEC ) ); + + if( ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec > 999999999 ) + return( __MCPU_EINVAL ); + + return( 0 ); + +} /* End of __cpu_timespec_load() */ + + +static __mpu_uint64_t +__cpu_time_i64_bits( __mpu_int64_t value ) +{ + __mpu_uint64_t bits; + + memcpy( &bits, &value, sizeof( bits ) ); + return( bits ); + +} /* End of __cpu_time_i64_bits() */ + + +static int +__cpu_timeval_copyout( __mpu_uint64_t ptr, const struct __cpu_timeval *tv ) +{ + __mpu_UNIT_t data[__CPU_TIMEVAL_SIZE]; + + if( !tv ) return( __MCPU_EFAULT ); + + memset( data, 0, sizeof( data ) ); + __cpu_data_put_u64( data + __CPU_TIMEVAL_TV_SEC, + __cpu_time_i64_bits( tv->tv_sec ) ); + __cpu_data_put_u64( data + __CPU_TIMEVAL_TV_USEC, + __cpu_time_i64_bits( tv->tv_usec ) ); + + return( __cpu_copyout( ptr, data, sizeof( data ) ) ); + +} /* End of __cpu_timeval_copyout() */ + + +static int +__cpu_timespec_copyout( __mpu_uint64_t ptr, const struct __cpu_timespec *ts ) +{ + __mpu_UNIT_t data[__CPU_TIMESPEC_SIZE]; + + if( !ts ) return( __MCPU_EFAULT ); + + memset( data, 0, sizeof( data ) ); + __cpu_data_put_u64( data + __CPU_TIMESPEC_TV_SEC, + __cpu_time_i64_bits( ts->tv_sec ) ); + __cpu_data_put_u64( data + __CPU_TIMESPEC_TV_NSEC, + __cpu_time_i64_bits( ts->tv_nsec ) ); + + return( __cpu_copyout( ptr, data, sizeof( data ) ) ); + +} /* End of __cpu_timespec_copyout() */ + + +static __mpu_uint64_t +__cpu_current_brk( void ) +{ + __mpu_uint64_t ptr = CPU_NULL_PTR; + + if( !__HEAP || __HLIMIT < CPU_HEAP_BEGIN || __HBRK < CPU_HEAP_BEGIN ) + return( CPU_NULL_PTR ); + + if( __cpu_ptr_make( &ptr, CPU_PTR_SEG_HEAP, __HBRK ) != 0 ) + return( CPU_NULL_PTR ); + + return( ptr ); + +} /* End of __cpu_current_brk() */ + + +__mpu_uint64_t +__cpu_SYS_brk( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t arg; + __mpu_uint64_t brk; + __mpu_uint64_t ptr = CPU_NULL_PTR; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_current_brk() ); + + arg = __cpu_syscall_arg( 0 ); + + if( arg == CPU_NULL_PTR ) return( __cpu_current_brk() ); + + if( __cpu_ptr_segment( arg ) != CPU_PTR_SEG_HEAP ) + return( __cpu_current_brk() ); + + brk = __cpu_heap_brk( __cpu_ptr_offset( arg ) ); + + if( brk < CPU_HEAP_BEGIN || __cpu_ptr_make( &ptr, CPU_PTR_SEG_HEAP, brk ) != 0 ) + return( CPU_NULL_PTR ); + + return( ptr ); + +} /* End of __cpu_SYS_brk() */ + + +__mpu_uint64_t +__cpu_SYS_close( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + if( pcctx->_fd[fd].owned ) + { + ret = __cpu_sys_close( host_fd ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + } + + pcctx->_fd[fd].host_fd = -1; + pcctx->_fd[fd].owned = 0; + pcctx->_fd[fd].flags = 0; + + return( 0 ); + +} /* End of __cpu_SYS_close() */ + + +__mpu_uint64_t +__cpu_SYS_dup( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int new_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + new_fd = __cpu_fd_find_from( 0 ); + if( new_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); + + ret = __cpu_sys_dup( host_fd ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + pcctx->_fd[new_fd].host_fd = (int)ret; + pcctx->_fd[new_fd].owned = 1; + pcctx->_fd[new_fd].flags = 0; + + return( (__mpu_uint64_t)new_fd ); + +} /* End of __cpu_SYS_dup() */ + + +__mpu_uint64_t +__cpu_SYS_dup2( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t old_fd; + __mpu_uint64_t new_fd; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + old_fd = __cpu_syscall_arg( 0 ); + new_fd = __cpu_syscall_arg( 1 ); + + error = __cpu_fd_get( old_fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + if( new_fd >= CPU_GUEST_FD_MAX ) return( __cpu_syscall_error( __MCPU_EBADF ) ); + + if( old_fd == new_fd ) return( new_fd ); + + ret = __cpu_sys_dup( host_fd ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + if( pcctx->_fd[new_fd].host_fd >= 0 && pcctx->_fd[new_fd].owned ) + (void)__cpu_sys_close( pcctx->_fd[new_fd].host_fd ); + + pcctx->_fd[new_fd].host_fd = (int)ret; + pcctx->_fd[new_fd].owned = 1; + pcctx->_fd[new_fd].flags = 0; + + return( new_fd ); + +} /* End of __cpu_SYS_dup2() */ + + +__mpu_uint64_t +__cpu_SYS_write( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_uint64_t ptr; + __mpu_uint64_t count; + __mpu_int64_t ret; + unsigned char *buf = (unsigned char *)0; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + ptr = __cpu_syscall_arg( 1 ); + count = __cpu_syscall_arg( 2 ); + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + if( count ) + { + if( count > (__mpu_uint64_t)(size_t)-1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + buf = (unsigned char *)malloc( (size_t)count ); + if( !buf ) return( __cpu_syscall_error( __MCPU_ENOMEM ) ); + error = __cpu_copyin( buf, ptr, count ); + if( error ) + { + free( buf ); + return( __cpu_syscall_error( error ) ); + } + } + + ret = __cpu_sys_write( host_fd, buf, count ); + free( buf ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_write() */ + + +__mpu_uint64_t +__cpu_SYS_read( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_uint64_t ptr; + __mpu_uint64_t count; + __mpu_int64_t ret; + unsigned char *buf = (unsigned char *)0; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + ptr = __cpu_syscall_arg( 1 ); + count = __cpu_syscall_arg( 2 ); + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + if( count ) + { + __mpu_UNIT_t *memory; + + if( count > (__mpu_uint64_t)(size_t)-1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + error = __cpu_memory_resolve( ptr, count, 1, &memory ); + if( error ) return( __cpu_syscall_error( error ) ); + + buf = (unsigned char *)malloc( (size_t)count ); + if( !buf ) return( __cpu_syscall_error( __MCPU_ENOMEM ) ); + } + + ret = __cpu_sys_read( host_fd, buf, count ); + if( ret > 0 ) + { + error = __cpu_copyout( ptr, buf, (__mpu_uint64_t)ret ); + if( error ) ret = -(__mpu_int64_t)error; + } + + free( buf ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_read() */ + + +__mpu_uint64_t +__cpu_SYS_lseek( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_uint64_t bits; + __mpu_int64_t offset; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + bits = __cpu_syscall_arg( 1 ); + memcpy( &offset, &bits, sizeof( offset ) ); + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_lseek( host_fd, offset, __cpu_syscall_arg( 2 ) ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_lseek() */ + + +__mpu_uint64_t +__cpu_SYS_open( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_open( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ), + __cpu_syscall_arg( 2 ) ); + free( path ); + + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + fd = __cpu_fd_install( (int)ret ); + if( fd < 0 ) + { + (void)__cpu_sys_close( (int)ret ); + return( __cpu_syscall_error( __MCPU_EMFILE ) ); + } + + return( (__mpu_uint64_t)fd ); + +} /* End of __cpu_SYS_open() */ + + +__mpu_uint64_t +__cpu_SYS_creat( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_creat( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); + free( path ); + + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + fd = __cpu_fd_install( (int)ret ); + if( fd < 0 ) + { + (void)__cpu_sys_close( (int)ret ); + return( __cpu_syscall_error( __MCPU_EMFILE ) ); + } + + return( (__mpu_uint64_t)fd ); + +} /* End of __cpu_SYS_creat() */ + + +__mpu_uint64_t +__cpu_SYS_link( __mpu_uint32_t sysno ) +{ + char *oldpath = (char *)0; + char *newpath = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &oldpath, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + error = __cpu_copyinstr( &newpath, __cpu_syscall_arg( 1 ) ); + if( error ) + { + free( oldpath ); + return( __cpu_syscall_error( error ) ); + } + + ret = __cpu_sys_link( pcctx->_cwd_fd, oldpath, newpath ); + free( newpath ); + free( oldpath ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_link() */ + + +__mpu_uint64_t +__cpu_SYS_unlink( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_unlink( pcctx->_cwd_fd, path ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_unlink() */ + + +__mpu_uint64_t +__cpu_SYS_chdir( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int old_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_chdir( pcctx->_cwd_fd, path ); + free( path ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + old_fd = pcctx->_cwd_fd; + pcctx->_cwd_fd = (int)ret; + pcctx->_cwd_initialized = 1; + if( old_fd >= 0 ) (void)__cpu_sys_close( old_fd ); + + return( 0 ); + +} /* End of __cpu_SYS_chdir() */ + + +__mpu_uint64_t +__cpu_SYS_fchdir( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int old_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_fchdir( host_fd ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + old_fd = pcctx->_cwd_fd; + pcctx->_cwd_fd = (int)ret; + pcctx->_cwd_initialized = 1; + if( old_fd >= 0 ) (void)__cpu_sys_close( old_fd ); + + return( 0 ); + +} /* End of __cpu_SYS_fchdir() */ + + +__mpu_uint64_t +__cpu_SYS_rename( __mpu_uint32_t sysno ) +{ + char *oldpath = (char *)0; + char *newpath = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &oldpath, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + error = __cpu_copyinstr( &newpath, __cpu_syscall_arg( 1 ) ); + if( error ) + { + free( oldpath ); + return( __cpu_syscall_error( error ) ); + } + + ret = __cpu_sys_rename( pcctx->_cwd_fd, oldpath, newpath ); + free( newpath ); + free( oldpath ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_rename() */ + + +__mpu_uint64_t +__cpu_SYS_mkdir( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_mkdir( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_mkdir() */ + + +__mpu_uint64_t +__cpu_SYS_chmod( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_chmod( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_chmod() */ + + +__mpu_uint64_t +__cpu_SYS_chown( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_chown( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ), + __cpu_syscall_arg( 2 ) ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_chown() */ + + +__mpu_uint64_t +__cpu_SYS_access( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_access( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_access() */ + + +__mpu_uint64_t +__cpu_SYS_rmdir( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_rmdir( pcctx->_cwd_fd, path ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_rmdir() */ + + +__mpu_uint64_t +__cpu_SYS_symlink( __mpu_uint32_t sysno ) +{ + char *target = (char *)0; + char *linkpath = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &target, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + error = __cpu_copyinstr( &linkpath, __cpu_syscall_arg( 1 ) ); + if( error ) + { + free( target ); + return( __cpu_syscall_error( error ) ); + } + + ret = __cpu_sys_symlink( pcctx->_cwd_fd, target, linkpath ); + free( linkpath ); + free( target ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_symlink() */ + + +__mpu_uint64_t +__cpu_SYS_readlink( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_uint64_t ptr; + __mpu_uint64_t count; + __mpu_int64_t ret; + unsigned char *buf = (unsigned char *)0; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ptr = __cpu_syscall_arg( 1 ); + count = __cpu_syscall_arg( 2 ); + + if( count ) + { + __mpu_UNIT_t *memory; + + if( count > (__mpu_uint64_t)(size_t)-1 ) + { + free( path ); + return( __cpu_syscall_error( __MCPU_EINVAL ) ); + } + + error = __cpu_memory_resolve( ptr, count, 1, &memory ); + if( error ) + { + free( path ); + return( __cpu_syscall_error( error ) ); + } + + buf = (unsigned char *)malloc( (size_t)count ); + if( !buf ) + { + free( path ); + return( __cpu_syscall_error( __MCPU_ENOMEM ) ); + } + } + + ret = __cpu_sys_readlink( pcctx->_cwd_fd, path, buf, count ); + free( path ); + + if( ret > 0 ) + { + error = __cpu_copyout( ptr, buf, (__mpu_uint64_t)ret ); + if( error ) ret = -(__mpu_int64_t)error; + } + + free( buf ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_readlink() */ + + +__mpu_uint64_t +__cpu_SYS_stat( __mpu_uint32_t sysno ) +{ + struct __cpu_stat st; + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_stat( pcctx->_cwd_fd, path, &st ); + free( path ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + error = __cpu_stat_copyout( __cpu_syscall_arg( 1 ), &st ); + if( error ) return( __cpu_syscall_error( error ) ); + + return( 0 ); + +} /* End of __cpu_SYS_stat() */ + + +__mpu_uint64_t +__cpu_SYS_fstat( __mpu_uint32_t sysno ) +{ + struct __cpu_stat st; + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_fstat( host_fd, &st ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + error = __cpu_stat_copyout( __cpu_syscall_arg( 1 ), &st ); + if( error ) return( __cpu_syscall_error( error ) ); + + return( 0 ); + +} /* End of __cpu_SYS_fstat() */ + + +__mpu_uint64_t +__cpu_SYS_lstat( __mpu_uint32_t sysno ) +{ + struct __cpu_stat st; + char *path = (char *)0; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_lstat( pcctx->_cwd_fd, path, &st ); + free( path ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + error = __cpu_stat_copyout( __cpu_syscall_arg( 1 ), &st ); + if( error ) return( __cpu_syscall_error( error ) ); + + return( 0 ); + +} /* End of __cpu_SYS_lstat() */ + + +__mpu_uint64_t +__cpu_SYS_getdents( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_uint64_t ptr; + __mpu_uint64_t count; + __mpu_uint64_t usable; + __mpu_int64_t ret; + struct __cpu_dirent *buf = (struct __cpu_dirent *)0; + __mpu_UNIT_t *memory; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + ptr = __cpu_syscall_arg( 1 ); + count = __cpu_syscall_arg( 2 ); + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + if( count < __CPU_DIRENT_SIZE ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + if( count > (__mpu_uint64_t)(size_t)-1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_memory_resolve( ptr, count, 1, &memory ); + if( error ) return( __cpu_syscall_error( error ) ); + + usable = ( count / __CPU_DIRENT_SIZE ) * __CPU_DIRENT_SIZE; + buf = (struct __cpu_dirent *)calloc( (size_t)( usable / __CPU_DIRENT_SIZE ), + sizeof( *buf ) ); + if( !buf ) return( __cpu_syscall_error( __MCPU_ENOMEM ) ); + + ret = __cpu_sys_getdents( host_fd, buf, usable ); + if( ret > 0 ) + { + error = __cpu_dirent_copyout( ptr, buf, (__mpu_uint64_t)ret ); + if( error ) ret = -(__mpu_int64_t)error; + } + + free( buf ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_getdents() */ + + +__mpu_uint64_t +__cpu_SYS_fcntl( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_uint64_t cmd; + __mpu_uint64_t arg; + __mpu_int64_t ret; + int host_fd; + int new_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + cmd = __cpu_syscall_arg( 1 ); + arg = __cpu_syscall_arg( 2 ); + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + switch( cmd ) + { + case __CPU_F_DUPFD: + if( arg >= CPU_GUEST_FD_MAX ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + new_fd = __cpu_fd_find_from( arg ); + if( new_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); + + ret = __cpu_sys_fcntl( host_fd, cmd, 0 ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + pcctx->_fd[new_fd].host_fd = (int)ret; + pcctx->_fd[new_fd].owned = 1; + pcctx->_fd[new_fd].flags = 0; + return( (__mpu_uint64_t)new_fd ); + + case __CPU_F_GETFD: + if( arg != 0 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + return( (__mpu_uint64_t)( pcctx->_fd[fd].flags & __CPU_FD_SUPPORTED ) ); + + case __CPU_F_SETFD: + if( arg & ~(__mpu_uint64_t)__CPU_FD_SUPPORTED ) + return( __cpu_syscall_error( __MCPU_EINVAL ) ); + pcctx->_fd[fd].flags = (unsigned int)arg; + return( 0 ); + + case __CPU_F_GETFL: + if( arg != 0 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + ret = __cpu_sys_fcntl( host_fd, cmd, 0 ); + return( (__mpu_uint64_t)ret ); + + case __CPU_F_SETFL: + ret = __cpu_sys_fcntl( host_fd, cmd, arg ); + return( (__mpu_uint64_t)ret ); + + default: + return( __cpu_syscall_error( __MCPU_EINVAL ) ); + } + +} /* End of __cpu_SYS_fcntl() */ + + +__mpu_uint64_t +__cpu_SYS_pipe2( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t ptr; + __mpu_uint64_t flags; + __mpu_UNIT_t data[__CPU_PIPEFD_SIZE]; + __mpu_UNIT_t *memory; + __mpu_int64_t ret; + unsigned int fd_flags; + int host_pipe[2] = { -1, -1 }; + int read_fd; + int write_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + ptr = __cpu_syscall_arg( 0 ); + flags = __cpu_syscall_arg( 1 ); + + if( flags & ~(__mpu_uint64_t)__CPU_PIPE2_SUPPORTED ) + return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_memory_resolve( ptr, __CPU_PIPEFD_SIZE, 1, &memory ); + if( error ) return( __cpu_syscall_error( error ) ); + (void)memory; + + read_fd = __cpu_fd_find_from( 3 ); + if( read_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); + + write_fd = __cpu_fd_find_from( (__mpu_uint64_t)read_fd + 1U ); + if( write_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); + + ret = __cpu_sys_pipe2( host_pipe, flags & __CPU_O_NONBLOCK ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + memset( data, 0, sizeof( data ) ); + __cpu_data_put_u64( data + __CPU_PIPEFD_READ, (__mpu_uint64_t)read_fd ); + __cpu_data_put_u64( data + __CPU_PIPEFD_WRITE, (__mpu_uint64_t)write_fd ); + + error = __cpu_copyout( ptr, data, sizeof( data ) ); + if( error ) + { + (void)__cpu_sys_close( host_pipe[0] ); + (void)__cpu_sys_close( host_pipe[1] ); + return( __cpu_syscall_error( error ) ); + } + + fd_flags = ( flags & __CPU_O_CLOEXEC ) ? __CPU_FD_CLOEXEC : 0U; + + pcctx->_fd[read_fd].host_fd = host_pipe[0]; + pcctx->_fd[read_fd].owned = 1; + pcctx->_fd[read_fd].flags = fd_flags; + + pcctx->_fd[write_fd].host_fd = host_pipe[1]; + pcctx->_fd[write_fd].owned = 1; + pcctx->_fd[write_fd].flags = fd_flags; + + return( 0 ); + +} /* End of __cpu_SYS_pipe2() */ + + + +__mpu_uint64_t +__cpu_SYS_select( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t nfds; + __mpu_uint64_t read_ptr; + __mpu_uint64_t write_ptr; + __mpu_uint64_t except_ptr; + __mpu_uint64_t timeout_ptr; + __mpu_uint64_t read_in[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; + __mpu_uint64_t write_in[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; + __mpu_uint64_t except_in[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; + __mpu_uint64_t read_out[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; + __mpu_uint64_t write_out[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; + __mpu_uint64_t except_out[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; + struct __cpu_select_entry entries[CPU_GUEST_FD_MAX]; + struct __cpu_timeval timeout; + const struct __cpu_timeval *ptimeout = (const struct __cpu_timeval *)0; + __mpu_int64_t ret; + __mpu_uint64_t nentries = 0; + __mpu_uint64_t ready = 0; + unsigned int fd; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 5 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + nfds = __cpu_syscall_arg( 0 ); + read_ptr = __cpu_syscall_arg( 1 ); + write_ptr = __cpu_syscall_arg( 2 ); + except_ptr = __cpu_syscall_arg( 3 ); + timeout_ptr = __cpu_syscall_arg( 4 ); + + if( nfds > CPU_GUEST_FD_MAX ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + if( read_ptr != CPU_NULL_PTR ) + { + error = __cpu_fdset_load( read_ptr, read_in ); + if( error ) return( __cpu_syscall_error( error ) ); + } + if( write_ptr != CPU_NULL_PTR ) + { + error = __cpu_fdset_load( write_ptr, write_in ); + if( error ) return( __cpu_syscall_error( error ) ); + } + if( except_ptr != CPU_NULL_PTR ) + { + error = __cpu_fdset_load( except_ptr, except_in ); + if( error ) return( __cpu_syscall_error( error ) ); + } + if( timeout_ptr != CPU_NULL_PTR ) + { + error = __cpu_timeval_load( timeout_ptr, &timeout ); + if( error ) return( __cpu_syscall_error( error ) ); + ptimeout = &timeout; + } + + memset( entries, 0, sizeof( entries ) ); + + for( fd = 0; fd < (unsigned int)nfds; ++fd ) + { + unsigned int events = 0; + + if( read_ptr != CPU_NULL_PTR && __cpu_fdset_isset( read_in, fd ) ) + events |= __CPU_SELECT_READ; + if( write_ptr != CPU_NULL_PTR && __cpu_fdset_isset( write_in, fd ) ) + events |= __CPU_SELECT_WRITE; + if( except_ptr != CPU_NULL_PTR && __cpu_fdset_isset( except_in, fd ) ) + events |= __CPU_SELECT_EXCEPT; + + if( !events ) continue; + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + entries[nentries].guest_fd = fd; + entries[nentries].host_fd = host_fd; + entries[nentries].events = events; + entries[nentries].revents = 0; + ++nentries; + } + + ret = __cpu_sys_select( entries, nentries, ptimeout ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + for( nfds = 0; nfds < nentries; ++nfds ) + { + fd = entries[nfds].guest_fd; + + if( ( entries[nfds].revents & __CPU_SELECT_READ ) && read_ptr != CPU_NULL_PTR ) + { + __cpu_fdset_set( read_out, fd ); + ++ready; + } + if( ( entries[nfds].revents & __CPU_SELECT_WRITE ) && write_ptr != CPU_NULL_PTR ) + { + __cpu_fdset_set( write_out, fd ); + ++ready; + } + if( ( entries[nfds].revents & __CPU_SELECT_EXCEPT ) && except_ptr != CPU_NULL_PTR ) + { + __cpu_fdset_set( except_out, fd ); + ++ready; + } + } + + if( read_ptr != CPU_NULL_PTR ) + { + error = __cpu_fdset_store( read_ptr, read_out ); + if( error ) return( __cpu_syscall_error( error ) ); + } + if( write_ptr != CPU_NULL_PTR ) + { + error = __cpu_fdset_store( write_ptr, write_out ); + if( error ) return( __cpu_syscall_error( error ) ); + } + if( except_ptr != CPU_NULL_PTR ) + { + error = __cpu_fdset_store( except_ptr, except_out ); + if( error ) return( __cpu_syscall_error( error ) ); + } + + return( ready ); + +} /* End of __cpu_SYS_select() */ + +__mpu_uint64_t +__cpu_SYS_gettimeofday( __mpu_uint32_t sysno ) +{ + struct __cpu_timespec ts; + struct __cpu_timeval tv; + __mpu_uint64_t tv_ptr; + __mpu_uint64_t tz_ptr; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + tv_ptr = __cpu_syscall_arg( 0 ); + tz_ptr = __cpu_syscall_arg( 1 ); + + if( tv_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); + if( tz_ptr != CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + ret = __cpu_sys_clock_gettime( __CPU_CLOCK_REALTIME, &ts ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + + error = __cpu_timeval_copyout( tv_ptr, &tv ); + if( error ) return( __cpu_syscall_error( error ) ); + + return( 0 ); + +} /* End of __cpu_SYS_gettimeofday() */ + + +__mpu_uint64_t +__cpu_SYS_clock_getres( __mpu_uint32_t sysno ) +{ + struct __cpu_timespec res; + __mpu_uint64_t clockid; + __mpu_uint64_t res_ptr; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + clockid = __cpu_syscall_arg( 0 ); + res_ptr = __cpu_syscall_arg( 1 ); + + ret = __cpu_sys_clock_getres( clockid, + res_ptr == CPU_NULL_PTR ? (struct __cpu_timespec *)0 : &res ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + if( res_ptr != CPU_NULL_PTR ) + { + error = __cpu_timespec_copyout( res_ptr, &res ); + if( error ) return( __cpu_syscall_error( error ) ); + } + + return( 0 ); + +} /* End of __cpu_SYS_clock_getres() */ + + +__mpu_uint64_t +__cpu_SYS_clock_gettime( __mpu_uint32_t sysno ) +{ + struct __cpu_timespec ts; + __mpu_uint64_t clockid; + __mpu_uint64_t tp_ptr; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + clockid = __cpu_syscall_arg( 0 ); + tp_ptr = __cpu_syscall_arg( 1 ); + + if( tp_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); + + ret = __cpu_sys_clock_gettime( clockid, &ts ); + if( ret < 0 ) return( (__mpu_uint64_t)ret ); + + error = __cpu_timespec_copyout( tp_ptr, &ts ); + if( error ) return( __cpu_syscall_error( error ) ); + + return( 0 ); + +} /* End of __cpu_SYS_clock_gettime() */ + + +__mpu_uint64_t +__cpu_SYS_nanosleep( __mpu_uint32_t sysno ) +{ + struct __cpu_timespec req; + struct __cpu_timespec rem; + __mpu_uint64_t req_ptr; + __mpu_uint64_t rem_ptr; + __mpu_UNIT_t *memory; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + req_ptr = __cpu_syscall_arg( 0 ); + rem_ptr = __cpu_syscall_arg( 1 ); + + if( req_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); + + error = __cpu_timespec_load( req_ptr, &req ); + if( error ) return( __cpu_syscall_error( error ) ); + + if( rem_ptr != CPU_NULL_PTR ) + { + error = __cpu_memory_resolve( rem_ptr, __CPU_TIMESPEC_SIZE, 1, &memory ); + if( error ) return( __cpu_syscall_error( error ) ); + (void)memory; + } + + ret = __cpu_sys_clock_nanosleep( __CPU_CLOCK_MONOTONIC, 0, &req, + rem_ptr == CPU_NULL_PTR ? (struct __cpu_timespec *)0 : &rem ); + + if( ret == -(__mpu_int64_t)__MCPU_EINTR && rem_ptr != CPU_NULL_PTR ) + { + error = __cpu_timespec_copyout( rem_ptr, &rem ); + if( error ) return( __cpu_syscall_error( error ) ); + } + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_nanosleep() */ + + +__mpu_uint64_t +__cpu_SYS_clock_nanosleep( __mpu_uint32_t sysno ) +{ + struct __cpu_timespec req; + struct __cpu_timespec rem; + __mpu_uint64_t clockid; + __mpu_uint64_t flags; + __mpu_uint64_t req_ptr; + __mpu_uint64_t rem_ptr; + __mpu_UNIT_t *memory; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 4 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + clockid = __cpu_syscall_arg( 0 ); + flags = __cpu_syscall_arg( 1 ); + req_ptr = __cpu_syscall_arg( 2 ); + rem_ptr = __cpu_syscall_arg( 3 ); + + if( flags & ~(__mpu_uint64_t)__CPU_TIMER_ABSTIME ) + return( __cpu_syscall_error( __MCPU_EINVAL ) ); + if( req_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); + + error = __cpu_timespec_load( req_ptr, &req ); + if( error ) return( __cpu_syscall_error( error ) ); + + if( !( flags & __CPU_TIMER_ABSTIME ) && rem_ptr != CPU_NULL_PTR ) + { + error = __cpu_memory_resolve( rem_ptr, __CPU_TIMESPEC_SIZE, 1, &memory ); + if( error ) return( __cpu_syscall_error( error ) ); + (void)memory; + } + + ret = __cpu_sys_clock_nanosleep( clockid, flags, &req, + ( flags & __CPU_TIMER_ABSTIME ) || rem_ptr == CPU_NULL_PTR ? + (struct __cpu_timespec *)0 : &rem ); + + if( ret == -(__mpu_int64_t)__MCPU_EINTR && !( flags & __CPU_TIMER_ABSTIME ) && + rem_ptr != CPU_NULL_PTR ) + { + error = __cpu_timespec_copyout( rem_ptr, &rem ); + if( error ) return( __cpu_syscall_error( error ) ); + } + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_clock_nanosleep() */ + + +__mpu_uint64_t +__cpu_SYS_fsync( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_fsync( host_fd ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_fsync() */ + + +__mpu_uint64_t +__cpu_SYS_truncate( __mpu_uint32_t sysno ) +{ + char *path = (char *)0; + __mpu_uint64_t bits; + __mpu_int64_t length; + __mpu_int64_t ret; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); + if( error ) return( __cpu_syscall_error( error ) ); + + bits = __cpu_syscall_arg( 1 ); + memcpy( &length, &bits, sizeof( length ) ); + + ret = __cpu_sys_truncate( pcctx->_cwd_fd, path, length ); + free( path ); + + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_truncate() */ + + +__mpu_uint64_t +__cpu_SYS_ftruncate( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_uint64_t bits; + __mpu_int64_t length; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + bits = __cpu_syscall_arg( 1 ); + memcpy( &length, &bits, sizeof( length ) ); + + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_ftruncate( host_fd, length ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_ftruncate() */ + + +__mpu_uint64_t +__cpu_SYS_fchmod( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_fchmod( host_fd, __cpu_syscall_arg( 1 ) ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_fchmod() */ + + +__mpu_uint64_t +__cpu_SYS_fchown( __mpu_uint32_t sysno ) +{ + __mpu_uint64_t fd; + __mpu_int64_t ret; + int host_fd; + int error; + + (void)sysno; + + if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + fd = __cpu_syscall_arg( 0 ); + error = __cpu_fd_get( fd, &host_fd ); + if( error ) return( __cpu_syscall_error( error ) ); + + ret = __cpu_sys_fchown( host_fd, __cpu_syscall_arg( 1 ), + __cpu_syscall_arg( 2 ) ); + return( (__mpu_uint64_t)ret ); + +} /* End of __cpu_SYS_fchown() */ + + +static const __cpu_syscall_handler_t __syscalls[] = +{ + [__NR_brk] = __cpu_SYS_brk, + [__NR_gettimeofday] = __cpu_SYS_gettimeofday, + [__NR_clock_getres] = __cpu_SYS_clock_getres, + [__NR_clock_gettime] = __cpu_SYS_clock_gettime, + [__NR_nanosleep] = __cpu_SYS_nanosleep, + [__NR_clock_nanosleep] = __cpu_SYS_clock_nanosleep, + [__NR_read] = __cpu_SYS_read, + [__NR_write] = __cpu_SYS_write, + [__NR_lseek] = __cpu_SYS_lseek, + [__NR_open] = __cpu_SYS_open, + [__NR_creat] = __cpu_SYS_creat, + [__NR_close] = __cpu_SYS_close, + [__NR_link] = __cpu_SYS_link, + [__NR_unlink] = __cpu_SYS_unlink, + [__NR_chdir] = __cpu_SYS_chdir, + [__NR_mkdir] = __cpu_SYS_mkdir, + [__NR_chmod] = __cpu_SYS_chmod, + [__NR_chown] = __cpu_SYS_chown, + [__NR_access] = __cpu_SYS_access, + [__NR_rename] = __cpu_SYS_rename, + [__NR_rmdir] = __cpu_SYS_rmdir, + [__NR_symlink] = __cpu_SYS_symlink, + [__NR_readlink] = __cpu_SYS_readlink, + [__NR_stat] = __cpu_SYS_stat, + [__NR_fstat] = __cpu_SYS_fstat, + [__NR_lstat] = __cpu_SYS_lstat, + [__NR_fcntl] = __cpu_SYS_fcntl, + [__NR_pipe2] = __cpu_SYS_pipe2, + [__NR_getdents] = __cpu_SYS_getdents, + [__NR_select] = __cpu_SYS_select, + [__NR_fsync] = __cpu_SYS_fsync, + [__NR_truncate] = __cpu_SYS_truncate, + [__NR_ftruncate] = __cpu_SYS_ftruncate, + [__NR_fchmod] = __cpu_SYS_fchmod, + [__NR_fchown] = __cpu_SYS_fchown, + [__NR_fchdir] = __cpu_SYS_fchdir, + [__NR_dup] = __cpu_SYS_dup, + [__NR_dup2] = __cpu_SYS_dup2, +}; + + +__mpu_uint64_t +__cpu_syscall_dispatch( void ) +{ + __mpu_uint32_t sysno; + + sysno = __cpu_data_get_u32( __cpu_reg_ptr( 32, CPU_SYSCALL_SYSNO_ADDR ) ); + + if( __cpu_syscall_nargs() > CPU_SYSCALL_MAX_ARGS ) + return( __cpu_syscall_error( __MCPU_EINVAL ) ); + + if( sysno >= sizeof( __syscalls ) / sizeof( __syscalls[0] ) || + __syscalls[sysno] == (__cpu_syscall_handler_t)0 ) + return( __cpu_syscall_error( __MCPU_ENOSYS ) ); + + return( __syscalls[sysno]( sysno ) ); + +} /* End of __cpu_syscall_dispatch() */ diff --git a/cpu/cpu-syscalls.h b/cpu/cpu-syscalls.h new file mode 100644 index 0000000..636c0e7 --- /dev/null +++ b/cpu/cpu-syscalls.h @@ -0,0 +1,59 @@ +/*************************************************************** + __CPU_SYSCALLS.H + + This file contains CPU SYSCALL operation functions & data + declarations. + + PART OF : CPU - library . + + USAGE : Internal only . + + NOTE : Include "libmcpu.h" before this FILE . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_SYSCALLS_H +#define __CPU_SYSCALLS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef __mpu_uint64_t (*__cpu_syscall_handler_t)( __mpu_uint32_t sysno ); + +extern void __cpu_fd_context_init( void ); +extern void __cpu_fd_context_free( void ); +extern void __cpu_cwd_context_init( void ); +extern void __cpu_cwd_context_free( void ); + +extern __mpu_uint64_t __cpu_SYS_brk( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_gettimeofday( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_clock_getres( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_clock_gettime( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_nanosleep( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_clock_nanosleep( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_open ( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_close( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_dup ( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_dup2 ( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_read ( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_write( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_lseek( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_chdir( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_fchdir( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_stat ( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_fstat( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_lstat( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_fcntl( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_SYS_pipe2( __mpu_uint32_t sysno ); +extern __mpu_uint64_t __cpu_syscall_dispatch( void ); + + +#ifdef __cplusplus +} /* ... extern "C" */ +#endif + +#endif /* __CPU_SYSCALLS_H */ diff --git a/cpu/cpu-sysdeps.h b/cpu/cpu-sysdeps.h new file mode 100644 index 0000000..81bb926 --- /dev/null +++ b/cpu/cpu-sysdeps.h @@ -0,0 +1,288 @@ +/*************************************************************** + __CPU_SYSDEPS.H + + This file contains HOST-dependent system call wrapper + declarations and internal MCPU syscall ABI constants. + + PART OF : CPU - library . + + USAGE : Internal only . + + NOTE : Include "libmcpu.h" before this FILE . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_SYSDEPS_H +#define __CPU_SYSDEPS_H + +#include <cpu-errno.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/* MCPU open(2) ABI. These values are HOST-independent. */ +#define __CPU_O_ACCMODE 00000003U +#define __CPU_O_RDONLY 00000000U +#define __CPU_O_WRONLY 00000001U +#define __CPU_O_RDWR 00000002U +#define __CPU_O_CREAT 00000100U +#define __CPU_O_EXCL 00000200U +#define __CPU_O_NOCTTY 00000400U +#define __CPU_O_TRUNC 00001000U +#define __CPU_O_APPEND 00002000U +#define __CPU_O_NONBLOCK 00004000U + +#define __CPU_O_SUPPORTED ( __CPU_O_ACCMODE | __CPU_O_CREAT | __CPU_O_EXCL | \ + __CPU_O_NOCTTY | __CPU_O_TRUNC | __CPU_O_APPEND | \ + __CPU_O_NONBLOCK ) + +/* MCPU fcntl(2) ABI. Commands and descriptor flags are guest values. */ +#define __CPU_F_DUPFD 0U +#define __CPU_F_GETFD 1U +#define __CPU_F_SETFD 2U +#define __CPU_F_GETFL 3U +#define __CPU_F_SETFL 4U + +#define __CPU_FD_CLOEXEC 1U +#define __CPU_FD_SUPPORTED __CPU_FD_CLOEXEC + +/* F_SETFL accepts access-mode bits for the conventional GETFL/SETFL cycle, + but only APPEND and NONBLOCK are mutable file-status flags. */ +#define __CPU_F_SETFL_SUPPORTED \ + ( __CPU_O_ACCMODE | __CPU_O_APPEND | __CPU_O_NONBLOCK ) + +/* MCPU pipe2(2) ABI. O_CLOEXEC is guest descriptor state; only + O_NONBLOCK is translated to a HOST file-status flag. */ +#define __CPU_O_CLOEXEC 02000000U +#define __CPU_PIPE2_SUPPORTED ( __CPU_O_NONBLOCK | __CPU_O_CLOEXEC ) +#define __CPU_PIPEFD_SIZE 16U +#define __CPU_PIPEFD_READ 0U +#define __CPU_PIPEFD_WRITE 8U + +/* MCPU mode bits used by open(2) when O_CREAT is present. */ +#define __CPU_S_ISUID 00004000U +#define __CPU_S_ISGID 00002000U +#define __CPU_S_ISVTX 00001000U +#define __CPU_S_IRUSR 00000400U +#define __CPU_S_IWUSR 00000200U +#define __CPU_S_IXUSR 00000100U +#define __CPU_S_IRGRP 00000040U +#define __CPU_S_IWGRP 00000020U +#define __CPU_S_IXGRP 00000010U +#define __CPU_S_IROTH 00000004U +#define __CPU_S_IWOTH 00000002U +#define __CPU_S_IXOTH 00000001U +#define __CPU_S_SUPPORTED 00007777U + +/* MCPU chown(2) ABI. UINT64_MAX means "leave this ID unchanged". */ +#define __CPU_ID_NO_CHANGE ((__mpu_uint64_t)-1) + +#define __CPU_SEEK_SET 0U +#define __CPU_SEEK_CUR 1U +#define __CPU_SEEK_END 2U + +/* MCPU access(2) ABI. These values are HOST-independent. */ +#define __CPU_F_OK 0U +#define __CPU_X_OK 1U +#define __CPU_W_OK 2U +#define __CPU_R_OK 4U +#define __CPU_ACCESS_SUPPORTED (__CPU_X_OK | __CPU_W_OK | __CPU_R_OK) + +/* MCPU time ABI. All time values use signed 64-bit seconds and a separate + signed 64-bit fractional field. Clock IDs are HOST-independent. */ +#define __CPU_CLOCK_REALTIME 0U +#define __CPU_CLOCK_MONOTONIC 1U +#define __CPU_TIMER_ABSTIME 1U + +#define __CPU_TIMEVAL_SIZE 16U +#define __CPU_TIMEVAL_TV_SEC 0U +#define __CPU_TIMEVAL_TV_USEC 8U + +#define __CPU_TIMESPEC_SIZE 16U +#define __CPU_TIMESPEC_TV_SEC 0U +#define __CPU_TIMESPEC_TV_NSEC 8U + +struct __cpu_timeval +{ + __mpu_int64_t tv_sec; + __mpu_int64_t tv_usec; +}; + +struct __cpu_timespec +{ + __mpu_int64_t tv_sec; + __mpu_int64_t tv_nsec; +}; + +/* MCPU select(2) ABI. Descriptor sets contain four target-order u64 + words, for a total of 256 guest descriptor bits. The timeout is input-only. */ +#define __CPU_FD_SETSIZE 256U +#define __CPU_FD_SET_WORDS 4U +#define __CPU_FD_SET_SIZE 32U + +#define __CPU_SELECT_READ 0x01U +#define __CPU_SELECT_WRITE 0x02U +#define __CPU_SELECT_EXCEPT 0x04U + +struct __cpu_select_entry +{ + unsigned int guest_fd; + int host_fd; + unsigned int events; + unsigned int revents; +}; + +/* MCPU stat(2) ABI. The structure is always exactly 128 bytes. */ +#define __CPU_STAT_SIZE 128U +#define __CPU_STAT_ST_DEV 0U +#define __CPU_STAT_ST_INO 8U +#define __CPU_STAT_ST_MODE 16U +#define __CPU_STAT_ST_NLINK 24U +#define __CPU_STAT_ST_UID 32U +#define __CPU_STAT_ST_GID 40U +#define __CPU_STAT_ST_RDEV 48U +#define __CPU_STAT_ST_SIZE 56U +#define __CPU_STAT_ST_BLKSIZE 64U +#define __CPU_STAT_ST_BLOCKS 72U +#define __CPU_STAT_ST_ATIME_SEC 80U +#define __CPU_STAT_ST_ATIME_NSEC 88U +#define __CPU_STAT_ST_MTIME_SEC 96U +#define __CPU_STAT_ST_MTIME_NSEC 104U +#define __CPU_STAT_ST_CTIME_SEC 112U +#define __CPU_STAT_ST_CTIME_NSEC 120U + +#define __CPU_S_IFMT 000170000U +#define __CPU_S_IFIFO 000010000U +#define __CPU_S_IFCHR 000020000U +#define __CPU_S_IFDIR 000040000U +#define __CPU_S_IFBLK 000060000U +#define __CPU_S_IFREG 000100000U +#define __CPU_S_IFLNK 000120000U +#define __CPU_S_IFSOCK 000140000U + +/* MCPU getdents(2) ABI. Records are fixed at 288 bytes. */ +#define __CPU_DIRENT_SIZE 288U +#define __CPU_DIRENT_D_INO 0U +#define __CPU_DIRENT_D_OFF 8U +#define __CPU_DIRENT_D_RECLEN 16U +#define __CPU_DIRENT_D_TYPE 24U +#define __CPU_DIRENT_D_NAME 32U +#define __CPU_DIRENT_NAME_SIZE 256U + +#define __CPU_DT_UNKNOWN 0U +#define __CPU_DT_FIFO 1U +#define __CPU_DT_CHR 2U +#define __CPU_DT_DIR 4U +#define __CPU_DT_BLK 6U +#define __CPU_DT_REG 8U +#define __CPU_DT_LNK 10U +#define __CPU_DT_SOCK 12U + +struct __cpu_dirent +{ + __mpu_uint64_t d_ino; + __mpu_int64_t d_off; + __mpu_uint64_t d_reclen; + __mpu_uint64_t d_type; + unsigned char d_name[__CPU_DIRENT_NAME_SIZE]; +}; + +struct __cpu_stat +{ + __mpu_uint64_t st_dev; + __mpu_uint64_t st_ino; + __mpu_uint64_t st_mode; + __mpu_uint64_t st_nlink; + __mpu_uint64_t st_uid; + __mpu_uint64_t st_gid; + __mpu_uint64_t st_rdev; + __mpu_int64_t st_size; + __mpu_int64_t st_blksize; + __mpu_int64_t st_blocks; + __mpu_int64_t st_atime_sec; + __mpu_uint64_t st_atime_nsec; + __mpu_int64_t st_mtime_sec; + __mpu_uint64_t st_mtime_nsec; + __mpu_int64_t st_ctime_sec; + __mpu_uint64_t st_ctime_nsec; +}; + + + +/* Translate a positive HOST errno value into the stable positive MCPU errno + namespace. Zero maps to zero; unknown values map to __MCPU_EUNKNOWN. */ +extern int __cpu_errno_from_host( int errnum ); + +extern __mpu_int64_t __cpu_sys_cwd_init( void ); +extern __mpu_int64_t __cpu_sys_chdir( int dirfd, const char *path ); +extern __mpu_int64_t __cpu_sys_fchdir( int fd ); + +extern __mpu_int64_t __cpu_sys_open ( int dirfd, const char *path, + __mpu_uint64_t flags, + __mpu_uint64_t mode ); +extern __mpu_int64_t __cpu_sys_creat( int dirfd, const char *path, + __mpu_uint64_t mode ); +extern __mpu_int64_t __cpu_sys_close( int fd ); +extern __mpu_int64_t __cpu_sys_dup ( int fd ); +extern __mpu_int64_t __cpu_sys_read ( int fd, void *buf, __mpu_uint64_t count ); +extern __mpu_int64_t __cpu_sys_write( int fd, const void *buf, __mpu_uint64_t count ); +extern __mpu_int64_t __cpu_sys_lseek( int fd, __mpu_int64_t offset, + __mpu_uint64_t whence ); +extern __mpu_int64_t __cpu_sys_link ( int dirfd, const char *oldpath, + const char *newpath ); +extern __mpu_int64_t __cpu_sys_unlink( int dirfd, const char *path ); +extern __mpu_int64_t __cpu_sys_rename( int dirfd, const char *oldpath, + const char *newpath ); +extern __mpu_int64_t __cpu_sys_symlink( int dirfd, const char *target, + const char *linkpath ); +extern __mpu_int64_t __cpu_sys_readlink( int dirfd, const char *path, + void *buf, __mpu_uint64_t count ); +extern __mpu_int64_t __cpu_sys_mkdir ( int dirfd, const char *path, + __mpu_uint64_t mode ); +extern __mpu_int64_t __cpu_sys_chmod ( int dirfd, const char *path, + __mpu_uint64_t mode ); +extern __mpu_int64_t __cpu_sys_chown ( int dirfd, const char *path, + __mpu_uint64_t uid, + __mpu_uint64_t gid ); +extern __mpu_int64_t __cpu_sys_rmdir ( int dirfd, const char *path ); +extern __mpu_int64_t __cpu_sys_access( int dirfd, const char *path, + __mpu_uint64_t mode ); + +extern __mpu_int64_t __cpu_sys_stat ( int dirfd, const char *path, + struct __cpu_stat *st ); +extern __mpu_int64_t __cpu_sys_fstat( int fd, struct __cpu_stat *st ); +extern __mpu_int64_t __cpu_sys_lstat( int dirfd, const char *path, + struct __cpu_stat *st ); +extern __mpu_int64_t __cpu_sys_getdents( int fd, struct __cpu_dirent *dirp, + __mpu_uint64_t count ); +extern __mpu_int64_t __cpu_sys_fsync( int fd ); +extern __mpu_int64_t __cpu_sys_truncate( int dirfd, const char *path, + __mpu_int64_t length ); +extern __mpu_int64_t __cpu_sys_ftruncate( int fd, __mpu_int64_t length ); +extern __mpu_int64_t __cpu_sys_fchmod( int fd, __mpu_uint64_t mode ); +extern __mpu_int64_t __cpu_sys_fchown( int fd, __mpu_uint64_t uid, + __mpu_uint64_t gid ); +extern __mpu_int64_t __cpu_sys_fcntl( int fd, __mpu_uint64_t cmd, + __mpu_uint64_t arg ); +extern __mpu_int64_t __cpu_sys_pipe2( int pipefd[2], __mpu_uint64_t flags ); +extern __mpu_int64_t __cpu_sys_select( struct __cpu_select_entry *entries, + __mpu_uint64_t count, + const struct __cpu_timeval *timeout ); +extern __mpu_int64_t __cpu_sys_clock_gettime( __mpu_uint64_t clockid, + struct __cpu_timespec *tp ); +extern __mpu_int64_t __cpu_sys_clock_getres( __mpu_uint64_t clockid, + struct __cpu_timespec *res ); +extern __mpu_int64_t __cpu_sys_clock_nanosleep( __mpu_uint64_t clockid, + __mpu_uint64_t flags, + const struct __cpu_timespec *req, + struct __cpu_timespec *rem ); + +#ifdef __cplusplus +} /* ... extern "C" */ +#endif + +#endif /* __CPU_SYSDEPS_H */ diff --git a/cpu/sysdeps/README b/cpu/sysdeps/README new file mode 100644 index 0000000..461226e --- /dev/null +++ b/cpu/sysdeps/README @@ -0,0 +1,19 @@ +LibMCPU HOST sysdeps +==================== + +This tree is the HOST-dependent adaptation layer for MCPU system-call wrappers. +configure builds the ordered `sysnames` search list from the canonical HOST, +architecture preconfigure fragments, the ABI/data model and Implies inheritance. +cpu/Makefile.am uses that ordered list as the GNU make `vpath %.c` search path, +so the first matching basename is the selected source. + +The search order is intentionally from the most specific implementation to the +most generic implementation. `cpu/sysdeps/generic` is always last. A generic +directory does not by itself make an otherwise unknown HOST supported. + +Starting with LibMCPU 0.3.25 raw HOST errno values must not escape this layer. +The inherited `sys-errno.c` implementation provides `__cpu_errno_from_host()`; +HOST syscall wrappers translate a real HOST failure into the stable MCPU errno +namespace before returning to common CPU code. Errors created by the MCPU ABI +itself use `__MCPU_E*` constants directly and are not sent through the HOST +translator. diff --git a/cpu/sysdeps/generic/README b/cpu/sysdeps/generic/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/generic/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/i386/configure-fragment b/cpu/sysdeps/i386/configure-fragment new file mode 100755 index 0000000..a64629c --- /dev/null +++ b/cpu/sysdeps/i386/configure-fragment @@ -0,0 +1,8 @@ +#!/bin/sh + +# Regenerate this directory's sourced preconfigure fragment from preconfigure.ac. +# Run from the architecture sysdeps directory. +autoconf -Wno-syntax -I ../../.. -o preconfigure preconfigure.ac || exit 1 +chmod a-x preconfigure +rm -f preconfigure~ +rm -rf autom4te.cache diff --git a/cpu/sysdeps/i386/i586/README b/cpu/sysdeps/i386/i586/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/i386/i586/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/i386/i686/README b/cpu/sysdeps/i386/i686/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/i386/i686/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/i386/i786/Implies b/cpu/sysdeps/i386/i786/Implies new file mode 100644 index 0000000..1cd29f6 --- /dev/null +++ b/cpu/sysdeps/i386/i786/Implies @@ -0,0 +1,2 @@ +# The PPro and PII cores are mostly the same. +i386/i686 diff --git a/cpu/sysdeps/i386/preconfigure b/cpu/sysdeps/i386/preconfigure new file mode 100644 index 0000000..43a17f4 --- /dev/null +++ b/cpu/sysdeps/i386/preconfigure @@ -0,0 +1,12 @@ +# This file is generated from preconfigure.ac by Autoconf. DO NOT EDIT! + +# Local preconfigure fragment for cpu/sysdeps/i386. + +case "$machine" in +i456786) + base_machine=i386 + machine=i386/$machine + MCPU_HOST_DATA_MODEL=ILP32 + ;; +esac + diff --git a/cpu/sysdeps/i386/preconfigure.ac b/cpu/sysdeps/i386/preconfigure.ac new file mode 100644 index 0000000..cd419ee --- /dev/null +++ b/cpu/sysdeps/i386/preconfigure.ac @@ -0,0 +1,11 @@ +dnl See acsite.m4 in the top-level source directory. +MCPU_PROVIDES +# Local preconfigure fragment for cpu/sysdeps/i386. + +case "$machine" in +i[4567]86) + base_machine=i386 + machine=i386/$machine + MCPU_HOST_DATA_MODEL=ILP32 + ;; +esac diff --git a/cpu/sysdeps/powerpc/configure-fragment b/cpu/sysdeps/powerpc/configure-fragment new file mode 100755 index 0000000..a64629c --- /dev/null +++ b/cpu/sysdeps/powerpc/configure-fragment @@ -0,0 +1,8 @@ +#!/bin/sh + +# Regenerate this directory's sourced preconfigure fragment from preconfigure.ac. +# Run from the architecture sysdeps directory. +autoconf -Wno-syntax -I ../../.. -o preconfigure preconfigure.ac || exit 1 +chmod a-x preconfigure +rm -f preconfigure~ +rm -rf autom4te.cache diff --git a/cpu/sysdeps/powerpc/powerpc32/README b/cpu/sysdeps/powerpc/powerpc32/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/powerpc/powerpc32/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/powerpc/powerpc64/README b/cpu/sysdeps/powerpc/powerpc64/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/powerpc/powerpc64/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/powerpc/powerpc64le/README b/cpu/sysdeps/powerpc/powerpc64le/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/powerpc/powerpc64le/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/powerpc/preconfigure b/cpu/sysdeps/powerpc/preconfigure new file mode 100644 index 0000000..ac680cc --- /dev/null +++ b/cpu/sysdeps/powerpc/preconfigure @@ -0,0 +1,22 @@ +# This file is generated from preconfigure.ac by Autoconf. DO NOT EDIT! + +# Local preconfigure fragment for cpu/sysdeps/powerpc. + +case "$machine" in +powerpc64le) + base_machine=powerpc + machine=powerpc/powerpc64le + MCPU_HOST_DATA_MODEL=LP64 + ;; +powerpc64*) + base_machine=powerpc + machine=powerpc/powerpc64 + MCPU_HOST_DATA_MODEL=LP64 + ;; +powerpc*) + base_machine=powerpc + machine=powerpc/powerpc32 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +esac + diff --git a/cpu/sysdeps/powerpc/preconfigure.ac b/cpu/sysdeps/powerpc/preconfigure.ac new file mode 100644 index 0000000..9fd020f --- /dev/null +++ b/cpu/sysdeps/powerpc/preconfigure.ac @@ -0,0 +1,21 @@ +dnl See acsite.m4 in the top-level source directory. +MCPU_PROVIDES +# Local preconfigure fragment for cpu/sysdeps/powerpc. + +case "$machine" in +powerpc64le) + base_machine=powerpc + machine=powerpc/powerpc64le + MCPU_HOST_DATA_MODEL=LP64 + ;; +powerpc64*) + base_machine=powerpc + machine=powerpc/powerpc64 + MCPU_HOST_DATA_MODEL=LP64 + ;; +powerpc*) + base_machine=powerpc + machine=powerpc/powerpc32 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +esac diff --git a/cpu/sysdeps/sparc/configure-fragment b/cpu/sysdeps/sparc/configure-fragment new file mode 100755 index 0000000..a64629c --- /dev/null +++ b/cpu/sysdeps/sparc/configure-fragment @@ -0,0 +1,8 @@ +#!/bin/sh + +# Regenerate this directory's sourced preconfigure fragment from preconfigure.ac. +# Run from the architecture sysdeps directory. +autoconf -Wno-syntax -I ../../.. -o preconfigure preconfigure.ac || exit 1 +chmod a-x preconfigure +rm -f preconfigure~ +rm -rf autom4te.cache diff --git a/cpu/sysdeps/sparc/preconfigure b/cpu/sysdeps/sparc/preconfigure new file mode 100644 index 0000000..ecf135c --- /dev/null +++ b/cpu/sysdeps/sparc/preconfigure @@ -0,0 +1,57 @@ +# This file is generated from preconfigure.ac by Autoconf. DO NOT EDIT! + +# Local preconfigure fragment for cpu/sysdeps/sparc. + +case "$machine" in +sparc | sparcv67) + base_machine=sparc + machine=sparc/sparc32 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv8 | supersparc | hypersparc) + base_machine=sparc + machine=sparc/sparc32/sparcv8 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv8plus | sparcv8plusa | sparcv9) + base_machine=sparc + machine=sparc/sparc32/sparcv9 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv8plusb | sparcv9b) + base_machine=sparc + machine=sparc/sparc32/sparcv9/sparcv9b + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv9v) + base_machine=sparc + machine=sparc/sparc32/sparcv9/sparcv9v + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv9v2) + base_machine=sparc + machine=sparc/sparc32/sparcv9/sparcv9v2 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparc64) + base_machine=sparc + machine=sparc/sparc64 + MCPU_HOST_DATA_MODEL=LP64 + ;; +sparc64b) + base_machine=sparc + machine=sparc/sparc64/sparcv9b + MCPU_HOST_DATA_MODEL=LP64 + ;; +sparc64v) + base_machine=sparc + machine=sparc/sparc64/sparcv9v + MCPU_HOST_DATA_MODEL=LP64 + ;; +sparc64v2) + base_machine=sparc + machine=sparc/sparc64/sparcv9v2 + MCPU_HOST_DATA_MODEL=LP64 + ;; +esac + diff --git a/cpu/sysdeps/sparc/preconfigure.ac b/cpu/sysdeps/sparc/preconfigure.ac new file mode 100644 index 0000000..3a3361b --- /dev/null +++ b/cpu/sysdeps/sparc/preconfigure.ac @@ -0,0 +1,56 @@ +dnl See acsite.m4 in the top-level source directory. +MCPU_PROVIDES +# Local preconfigure fragment for cpu/sysdeps/sparc. + +case "$machine" in +sparc | sparcv[67]) + base_machine=sparc + machine=sparc/sparc32 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv8 | supersparc | hypersparc) + base_machine=sparc + machine=sparc/sparc32/sparcv8 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv8plus | sparcv8plusa | sparcv9) + base_machine=sparc + machine=sparc/sparc32/sparcv9 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv8plusb | sparcv9b) + base_machine=sparc + machine=sparc/sparc32/sparcv9/sparcv9b + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv9v) + base_machine=sparc + machine=sparc/sparc32/sparcv9/sparcv9v + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparcv9v2) + base_machine=sparc + machine=sparc/sparc32/sparcv9/sparcv9v2 + MCPU_HOST_DATA_MODEL=ILP32 + ;; +sparc64) + base_machine=sparc + machine=sparc/sparc64 + MCPU_HOST_DATA_MODEL=LP64 + ;; +sparc64b) + base_machine=sparc + machine=sparc/sparc64/sparcv9b + MCPU_HOST_DATA_MODEL=LP64 + ;; +sparc64v) + base_machine=sparc + machine=sparc/sparc64/sparcv9v + MCPU_HOST_DATA_MODEL=LP64 + ;; +sparc64v2) + base_machine=sparc + machine=sparc/sparc64/sparcv9v2 + MCPU_HOST_DATA_MODEL=LP64 + ;; +esac diff --git a/cpu/sysdeps/unix/sys-errno.c b/cpu/sysdeps/unix/sys-errno.c new file mode 100644 index 0000000..ffcbb1d --- /dev/null +++ b/cpu/sysdeps/unix/sys-errno.c @@ -0,0 +1,442 @@ +/*************************************************************** + SYS-ERRNO.C + + This file contains Linux/x86_64/LP64 HOST errno to MCPU + errno translation. + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +int +__cpu_errno_from_host( int errnum ) +{ + if( errnum == 0 ) return( 0 ); + if( errnum < 0 ) return( __MCPU_EUNKNOWN ); + +#ifdef EPERM + if( errnum == EPERM ) return( __MCPU_EPERM ); +#endif +#ifdef ENOENT + if( errnum == ENOENT ) return( __MCPU_ENOENT ); +#endif +#ifdef ESRCH + if( errnum == ESRCH ) return( __MCPU_ESRCH ); +#endif +#ifdef EINTR + if( errnum == EINTR ) return( __MCPU_EINTR ); +#endif +#ifdef EIO + if( errnum == EIO ) return( __MCPU_EIO ); +#endif +#ifdef ENXIO + if( errnum == ENXIO ) return( __MCPU_ENXIO ); +#endif +#ifdef E2BIG + if( errnum == E2BIG ) return( __MCPU_E2BIG ); +#endif +#ifdef ENOEXEC + if( errnum == ENOEXEC ) return( __MCPU_ENOEXEC ); +#endif +#ifdef EBADF + if( errnum == EBADF ) return( __MCPU_EBADF ); +#endif +#ifdef ECHILD + if( errnum == ECHILD ) return( __MCPU_ECHILD ); +#endif +#ifdef EAGAIN + if( errnum == EAGAIN ) return( __MCPU_EAGAIN ); +#endif +#ifdef ENOMEM + if( errnum == ENOMEM ) return( __MCPU_ENOMEM ); +#endif +#ifdef EACCES + if( errnum == EACCES ) return( __MCPU_EACCES ); +#endif +#ifdef EFAULT + if( errnum == EFAULT ) return( __MCPU_EFAULT ); +#endif +#ifdef ENOTBLK + if( errnum == ENOTBLK ) return( __MCPU_ENOTBLK ); +#endif +#ifdef EBUSY + if( errnum == EBUSY ) return( __MCPU_EBUSY ); +#endif +#ifdef EEXIST + if( errnum == EEXIST ) return( __MCPU_EEXIST ); +#endif +#ifdef EXDEV + if( errnum == EXDEV ) return( __MCPU_EXDEV ); +#endif +#ifdef ENODEV + if( errnum == ENODEV ) return( __MCPU_ENODEV ); +#endif +#ifdef ENOTDIR + if( errnum == ENOTDIR ) return( __MCPU_ENOTDIR ); +#endif +#ifdef EISDIR + if( errnum == EISDIR ) return( __MCPU_EISDIR ); +#endif +#ifdef EINVAL + if( errnum == EINVAL ) return( __MCPU_EINVAL ); +#endif +#ifdef ENFILE + if( errnum == ENFILE ) return( __MCPU_ENFILE ); +#endif +#ifdef EMFILE + if( errnum == EMFILE ) return( __MCPU_EMFILE ); +#endif +#ifdef ENOTTY + if( errnum == ENOTTY ) return( __MCPU_ENOTTY ); +#endif +#ifdef ETXTBSY + if( errnum == ETXTBSY ) return( __MCPU_ETXTBSY ); +#endif +#ifdef EFBIG + if( errnum == EFBIG ) return( __MCPU_EFBIG ); +#endif +#ifdef ENOSPC + if( errnum == ENOSPC ) return( __MCPU_ENOSPC ); +#endif +#ifdef ESPIPE + if( errnum == ESPIPE ) return( __MCPU_ESPIPE ); +#endif +#ifdef EROFS + if( errnum == EROFS ) return( __MCPU_EROFS ); +#endif +#ifdef EMLINK + if( errnum == EMLINK ) return( __MCPU_EMLINK ); +#endif +#ifdef EPIPE + if( errnum == EPIPE ) return( __MCPU_EPIPE ); +#endif +#ifdef EDOM + if( errnum == EDOM ) return( __MCPU_EDOM ); +#endif +#ifdef ERANGE + if( errnum == ERANGE ) return( __MCPU_ERANGE ); +#endif +#ifdef EDEADLK + if( errnum == EDEADLK ) return( __MCPU_EDEADLK ); +#endif +#ifdef ENAMETOOLONG + if( errnum == ENAMETOOLONG ) return( __MCPU_ENAMETOOLONG ); +#endif +#ifdef ENOLCK + if( errnum == ENOLCK ) return( __MCPU_ENOLCK ); +#endif +#ifdef ENOSYS + if( errnum == ENOSYS ) return( __MCPU_ENOSYS ); +#endif +#ifdef ENOTEMPTY + if( errnum == ENOTEMPTY ) return( __MCPU_ENOTEMPTY ); +#endif +#ifdef ELOOP + if( errnum == ELOOP ) return( __MCPU_ELOOP ); +#endif +#ifdef ENOMSG + if( errnum == ENOMSG ) return( __MCPU_ENOMSG ); +#endif +#ifdef EIDRM + if( errnum == EIDRM ) return( __MCPU_EIDRM ); +#endif +#ifdef ECHRNG + if( errnum == ECHRNG ) return( __MCPU_ECHRNG ); +#endif +#ifdef EL2NSYNC + if( errnum == EL2NSYNC ) return( __MCPU_EL2NSYNC ); +#endif +#ifdef EL3HLT + if( errnum == EL3HLT ) return( __MCPU_EL3HLT ); +#endif +#ifdef EL3RST + if( errnum == EL3RST ) return( __MCPU_EL3RST ); +#endif +#ifdef ELNRNG + if( errnum == ELNRNG ) return( __MCPU_ELNRNG ); +#endif +#ifdef EUNATCH + if( errnum == EUNATCH ) return( __MCPU_EUNATCH ); +#endif +#ifdef ENOCSI + if( errnum == ENOCSI ) return( __MCPU_ENOCSI ); +#endif +#ifdef EL2HLT + if( errnum == EL2HLT ) return( __MCPU_EL2HLT ); +#endif +#ifdef EBADE + if( errnum == EBADE ) return( __MCPU_EBADE ); +#endif +#ifdef EBADR + if( errnum == EBADR ) return( __MCPU_EBADR ); +#endif +#ifdef EXFULL + if( errnum == EXFULL ) return( __MCPU_EXFULL ); +#endif +#ifdef ENOANO + if( errnum == ENOANO ) return( __MCPU_ENOANO ); +#endif +#ifdef EBADRQC + if( errnum == EBADRQC ) return( __MCPU_EBADRQC ); +#endif +#ifdef EBADSLT + if( errnum == EBADSLT ) return( __MCPU_EBADSLT ); +#endif +#ifdef EBFONT + if( errnum == EBFONT ) return( __MCPU_EBFONT ); +#endif +#ifdef ENOSTR + if( errnum == ENOSTR ) return( __MCPU_ENOSTR ); +#endif +#ifdef ENODATA + if( errnum == ENODATA ) return( __MCPU_ENODATA ); +#endif +#ifdef ETIME + if( errnum == ETIME ) return( __MCPU_ETIME ); +#endif +#ifdef ENOSR + if( errnum == ENOSR ) return( __MCPU_ENOSR ); +#endif +#ifdef ENONET + if( errnum == ENONET ) return( __MCPU_ENONET ); +#endif +#ifdef ENOPKG + if( errnum == ENOPKG ) return( __MCPU_ENOPKG ); +#endif +#ifdef EREMOTE + if( errnum == EREMOTE ) return( __MCPU_EREMOTE ); +#endif +#ifdef ENOLINK + if( errnum == ENOLINK ) return( __MCPU_ENOLINK ); +#endif +#ifdef EADV + if( errnum == EADV ) return( __MCPU_EADV ); +#endif +#ifdef ESRMNT + if( errnum == ESRMNT ) return( __MCPU_ESRMNT ); +#endif +#ifdef ECOMM + if( errnum == ECOMM ) return( __MCPU_ECOMM ); +#endif +#ifdef EPROTO + if( errnum == EPROTO ) return( __MCPU_EPROTO ); +#endif +#ifdef EMULTIHOP + if( errnum == EMULTIHOP ) return( __MCPU_EMULTIHOP ); +#endif +#ifdef EDOTDOT + if( errnum == EDOTDOT ) return( __MCPU_EDOTDOT ); +#endif +#ifdef EBADMSG + if( errnum == EBADMSG ) return( __MCPU_EBADMSG ); +#endif +#ifdef EOVERFLOW + if( errnum == EOVERFLOW ) return( __MCPU_EOVERFLOW ); +#endif +#ifdef ENOTUNIQ + if( errnum == ENOTUNIQ ) return( __MCPU_ENOTUNIQ ); +#endif +#ifdef EBADFD + if( errnum == EBADFD ) return( __MCPU_EBADFD ); +#endif +#ifdef EREMCHG + if( errnum == EREMCHG ) return( __MCPU_EREMCHG ); +#endif +#ifdef ELIBACC + if( errnum == ELIBACC ) return( __MCPU_ELIBACC ); +#endif +#ifdef ELIBBAD + if( errnum == ELIBBAD ) return( __MCPU_ELIBBAD ); +#endif +#ifdef ELIBSCN + if( errnum == ELIBSCN ) return( __MCPU_ELIBSCN ); +#endif +#ifdef ELIBMAX + if( errnum == ELIBMAX ) return( __MCPU_ELIBMAX ); +#endif +#ifdef ELIBEXEC + if( errnum == ELIBEXEC ) return( __MCPU_ELIBEXEC ); +#endif +#ifdef EILSEQ + if( errnum == EILSEQ ) return( __MCPU_EILSEQ ); +#endif +#ifdef ERESTART + if( errnum == ERESTART ) return( __MCPU_ERESTART ); +#endif +#ifdef ESTRPIPE + if( errnum == ESTRPIPE ) return( __MCPU_ESTRPIPE ); +#endif +#ifdef EUSERS + if( errnum == EUSERS ) return( __MCPU_EUSERS ); +#endif +#ifdef ENOTSOCK + if( errnum == ENOTSOCK ) return( __MCPU_ENOTSOCK ); +#endif +#ifdef EDESTADDRREQ + if( errnum == EDESTADDRREQ ) return( __MCPU_EDESTADDRREQ ); +#endif +#ifdef EMSGSIZE + if( errnum == EMSGSIZE ) return( __MCPU_EMSGSIZE ); +#endif +#ifdef EPROTOTYPE + if( errnum == EPROTOTYPE ) return( __MCPU_EPROTOTYPE ); +#endif +#ifdef ENOPROTOOPT + if( errnum == ENOPROTOOPT ) return( __MCPU_ENOPROTOOPT ); +#endif +#ifdef EPROTONOSUPPORT + if( errnum == EPROTONOSUPPORT ) return( __MCPU_EPROTONOSUPPORT ); +#endif +#ifdef ESOCKTNOSUPPORT + if( errnum == ESOCKTNOSUPPORT ) return( __MCPU_ESOCKTNOSUPPORT ); +#endif +#ifdef EOPNOTSUPP + if( errnum == EOPNOTSUPP ) return( __MCPU_EOPNOTSUPP ); +#endif +#ifdef EPFNOSUPPORT + if( errnum == EPFNOSUPPORT ) return( __MCPU_EPFNOSUPPORT ); +#endif +#ifdef EAFNOSUPPORT + if( errnum == EAFNOSUPPORT ) return( __MCPU_EAFNOSUPPORT ); +#endif +#ifdef EADDRINUSE + if( errnum == EADDRINUSE ) return( __MCPU_EADDRINUSE ); +#endif +#ifdef EADDRNOTAVAIL + if( errnum == EADDRNOTAVAIL ) return( __MCPU_EADDRNOTAVAIL ); +#endif +#ifdef ENETDOWN + if( errnum == ENETDOWN ) return( __MCPU_ENETDOWN ); +#endif +#ifdef ENETUNREACH + if( errnum == ENETUNREACH ) return( __MCPU_ENETUNREACH ); +#endif +#ifdef ENETRESET + if( errnum == ENETRESET ) return( __MCPU_ENETRESET ); +#endif +#ifdef ECONNABORTED + if( errnum == ECONNABORTED ) return( __MCPU_ECONNABORTED ); +#endif +#ifdef ECONNRESET + if( errnum == ECONNRESET ) return( __MCPU_ECONNRESET ); +#endif +#ifdef ENOBUFS + if( errnum == ENOBUFS ) return( __MCPU_ENOBUFS ); +#endif +#ifdef EISCONN + if( errnum == EISCONN ) return( __MCPU_EISCONN ); +#endif +#ifdef ENOTCONN + if( errnum == ENOTCONN ) return( __MCPU_ENOTCONN ); +#endif +#ifdef ESHUTDOWN + if( errnum == ESHUTDOWN ) return( __MCPU_ESHUTDOWN ); +#endif +#ifdef ETOOMANYREFS + if( errnum == ETOOMANYREFS ) return( __MCPU_ETOOMANYREFS ); +#endif +#ifdef ETIMEDOUT + if( errnum == ETIMEDOUT ) return( __MCPU_ETIMEDOUT ); +#endif +#ifdef ECONNREFUSED + if( errnum == ECONNREFUSED ) return( __MCPU_ECONNREFUSED ); +#endif +#ifdef EHOSTDOWN + if( errnum == EHOSTDOWN ) return( __MCPU_EHOSTDOWN ); +#endif +#ifdef EHOSTUNREACH + if( errnum == EHOSTUNREACH ) return( __MCPU_EHOSTUNREACH ); +#endif +#ifdef EALREADY + if( errnum == EALREADY ) return( __MCPU_EALREADY ); +#endif +#ifdef EINPROGRESS + if( errnum == EINPROGRESS ) return( __MCPU_EINPROGRESS ); +#endif +#ifdef ESTALE + if( errnum == ESTALE ) return( __MCPU_ESTALE ); +#endif +#ifdef EUCLEAN + if( errnum == EUCLEAN ) return( __MCPU_EUCLEAN ); +#endif +#ifdef ENOTNAM + if( errnum == ENOTNAM ) return( __MCPU_ENOTNAM ); +#endif +#ifdef ENAVAIL + if( errnum == ENAVAIL ) return( __MCPU_ENAVAIL ); +#endif +#ifdef EISNAM + if( errnum == EISNAM ) return( __MCPU_EISNAM ); +#endif +#ifdef EREMOTEIO + if( errnum == EREMOTEIO ) return( __MCPU_EREMOTEIO ); +#endif +#ifdef EDQUOT + if( errnum == EDQUOT ) return( __MCPU_EDQUOT ); +#endif +#ifdef ENOMEDIUM + if( errnum == ENOMEDIUM ) return( __MCPU_ENOMEDIUM ); +#endif +#ifdef EMEDIUMTYPE + if( errnum == EMEDIUMTYPE ) return( __MCPU_EMEDIUMTYPE ); +#endif +#ifdef ECANCELED + if( errnum == ECANCELED ) return( __MCPU_ECANCELED ); +#endif +#ifdef ENOKEY + if( errnum == ENOKEY ) return( __MCPU_ENOKEY ); +#endif +#ifdef EKEYEXPIRED + if( errnum == EKEYEXPIRED ) return( __MCPU_EKEYEXPIRED ); +#endif +#ifdef EKEYREVOKED + if( errnum == EKEYREVOKED ) return( __MCPU_EKEYREVOKED ); +#endif +#ifdef EKEYREJECTED + if( errnum == EKEYREJECTED ) return( __MCPU_EKEYREJECTED ); +#endif +#ifdef EOWNERDEAD + if( errnum == EOWNERDEAD ) return( __MCPU_EOWNERDEAD ); +#endif +#ifdef ENOTRECOVERABLE + if( errnum == ENOTRECOVERABLE ) return( __MCPU_ENOTRECOVERABLE ); +#endif +#ifdef ERFKILL + if( errnum == ERFKILL ) return( __MCPU_ERFKILL ); +#endif +#ifdef EHWPOISON + if( errnum == EHWPOISON ) return( __MCPU_EHWPOISON ); +#endif +#ifdef EFTYPE + if( errnum == EFTYPE ) return( __MCPU_EFTYPE ); +#endif +#ifdef EWOULDBLOCK + if( errnum == EWOULDBLOCK ) return( __MCPU_EWOULDBLOCK ); +#endif +#ifdef EDEADLOCK + if( errnum == EDEADLOCK ) return( __MCPU_EDEADLOCK ); +#endif +#ifdef ENOTSUP + if( errnum == ENOTSUP ) return( __MCPU_ENOTSUP ); +#endif +#ifdef EUNKNOWN + if( errnum == EUNKNOWN ) return( __MCPU_EUNKNOWN ); +#endif + + return( __MCPU_EUNKNOWN ); + +} /* End of __cpu_errno_from_host() */ diff --git a/cpu/sysdeps/unix/sysv/linux/i386/i686/README b/cpu/sysdeps/unix/sysv/linux/i386/i686/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/i386/i686/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/unix/sysv/linux/i386/i786/Implies b/cpu/sysdeps/unix/sysv/linux/i386/i786/Implies new file mode 100644 index 0000000..7cb7d9a --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/i386/i786/Implies @@ -0,0 +1,2 @@ +# The PPro and PII cores are mostly the same. +unix/sysv/linux/i386/i686 diff --git a/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc32/README b/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc32/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc32/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc64/README b/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc64/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc64/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc64le/README b/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc64le/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/powerpc/powerpc64le/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/README b/cpu/sysdeps/unix/sysv/linux/x86_64/64/README new file mode 100644 index 0000000..c28377c --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/README @@ -0,0 +1,8 @@ +Linux/x86_64/LP64 HOST sysdeps +============================== + +This directory contains the selected low-level syscall adapters for the +currently supported Linux/x86_64 LP64 HOST profile. The common UNIX errno +translator is inherited from `cpu/sysdeps/unix/sys-errno.c`; all real HOST +failures are translated to stable MCPU errno values before control returns to +the common CPU layer. diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-chown-linux.h b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-chown-linux.h new file mode 100644 index 0000000..7b39ae4 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-chown-linux.h @@ -0,0 +1,66 @@ +/*************************************************************** + CPU-CHOWN-LINUX.H + + This file contains Linux/x86_64/LP64 conversion helpers + for MCPU uid/gid values -> HOST uid_t/gid_t. + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_CHOWN_LINUX_H +#define __CPU_CHOWN_LINUX_H + +#include <errno.h> +#include <sys/types.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static int +__cpu_uid_to_host( __mpu_uint64_t uid, uid_t *host_uid ) +{ + uid_t u; + + if( !host_uid ) return( __MCPU_EINVAL ); + if( uid == __CPU_ID_NO_CHANGE ) + { + *host_uid = (uid_t)-1; + return( 0 ); + } + + u = (uid_t)uid; + if( (__mpu_uint64_t)u != uid ) return( __MCPU_EOVERFLOW ); + + *host_uid = u; + return( 0 ); + +} /* End of __cpu_uid_to_host() */ + + +static int +__cpu_gid_to_host( __mpu_uint64_t gid, gid_t *host_gid ) +{ + gid_t g; + + if( !host_gid ) return( __MCPU_EINVAL ); + if( gid == __CPU_ID_NO_CHANGE ) + { + *host_gid = (gid_t)-1; + return( 0 ); + } + + g = (gid_t)gid; + if( (__mpu_uint64_t)g != gid ) return( __MCPU_EOVERFLOW ); + + *host_gid = g; + return( 0 ); + +} /* End of __cpu_gid_to_host() */ + +#endif /* __CPU_CHOWN_LINUX_H */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-mode-linux.h b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-mode-linux.h new file mode 100644 index 0000000..a68e50c --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-mode-linux.h @@ -0,0 +1,53 @@ +/*************************************************************** + CPU-MODE-LINUX.H + + This file contains Linux/x86_64/LP64 conversion helper + for MCPU permission bits -> HOST mode_t. + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_MODE_LINUX_H +#define __CPU_MODE_LINUX_H + +#include <errno.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static int +__cpu_mode_to_host( __mpu_uint64_t mode, mode_t *host_mode ) +{ + mode_t m = 0; + + if( !host_mode ) return( __MCPU_EINVAL ); + if( mode & ~(__mpu_uint64_t)__CPU_S_SUPPORTED ) return( __MCPU_EINVAL ); + + if( mode & __CPU_S_ISUID ) m |= S_ISUID; + if( mode & __CPU_S_ISGID ) m |= S_ISGID; +#ifdef S_ISVTX + if( mode & __CPU_S_ISVTX ) m |= S_ISVTX; +#endif + if( mode & __CPU_S_IRUSR ) m |= S_IRUSR; + if( mode & __CPU_S_IWUSR ) m |= S_IWUSR; + if( mode & __CPU_S_IXUSR ) m |= S_IXUSR; + if( mode & __CPU_S_IRGRP ) m |= S_IRGRP; + if( mode & __CPU_S_IWGRP ) m |= S_IWGRP; + if( mode & __CPU_S_IXGRP ) m |= S_IXGRP; + if( mode & __CPU_S_IROTH ) m |= S_IROTH; + if( mode & __CPU_S_IWOTH ) m |= S_IWOTH; + if( mode & __CPU_S_IXOTH ) m |= S_IXOTH; + + *host_mode = m; + return( 0 ); + +} /* End of __cpu_mode_to_host() */ + +#endif /* __CPU_MODE_LINUX_H */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-stat-linux.h b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-stat-linux.h new file mode 100644 index 0000000..58ac956 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-stat-linux.h @@ -0,0 +1,124 @@ +/*************************************************************** + CPU-STAT-LINUX.H + + This file contains Linux/x86_64/LP64 conversion helpers + for the HOST struct stat -> MCPU struct __cpu_stat ABI. + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_STAT_LINUX_H +#define __CPU_STAT_LINUX_H + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static int +__cpu_stat_mode( mode_t mode, __mpu_uint64_t *out ) +{ + __mpu_uint64_t m = 0; + + if( !out ) return( __MCPU_EFAULT ); + + switch( mode & S_IFMT ) + { + case S_IFIFO: m |= __CPU_S_IFIFO; break; + case S_IFCHR: m |= __CPU_S_IFCHR; break; + case S_IFDIR: m |= __CPU_S_IFDIR; break; + case S_IFBLK: m |= __CPU_S_IFBLK; break; + case S_IFREG: m |= __CPU_S_IFREG; break; + case S_IFLNK: m |= __CPU_S_IFLNK; break; +#ifdef S_IFSOCK + case S_IFSOCK: m |= __CPU_S_IFSOCK; break; +#endif + default: return( __MCPU_EOVERFLOW ); + } + + if( mode & S_ISUID ) m |= __CPU_S_ISUID; + if( mode & S_ISGID ) m |= __CPU_S_ISGID; +#ifdef S_ISVTX + if( mode & S_ISVTX ) m |= __CPU_S_ISVTX; +#endif + if( mode & S_IRUSR ) m |= __CPU_S_IRUSR; + if( mode & S_IWUSR ) m |= __CPU_S_IWUSR; + if( mode & S_IXUSR ) m |= __CPU_S_IXUSR; + if( mode & S_IRGRP ) m |= __CPU_S_IRGRP; + if( mode & S_IWGRP ) m |= __CPU_S_IWGRP; + if( mode & S_IXGRP ) m |= __CPU_S_IXGRP; + if( mode & S_IROTH ) m |= __CPU_S_IROTH; + if( mode & S_IWOTH ) m |= __CPU_S_IWOTH; + if( mode & S_IXOTH ) m |= __CPU_S_IXOTH; + + *out = m; + return( 0 ); + +} /* End of __cpu_stat_mode() */ + + +static int +__cpu_stat_from_host( struct __cpu_stat *dst, const struct stat *src ) +{ + int error; + + if( !dst || !src ) return( __MCPU_EFAULT ); + + dst->st_dev = (__mpu_uint64_t)src->st_dev; + if( (dev_t)dst->st_dev != src->st_dev ) return( __MCPU_EOVERFLOW ); + + dst->st_ino = (__mpu_uint64_t)src->st_ino; + if( (ino_t)dst->st_ino != src->st_ino ) return( __MCPU_EOVERFLOW ); + + error = __cpu_stat_mode( src->st_mode, &dst->st_mode ); + if( error ) return( error ); + + dst->st_nlink = (__mpu_uint64_t)src->st_nlink; + if( (nlink_t)dst->st_nlink != src->st_nlink ) return( __MCPU_EOVERFLOW ); + + dst->st_uid = (__mpu_uint64_t)src->st_uid; + if( (uid_t)dst->st_uid != src->st_uid ) return( __MCPU_EOVERFLOW ); + + dst->st_gid = (__mpu_uint64_t)src->st_gid; + if( (gid_t)dst->st_gid != src->st_gid ) return( __MCPU_EOVERFLOW ); + + dst->st_rdev = (__mpu_uint64_t)src->st_rdev; + if( (dev_t)dst->st_rdev != src->st_rdev ) return( __MCPU_EOVERFLOW ); + + dst->st_size = (__mpu_int64_t)src->st_size; + if( (off_t)dst->st_size != src->st_size ) return( __MCPU_EOVERFLOW ); + + dst->st_blksize = (__mpu_int64_t)src->st_blksize; + if( (blksize_t)dst->st_blksize != src->st_blksize ) return( __MCPU_EOVERFLOW ); + + dst->st_blocks = (__mpu_int64_t)src->st_blocks; + if( (blkcnt_t)dst->st_blocks != src->st_blocks ) return( __MCPU_EOVERFLOW ); + + dst->st_atime_sec = (__mpu_int64_t)src->st_atim.tv_sec; + if( (time_t)dst->st_atime_sec != src->st_atim.tv_sec ) return( __MCPU_EOVERFLOW ); + if( src->st_atim.tv_nsec < 0 ) return( __MCPU_EOVERFLOW ); + dst->st_atime_nsec = (__mpu_uint64_t)src->st_atim.tv_nsec; + + dst->st_mtime_sec = (__mpu_int64_t)src->st_mtim.tv_sec; + if( (time_t)dst->st_mtime_sec != src->st_mtim.tv_sec ) return( __MCPU_EOVERFLOW ); + if( src->st_mtim.tv_nsec < 0 ) return( __MCPU_EOVERFLOW ); + dst->st_mtime_nsec = (__mpu_uint64_t)src->st_mtim.tv_nsec; + + dst->st_ctime_sec = (__mpu_int64_t)src->st_ctim.tv_sec; + if( (time_t)dst->st_ctime_sec != src->st_ctim.tv_sec ) return( __MCPU_EOVERFLOW ); + if( src->st_ctim.tv_nsec < 0 ) return( __MCPU_EOVERFLOW ); + dst->st_ctime_nsec = (__mpu_uint64_t)src->st_ctim.tv_nsec; + + return( 0 ); + +} /* End of __cpu_stat_from_host() */ + +#endif /* __CPU_STAT_LINUX_H */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-time-linux.h b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-time-linux.h new file mode 100644 index 0000000..8bdda84 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/cpu-time-linux.h @@ -0,0 +1,64 @@ +/*************************************************************** + CPU-TIME-LINUX.H + + Linux/x86_64/LP64 conversion helpers for the MCPU time ABI. + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __CPU_TIME_LINUX_H +#define __CPU_TIME_LINUX_H + +#include <errno.h> +#include <time.h> + + +static int +__cpu_clockid_to_host( __mpu_uint64_t clockid, clockid_t *host_clockid ) +{ + if( !host_clockid ) return( __MCPU_EFAULT ); + + switch( clockid ) + { + case __CPU_CLOCK_REALTIME: + *host_clockid = CLOCK_REALTIME; + return( 0 ); + case __CPU_CLOCK_MONOTONIC: + *host_clockid = CLOCK_MONOTONIC; + return( 0 ); + default: + return( __MCPU_EINVAL ); + } + +} /* End of __cpu_clockid_to_host() */ + + +static int +__cpu_timespec_from_host( struct __cpu_timespec *dst, + const struct timespec *src ) +{ + __mpu_int64_t sec; + __mpu_int64_t nsec; + + if( !dst || !src ) return( __MCPU_EFAULT ); + + sec = (__mpu_int64_t)src->tv_sec; + if( (time_t)sec != src->tv_sec ) return( __MCPU_EOVERFLOW ); + + nsec = (__mpu_int64_t)src->tv_nsec; + if( (long)nsec != src->tv_nsec ) return( __MCPU_EOVERFLOW ); + if( nsec < 0 || nsec > 999999999 ) return( __MCPU_EOVERFLOW ); + + dst->tv_sec = sec; + dst->tv_nsec = nsec; + + return( 0 ); + +} /* End of __cpu_timespec_from_host() */ + +#endif /* __CPU_TIME_LINUX_H */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-access.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-access.c new file mode 100644 index 0000000..5bb9a45 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-access.c @@ -0,0 +1,42 @@ +/*************************************************************** + SYS-ACCESS.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_access(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_access( int dirfd, const char *path, __mpu_uint64_t mode ) +{ + int host_mode = 0; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + if( mode & ~(__mpu_uint64_t)__CPU_ACCESS_SUPPORTED ) + return( -(__mpu_int64_t)__MCPU_EINVAL ); + + if( mode & __CPU_R_OK ) host_mode |= R_OK; + if( mode & __CPU_W_OK ) host_mode |= W_OK; + if( mode & __CPU_X_OK ) host_mode |= X_OK; + + if( faccessat( dirfd, path, host_mode, 0 ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_access() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chdir.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chdir.c new file mode 100644 index 0000000..c6da354 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chdir.c @@ -0,0 +1,53 @@ +/*************************************************************** + SYS-CHDIR.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_cwd_init() and __cpu_sys_chdir(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static __mpu_int64_t +__cpu_open_directory( int dirfd, const char *path ) +{ + int fd; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + fd = openat( dirfd, path, O_PATH | O_DIRECTORY | O_CLOEXEC ); + if( fd < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)fd ); + +} /* End of __cpu_open_directory() */ + + +__mpu_int64_t +__cpu_sys_cwd_init( void ) +{ + return( __cpu_open_directory( AT_FDCWD, "." ) ); + +} /* End of __cpu_sys_cwd_init() */ + + +__mpu_int64_t +__cpu_sys_chdir( int dirfd, const char *path ) +{ + return( __cpu_open_directory( dirfd, path ) ); + +} /* End of __cpu_sys_chdir() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chmod.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chmod.c new file mode 100644 index 0000000..6719bf7 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chmod.c @@ -0,0 +1,41 @@ +/*************************************************************** + SYS-CHMOD.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_chmod(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-mode-linux.h" + + +__mpu_int64_t +__cpu_sys_chmod( int dirfd, const char *path, __mpu_uint64_t mode ) +{ + mode_t host_mode; + int error; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + error = __cpu_mode_to_host( mode, &host_mode ); + if( error ) return( -(__mpu_int64_t)error ); + + if( fchmodat( dirfd, path, host_mode, 0 ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_chmod() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chown.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chown.c new file mode 100644 index 0000000..42e748e --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-chown.c @@ -0,0 +1,45 @@ +/*************************************************************** + SYS-CHOWN.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_chown(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-chown-linux.h" + + +__mpu_int64_t +__cpu_sys_chown( int dirfd, const char *path, __mpu_uint64_t uid, + __mpu_uint64_t gid ) +{ + uid_t host_uid; + gid_t host_gid; + int error; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + error = __cpu_uid_to_host( uid, &host_uid ); + if( error ) return( -(__mpu_int64_t)error ); + error = __cpu_gid_to_host( gid, &host_gid ); + if( error ) return( -(__mpu_int64_t)error ); + + if( fchownat( dirfd, path, host_uid, host_gid, 0 ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_chown() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_getres.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_getres.c new file mode 100644 index 0000000..d156d61 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_getres.c @@ -0,0 +1,48 @@ +/*************************************************************** + SYS-CLOCK_GETRES.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_clock_getres(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <time.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-time-linux.h" + + +__mpu_int64_t +__cpu_sys_clock_getres( __mpu_uint64_t clockid, struct __cpu_timespec *res ) +{ + struct timespec ts; + clockid_t host_clockid; + int error; + + error = __cpu_clockid_to_host( clockid, &host_clockid ); + if( error ) return( -(__mpu_int64_t)error ); + + if( clock_getres( host_clockid, res ? &ts : (struct timespec *)0 ) < 0 ) + return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + if( res ) + { + error = __cpu_timespec_from_host( res, &ts ); + if( error ) return( -(__mpu_int64_t)error ); + } + + return( 0 ); + +} /* End of __cpu_sys_clock_getres() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_gettime.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_gettime.c new file mode 100644 index 0000000..6e017fc --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_gettime.c @@ -0,0 +1,47 @@ +/*************************************************************** + SYS-CLOCK_GETTIME.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_clock_gettime(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <time.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-time-linux.h" + + +__mpu_int64_t +__cpu_sys_clock_gettime( __mpu_uint64_t clockid, struct __cpu_timespec *tp ) +{ + struct timespec ts; + clockid_t host_clockid; + int error; + + if( !tp ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + error = __cpu_clockid_to_host( clockid, &host_clockid ); + if( error ) return( -(__mpu_int64_t)error ); + + if( clock_gettime( host_clockid, &ts ) < 0 ) + return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + error = __cpu_timespec_from_host( tp, &ts ); + if( error ) return( -(__mpu_int64_t)error ); + + return( 0 ); + +} /* End of __cpu_sys_clock_gettime() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_nanosleep.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_nanosleep.c new file mode 100644 index 0000000..8659441 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-clock_nanosleep.c @@ -0,0 +1,93 @@ +/*************************************************************** + SYS-CLOCK_NANOSLEEP.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_clock_nanosleep(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <time.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-time-linux.h" + + +static int +__cpu_timespec_to_host( struct timespec *dst, + const struct __cpu_timespec *src ) +{ + time_t sec; + long nsec; + + if( !dst || !src ) return( __MCPU_EFAULT ); + if( src->tv_sec < 0 || src->tv_nsec < 0 || src->tv_nsec > 999999999 ) + return( __MCPU_EINVAL ); + + sec = (time_t)src->tv_sec; + if( (__mpu_int64_t)sec != src->tv_sec ) return( __MCPU_EOVERFLOW ); + + nsec = (long)src->tv_nsec; + if( (__mpu_int64_t)nsec != src->tv_nsec ) return( __MCPU_EOVERFLOW ); + + dst->tv_sec = sec; + dst->tv_nsec = nsec; + + return( 0 ); + +} /* End of __cpu_timespec_to_host() */ + + +__mpu_int64_t +__cpu_sys_clock_nanosleep( __mpu_uint64_t clockid, __mpu_uint64_t flags, + const struct __cpu_timespec *req, + struct __cpu_timespec *rem ) +{ + struct timespec host_req; + struct timespec host_rem; + struct timespec *host_prem = (struct timespec *)0; + clockid_t host_clockid; + int host_flags = 0; + int ret; + int error; + + if( !req ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + error = __cpu_clockid_to_host( clockid, &host_clockid ); + if( error ) return( -(__mpu_int64_t)error ); + + if( flags == __CPU_TIMER_ABSTIME ) + host_flags = TIMER_ABSTIME; + else if( flags != 0 ) + return( -(__mpu_int64_t)__MCPU_EINVAL ); + + error = __cpu_timespec_to_host( &host_req, req ); + if( error ) return( -(__mpu_int64_t)error ); + + if( !host_flags && rem ) host_prem = &host_rem; + + ret = clock_nanosleep( host_clockid, host_flags, &host_req, host_prem ); + if( ret != 0 ) + { + if( ret == EINTR && host_prem ) + { + error = __cpu_timespec_from_host( rem, &host_rem ); + if( error ) return( -(__mpu_int64_t)error ); + } + return( -(__mpu_int64_t)__cpu_errno_from_host( ret ) ); + } + + return( 0 ); + +} /* End of __cpu_sys_clock_nanosleep() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-close.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-close.c new file mode 100644 index 0000000..48aceed --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-close.c @@ -0,0 +1,16 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + +__mpu_int64_t +__cpu_sys_close( int fd ) +{ + if( close( fd ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); +} diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-creat.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-creat.c new file mode 100644 index 0000000..9bbccce --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-creat.c @@ -0,0 +1,30 @@ +/*************************************************************** + SYS-CREAT.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_creat(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_creat( int dirfd, const char *path, __mpu_uint64_t mode ) +{ + return( __cpu_sys_open( dirfd, path, + __CPU_O_WRONLY | __CPU_O_CREAT | __CPU_O_TRUNC, + mode ) ); + +} /* End of __cpu_sys_creat() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-dup.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-dup.c new file mode 100644 index 0000000..f140b69 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-dup.c @@ -0,0 +1,36 @@ +/*************************************************************** + SYS-DUP.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_dup(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_dup( int fd ) +{ + int ret; + + ret = dup( fd ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + return( (__mpu_int64_t)ret ); + +} /* End of __cpu_sys_dup() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchdir.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchdir.c new file mode 100644 index 0000000..3323975 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchdir.c @@ -0,0 +1,35 @@ +/*************************************************************** + SYS-FCHDIR.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_fchdir(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_fchdir( int fd ) +{ + int cwd_fd; + + cwd_fd = openat( fd, ".", O_PATH | O_DIRECTORY | O_CLOEXEC ); + if( cwd_fd < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)cwd_fd ); + +} /* End of __cpu_sys_fchdir() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchmod.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchmod.c new file mode 100644 index 0000000..a4f90be --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchmod.c @@ -0,0 +1,39 @@ +/*************************************************************** + SYS-FCHMOD.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_fchmod(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-mode-linux.h" + + +__mpu_int64_t +__cpu_sys_fchmod( int fd, __mpu_uint64_t mode ) +{ + mode_t host_mode; + int error; + + error = __cpu_mode_to_host( mode, &host_mode ); + if( error ) return( -(__mpu_int64_t)error ); + + if( fchmod( fd, host_mode ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_fchmod() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchown.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchown.c new file mode 100644 index 0000000..a3e793b --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fchown.c @@ -0,0 +1,42 @@ +/*************************************************************** + SYS-FCHOWN.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_fchown(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-chown-linux.h" + + +__mpu_int64_t +__cpu_sys_fchown( int fd, __mpu_uint64_t uid, __mpu_uint64_t gid ) +{ + uid_t host_uid; + gid_t host_gid; + int error; + + error = __cpu_uid_to_host( uid, &host_uid ); + if( error ) return( -(__mpu_int64_t)error ); + error = __cpu_gid_to_host( gid, &host_gid ); + if( error ) return( -(__mpu_int64_t)error ); + + if( fchown( fd, host_uid, host_gid ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_fchown() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fcntl.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fcntl.c new file mode 100644 index 0000000..d04074e --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fcntl.c @@ -0,0 +1,115 @@ +/*************************************************************** + SYS-FCNTL.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_fcntl(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static int +__cpu_fcntl_getfl( int host_flags, __mpu_uint64_t *guest_flags ) +{ + __mpu_uint64_t flags = 0; + + if( !guest_flags ) return( __MCPU_EINVAL ); + + switch( host_flags & O_ACCMODE ) + { + case O_RDONLY: flags |= __CPU_O_RDONLY; break; + case O_WRONLY: flags |= __CPU_O_WRONLY; break; + case O_RDWR: flags |= __CPU_O_RDWR; break; + default: return( __MCPU_EINVAL ); + } + + if( host_flags & O_APPEND ) flags |= __CPU_O_APPEND; + if( host_flags & O_NONBLOCK ) flags |= __CPU_O_NONBLOCK; + + *guest_flags = flags; + return( 0 ); + +} /* End of __cpu_fcntl_getfl() */ + + +static int +__cpu_fcntl_setfl( __mpu_uint64_t guest_flags, int *host_flags ) +{ + int flags = 0; + + if( !host_flags ) return( __MCPU_EINVAL ); + if( guest_flags & ~(__mpu_uint64_t)__CPU_F_SETFL_SUPPORTED ) + return( __MCPU_EINVAL ); + + switch( guest_flags & __CPU_O_ACCMODE ) + { + case __CPU_O_RDONLY: + case __CPU_O_WRONLY: + case __CPU_O_RDWR: + break; + default: + return( __MCPU_EINVAL ); + } + + if( guest_flags & __CPU_O_APPEND ) flags |= O_APPEND; + if( guest_flags & __CPU_O_NONBLOCK ) flags |= O_NONBLOCK; + + *host_flags = flags; + return( 0 ); + +} /* End of __cpu_fcntl_setfl() */ + + +__mpu_int64_t +__cpu_sys_fcntl( int fd, __mpu_uint64_t cmd, __mpu_uint64_t arg ) +{ + __mpu_uint64_t guest_flags; + int host_flags; + int error; + int ret; + + switch( cmd ) + { + case __CPU_F_DUPFD: + if( arg != 0 ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + ret = fcntl( fd, F_DUPFD, 0 ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)ret ); + + case __CPU_F_GETFL: + if( arg != 0 ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + ret = fcntl( fd, F_GETFL ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + error = __cpu_fcntl_getfl( ret, &guest_flags ); + if( error ) return( -(__mpu_int64_t)error ); + return( (__mpu_int64_t)guest_flags ); + + case __CPU_F_SETFL: + error = __cpu_fcntl_setfl( arg, &host_flags ); + if( error ) return( -(__mpu_int64_t)error ); + + ret = fcntl( fd, F_SETFL, host_flags ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + + default: + return( -(__mpu_int64_t)__MCPU_EINVAL ); + } + +} /* End of __cpu_sys_fcntl() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fstat.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fstat.c new file mode 100644 index 0000000..53b0309 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fstat.c @@ -0,0 +1,43 @@ +/*************************************************************** + SYS-FSTAT.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_fstat(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-stat-linux.h" + + +__mpu_int64_t +__cpu_sys_fstat( int fd, struct __cpu_stat *st ) +{ + struct stat host_st; + int error; + + if( fd < 0 ) return( -(__mpu_int64_t)__MCPU_EBADF ); + if( !st ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( fstat( fd, &host_st ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + error = __cpu_stat_from_host( st, &host_st ); + if( error ) return( -(__mpu_int64_t)error ); + + return( 0 ); + +} /* End of __cpu_sys_fstat() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fsync.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fsync.c new file mode 100644 index 0000000..3ba7e11 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-fsync.c @@ -0,0 +1,32 @@ +/*************************************************************** + SYS-FSYNC.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_fsync(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_fsync( int fd ) +{ + if( fsync( fd ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_fsync() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-ftruncate.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-ftruncate.c new file mode 100644 index 0000000..f5e55ad --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-ftruncate.c @@ -0,0 +1,39 @@ +/*************************************************************** + SYS-FTRUNCATE.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_ftruncate(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_ftruncate( int fd, __mpu_int64_t length ) +{ + off_t host_length; + + host_length = (off_t)length; + if( (__mpu_int64_t)host_length != length ) + return( -(__mpu_int64_t)__MCPU_EOVERFLOW ); + + if( ftruncate( fd, host_length ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_ftruncate() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-getdents.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-getdents.c new file mode 100644 index 0000000..6b8928c --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-getdents.c @@ -0,0 +1,227 @@ +/*************************************************************** + SYS-GETDENTS.C + + Linux/x86_64/LP64 implementation of __cpu_sys_getdents(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <dirent.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + +#define __CPU_HOST_DIRENT_BUFFER 4096U + +struct __cpu_linux_dirent64 +{ + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; +}; + +static int +__cpu_dirent_utf8_valid( const unsigned char *s, size_t n ) +{ + size_t i = 0; + + while( i < n ) + { + unsigned int c = s[i++]; + + if( c < 0x80U ) continue; + if( c >= 0xc2U && c <= 0xdfU ) + { + if( i >= n || ( s[i] & 0xc0U ) != 0x80U ) return( 0 ); + ++i; continue; + } + if( c == 0xe0U ) + { + if( i + 1 >= n || s[i] < 0xa0U || s[i] > 0xbfU || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; continue; + } + if( c >= 0xe1U && c <= 0xecU ) + { + if( i + 1 >= n || ( s[i] & 0xc0U ) != 0x80U || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; continue; + } + if( c == 0xedU ) + { + if( i + 1 >= n || s[i] < 0x80U || s[i] > 0x9fU || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; continue; + } + if( c >= 0xeeU && c <= 0xefU ) + { + if( i + 1 >= n || ( s[i] & 0xc0U ) != 0x80U || + ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); + i += 2; continue; + } + if( c == 0xf0U ) + { + if( i + 2 >= n || s[i] < 0x90U || s[i] > 0xbfU || + ( s[i + 1] & 0xc0U ) != 0x80U || + ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); + i += 3; continue; + } + if( c >= 0xf1U && c <= 0xf3U ) + { + if( i + 2 >= n || ( s[i] & 0xc0U ) != 0x80U || + ( s[i + 1] & 0xc0U ) != 0x80U || + ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); + i += 3; continue; + } + if( c == 0xf4U ) + { + if( i + 2 >= n || s[i] < 0x80U || s[i] > 0x8fU || + ( s[i + 1] & 0xc0U ) != 0x80U || + ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); + i += 3; continue; + } + return( 0 ); + } + return( 1 ); +} + +static __mpu_uint64_t +__cpu_dirent_type( unsigned char type ) +{ + switch( type ) + { +#ifdef DT_FIFO + case DT_FIFO: return( __CPU_DT_FIFO ); +#endif +#ifdef DT_CHR + case DT_CHR: return( __CPU_DT_CHR ); +#endif +#ifdef DT_DIR + case DT_DIR: return( __CPU_DT_DIR ); +#endif +#ifdef DT_BLK + case DT_BLK: return( __CPU_DT_BLK ); +#endif +#ifdef DT_REG + case DT_REG: return( __CPU_DT_REG ); +#endif +#ifdef DT_LNK + case DT_LNK: return( __CPU_DT_LNK ); +#endif +#ifdef DT_SOCK + case DT_SOCK: return( __CPU_DT_SOCK ); +#endif + default: return( __CPU_DT_UNKNOWN ); + } +} + +__mpu_int64_t +__cpu_sys_getdents( int fd, struct __cpu_dirent *dirp, __mpu_uint64_t count ) +{ + unsigned char hostbuf[__CPU_HOST_DIRENT_BUFFER]; + struct stat st; + off_t start; + off_t resume; + ssize_t nread; + size_t pos = 0; + size_t nrecords = 0; + size_t maxrecords; + + if( !dirp ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + if( count < __CPU_DIRENT_SIZE ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + + maxrecords = (size_t)( count / __CPU_DIRENT_SIZE ); + + if( fstat( fd, &st ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + if( !S_ISDIR( st.st_mode ) ) return( -(__mpu_int64_t)__MCPU_ENOTDIR ); + + start = lseek( fd, (off_t)0, SEEK_CUR ); + if( start == (off_t)-1 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + resume = start; + + nread = syscall( SYS_getdents64, fd, hostbuf, sizeof( hostbuf ) ); + if( nread < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + if( nread == 0 ) return( 0 ); + + while( pos < (size_t)nread ) + { + struct __cpu_linux_dirent64 *de; + const char *nul; + size_t namespace; + size_t namelen; + + if( (size_t)nread - pos < offsetof( struct __cpu_linux_dirent64, d_name ) + 1U ) + goto malformed; + + de = (struct __cpu_linux_dirent64 *)( hostbuf + pos ); + if( de->d_reclen < offsetof( struct __cpu_linux_dirent64, d_name ) + 1U || + de->d_reclen > (size_t)nread - pos ) goto malformed; + + if( nrecords >= maxrecords ) break; + + namespace = de->d_reclen - offsetof( struct __cpu_linux_dirent64, d_name ); + nul = (const char *)memchr( de->d_name, '\0', namespace ); + if( !nul ) goto malformed; + namelen = (size_t)( nul - de->d_name ); + + if( namelen >= __CPU_DIRENT_NAME_SIZE ) + { + if( lseek( fd, resume, SEEK_SET ) == (off_t)-1 ) + return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( nrecords ? (__mpu_int64_t)( nrecords * __CPU_DIRENT_SIZE ) + : -(__mpu_int64_t)__MCPU_ENAMETOOLONG ); + } + + if( !__cpu_dirent_utf8_valid( (const unsigned char *)de->d_name, namelen ) ) + { + if( lseek( fd, resume, SEEK_SET ) == (off_t)-1 ) + return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( nrecords ? (__mpu_int64_t)( nrecords * __CPU_DIRENT_SIZE ) + : -(__mpu_int64_t)__MCPU_EILSEQ ); + } + + dirp[nrecords].d_ino = (__mpu_uint64_t)de->d_ino; + dirp[nrecords].d_off = (__mpu_int64_t)de->d_off; + dirp[nrecords].d_reclen = __CPU_DIRENT_SIZE; + dirp[nrecords].d_type = __cpu_dirent_type( de->d_type ); + memset( dirp[nrecords].d_name, 0, __CPU_DIRENT_NAME_SIZE ); + memcpy( dirp[nrecords].d_name, de->d_name, namelen ); + + resume = (off_t)de->d_off; + ++nrecords; + pos += de->d_reclen; + } + + if( pos < (size_t)nread ) + { + if( lseek( fd, resume, SEEK_SET ) == (off_t)-1 ) + return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + } + + return( (__mpu_int64_t)( nrecords * __CPU_DIRENT_SIZE ) ); + +malformed: + if( lseek( fd, start, SEEK_SET ) == (off_t)-1 ) + return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( -(__mpu_int64_t)__MCPU_EIO ); + +} /* End of __cpu_sys_getdents() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-link.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-link.c new file mode 100644 index 0000000..fd19f0d --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-link.c @@ -0,0 +1,34 @@ +/*************************************************************** + SYS-LINK.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_link(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_link( int dirfd, const char *oldpath, const char *newpath ) +{ + if( !oldpath || !newpath ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( linkat( dirfd, oldpath, dirfd, newpath, 0 ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_link() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-lseek.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-lseek.c new file mode 100644 index 0000000..0de650e --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-lseek.c @@ -0,0 +1,35 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <limits.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + +__mpu_int64_t +__cpu_sys_lseek( int fd, __mpu_int64_t offset, __mpu_uint64_t whence ) +{ + off_t host_offset; + off_t ret; + int host_whence; + + switch( whence ) + { + case __CPU_SEEK_SET: host_whence = SEEK_SET; break; + case __CPU_SEEK_CUR: host_whence = SEEK_CUR; break; + case __CPU_SEEK_END: host_whence = SEEK_END; break; + default: return( -(__mpu_int64_t)__MCPU_EINVAL ); + } + + host_offset = (off_t)offset; + if( (__mpu_int64_t)host_offset != offset ) return( -(__mpu_int64_t)__MCPU_EOVERFLOW ); + + ret = lseek( fd, host_offset, host_whence ); + if( ret == (off_t)-1 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + if( (off_t)(__mpu_int64_t)ret != ret ) return( -(__mpu_int64_t)__MCPU_EOVERFLOW ); + return( (__mpu_int64_t)ret ); +} diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-lstat.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-lstat.c new file mode 100644 index 0000000..3ea9353 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-lstat.c @@ -0,0 +1,43 @@ +/*************************************************************** + SYS-LSTAT.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_lstat(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-stat-linux.h" + + +__mpu_int64_t +__cpu_sys_lstat( int dirfd, const char *path, struct __cpu_stat *st ) +{ + struct stat host_st; + int error; + + if( !path || !st ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( fstatat( dirfd, path, &host_st, AT_SYMLINK_NOFOLLOW ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + error = __cpu_stat_from_host( st, &host_st ); + if( error ) return( -(__mpu_int64_t)error ); + + return( 0 ); + +} /* End of __cpu_sys_lstat() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-mkdir.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-mkdir.c new file mode 100644 index 0000000..76ced3a --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-mkdir.c @@ -0,0 +1,69 @@ +/*************************************************************** + SYS-MKDIR.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_mkdir(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static int +__cpu_mkdir_mode( __mpu_uint64_t mode, mode_t *host_mode ) +{ + mode_t m = 0; + + if( !host_mode ) return( __MCPU_EINVAL ); + if( mode & ~(__mpu_uint64_t)__CPU_S_SUPPORTED ) return( __MCPU_EINVAL ); + + if( mode & __CPU_S_ISUID ) m |= S_ISUID; + if( mode & __CPU_S_ISGID ) m |= S_ISGID; +#ifdef S_ISVTX + if( mode & __CPU_S_ISVTX ) m |= S_ISVTX; +#endif + if( mode & __CPU_S_IRUSR ) m |= S_IRUSR; + if( mode & __CPU_S_IWUSR ) m |= S_IWUSR; + if( mode & __CPU_S_IXUSR ) m |= S_IXUSR; + if( mode & __CPU_S_IRGRP ) m |= S_IRGRP; + if( mode & __CPU_S_IWGRP ) m |= S_IWGRP; + if( mode & __CPU_S_IXGRP ) m |= S_IXGRP; + if( mode & __CPU_S_IROTH ) m |= S_IROTH; + if( mode & __CPU_S_IWOTH ) m |= S_IWOTH; + if( mode & __CPU_S_IXOTH ) m |= S_IXOTH; + + *host_mode = m; + return( 0 ); + +} /* End of __cpu_mkdir_mode() */ + + +__mpu_int64_t +__cpu_sys_mkdir( int dirfd, const char *path, __mpu_uint64_t mode ) +{ + mode_t host_mode; + int error; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + error = __cpu_mkdir_mode( mode, &host_mode ); + if( error ) return( -(__mpu_int64_t)error ); + + if( mkdirat( dirfd, path, host_mode ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_mkdir() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-open.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-open.c new file mode 100644 index 0000000..36a9994 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-open.c @@ -0,0 +1,114 @@ +/*************************************************************** + SYS-OPEN.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_open(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +static int +__cpu_open_flags( __mpu_uint64_t flags, int *host_flags ) +{ + int f = 0; + + if( !host_flags ) return( __MCPU_EINVAL ); + if( flags & ~(__mpu_uint64_t)__CPU_O_SUPPORTED ) return( __MCPU_EINVAL ); + + switch( flags & __CPU_O_ACCMODE ) + { + case __CPU_O_RDONLY: f |= O_RDONLY; break; + case __CPU_O_WRONLY: f |= O_WRONLY; break; + case __CPU_O_RDWR: f |= O_RDWR; break; + default: return( __MCPU_EINVAL ); + } + + if( flags & __CPU_O_CREAT ) f |= O_CREAT; + if( flags & __CPU_O_EXCL ) f |= O_EXCL; + if( flags & __CPU_O_NOCTTY ) f |= O_NOCTTY; + if( flags & __CPU_O_TRUNC ) f |= O_TRUNC; + if( flags & __CPU_O_APPEND ) f |= O_APPEND; + if( flags & __CPU_O_NONBLOCK ) f |= O_NONBLOCK; + + *host_flags = f; + return( 0 ); + +} /* End of __cpu_open_flags() */ + + +static int +__cpu_open_mode( __mpu_uint64_t mode, mode_t *host_mode ) +{ + mode_t m = 0; + + if( !host_mode ) return( __MCPU_EINVAL ); + if( mode & ~(__mpu_uint64_t)__CPU_S_SUPPORTED ) return( __MCPU_EINVAL ); + + if( mode & __CPU_S_ISUID ) m |= S_ISUID; + if( mode & __CPU_S_ISGID ) m |= S_ISGID; +#ifdef S_ISVTX + if( mode & __CPU_S_ISVTX ) m |= S_ISVTX; +#endif + if( mode & __CPU_S_IRUSR ) m |= S_IRUSR; + if( mode & __CPU_S_IWUSR ) m |= S_IWUSR; + if( mode & __CPU_S_IXUSR ) m |= S_IXUSR; + if( mode & __CPU_S_IRGRP ) m |= S_IRGRP; + if( mode & __CPU_S_IWGRP ) m |= S_IWGRP; + if( mode & __CPU_S_IXGRP ) m |= S_IXGRP; + if( mode & __CPU_S_IROTH ) m |= S_IROTH; + if( mode & __CPU_S_IWOTH ) m |= S_IWOTH; + if( mode & __CPU_S_IXOTH ) m |= S_IXOTH; + + *host_mode = m; + return( 0 ); + +} /* End of __cpu_open_mode() */ + + +__mpu_int64_t +__cpu_sys_open( int dirfd, const char *path, __mpu_uint64_t flags, + __mpu_uint64_t mode ) +{ + mode_t host_mode = 0; + int host_flags; + int error; + int fd; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + error = __cpu_open_flags( flags, &host_flags ); + if( error ) return( -(__mpu_int64_t)error ); + + if( flags & __CPU_O_CREAT ) + { + error = __cpu_open_mode( mode, &host_mode ); + if( error ) return( -(__mpu_int64_t)error ); + fd = openat( dirfd, path, host_flags, host_mode ); + } + else + { + if( mode != 0 ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + fd = openat( dirfd, path, host_flags ); + } + + if( fd < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)fd ); + +} /* End of __cpu_sys_open() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-pipe2.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-pipe2.c new file mode 100644 index 0000000..bb211a2 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-pipe2.c @@ -0,0 +1,44 @@ +/*************************************************************** + SYS-PIPE2.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_pipe2(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_pipe2( int pipefd[2], __mpu_uint64_t flags ) +{ + int host_flags = 0; + int ret; + + if( !pipefd ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + if( flags & ~(__mpu_uint64_t)__CPU_O_NONBLOCK ) + return( -(__mpu_int64_t)__MCPU_EINVAL ); + + if( flags & __CPU_O_NONBLOCK ) host_flags |= O_NONBLOCK; + + ret = pipe2( pipefd, host_flags ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + return( 0 ); + +} /* End of __cpu_sys_pipe2() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-read.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-read.c new file mode 100644 index 0000000..4816d37 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-read.c @@ -0,0 +1,21 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdint.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + +__mpu_int64_t +__cpu_sys_read( int fd, void *buf, __mpu_uint64_t count ) +{ + ssize_t ret; + + if( count > (__mpu_uint64_t)SIZE_MAX ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + ret = read( fd, buf, (size_t)count ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)ret ); +} diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-readlink.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-readlink.c new file mode 100644 index 0000000..bda2a47 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-readlink.c @@ -0,0 +1,40 @@ +/*************************************************************** + SYS-READLINK.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_readlink(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdint.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_readlink( int dirfd, const char *path, void *buf, + __mpu_uint64_t count ) +{ + ssize_t ret; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + if( count > (__mpu_uint64_t)SIZE_MAX ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + + ret = readlinkat( dirfd, path, (char *)buf, (size_t)count ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)ret ); + +} /* End of __cpu_sys_readlink() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-rename.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-rename.c new file mode 100644 index 0000000..d79b3fb --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-rename.c @@ -0,0 +1,34 @@ +/*************************************************************** + SYS-RENAME.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_rename(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdio.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_rename( int dirfd, const char *oldpath, const char *newpath ) +{ + if( !oldpath || !newpath ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( renameat( dirfd, oldpath, dirfd, newpath ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_rename() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-rmdir.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-rmdir.c new file mode 100644 index 0000000..41ee0c2 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-rmdir.c @@ -0,0 +1,35 @@ +/*************************************************************** + SYS-RMDIR.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_rmdir(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_rmdir( int dirfd, const char *path ) +{ + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( unlinkat( dirfd, path, AT_REMOVEDIR ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_rmdir() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-select.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-select.c new file mode 100644 index 0000000..a87d138 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-select.c @@ -0,0 +1,109 @@ +/*************************************************************** + SYS-SELECT.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_select(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <poll.h> +#include <signal.h> +#include <stdlib.h> +#include <time.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_select( struct __cpu_select_entry *entries, __mpu_uint64_t count, + const struct __cpu_timeval *timeout ) +{ + struct pollfd *pfds = (struct pollfd *)0; + struct timespec ts; + struct timespec *pts = (struct timespec *)0; + __mpu_uint64_t i; + time_t sec; + int ret; + + if( count && !entries ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + if( count > (__mpu_uint64_t)(size_t)-1 / sizeof( *pfds ) ) + return( -(__mpu_int64_t)__MCPU_EINVAL ); + + if( timeout ) + { + if( timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999 ) + return( -(__mpu_int64_t)__MCPU_EINVAL ); + + sec = (time_t)timeout->tv_sec; + if( (__mpu_int64_t)sec != timeout->tv_sec ) + return( -(__mpu_int64_t)__MCPU_EOVERFLOW ); + + ts.tv_sec = sec; + ts.tv_nsec = (long)( timeout->tv_usec * 1000 ); + pts = &ts; + } + + if( count ) + { + pfds = (struct pollfd *)calloc( (size_t)count, sizeof( *pfds ) ); + if( !pfds ) return( -(__mpu_int64_t)__MCPU_ENOMEM ); + } + + for( i = 0; i < count; ++i ) + { + pfds[i].fd = entries[i].host_fd; + pfds[i].events = 0; + pfds[i].revents = 0; + entries[i].revents = 0; + + if( entries[i].events & __CPU_SELECT_READ ) pfds[i].events |= POLLIN; + if( entries[i].events & __CPU_SELECT_WRITE ) pfds[i].events |= POLLOUT; + if( entries[i].events & __CPU_SELECT_EXCEPT ) pfds[i].events |= POLLPRI; + } + + ret = ppoll( pfds, (nfds_t)count, pts, (const sigset_t *)0 ); + if( ret < 0 ) + { + ret = -(__mpu_int64_t)__cpu_errno_from_host( errno ); + free( pfds ); + return( (__mpu_int64_t)ret ); + } + + for( i = 0; i < count; ++i ) + { + short revents = pfds[i].revents; + + if( revents & POLLNVAL ) + { + free( pfds ); + return( -(__mpu_int64_t)__MCPU_EBADF ); + } + + if( ( entries[i].events & __CPU_SELECT_READ ) && + ( revents & ( POLLIN | POLLHUP | POLLERR ) ) ) + entries[i].revents |= __CPU_SELECT_READ; + + if( ( entries[i].events & __CPU_SELECT_WRITE ) && + ( revents & ( POLLOUT | POLLERR ) ) ) + entries[i].revents |= __CPU_SELECT_WRITE; + + if( ( entries[i].events & __CPU_SELECT_EXCEPT ) && ( revents & POLLPRI ) ) + entries[i].revents |= __CPU_SELECT_EXCEPT; + } + + free( pfds ); + return( 0 ); + +} /* End of __cpu_sys_select() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-stat.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-stat.c new file mode 100644 index 0000000..bb3a154 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-stat.c @@ -0,0 +1,42 @@ +/*************************************************************** + SYS-STAT.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_stat(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/stat.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> +#include "cpu-stat-linux.h" + + +__mpu_int64_t +__cpu_sys_stat( int dirfd, const char *path, struct __cpu_stat *st ) +{ + struct stat host_st; + int error; + + if( !path || !st ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( fstatat( dirfd, path, &host_st, 0 ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + error = __cpu_stat_from_host( st, &host_st ); + if( error ) return( -(__mpu_int64_t)error ); + + return( 0 ); + +} /* End of __cpu_sys_stat() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-symlink.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-symlink.c new file mode 100644 index 0000000..276a277 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-symlink.c @@ -0,0 +1,34 @@ +/*************************************************************** + SYS-SYMLINK.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_symlink(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_symlink( int dirfd, const char *target, const char *linkpath ) +{ + if( !target || !linkpath ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( symlinkat( target, dirfd, linkpath ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_symlink() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-truncate.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-truncate.c new file mode 100644 index 0000000..4a34b44 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-truncate.c @@ -0,0 +1,58 @@ +/*************************************************************** + SYS-TRUNCATE.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_truncate(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_truncate( int dirfd, const char *path, __mpu_int64_t length ) +{ + off_t host_length; + + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + host_length = (off_t)length; + if( (__mpu_int64_t)host_length != length ) + return( -(__mpu_int64_t)__MCPU_EOVERFLOW ); + + { + int fd; + int error; + + fd = openat( dirfd, path, O_WRONLY | O_CLOEXEC ); + if( fd < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + + if( ftruncate( fd, host_length ) < 0 ) + { + error = errno; + (void)close( fd ); + return( -(__mpu_int64_t)__cpu_errno_from_host( error ) ); + } + + (void)close( fd ); + } + + return( 0 ); + +} /* End of __cpu_sys_truncate() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-unlink.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-unlink.c new file mode 100644 index 0000000..155dc79 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-unlink.c @@ -0,0 +1,34 @@ +/*************************************************************** + SYS-UNLINK.C + + This file contains Linux/x86_64/LP64 implementation of + __cpu_sys_unlink(). + + PART OF : CPU - library . + + USAGE : Internal only . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + + +__mpu_int64_t +__cpu_sys_unlink( int dirfd, const char *path ) +{ + if( !path ) return( -(__mpu_int64_t)__MCPU_EFAULT ); + + if( unlinkat( dirfd, path, 0 ) < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( 0 ); + +} /* End of __cpu_sys_unlink() */ diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-write.c b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-write.c new file mode 100644 index 0000000..e5398c7 --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/64/sys-write.c @@ -0,0 +1,21 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdint.h> +#include <unistd.h> + +#include <libmcpu.h> +#include <cpu-sysdeps.h> + +__mpu_int64_t +__cpu_sys_write( int fd, const void *buf, __mpu_uint64_t count ) +{ + ssize_t ret; + + if( count > (__mpu_uint64_t)SIZE_MAX ) return( -(__mpu_int64_t)__MCPU_EINVAL ); + ret = write( fd, buf, (size_t)count ); + if( ret < 0 ) return( -(__mpu_int64_t)__cpu_errno_from_host( errno ) ); + return( (__mpu_int64_t)ret ); +} diff --git a/cpu/sysdeps/unix/sysv/linux/x86_64/x32/README b/cpu/sysdeps/unix/sysv/linux/x86_64/x32/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/unix/sysv/linux/x86_64/x32/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/x86_64/64/README b/cpu/sysdeps/x86_64/64/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/x86_64/64/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. diff --git a/cpu/sysdeps/x86_64/configure-fragment b/cpu/sysdeps/x86_64/configure-fragment new file mode 100755 index 0000000..a64629c --- /dev/null +++ b/cpu/sysdeps/x86_64/configure-fragment @@ -0,0 +1,8 @@ +#!/bin/sh + +# Regenerate this directory's sourced preconfigure fragment from preconfigure.ac. +# Run from the architecture sysdeps directory. +autoconf -Wno-syntax -I ../../.. -o preconfigure preconfigure.ac || exit 1 +chmod a-x preconfigure +rm -f preconfigure~ +rm -rf autom4te.cache diff --git a/cpu/sysdeps/x86_64/preconfigure b/cpu/sysdeps/x86_64/preconfigure new file mode 100644 index 0000000..9abbeec --- /dev/null +++ b/cpu/sysdeps/x86_64/preconfigure @@ -0,0 +1,79 @@ +# This file is generated from preconfigure.ac by Autoconf. DO NOT EDIT! + +# Local preconfigure fragment for cpu/sysdeps/x86_64. + +test -n "$base_machine" || case "$machine" in +x86_64) + base_machine=x86_64 + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC uses the x86_64 x32 data model by default" >&5 +printf %s "checking whether $CC uses the x86_64 x32 data model by default... " >&6; } +if test ${mcpu_cv_x86_64_x32+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifndef __ILP32__ +# error not x32 +#endif +int main( void ) { return 0; } + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + mcpu_cv_x86_64_x32=yes +else case e in #( + e) mcpu_cv_x86_64_x32=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $mcpu_cv_x86_64_x32" >&5 +printf "%s\n" "$mcpu_cv_x86_64_x32" >&6; } + + if test "$mcpu_cv_x86_64_x32" = yes; then + machine=x86_64/x32 + MCPU_HOST_DATA_MODEL=ILP32 + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC uses the x86_64 LP64 data model" >&5 +printf %s "checking whether $CC uses the x86_64 LP64 data model... " >&6; } +if test ${mcpu_cv_x86_64_lp64+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +typedef char mcpu_int_must_be_4[(sizeof(int) == 4) ? 1 : -1]; +typedef char mcpu_long_must_be_8[(sizeof(long) == 8) ? 1 : -1]; +typedef char mcpu_ptr_must_be_8[(sizeof(void *) == 8) ? 1 : -1]; +int main( void ) { return 0; } + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + mcpu_cv_x86_64_lp64=yes +else case e in #( + e) mcpu_cv_x86_64_lp64=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $mcpu_cv_x86_64_lp64" >&5 +printf "%s\n" "$mcpu_cv_x86_64_lp64" >&6; } + if test "$mcpu_cv_x86_64_lp64" != yes; then + as_fn_error $? "Not supported HOST $host: unsupported x86_64 data model" "$LINENO" 5 + fi + machine=x86_64/64 + MCPU_HOST_DATA_MODEL=LP64 + fi + ;; +esac + diff --git a/cpu/sysdeps/x86_64/preconfigure.ac b/cpu/sysdeps/x86_64/preconfigure.ac new file mode 100644 index 0000000..7679c59 --- /dev/null +++ b/cpu/sysdeps/x86_64/preconfigure.ac @@ -0,0 +1,39 @@ +dnl See acsite.m4 in the top-level source directory. +MCPU_PROVIDES +# Local preconfigure fragment for cpu/sysdeps/x86_64. + +test -n "$base_machine" || case "$machine" in +x86_64) + base_machine=x86_64 + + AC_CACHE_CHECK([whether $CC uses the x86_64 x32 data model by default], + [mcpu_cv_x86_64_x32], [dnl + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +#ifndef __ILP32__ +# error not x32 +#endif +int main( void ) { return 0; } + ]])], [mcpu_cv_x86_64_x32=yes], [mcpu_cv_x86_64_x32=no]) + ]) + + if test "$mcpu_cv_x86_64_x32" = yes; then + machine=x86_64/x32 + MCPU_HOST_DATA_MODEL=ILP32 + else + AC_CACHE_CHECK([whether $CC uses the x86_64 LP64 data model], + [mcpu_cv_x86_64_lp64], [dnl + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +typedef char mcpu_int_must_be_4[(sizeof(int) == 4) ? 1 : -1]; +typedef char mcpu_long_must_be_8[(sizeof(long) == 8) ? 1 : -1]; +typedef char mcpu_ptr_must_be_8[(sizeof(void *) == 8) ? 1 : -1]; +int main( void ) { return 0; } + ]])], [mcpu_cv_x86_64_lp64=yes], [mcpu_cv_x86_64_lp64=no]) + ]) + if test "$mcpu_cv_x86_64_lp64" != yes; then + AC_MSG_ERROR([Not supported HOST $host: unsupported x86_64 data model]) + fi + machine=x86_64/64 + MCPU_HOST_DATA_MODEL=LP64 + fi + ;; +esac diff --git a/cpu/sysdeps/x86_64/x32/README b/cpu/sysdeps/x86_64/x32/README new file mode 100644 index 0000000..f00b0cb --- /dev/null +++ b/cpu/sysdeps/x86_64/x32/README @@ -0,0 +1,2 @@ +This directory is part of the LibMCPU HOST sysdeps inheritance tree. +HOST-dependent syscall wrappers will be added here in later releases. |
