├── Makefile ├── README.md ├── Start_RISC_OS.desktop ├── Unix ├── LinuxSupport │ ├── Finish │ ├── Start_RISC_OS.desktop │ ├── amu_id.mk │ ├── arm_test │ ├── comma2attr.c │ ├── common.mk │ ├── download.sh │ ├── gen_seccomp.c │ ├── lib.sh │ ├── qemu_swi.diff │ ├── rpcemu.cfg │ ├── rpcemu.diff │ ├── run_RISC_OS │ ├── source │ ├── test_runner_linux.sh │ ├── test_runner_rpcemu.sh │ ├── wait_stdin.c │ └── wrapper.c ├── RISCOS.IMG └── SocketKVMFrontends │ ├── Keyboard.h │ ├── Makefile,fe1 │ ├── SocketKVM_Protocol.h │ ├── build.mk │ ├── frontend_common.h │ ├── identify_abi.c │ ├── opengl.cpp │ ├── sdl.cpp │ └── sdlkey.c └── run_RISC_OS /Makefile: -------------------------------------------------------------------------------- 1 | Unix/LinuxSupport/common.mk -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux port of RISC OS 2 | 3 | It is currently being discussed on the [RISC OS Open website](https://www.riscosopen.org/forum/forums/3/topics/9068). There is no sound support at present, and is incomplete in other ways. You should not reguard any new APIs to be stable. 4 | 5 | It should run on a 32-bit capable ARM Linux system natively, or slow on other Linux systems with the aid of a slightly [modified](mixed/Linux/Support/qemu_swi.diff) QEMU. Unfortunately server class ARM hardware is typically 64-bit only. 6 | 7 | The RISC OS "ROM" Image is a Linux executable. 8 | 9 | If you run RISC OS directly then, unlike virtual machines such as RPCEmu, there is **no restriction on what RISC OS programs can do to the Linux environment** beyond that provided by Linux. If you use the provided scripts then RISC OS should be prevented from causing harm. 10 | 11 | You can disable the secure sandbox by seting the environment variable `RISC_OS__INSECURE` to `YES` when running `run_RISC_OS`, for example: 12 | 13 | ``` 14 | RISC_OS__INSECURE=YES ./run_RISC_OS 15 | ``` 16 | 17 | RISC OS Open Limited’s DDE is required to build RISC OS, this is proprietary software that may be brought from [RISC OS Open Limited](https://www.riscosopen.org/content/sales/dde) 18 | 19 | ## Compiling on RISC OS 20 | 21 | This Linux port of RISC OS can be built in similar fashion to the traditional method as documented on the RISC OS website, it is not necessary to run InstallTools as the relevant files will be accessed from the DDE without copying. However this will not build the SDL front-end which connects RISC OS to the Linux graphics system, without it RISC OS is limited to a text only interface. 22 | 23 | ## Compiling on Linux 24 | 25 | It can also be built on Linux using the Makefiles, which runs the majority of the build on RISC OS, by default using a binary of the Linux port that is automatically downloaded from [github](https://github.com/TimothyEBaldwin/RO_Linux) and RISC OS Open Limited’s DDE in ../DDE. Bash, Bubblewrap, GCC, GNU Make, Libattr, Libseccomp and SDL 2 are also required by Makefiles and support code. Either Bubblewrap must be setuid root, or unprivileged user namespaces must be enabled, or insecure mode enabled. 26 | 27 | On Debian and Ubuntu the dependencies are in the packages "bash bubblewrap gcc g++ make libattr1-dev libseccomp-dev libsdl2-dev", on Fedora the dependencies are in the packages "bash gcc gcc-c++ glib2-devel libattr-devel libseccomp-devel patch SDL2-devel". 28 | 29 | Additional packages are required for building QEMU. 30 | 31 | The following variables are accepted by the Makefiles: 32 | 33 | | Variable | | 34 | | --- | --- | 35 | | ACORN_CPP | Path to AcornC.C++ diectory of DDE, default is `../DDE/AcornC.C++` 36 | | TARGET | What to build, such as `IOMD32` for a RiscPC/A7000 ROM image. Only `Linux` and `IOMD32` are supported by this source. | 37 | | METHOD | How to build, valid values are `rpcemu` and `Linux`. | 38 | | JOBS | Number of CPUs to use for building, if 0 or unset build sequentially. | 39 | | LINUX_ROM | Location of Linux RISC OS executable to use for building. | 40 | | QEMU | Location of qemu-arm executable. | 41 | | PHASES | Space separated list of build phases to run. | 42 | | INSECURE | Set to YES to enable insecure mode. | 43 | | VERBOSE | Set to 1 to make build more verbose. | 44 | 45 | The following targets are provided by the Makefiles: 46 | 47 | | Target | Action | 48 | | --- | --- | 49 | | build | Build RISC OS (or some other thing). | 50 | | check | Build and test RISC OS. | 51 | | fast | Runs only rom_install and join phases and tests. | 52 | 53 | This following items will be download to ~/Downloads if needed: 54 | * RISC OS 5.24 Disc Archive 55 | * RISC OS 5.24 IOMD ROM Image 56 | * RPCEmu 0.8.15 57 | * QEMU 5.0.0 58 | 59 | ## IXFS 60 | 61 | ### File type handling 62 | 63 | Unlike other software IXFS by default stores RISC OS file types in POSIX extended attributes, by default only writing extensions if writing a POSIX extended attribute fails. How IXFS handles file types can be configured using the special field. 64 | 65 | | Special Field | Mode Name | Write extension | Read and strip extension | Read extended attribute | 66 | | :---: | --- | --- | --- | --- | 67 | | R | Raw | Never | No | Yes | 68 | | P | Pure | Remove if wrong | Yes | Only if no extension | 69 | | | Normal | If needed | Yes | Only if no extension | 70 | | W | Write | Always | Yes | Only if no extension | 71 | | X | Exclusive | Always | Yes | Never | 72 | 73 | ### Case sensitivity 74 | 75 | As is standard for RISC OS filing systems IXFS is case insensitive by default, if 2 filenames only differ by case it is unpredictable which file is acted upon unless the exact filename is provided to IXFS. Case sensitivity may be enabled by adding "C" to the special field. 76 | 77 | ## Linux RISC OS command line options 78 | 79 | | Option | Action | 80 | | --- | --- | 81 | | --abort-on-input | Abort on debug terminal input | 82 | | --help | Display help message | 83 | | --highmem | Allow use of virtual memory addresses above 2GB | 84 | | --isreboot | Indicate hard reset to RISC OS (not power on) | 85 | | --nvram FILE | Filename for nvram | 86 | | --noaborts | Disable aborts - RISC OS will die with SIGSEGV | 87 | | --noseccomp | Disable seccomp support | 88 | | --notimers | Disable HAL timers | 89 | 90 | ## Linux RISC OS error codes 91 | 92 | | Return Code | Error | 93 | | --- | --- | 94 | | 100 | Reboot requested | 95 | | 101 | Memory mapping failed, try running "sudo sysctl vm.mmap_min_addr=8192" | 96 | | 102 | Unrecognised command line option | 97 | | 103 | Unable to open NVRAM file. | 98 | | 104 | Permission denied when attempting to open NVRAM file. | 99 | | 106 | Unable to read size of NVRAM file. | 100 | | 107 | Unable to enlarge NVRAM file. | 101 | | 108 | Failed to reserve address space, try running "sudo sysctl vm.mmap_min_addr=12288." | 102 | | 109 | Unable to fork | 103 | | 110 | Parent process exited (no message) | 104 | | 111 | Cloning ptrace thread failed | 105 | | 112 | Failed to set alternative signal stack. | 106 | | 113 | SWI intercept failure | 107 | | 114 | RISC OS kernel returned to HAL | 108 | | 115 | Interrupt test failed | 109 | | 116 | Exec failed | 110 | | 117 | HAL_DebugRX called and --abort-on-input given. | 111 | | 118 | Failed to reserve address space for system heap. | 112 | | 119 | Problem starting fork server thread. | 113 | 114 | 115 | ## To do List 116 | 117 | - [x] Complete the key map. 118 | - [x] Fix the realtime clock. 119 | - [x] Make data aborts raise errors. 120 | - [x] Support writing timestamps in IXFS. 121 | - [x] Support reading timestamps in IXFS to centisecond resolution. 122 | - [x] Test timestamps. 123 | - [x] Add sound modules. 124 | - [ ] Add sound output. 125 | - [x] Officially allocate names and SWI numbers etc. 126 | - [x] Fix failure to truncate of unbuffered files when opened for output, and associated race condition. 127 | - [x] Fix spurious calls of FSEntry_Args 6 (flush file to disc) when files are closed. 128 | - [ ] Perform proper error handling in IXFS. 129 | - [x] Split video keyboard and mouse driver into separate module. 130 | - [ ] Detect screen updates to avoid copying full screen 20 times a second. 131 | - [ ] Finish video keyboard and mouse driver. 132 | - [ ] Fix overwriting of ROM image when rebuilding RISC OS, which will cause a crash if the overwritten ROM image is currently being run. 133 | - [ ] Provide a means to run Linux programs. 134 | - [ ] Implement PMP dynamic areas. 135 | - [x] Replace the changes that are labeled "Hack" 136 | - [x] Replace the branch table at the beginning of the HAL. 137 | - [ ] Write test cases for VFP errors. 138 | - [ ] Implement VFPSupport. 139 | - [ ] Possibly add a binary release to the ABRelase phase. 140 | -------------------------------------------------------------------------------- /Start_RISC_OS.desktop: -------------------------------------------------------------------------------- 1 | Unix/LinuxSupport/Start_RISC_OS.desktop -------------------------------------------------------------------------------- /Unix/LinuxSupport/Finish: -------------------------------------------------------------------------------- 1 | REM Copyright (c) 2013, Timothy Baldwin 2 | REM 3 | REM Licensed under the Apache License, Version 2.0 (the "License"); 4 | REM you may not use this file except in compliance with the License. 5 | REM You may obtain a copy of the License at 6 | REM 7 | REM http://www.apache.org/licenses/LICENSE-2.0 8 | REM 9 | REM Unless required by applicable law or agreed to in writing, software 10 | REM distributed under the License is distributed on an "AS IS" BASIS, 11 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | REM See the License for the specific language governing permissions and 13 | REM limitations under the License. 14 | 15 | DIM buffer% 100 16 | SYS "OS_ReadVarVal","Sys$ReturnCode",buffer%,100,0,3 TO ,R$ 17 | R% = VAL(R$) 18 | PRINT 19 | 20 | *Shutdown 21 | SYS "XOS_SWINumberFromString",,"IXSupport_LinuxSyscall" TO LinuxSyscall%; V% 22 | IF V% AND 1 THEN LinuxSyscall%=&59EC0 ELSE VDU 7 23 | SYS LinuxSyscall%,R%,,,,,,,248 24 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/Start_RISC_OS.desktop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env xdg-open 2 | # Copyright 2018 Timothy Baldwin 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | [Desktop Entry] 18 | Type=Application 19 | Name=RISC OS (Linux Port) 20 | Comment=The port of RISC OS to Linux. 21 | Exec=sh -e -c "cd \\"\\$(dirname \\"\\$0\\")\\"; RISC_OS__OpenTerm=1 exec Unix/LinuxSupport/run_RISC_OS >/dev/null" %k 22 | Actions=normal;noboot;gos;basic; 23 | 24 | [Desktop Action normal] 25 | Name=Start Normally 26 | Exec=sh -e -c "cd \\"\\$(dirname \\"\\$0\\")\\"; RISC_OS__OpenTerm=1 exec Unix/LinuxSupport/run_RISC_OS >/dev/null" %k 27 | 28 | [Desktop Action noboot] 29 | Name=Start without !Boot 30 | Exec=bash -e -c "cd \\"\\$(dirname \\"\\$0\\")\\"; RISC_OS__OpenTerm=1 RISC_OS_Alias_IXFSBoot2=\\$'X AddTinyDir IXFS:\\$\\\\nX AddTinyDir ' RISC_OS_Alias_IXFSBoot='Desktop IXFSBoot2' exec Unix/LinuxSupport/run_RISC_OS >/dev/null" %k 31 | 32 | [Desktop Action gos] 33 | Name=Command line 34 | Exec=sh -e -c "cd \\"\\$(dirname \\"\\$0\\")\\"; RISC_OS__OpenTerm=1 RISC_OS_Alias_IXFSBoot=GOS exec Unix/LinuxSupport/run_RISC_OS >/dev/null" %k 35 | 36 | [Desktop Action basic] 37 | Name=BASIC 38 | Exec=sh -e -c "cd \\"\\$(dirname \\"\\$0\\")\\"; RISC_OS__OpenTerm=1 RISC_OS_Alias_IXFSBoot=BASIC exec Unix/LinuxSupport/run_RISC_OS >/dev/null" %k 39 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/amu_id.mk: -------------------------------------------------------------------------------- 1 | id: 2 | Save RAM:amu_id 8100 +4000 3 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/arm_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimothyEBaldwin/RISC_OS_Linux_Binary/aba24d022f3bfa40873d5fa4a74602987bdf94da/Unix/LinuxSupport/arm_test -------------------------------------------------------------------------------- /Unix/LinuxSupport/comma2attr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define _GNU_SOURCE 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifndef RENAME_NOREPLACE 39 | #define RENAME_NOREPLACE (1 << 0) 40 | #endif 41 | 42 | struct ro_attr { 43 | unsigned load, exec, attributes; 44 | }; 45 | 46 | static char dest[PATH_MAX]; 47 | static char path[PATH_MAX * 100]; 48 | static int return_code = 0; 49 | static bool strip = false; 50 | static bool attribute_priority = false; 51 | static bool write_suffix = false; 52 | static bool recurse = false; 53 | static bool write_symlink = false; 54 | 55 | static inline bool is_suffix(const char *end) { 56 | if (end[-4] != ',') return false; 57 | for (int i = -1; i != -4; --i) { 58 | char c = end[i]; 59 | if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false; 60 | } 61 | return true; 62 | } 63 | 64 | static void process(int dirfd, const char *source, char *path_end) { 65 | int r; 66 | 67 | for(const char *i = source; *i && path_end < path + sizeof(path) - 2; ++i) { 68 | char c = *i; 69 | if (c == 127 || c < 32) c = '?'; 70 | *path_end++ = c; 71 | } 72 | *path_end = 0; 73 | 74 | struct stat s; 75 | r = fstatat(dirfd, source, &s, 0); 76 | if (r) { 77 | fprintf(stderr, "Unable to read object metadata: %s: %s\n", path, strerror(errno)); 78 | return_code |= 2; 79 | return; 80 | } 81 | 82 | if (recurse && S_ISDIR(s.st_mode)) { 83 | int fd = openat(dirfd, source, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 84 | if (fd >= 0) { 85 | DIR *dir = fdopendir(fd); 86 | struct dirent *e; 87 | *path_end = '/'; 88 | while(errno= 0, e = readdir(dir)) { 89 | if (e->d_name[0] != '.' || (e->d_name[1] && (e->d_name[1] != '.' || e->d_name[2]))) { 90 | process(fd, e->d_name, path_end + 1); 91 | } 92 | } 93 | *path_end = 0; 94 | if (errno) { 95 | fprintf(stderr, "Unable to read directory entry from %s: %s\n", path, strerror(errno)); 96 | } 97 | closedir(dir); 98 | } else if (errno != ENOTDIR) { 99 | fprintf(stderr, "Unable to open directory %s: %s\n", path, strerror(errno)); 100 | return_code |= 64; 101 | } 102 | } 103 | 104 | fchdir(dirfd); 105 | 106 | if (strlen(source) > sizeof(dest)) { 107 | fprintf(stderr, "Name too long: %s\n", path); 108 | return_code |= 1; 109 | return; 110 | } 111 | 112 | char *end = stpcpy(dest, source); 113 | struct ro_attr attr = {}; 114 | unsigned filetype = 0xFFFFFFFF; 115 | unsigned attr_filetype = 0xFFFFFFFF; 116 | unsigned suffix_filetype = 0xFFFFFFFF; 117 | 118 | int attr_len = getxattr(source, "user.RISC_OS.LoadExec", &attr, sizeof(attr)); 119 | if (attr_len < 0 && errno != ENOATTR) { 120 | fprintf(stderr, "Unable to read attribute from %s: %s\n", path, strerror(errno)); 121 | return_code |= 4; 122 | return; 123 | } 124 | 125 | if (attr_len >= 8 && (attr.load & htole32(0xFFF00000)) == htole32(0xFFF00000)) { 126 | filetype = attr_filetype = (le32toh(attr.load) >> 8) & 0xFFF; 127 | } 128 | 129 | bool suffixed = is_suffix(end); 130 | 131 | if (suffixed) { 132 | suffix_filetype = strtoul(end - 3, 0, 16); 133 | if (!attribute_priority || filetype == 0xFFFFFFFF) filetype = suffix_filetype; 134 | } 135 | 136 | if (filetype <= 0xFFF && filetype != attr_filetype) { 137 | uint64_t time = ((uint64_t)s.st_mtime + 25567ULL * 24 * 3600) * 100 + s.st_mtim.tv_nsec / 10000000; 138 | attr.load = htole32(0xFFF00000U | (time >> 32) | (filetype << 8)); 139 | attr.exec = htole32((uint32_t)(time)); 140 | if (attr_len < 8) attr_len = 8; 141 | r = lsetxattr(source, "user.RISC_OS.LoadExec", &attr, attr_len, 0); 142 | 143 | if (r) { 144 | if (errno != EPERM) { 145 | fprintf(stderr, "Unable to set attribute on %s: %s\n", path, strerror(errno)); 146 | return_code |= 32; 147 | } 148 | if (filetype != attr_filetype && strip) { 149 | return_code |= 8; 150 | return; 151 | } 152 | } 153 | } 154 | 155 | if (write_suffix && filetype <= 0xFFF) { 156 | if (suffixed) end -= 4; 157 | if (!S_ISDIR(s.st_mode) && ((filetype != 0xFFF && filetype != 0xFE6) || filetype == suffix_filetype)) { 158 | end += sprintf(end, ",%03x" , filetype); 159 | } 160 | } else if ((strip || suffix_filetype != filetype ) && suffixed) { 161 | end -= 4; 162 | } 163 | 164 | *end = 0; 165 | if (strcmp(source, dest)) { 166 | #ifdef SYS_renameat2 167 | r = syscall(SYS_renameat2, AT_FDCWD, source, AT_FDCWD, dest, RENAME_NOREPLACE); 168 | if (r && errno == ENOSYS) 169 | #endif 170 | { 171 | if (!stat(dest, &s)) errno = EEXIST; 172 | if (errno != ENOENT) r = rename(source, dest); 173 | } 174 | if (r) { 175 | fprintf(stderr, "Unable to rename %s to %s: %s\n", path, dest, strerror(errno)); 176 | return_code |= 16; 177 | return; 178 | } 179 | } 180 | 181 | } 182 | 183 | int main(int argc, char **argv) { 184 | int opt; 185 | 186 | static const struct option opts[] = { 187 | {"attribute-priority", no_argument, NULL, 'a'}, 188 | {"suffix-priority", no_argument, NULL, 'p'}, 189 | {"recurse", no_argument, NULL, 'r'}, 190 | {"write-suffix", no_argument, NULL, 'w'}, 191 | {"write-attribute-via-symlink", no_argument, NULL, 'l'}, 192 | {"strip", no_argument, NULL, 's'}, 193 | {NULL, 0, NULL, 0} 194 | }; 195 | 196 | while ((opt = getopt_long(argc, argv, "aprws", opts, NULL)) != -1) { 197 | switch (opt) { 198 | case 'a': 199 | attribute_priority = true; 200 | break; 201 | case 'p': 202 | attribute_priority = false; 203 | break; 204 | case 'r': 205 | recurse = true; 206 | break; 207 | case 'w': 208 | write_suffix = true; 209 | break; 210 | case 's': 211 | strip = true; 212 | break; 213 | case 'l': 214 | write_symlink = true; 215 | break; 216 | default: 217 | fprintf(stderr, "usage\n"); 218 | return 1; 219 | } 220 | } 221 | 222 | int dirfd = open(".", O_RDONLY); 223 | if (dirfd < 0) { 224 | fprintf(stderr, "Unable to open CSD: %s\n", strerror(errno)); 225 | return 1; 226 | } 227 | 228 | while(optind != argc) process(dirfd, argv[optind++], path); 229 | return return_code; 230 | } 231 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/common.mk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # 3 | # Copyright (c) 2013-2019, Timothy Baldwin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | HARDDISC4=$(HOME)/Downloads/HardDisc4.5.28.util 19 | QEMU_SRC=$(HOME)/Downloads/qemu-5.2.0.tar.xz 20 | RPCEMU=$(HOME)/Downloads/rpcemu-0.9.3.tar.gz 21 | IOMD=$(HOME)/Downloads/IOMD-Soft.5.28.zip 22 | 23 | LINUX_ROM=Unix/RISCOS.IMG 24 | VERBOSE= 25 | 26 | # From: https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function 27 | pathsearch = $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH))))) 28 | 29 | QEMU1:=$(call pathsearch,qemu-arm) 30 | BASH:=$(call pathsearch,bash) 31 | BWRAP=bwrap 32 | export BWARP 33 | 34 | SHELL=$(BASH) 35 | JOBS:=$(shell getconf _NPROCESSORS_ONLN) 36 | QEMU:=$(shell . Unix/LinuxSupport/lib.sh; arm_test || kill $$PPID; echo "$$QEMU") 37 | export JOBS 38 | 39 | .SHELLFLAGS:=-e -c $(if $(VERBOSE), -x) 40 | BASHF:=$(BASH) $(.SHELLFLAGS) 41 | .ONESHELL: 42 | .SILENT: 43 | 44 | .SUFFIXES: 45 | .DELETE_ON_ERROR: 46 | .PHONY: all script-all 47 | 48 | all: comma2attr 49 | 50 | robind = $(foreach dir,$(wildcard $(1)),--ro-bind $(dir) $(dir)) 51 | sandbox = $(BWRAP) --die-with-parent --cap-drop ALL --unsetenv TMPDIR --unshare-all --seccomp 9 9< <(Built/gen_seccomp $(1)) --proc /proc --dir /tmp $(call robind,/bin /lib* /usr /etc/alternatives) --dev /dev --tmpfs /usr/local 52 | lib_depends := $(wildcard /etc/alternatives /etc/ld.so.* Unix/LinuxSupport/*.mk) 53 | 54 | include $(wildcard Unix/LinuxSupport/build.mk) 55 | include $(wildcard Unix/SocketKVMFrontends/build.mk) 56 | 57 | SHELL=$(warning Building $@)$(BASH) 58 | 59 | script-all: HardDisc4 Built/wrapper Built/wait_stdin Built/qemu-link 60 | 61 | Built: 62 | ! setfattr -n user.RISC_OS.LoadExec -v 0x00e5ffff00000000 Unix/RISCOS.IMG 63 | mkdir Built 64 | 65 | comma2attr: Built/comma2attr 66 | ln -sf Built/comma2attr comma2attr 67 | 68 | Built/comma2attr: Unix/LinuxSupport/comma2attr.c $(lib_depends) | Built 69 | gcc -std=gnu99 -Wall -g Unix/LinuxSupport/comma2attr.c -o Built/comma2attr 70 | 71 | Built/wait_stdin: Unix/LinuxSupport/wait_stdin.c $(lib_depends) | Built 72 | gcc -std=c99 -Wall -Os Unix/LinuxSupport/wait_stdin.c -o Built/wait_stdin 73 | 74 | Built/wrapper: Unix/LinuxSupport/wrapper.c $(lib_depends) | Built 75 | gcc -std=gnu99 -Wall -Os Unix/LinuxSupport/wrapper.c -o Built/wrapper 76 | 77 | Built/gen_seccomp: Unix/LinuxSupport/gen_seccomp.c $(lib_depends) | Built 78 | gcc -std=c99 -Wall -Os Unix/LinuxSupport/gen_seccomp.c -o Built/gen_seccomp -lseccomp 79 | 80 | Built/seccomp%: Built/gen_seccomp 81 | Built/gen_seccomp $* > $@ 82 | 83 | Built/rpcemu/stamp3: $(RPCEMU) Unix/LinuxSupport/rpcemu.diff | Built/gen_seccomp 84 | set -o pipefail 85 | rm -rf Built/rpcemu* 86 | mkdir -p Built/rpcemu_files 87 | unpack() { 88 | echo "33b89e02e62b5621c625aa6d388d3a357e7ee013e74a00fcf53ef68f31d19605 /rpcemu.tar.gz" | sha256sum -c 89 | tar -zxf /rpcemu.tar.gz 90 | cd rpcemu-0.9.3 91 | patch -p1 < /d 92 | touch stamp3 93 | } 94 | export -f unpack 95 | $(sandbox) --file 8 8<'$(RPCEMU)' /rpcemu.tar.gz --ro-bind Unix/LinuxSupport/rpcemu.diff /d --bind Built/rpcemu_files /r --chdir /r $(BASHF) unpack cmos.ram 115 | touch rpcemu 116 | } 117 | export -f build 118 | $(sandbox) --bind Built/rpcemu /r --chdir /r $(BASHF) build \n' > 'HardDisc4_files/HardDisc4/!Boot/Choices/Boot/Tasks/Pinboard,feb' 174 | mkdir 'HardDisc4_files/HardDisc4/!Boot/Loader' 175 | mv HardDisc4_files/CMOS 'HardDisc4_files/HardDisc4/!Boot/Loader/CMOS' 176 | mv HardDisc4_files/HardDisc4 . 177 | echo Finished extracting HardDisc4 178 | 179 | Built/boot_iomd_rom: $(IOMD) | Built/gen_seccomp 180 | echo 'd1e955ff8e6dce905c455b9135391f3f1879673965fb4949c5f10716b4fe3e3e *$(IOMD)' | sha256sum -c 181 | $(sandbox) --ro-bind '$(IOMD)' /iomd.zip unzip -p iomd.zip "soft/!Boot/Choices/Boot/PreDesk/!!SoftLoad/riscos" > $@ 182 | echo '051bd488965d43dc8d74757ee29fe72927e0f018dfe45e9c88e511496f0ec316 *$@' | sha256sum -c 183 | setfattr -n user.RISC_OS.LoadExec -v 0x00e5ffff00000000 $@ || true 184 | 185 | $(HARDDISC4): 186 | sh Unix/LinuxSupport/download.sh '$(HARDDISC4)' "https://www.riscosopen.org/zipfiles/platform/common/HardDisc4.5.28.util" "64607412d987a3f974217f109128de89e1ec9a6cd3284f52b3cf9c39fa0f6b60" 187 | setfattr -n user.RISC_OS.LoadExec -v 0x00fcffff00000000 $@ || true 188 | 189 | $(IOMD): 190 | sh Unix/LinuxSupport/download.sh '$(IOMD)' "https://www.riscosopen.org/zipfiles/platform/riscpc/IOMD-Soft.5.28.zip" "d1e955ff8e6dce905c455b9135391f3f1879673965fb4949c5f10716b4fe3e3e" 191 | setfattr -n user.RISC_OS.LoadExec -v 0x0091faff00000000 $@ || true 192 | 193 | ${QEMU_SRC}: 194 | sh Unix/LinuxSupport/download.sh '${QEMU_SRC}' "https://download.qemu.org/qemu-5.2.0.tar.xz" "cb18d889b628fbe637672b0326789d9b0e3b8027e0445b936537c78549df17bc" 195 | setfattr -n user.RISC_OS.LoadExec -v 0x00fdffff00000000 $@ || true 196 | 197 | $(RPCEMU): 198 | sh Unix/LinuxSupport/download.sh '$(RPCEMU)' "http://www.marutan.net/rpcemu/cgi/download.php?sFName=0.9.3/rpcemu-0.9.3.tar.gz" "33b89e02e62b5621c625aa6d388d3a357e7ee013e74a00fcf53ef68f31d19605" 199 | setfattr -n user.RISC_OS.LoadExec -v 0x0089ffff00000000 $@ || true 200 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright 2013 Timothy Baldwin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | set -e 19 | 20 | leaf="$(basename "$1")" 21 | 22 | mkdir -p "$(dirname "$1")" 23 | wget --no-check-certificate -c -O "$leaf" "$2" 24 | echo "$3 *$leaf" | sha256sum -c 25 | mv "$leaf" "$1" 26 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/gen_seccomp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define _POSIX_C_SOURCE 2 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | static scmp_filter_ctx ctx; 29 | 30 | static void ban(int syscall, const char* message) { 31 | int rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), syscall, 0); 32 | if (rc) error(1, -rc, "%s", message); 33 | } 34 | 35 | #define BAN(s) ban(SCMP_SYS(s), "Unable to create " #s " rule") 36 | 37 | int main(int argc, char **argv) { 38 | 39 | int opt, rc; 40 | bool allow_symlinks = false; 41 | bool allow_ptrace = false; 42 | 43 | while ((opt = getopt(argc, argv, "+usp")) != -1) switch (opt) { 44 | case 's': 45 | allow_symlinks = true; 46 | break; 47 | case 'p': 48 | allow_ptrace = true; 49 | break; 50 | } 51 | 52 | ctx = seccomp_init(SCMP_ACT_ALLOW); 53 | if (!ctx) error(1, errno, "Unable to create libseccomp context"); 54 | 55 | #ifdef __aarch64__ 56 | rc = seccomp_arch_add(ctx, SCMP_ARCH_ARM); 57 | if (rc) error(0, -rc, "Unable to add ARM to libseccomp context"); 58 | #endif 59 | 60 | // Don't allow inserting into terminal input buffer 61 | rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TIOCSTI)); 62 | if (rc) error(1, -rc, "Unable to create rule to block inserting into terminal input buffer"); 63 | 64 | if (!allow_symlinks) { 65 | BAN(symlink); 66 | BAN(symlinkat); 67 | } 68 | 69 | if (!allow_ptrace) { 70 | BAN(ptrace); 71 | } else { 72 | BAN(seccomp); 73 | rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(prctl), 1, SCMP_A0(SCMP_CMP_EQ, PR_SET_SECCOMP)); 74 | if (rc) error(1, -rc, "Unable to create prctl(PR_SET_SECCOMP...) rule"); 75 | } 76 | 77 | BAN(keyctl); 78 | BAN(request_key); 79 | BAN(add_key); 80 | 81 | rc = seccomp_export_bpf(ctx, STDOUT_FILENO); 82 | if (rc) error(1, -rc, "Unable to export seccomp rules"); 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/lib.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Timothy Baldwin 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | arm_test() { 16 | "${BASH_SOURCE%%lib.sh}arm_test" 17 | ret=$? 18 | case $ret in 19 | 0 ) QEMU=/usr/bin/env ;; 20 | 1 ) echo "This Linux is ancient, EABI system calls don't work!" 1>&2;; 21 | 2 ) echo "Bug in arm_test? - mystery SIGILL" 1>&2;; 22 | 3 ) echo "Can't intercept SWIs, no SECCOMP, no ptrace, QEMU hack raises SIGILL" 1>&2;; 23 | 4 ) echo "Can't intercept SWIs, no SECCOMP, no ptrace, QEMU hack is EABI system call" 1>&2;; 24 | 5 ) echo "Can't intercept SWIs, no SECCOMP, no ptrace, QEMU hack returns ENOSYS" 1>&2;; 25 | 6 ) echo "Systems which implement FPA instructions currently don't work" 1>&2;; 26 | 7 ) echo 'Unable to map low address space, try "sudo sysctl vm.mmap_min_addr=12288"' 1>&2;; 27 | 126 ) 28 | if [[ "$(uname)" != Linux ]]; then 29 | echo "This is the Linux Port of RISC OS, not for some other operating system." 1>&2; 30 | false 31 | elif [[ "$(uname -m)" == arm* ]]; then 32 | echo "Weird or ancient ARM system can't execute ARM ELF executables" 1>&2; 33 | false 34 | else 35 | QEMU="$(command -v qemu-arm)" 36 | "$QEMU" "${BASH_SOURCE%%lib.sh}arm_test" || QEMU=Built/qemu-arm 37 | return 0 38 | fi;; 39 | * ) echo "arm_test has failed with unknown return code $ret" 1>&2;; 40 | esac 41 | return $ret 42 | } 43 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/qemu_swi.diff: -------------------------------------------------------------------------------- 1 | From 3962afcb6fdc10f442f101df290d7425e08710e4 Mon Sep 17 00:00:00 2001 2 | From: Timothy E Baldwin 3 | Date: Thu, 23 Aug 2018 21:47:34 +0100 4 | Subject: [PATCH 1/3] linux-user: SWI Intercept and disable FPA (for RISC OS) 5 | 6 | Signed-off-by: Timothy E Baldwin 7 | --- 8 | linux-user/arm/cpu_loop.c | 19 +++++++++++++++++-- 9 | linux-user/syscall_defs.h | 7 +++++++ 10 | 2 files changed, 24 insertions(+), 2 deletions(-) 11 | 12 | diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c 13 | index 3d272b56ef..51154aa304 100644 14 | --- a/linux-user/arm/cpu_loop.c 15 | +++ b/linux-user/arm/cpu_loop.c 16 | @@ -225,6 +225,10 @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb) 17 | 18 | void cpu_loop(CPUARMState *env) 19 | { 20 | + static bool use_nwfpe = true; 21 | + static abi_ulong sys_base = 0; 22 | + static abi_ulong sys_limit = 0xFFFFFFFF; 23 | + 24 | CPUState *cs = env_cpu(env); 25 | int trapnr; 26 | unsigned int n, insn; 27 | @@ -262,7 +266,7 @@ void cpu_loop(CPUARMState *env) 28 | goto excp_debug; 29 | } 30 | 31 | - rc = EmulateAll(opcode, &ts->fpa, env); 32 | + rc = use_nwfpe && EmulateAll(opcode, &ts->fpa, env); 33 | if (rc == 0) { /* illegal instruction */ 34 | info.si_signo = TARGET_SIGILL; 35 | info.si_errno = 0; 36 | @@ -326,6 +330,12 @@ void cpu_loop(CPUARMState *env) 37 | { 38 | env->eabi = 1; 39 | /* system call */ 40 | + if (env->regs[15] < sys_base || env->regs[15] > sys_limit) { 41 | + info.si_signo = TARGET_SIGSYS; 42 | + info.si_call_addr = env->regs[15]; 43 | + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 44 | + break; 45 | + } 46 | if (env->thumb) { 47 | /* Thumb is always EABI style with syscall number in r7 */ 48 | n = env->regs[7]; 49 | @@ -370,7 +380,12 @@ void cpu_loop(CPUARMState *env) 50 | env->regs[0] = cpu_get_tls(env); 51 | break; 52 | default: 53 | - if (n < 0xf0800) { 54 | + if (n == (0xC0001 ^ ARM_SYSCALL_BASE)) { 55 | + /* RISC OS: Control SWI Intercept and FPA */ 56 | + sys_base = env->regs[0]; 57 | + sys_limit = env->regs[1]; 58 | + use_nwfpe = env->regs[2]; 59 | + } else if (n < 0xf0800) { 60 | /* 61 | * Syscalls 0xf0000..0xf07ff (or 0x9f0000.. 62 | * 0x9f07ff in OABI numbering) are defined 63 | diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h 64 | index cabbfb762d..ab77f9c6e2 100644 65 | --- a/linux-user/syscall_defs.h 66 | +++ b/linux-user/syscall_defs.h 67 | @@ -657,6 +657,13 @@ typedef struct target_siginfo { 68 | int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ 69 | int _fd; 70 | } _sigpoll; 71 | + 72 | + /* SIGSYS */ 73 | + struct { 74 | + abi_ulong _call_addr; /* calling user insn */ 75 | + int _syscall; /* triggering system call number */ 76 | + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ 77 | + } _sigsys; 78 | } _sifields; 79 | } target_siginfo_t; 80 | 81 | -- 82 | 2.32.0 83 | 84 | From ab72f22ab469a5283ceedf3dd8f9b31d60ea2bb2 Mon Sep 17 00:00:00 2001 85 | From: Timothy E Baldwin 86 | Date: Wed, 13 May 2020 18:45:22 +0100 87 | Subject: [PATCH 2/3] linux-user: Unity map most real-time signals. 88 | 89 | This avoids breaking programs in cases if QEMU only maps signal 90 | numbers in some uses, such as unsupported syscalls and native code. 91 | 92 | Signed-off-by: Timothy E Baldwin 93 | --- 94 | linux-user/signal.c | 4 ++-- 95 | 1 file changed, 2 insertions(+), 2 deletions(-) 96 | 97 | diff --git a/linux-user/signal.c b/linux-user/signal.c 98 | index 73de934c65..fcdc89bfb2 100644 99 | --- a/linux-user/signal.c 100 | +++ b/linux-user/signal.c 101 | @@ -511,8 +511,8 @@ static void signal_table_init(void) 102 | * Attempts for configure "missing" signals via sigaction will be 103 | * silently ignored. 104 | */ 105 | - for (host_sig = SIGRTMIN; host_sig <= SIGRTMAX; host_sig++) { 106 | - target_sig = host_sig - SIGRTMIN + TARGET_SIGRTMIN; 107 | + for (host_sig = SIGRTMAX + TARGET_SIGRTMIN - SIGRTMIN, target_sig = TARGET_SIGRTMIN; 108 | + host_sig <= SIGRTMAX; host_sig++, target_sig++) { 109 | if (target_sig <= TARGET_NSIG) { 110 | host_to_target_signal_table[host_sig] = target_sig; 111 | } 112 | -- 113 | 2.32.0 114 | 115 | From d3c413aec1e4d59b1f9a4b7f8e086811d8cb9125 Mon Sep 17 00:00:00 2001 116 | From: Timothy E Baldwin 117 | Date: Mon, 24 Jan 2022 20:55:05 +0000 118 | Subject: [PATCH 3/3] Fix mapping of sparse ELF files 119 | 120 | The virtual address space between ELF segments should be available 121 | for future allocations. 122 | 123 | Also reset mmap_next_start so allocations continue from high addresses 124 | like Linux. 125 | 126 | Signed-off-by: Timothy E Baldwin 127 | --- 128 | linux-user/elfload.c | 18 ++++++++++++------ 129 | 1 file changed, 12 insertions(+), 6 deletions(-) 130 | 131 | diff --git a/linux-user/elfload.c b/linux-user/elfload.c 132 | index 0b02a92602..b3b048889e 100644 133 | --- a/linux-user/elfload.c 134 | +++ b/linux-user/elfload.c 135 | @@ -2697,13 +2697,18 @@ static void load_elf_image(const char *image_name, int image_fd, 136 | * In both cases, we will overwrite pages in this range with mappings 137 | * from the executable. 138 | */ 139 | - load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE, 140 | - MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | 141 | - (ehdr->e_type == ET_EXEC ? MAP_FIXED : 0), 142 | - -1, 0); 143 | - if (load_addr == -1) { 144 | - goto exit_mmap; 145 | + if (ehdr->e_type != ET_EXEC) { 146 | + load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE, 147 | + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 148 | + -1, 0); 149 | + if (load_addr == -1) { 150 | + goto exit_mmap; 151 | + } 152 | + target_munmap(loaddr, hiaddr - loaddr); 153 | + } else { 154 | + load_addr = loaddr; 155 | } 156 | + 157 | load_bias = load_addr - loaddr; 158 | 159 | if (elf_is_fdpic(ehdr)) { 160 | @@ -2853,6 +2858,7 @@ static void load_elf_image(const char *image_name, int image_fd, 161 | load_symbols(ehdr, image_fd, load_bias); 162 | } 163 | 164 | + mmap_next_start = 0; 165 | mmap_unlock(); 166 | 167 | close(image_fd); 168 | -- 169 | 2.32.0 170 | 171 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/rpcemu.cfg: -------------------------------------------------------------------------------- 1 | model = RPCSA 2 | mouse_twobutton = 0 3 | network_type = off 4 | mouse_following = 1 5 | cdrom_type = 0 6 | cdrom_enabled = 1 7 | refresh_rate = 60 8 | stretch_mode = 1 9 | sound_enabled = 0 10 | vram_size = 2 11 | mem_size = 64 12 | ipaddress = 172.31.0.1 13 | cpu_idle = 1 14 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/rpcemu.diff: -------------------------------------------------------------------------------- 1 | diff -ur a/src/arm_common.c b/src/arm_common.c 2 | --- a/src/arm_common.c 2020-05-06 20:19:23.000000000 +0100 3 | +++ b/src/arm_common.c 2021-01-30 11:24:57.899829916 +0000 4 | @@ -40,6 +40,8 @@ 5 | #define SWI_OS_CallASWI 0x6f 6 | #define SWI_OS_CallASWIR12 0x71 7 | 8 | +#define SWI_IXSupport_LinuxSyscall 0x59EC0 9 | + 10 | #define SWI_Portable_ReadFeatures 0x42fc5 11 | #define SWI_Portable_Idle 0x42fc6 12 | 13 | @@ -622,6 +624,10 @@ 14 | mouse_hack_osmouse(); 15 | arm.reg[cpsr] &= ~VFLAG; 16 | 17 | + } else if (swinum == SWI_IXSupport_LinuxSyscall && (arm.reg[7] == 1 || arm.reg[7] == 248)) { 18 | + /* IXSupport_LinuxSyscall exit */ 19 | + exit(arm.reg[0]); 20 | + 21 | } else if (swinum == ARCEM_SWI_HOSTFS) { 22 | ARMul_State state; 23 | 24 | diff -ur a/src/qt5/rpcemu.pro b/src/qt5/rpcemu.pro 25 | --- a/src/qt5/rpcemu.pro 2020-05-06 20:19:23.000000000 +0100 26 | +++ b/src/qt5/rpcemu.pro 2021-01-30 11:29:08.629426401 +0000 27 | @@ -162,22 +162,13 @@ 28 | HEADERS += ../codegen_x86.h 29 | SOURCES += ../codegen_x86.c 30 | } 31 | - 32 | - win32 { 33 | - TARGET = RPCEmu-Recompiler 34 | - } else { 35 | - TARGET = rpcemu-recompiler 36 | - } 37 | } else { 38 | SOURCES += ../arm.c \ 39 | ../codegen_null.c 40 | - win32 { 41 | - TARGET = RPCEmu-Interpreter 42 | - } else { 43 | - TARGET = rpcemu-interpreter 44 | - } 45 | } 46 | 47 | +TARGET = rpcemu 48 | + 49 | # Big endian architectures 50 | # need to find defines for sparc, arm be, mips be 51 | contains(QMAKE_HOST.arch, ppc)|contains(QMAKE_HOST.arch, ppc64) { 52 | diff -r 00a162d7e6cd src/ArmDynarec.c 53 | --- a/src/ArmDynarec.c Wed May 06 20:17:33 2020 +0100 54 | +++ b/src/ArmDynarec.c Sat Jan 30 15:08:40 2021 +0000 55 | @@ -20,8 +20,6 @@ 56 | 57 | #include "rpcemu.h" 58 | 59 | -int blockend; 60 | - 61 | /*Preliminary FPA emulation. This works to an extent - !Draw works with it, !SICK 62 | seems to (FPA Whetstone scores are around 100x without), but !AMPlayer doesn't 63 | work, and GCC stuff tends to crash.*/ 64 | @@ -681,8 +679,6 @@ 65 | opSWI, opSWI, opSWI, opSWI, opSWI, opSWI, opSWI, opSWI //F8 66 | }; 67 | 68 | -int linecyc=0; 69 | - 70 | static inline int 71 | arm_opcode_may_abort(uint32_t opcode) 72 | { 73 | diff -r 00a162d7e6cd src/codegen_amd64.h 74 | --- a/src/codegen_amd64.h Wed May 06 20:17:33 2020 +0100 75 | +++ b/src/codegen_amd64.h Sat Jan 30 15:08:40 2021 +0000 76 | @@ -28,6 +28,8 @@ 77 | extern int codeblocknum[0x8000]; 78 | 79 | extern uint8_t flaglookup[16][16]; 80 | +extern int blockend; 81 | +extern int linecyc; 82 | 83 | #define BLOCKSTART 32 84 | 85 | diff -r 00a162d7e6cd src/codegen_x86.h 86 | --- a/src/codegen_x86.h Wed May 06 20:17:33 2020 +0100 87 | +++ b/src/codegen_x86.h Sat Jan 30 15:08:40 2021 +0000 88 | @@ -28,6 +28,8 @@ 89 | extern int codeblocknum[0x8000]; 90 | 91 | extern uint8_t flaglookup[16][16]; 92 | +extern int blockend; 93 | +extern int linecyc; 94 | 95 | #define BLOCKSTART 16 96 | //uint32_t blocks[1024]; 97 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/run_RISC_OS: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2018, Timothy Baldwin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | set -e 19 | 20 | : ${RISC_OS__OpenTerm:=0} 21 | 22 | term= 23 | choose_term() { 24 | for term in xterm x-terminal-emulator konsole gnome-terminal mate-terminal 25 | do 26 | if command -v $term 2>/dev/null; then 27 | return 0 28 | fi 29 | done 30 | return 1 31 | } 32 | 33 | readonly() { 34 | RISC_OS__BWRAP_EXTRA="$RISC_OS__BWRAP_EXTRA --ro-bind ${1@Q} ${1@Q}" 35 | } 36 | 37 | readwrite() { 38 | RISC_OS__BWRAP_EXTRA="$RISC_OS__BWRAP_EXTRA --bind ${1@Q} ${1@Q}" 39 | } 40 | 41 | init_make_opts() { 42 | make_opts=( -f Unix/LinuxSupport/common.mk script-all ) 43 | if [[ "$RISC_OS__INSECURE" == "YES" ]]; then 44 | make_opts+=( INSECURE=YES ) 45 | else 46 | make_opts+=( Built/seccomp- ) 47 | fi 48 | } 49 | 50 | gui_make_opts() { 51 | eval "gui=( ${RISC_OS__GUI:=Built/sdl} )" 52 | if [[ $gui == Built/sdl || $gui == Built/opengl ]]; then 53 | make_opts+=( "$gui" ) 54 | fi 55 | } 56 | 57 | run_make() { 58 | mkdir -p Built 59 | if [[ $RISC_OS__OpenTerm -gt 0 ]]; then 60 | ( 61 | flock --close Built make -j$(getconf _NPROCESSORS_ONLN) "${make_opts[@]}" || { sleep 3600; false; } 62 | ) 2>&1 | ( 63 | if ! Built/wait_stdin; then 64 | choose_term 65 | ( $term -e bash -c "cat /dev/null >(cat >&2) 80 | fi 81 | 82 | init_make_opts 83 | gui_make_opts 84 | run_make 85 | 86 | if [[ ! -e 'HardDisc4/!Boot/Loader/CMOS' ]]; then ( 87 | shopt -s nullglob 88 | mkdir -p 'HardDisc4/!Boot/Loader' 89 | nvram=('HardDisc4/!Boot/CMOS',??? 'HardDisc4/!Boot/CMOS') 90 | ln "$nvram" 'HardDisc4/!Boot/Loader/CMOS' 91 | ) fi 92 | 93 | : ${RISC_OS_Alias_IXFSBoot:='/.!Boot'} 94 | export RISC_OS_Alias_IXFSBoot 95 | eval "bwrap_extra=($RISC_OS__BWRAP_EXTRA)" 96 | 97 | for i in /usr /sbin /bin /lib* /etc/alternatives /etc/manpath.config; do 98 | if [[ -L "$i" ]]; then 99 | bwrap_extra+=(--symlink "$(readlink "$i")" "$i") 100 | else 101 | bwrap_extra+=(--ro-bind-try "$i" "$i") 102 | fi 103 | done 104 | 105 | if [[ "$RISC_OS__INSECURE" == "YES" ]]; then 106 | RISC_OS_IXFS_HardDisc4='IXFS:$.dev.fd.5.HardDisc4' exec $RISC_OS__GUI Built/wrapper --handle-reboots -- Built/qemu-link Unix/RISCOS.IMG --nvram 'HardDisc4/!Boot/Loader/CMOS' 5<. 107 | else 108 | RISC_OS_IXFS_HardDisc4='IXFS:$.HardDisc4' exec $RISC_OS__GUI Built/wrapper --network --handle-reboots \ 109 | bwrap --seccomp -- --unshare-all --die-with-parent --cap-drop ALL --tmpfs / --proc /proc --dev /dev \ 110 | --ro-bind Built /Built \ 111 | --ro-bind Unix/RISCOS.IMG /RISC_OS \ 112 | --bind HardDisc4 /HardDisc4 \ 113 | "${bwrap_extra[@]}" --chdir /bin \ 114 | --tmpfs /tmp --tmpfs /run \ 115 | --remount-ro / \ 116 | /Built/qemu-link /RISC_OS --nvram '/HardDisc4/!Boot/Loader/CMOS' 117 | fi 118 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/source: -------------------------------------------------------------------------------- 1 | # Source and build GIT commits 2 | SOURCE=385115bccdea8e5d9bf65ed50fa3dcb8aae47f43 3 | BINARY=2853b81a6c69fb9796783bed274457f727101782 4 | 5 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/test_runner_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | export RISC_OS_Test_Dir='IXFS:$.Tests' 6 | export RISC_OS_Test_TmpDir='IXFS:$.tmp' 7 | export RISC_OS_Test_System='Linux' 8 | export RISC_OS_Test_Log='IXFS:$.proc.self.fd.2' 9 | export RISC_OS_Alias_TestLog='Echo %*0 { > }' 10 | export RISC_OS_Test_NetOK=YES 11 | export risc_os="$1" 12 | 13 | # cat is needed here as stdout is reopened, which would reset the pointer of regular files. 14 | exec /dev/null > >(cat) 2>&1 15 | 16 | binds=() 17 | for i in /usr /bin /lib*; do 18 | binds+=(--ro-bind "$i" "$i") 19 | done 20 | 21 | 22 | run() { 23 | timeout --foreground -sKILL 60 \ 24 | bwrap --unshare-all --proc /proc --dev /dev --dir /tmp --seccomp 9 9< <(Built/gen_seccomp $1) \ 25 | --ro-bind "$risc_os" /RISC_OS --ro-bind mixed/Linux/Tests /Tests --die-with-parent --cap-drop ALL \ 26 | --ro-bind Built /Built "${binds[@]}" \ 27 | /Built/qemu-link /RISC_OS "${@:2}" 28 | } 29 | 30 | set -x 31 | 32 | for i in '"-p"' '"" --cswi' '""' 33 | do 34 | 35 | # Various tests that shouldn't cause data aborts 36 | RISC_OS_Alias_IXFSBoot='Obey -v .PreDesk_NoAbort' eval run $i --abort-on-input --noaborts 37 | 38 | # Various tests that require data aborts 39 | RISC_OS_Alias_IXFSBoot='Obey -v .PreDesk_Aborts' eval run $i 40 | 41 | done 42 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/test_runner_rpcemu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | binds=() 4 | shopt -s nullglob 5 | for i in /bin /lib* /usr /etc/machine-id /var/lib/dbus/machine-id ; do 6 | binds+=(--ro-bind "$i" "$i") 7 | done 8 | shopt -u nullglob 9 | 10 | rpc_test() { 11 | cd /r 12 | timeout --foreground -sKILL 60 /r/rpcemu 13 | E=$? 14 | tr -d '\r' < /r/hostfs/tmp/log* 15 | exit $E 16 | } 17 | export -f rpc_test 18 | 19 | exec ${BWRAP:=bwrap} --unshare-pid --unshare-net "${binds[@]}" \ 20 | --ro-bind /tmp/.X11-unix /tmp/.X11-unix \ 21 | --proc /proc \ 22 | --ro-bind Built/rpcemu /r \ 23 | --tmpfs /r/hostfs \ 24 | --dev-bind /dev/null /r/hd4.hdf \ 25 | --ro-bind "$1" /r/roms/ROM \ 26 | --ro-bind mixed/Linux/Tests /r/hostfs/Tests \ 27 | --dir /r/hostfs/tmp \ 28 | --symlink 'Tests/!Boot,feb' '/r/hostfs/!Boot,feb' \ 29 | bash -c rpc_test 30 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/wait_stdin.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) { 4 | struct pollfd p = {0, POLLIN, 0}; 5 | poll(&p, 1, 2000); 6 | return !(p.revents & POLLHUP) || !!(p.revents & POLLIN); 7 | } 8 | -------------------------------------------------------------------------------- /Unix/LinuxSupport/wrapper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define _GNU_SOURCE 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | struct termios newTioIn; 35 | 36 | struct terminal { 37 | struct termios tio; 38 | bool is_term; 39 | } terminals[3]; 40 | 41 | volatile pid_t child; 42 | 43 | static void restore_terminal(void) { 44 | for(int i = 0; i != 3; ++i) 45 | if (terminals[i].is_term) 46 | tcsetattr(i, TCSANOW, &terminals[i].tio); 47 | } 48 | 49 | static void stop_handler(int s) { 50 | restore_terminal(); 51 | raise(SIGSTOP); 52 | if (terminals[0].is_term) 53 | tcsetattr(0, TCSANOW, &newTioIn); 54 | } 55 | 56 | static void fatal_handler(int s) { 57 | pid_t child2 = child; 58 | if (child2) kill(child2, s); 59 | } 60 | 61 | static void child_handler(int s) { 62 | child = 0; 63 | } 64 | 65 | static int seccomp_file = 9; 66 | 67 | static void __attribute__((noreturn)) do_exec(char **argv) { 68 | if (seccomp_file >= 0) lseek(seccomp_file, SEEK_SET, 0); 69 | execvp(*argv, argv); 70 | _exit(116); 71 | } 72 | 73 | int main(int argc, char **argv) { 74 | 75 | bool socket_server = false; 76 | bool handle_reboots = false; 77 | 78 | static const struct option opts[] = { 79 | {"arg", required_argument, NULL, 'a'}, 80 | {"network", no_argument, NULL, 'n'}, 81 | {"handle-reboots", no_argument, NULL, 'r'}, 82 | {"seccomp", no_argument, NULL, 's'}, 83 | {NULL, 0, NULL, 0} 84 | }; 85 | 86 | char *args[argc + 2]; 87 | char **argp = args; 88 | 89 | int opt; 90 | while ((opt = getopt_long(argc, argv, "-nr", opts, NULL)) != -1) { 91 | switch (opt) { 92 | case 1: 93 | case 'a': 94 | *argp++ = optarg; 95 | break; 96 | case 'n': 97 | socket_server = true; 98 | break; 99 | case 'r': 100 | handle_reboots = true; 101 | break; 102 | case 's': { 103 | const char *file = getenv("RISC_OS__seccomp"); 104 | if (!file) 105 | file = "Built/seccomp-"; 106 | seccomp_file = open(file, O_RDONLY); 107 | if (seccomp_file < 0) error(1, errno, "Unable to open seccomp rule file '%s'", file); 108 | static char s[11]; 109 | sprintf(s, "%i", seccomp_file); 110 | *argp++ = "--seccomp"; 111 | *argp++ = s; 112 | break; 113 | } 114 | default: 115 | fprintf(stderr, "usage\n"); 116 | return 1; 117 | } 118 | } 119 | 120 | while(optind != argc) *argp++ = argv[optind++]; 121 | *argp = 0; 122 | 123 | // Die if parent dies 124 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); 125 | 126 | bool have_terminal = false; 127 | for(int i = 0; i != 3; ++i) { 128 | if (!tcgetattr(0, &terminals[i].tio)) { 129 | terminals[i].is_term = true; 130 | have_terminal = true; 131 | } 132 | } 133 | 134 | if (!have_terminal && !handle_reboots && !socket_server) 135 | do_exec(args); 136 | 137 | // Is standard input a terminal? 138 | if (terminals[0].is_term) { 139 | 140 | // Standard input is a terminal, so reopen to it avoid 141 | // other programs having to cope with non-blocking etc. 142 | int fd = open("/proc/self/fd/0", O_RDONLY); 143 | if (fd > 0) { 144 | dup2(fd, 0); 145 | close(fd); 146 | } 147 | 148 | // Disable terminal echo. 149 | newTioIn = terminals[0].tio; 150 | newTioIn.c_iflag &= ~IGNCR & ~INLCR; 151 | newTioIn.c_cc[VMIN] = 1; 152 | newTioIn.c_cc[VTIME] = 0; 153 | newTioIn.c_lflag &= ~ICANON & ~ECHO; 154 | } 155 | 156 | // Install cleanup signal handlers 157 | struct sigaction sigact = {}; 158 | sigfillset(&sigact.sa_mask); 159 | sigact.sa_flags = SA_RESTART | SA_NOCLDSTOP; 160 | sigact.sa_handler = &child_handler; 161 | sigaction(SIGCHLD, &sigact, 0); 162 | 163 | sigdelset(&sigact.sa_mask, SIGCHLD); 164 | sigact.sa_handler = &stop_handler; 165 | sigaction(SIGTSTP, &sigact, 0); 166 | sigaction(SIGTTIN, &sigact, 0); 167 | sigaction(SIGTTOU, &sigact, 0); 168 | 169 | sigact.sa_handler = &fatal_handler; 170 | sigaction(SIGINT, &sigact, 0); 171 | sigaction(SIGHUP, &sigact, 0); 172 | sigaction(SIGTERM, &sigact, 0); 173 | 174 | if (terminals[0].is_term) { 175 | // Set new termnal state 176 | tcsetattr(0, TCSANOW, &newTioIn); 177 | } 178 | 179 | int status = 0; 180 | 181 | do { 182 | int sockets[2]; 183 | if (socket_server) 184 | socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets); 185 | 186 | // Block signals 187 | sigset_t sigset; 188 | sigfillset(&sigset); 189 | sigprocmask(SIG_BLOCK, &sigset, 0); 190 | 191 | // Do the fork! 192 | pid_t self = getpid(); 193 | pid_t pid = fork(); 194 | if (pid < 0) { 195 | restore_terminal(); 196 | return 109; 197 | } 198 | if (!pid) { 199 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); 200 | if (getppid() != self) _exit(110); 201 | 202 | if (socket_server) { 203 | close(sockets[0]); 204 | char s[48]; 205 | sprintf(s, "RISC_OS_Internet_SocketServer=%i", sockets[1]); 206 | putenv(s); 207 | } 208 | 209 | sigprocmask(SIG_UNBLOCK, &sigset, 0); 210 | do_exec(args); 211 | } 212 | child = pid; 213 | sigprocmask(SIG_UNBLOCK, &sigset, 0); 214 | 215 | 216 | if (socket_server) { 217 | close(sockets[1]); 218 | 219 | while(true) { 220 | int32_t socket_args[3]; 221 | int s = read(sockets[0], socket_args, sizeof(socket_args)); 222 | if (s == 0) break; 223 | 224 | if (socket_args[0] == AF_INET) { 225 | s = socket(socket_args[0], socket_args[1], socket_args[2]); 226 | } else { 227 | s = -1; 228 | errno = EPERM; 229 | } 230 | 231 | if (s < 0) { 232 | int32_t e = -errno; 233 | write(sockets[0], &e, 4); 234 | } else { 235 | 236 | union { 237 | char buf[CMSG_SPACE(sizeof(int))]; 238 | struct cmsghdr align; 239 | } u; 240 | 241 | struct msghdr msg = { 242 | .msg_control = u.buf, 243 | .msg_controllen = sizeof(u.buf) 244 | }; 245 | 246 | struct cmsghdr *cmsg; 247 | cmsg = CMSG_FIRSTHDR(&msg); 248 | cmsg->cmsg_level = SOL_SOCKET; 249 | cmsg->cmsg_type = SCM_RIGHTS; 250 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 251 | memcpy(CMSG_DATA(cmsg), &s, sizeof(s)); 252 | 253 | sendmsg(sockets[0], &msg, 0); 254 | close(s); 255 | } 256 | } 257 | 258 | close(sockets[0]); 259 | } 260 | 261 | int wstatus; 262 | waitpid(pid, &wstatus, 0); 263 | status = WEXITSTATUS(wstatus); 264 | 265 | // Write a new line to keep output tidy. 266 | if (isatty(1)) write(1, "\n", 1); 267 | 268 | argp[0] = "--isreboot"; 269 | argp[1] = 0; 270 | 271 | } while(status == 100 && handle_reboots); 272 | 273 | // Restore terminal 274 | restore_terminal(); 275 | return status; 276 | 277 | } 278 | -------------------------------------------------------------------------------- /Unix/RISCOS.IMG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimothyEBaldwin/RISC_OS_Linux_Binary/aba24d022f3bfa40873d5fa4a74602987bdf94da/Unix/RISCOS.IMG -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/Keyboard.h: -------------------------------------------------------------------------------- 1 | /* Created by Hdr2H. Pragmas removed manually. */ 2 | #ifndef IXFS___DEV_FD_5_BUILD_LINUX_RISCOS_EXPORT_APCS_32_C_GLOBAL_KEYBOARD_H 3 | #define IXFS___DEV_FD_5_BUILD_LINUX_RISCOS_EXPORT_APCS_32_C_GLOBAL_KEYBOARD_H 4 | 5 | #define KeyboardID_A500 (0) 6 | #define KeyboardID_Archimedes (1) 7 | #define KeyboardID_PC (2) 8 | #define KeyboardID_A4 (KeyboardID_PC) 9 | #define KeyboardID_RCMM (3) 10 | #define KeyboardID_Pandora (4) 11 | #define KeyboardID_None (0xff) 12 | #define KeyV_KeyboardPresent (0) 13 | #define KeyV_KeyUp (1) 14 | #define KeyV_KeyDown (2) 15 | #define KeyV_NotifyLEDState (3) 16 | #define KeyV_EnableDrivers (4) 17 | #define KeyV_PseudoEnable (5) 18 | #define KeyV_PseudoDisable (6) 19 | #define KeyV_PseudoIntMask (7) 20 | #define KeyV_PseudoRXInt (8) 21 | #define KeyV_PseudoTXInt (9) 22 | #define KeyV_PortInfo (10) 23 | #define KeyV_DummyKeyboard (11) 24 | #define KeyV_KeyboardRemoved (16) 25 | #define KeyV_LED_CapsLock (1) 26 | #define KeyV_LED_NumLock (2) 27 | #define KeyV_LED_ScrollLock (4) 28 | #define KeyHandler_KeyTran (0) 29 | #define KeyHandler_KeyTranSize (4) 30 | #define KeyHandler_InkeyTran (8) 31 | #define KeyHandler_ShiftingList (12) 32 | #define KeyHandler_SpecialList (16) 33 | #define KeyHandler_SpecialCodeTable (20) 34 | #define KeyHandler_Init (24) 35 | #define KeyHandler_PendingAltCode (28) 36 | #define KeyHandler_Flags (32) 37 | #define KeyHandler_Size (36) 38 | #define KeyHandler_HasFlags (0x80000000) 39 | #define KeyHandler_Flag_Wide (0x1) 40 | #define KeyNo_Escape (0x0) 41 | #define KeyNo_Function1 (0x1) 42 | #define KeyNo_Function2 (0x2) 43 | #define KeyNo_Function3 (0x3) 44 | #define KeyNo_Function4 (0x4) 45 | #define KeyNo_Function5 (0x5) 46 | #define KeyNo_Function6 (0x6) 47 | #define KeyNo_Function7 (0x7) 48 | #define KeyNo_Function8 (0x8) 49 | #define KeyNo_Function9 (0x9) 50 | #define KeyNo_Function10 (0xa) 51 | #define KeyNo_Function11 (0xb) 52 | #define KeyNo_Function12 (0xc) 53 | #define KeyNo_Print (0xd) 54 | #define KeyNo_ScrollLock (0xe) 55 | #define KeyNo_Break (0xf) 56 | #define KeyNo_BackTick (0x10) 57 | #define KeyNo_Digit1 (0x11) 58 | #define KeyNo_Digit2 (0x12) 59 | #define KeyNo_Digit3 (0x13) 60 | #define KeyNo_Digit4 (0x14) 61 | #define KeyNo_Digit5 (0x15) 62 | #define KeyNo_Digit6 (0x16) 63 | #define KeyNo_Digit7 (0x17) 64 | #define KeyNo_Digit8 (0x18) 65 | #define KeyNo_Digit9 (0x19) 66 | #define KeyNo_Digit0 (0x1a) 67 | #define KeyNo_Minus (0x1b) 68 | #define KeyNo_Equals (0x1c) 69 | #define KeyNo_Pound (0x1d) 70 | #define KeyNo_BackSpace (0x1e) 71 | #define KeyNo_Insert (0x1f) 72 | #define KeyNo_Home (0x20) 73 | #define KeyNo_PageUp (0x21) 74 | #define KeyNo_NumLock (0x22) 75 | #define KeyNo_NumPadSlash (0x23) 76 | #define KeyNo_NumPadStar (0x24) 77 | #define KeyNo_NumPadHash (0x25) 78 | #define KeyNo_Tab (0x26) 79 | #define KeyNo_LetterQ (0x27) 80 | #define KeyNo_LetterW (0x28) 81 | #define KeyNo_LetterE (0x29) 82 | #define KeyNo_LetterR (0x2a) 83 | #define KeyNo_LetterT (0x2b) 84 | #define KeyNo_LetterY (0x2c) 85 | #define KeyNo_LetterU (0x2d) 86 | #define KeyNo_LetterI (0x2e) 87 | #define KeyNo_LetterO (0x2f) 88 | #define KeyNo_LetterP (0x30) 89 | #define KeyNo_OpenSquare (0x31) 90 | #define KeyNo_CloseSquare (0x32) 91 | #define KeyNo_BackSlash (0x33) 92 | #define KeyNo_Delete (0x34) 93 | #define KeyNo_Copy (0x35) 94 | #define KeyNo_PageDown (0x36) 95 | #define KeyNo_NumPad7 (0x37) 96 | #define KeyNo_NumPad8 (0x38) 97 | #define KeyNo_NumPad9 (0x39) 98 | #define KeyNo_NumPadMinus (0x3a) 99 | #define KeyNo_CtrlLeft (0x3b) 100 | #define KeyNo_LetterA (0x3c) 101 | #define KeyNo_LetterS (0x3d) 102 | #define KeyNo_LetterD (0x3e) 103 | #define KeyNo_LetterF (0x3f) 104 | #define KeyNo_LetterG (0x40) 105 | #define KeyNo_LetterH (0x41) 106 | #define KeyNo_LetterJ (0x42) 107 | #define KeyNo_LetterK (0x43) 108 | #define KeyNo_LetterL (0x44) 109 | #define KeyNo_SemiColon (0x45) 110 | #define KeyNo_Tick (0x46) 111 | #define KeyNo_Return (0x47) 112 | #define KeyNo_NumPad4 (0x48) 113 | #define KeyNo_NumPad5 (0x49) 114 | #define KeyNo_NumPad6 (0x4a) 115 | #define KeyNo_NumPadPlus (0x4b) 116 | #define KeyNo_ShiftLeft (0x4c) 117 | #define KeyNo_NotFittedLeft (0x4d) 118 | #define KeyNo_LetterZ (0x4e) 119 | #define KeyNo_LetterX (0x4f) 120 | #define KeyNo_LetterC (0x50) 121 | #define KeyNo_LetterV (0x51) 122 | #define KeyNo_LetterB (0x52) 123 | #define KeyNo_LetterN (0x53) 124 | #define KeyNo_LetterM (0x54) 125 | #define KeyNo_Comma (0x55) 126 | #define KeyNo_Dot (0x56) 127 | #define KeyNo_Slash (0x57) 128 | #define KeyNo_ShiftRight (0x58) 129 | #define KeyNo_CursorUp (0x59) 130 | #define KeyNo_NumPad1 (0x5a) 131 | #define KeyNo_NumPad2 (0x5b) 132 | #define KeyNo_NumPad3 (0x5c) 133 | #define KeyNo_CapsLock (0x5d) 134 | #define KeyNo_AltLeft (0x5e) 135 | #define KeyNo_Space (0x5f) 136 | #define KeyNo_AltRight (0x60) 137 | #define KeyNo_CtrlRight (0x61) 138 | #define KeyNo_CursorLeft (0x62) 139 | #define KeyNo_CursorDown (0x63) 140 | #define KeyNo_CursorRight (0x64) 141 | #define KeyNo_NumPad0 (0x65) 142 | #define KeyNo_NumPadDot (0x66) 143 | #define KeyNo_NumPadEnter (0x67) 144 | #define KeyNo_AcornLeft (0x68) 145 | #define KeyNo_AcornRight (0x69) 146 | #define KeyNo_Menu (0x6a) 147 | #define KeyNo_NoConvert (0x6b) 148 | #define KeyNo_Convert (0x6c) 149 | #define KeyNo_Kana (0x6d) 150 | #define KeyNo_NotFittedRight (0x6e) 151 | #define KeyNo_FN (0x6f) 152 | #define KeyNo_LeftMouse (0x70) 153 | #define KeyNo_CentreMouse (0x71) 154 | #define KeyNo_RightMouse (0x72) 155 | #define KeyNo_Mouse1 (0x73) 156 | #define KeyNo_Mouse2 (0x74) 157 | #define KeyNo_CommercialAt (0x200) 158 | #define KeyNo_LeftParenthesis (0x201) 159 | #define KeyNo_RightParenthesis (0x202) 160 | #define KeyNo_ExclamationMark (0x203) 161 | #define KeyNo_LowLine (0x204) 162 | #define KeyNo_BrightnessDown (0x205) 163 | #define KeyNo_BrightnessUp (0x206) 164 | #define KeyNo_QuotationMark (0x207) 165 | #define KeyNo_PlusSign (0x208) 166 | #define KeyNo_AcuteAccent (0x209) 167 | #define KeyNo_YenSign (0x20a) 168 | #define KeyNo_Colon (0x20b) 169 | #define KeyNo_QuestionMark (0x20c) 170 | #define KeyNo_VerticalLine (0x20d) 171 | #define KeyNo_DollarSign (0x20e) 172 | #define KeyNo_EuroSign (0x20f) 173 | #define KeyNo_LidClosed (0x210) 174 | #define KeyNo_Power (0x211) 175 | #define KeyScan_ShiftEither (0) 176 | #define KeyScan_CtrlEither (1) 177 | #define KeyScan_AltEither (2) 178 | #define KeyScan_ShiftLeft (3) 179 | #define KeyScan_CtrlLeft (4) 180 | #define KeyScan_AltLeft (5) 181 | #define KeyScan_ShiftRight (6) 182 | #define KeyScan_CtrlRight (7) 183 | #define KeyScan_AltRight (8) 184 | #define KeyScan_LeftMouse (9) 185 | #define KeyScan_CentreMouse (10) 186 | #define KeyScan_RightMouse (11) 187 | #define KeyScan_FN (12) 188 | #define KeyScan_LetterQ (16) 189 | #define KeyScan_Digit3 (17) 190 | #define KeyScan_Digit4 (18) 191 | #define KeyScan_Digit5 (19) 192 | #define KeyScan_Function4 (20) 193 | #define KeyScan_Digit8 (21) 194 | #define KeyScan_Function7 (22) 195 | #define KeyScan_Minus (23) 196 | #define KeyScan_CircumflexAccent (24) 197 | #define KeyScan_CursorLeft (25) 198 | #define KeyScan_NumPad6 (26) 199 | #define KeyScan_NumPad7 (27) 200 | #define KeyScan_Function11 (28) 201 | #define KeyScan_Function12 (29) 202 | #define KeyScan_Function10 (30) 203 | #define KeyScan_ScrollLock (31) 204 | #define KeyScan_Print (32) 205 | #define KeyScan_LetterW (33) 206 | #define KeyScan_LetterE (34) 207 | #define KeyScan_LetterT (35) 208 | #define KeyScan_Digit7 (36) 209 | #define KeyScan_LetterI (37) 210 | #define KeyScan_Digit9 (38) 211 | #define KeyScan_Digit0 (39) 212 | #define KeyScan_LowLine (40) 213 | #define KeyScan_CursorDown (41) 214 | #define KeyScan_NumPad8 (42) 215 | #define KeyScan_NumPad9 (43) 216 | #define KeyScan_Break (44) 217 | #define KeyScan_BackTick (45) 218 | #define KeyScan_Pound (46) 219 | #define KeyScan_BackSpace (47) 220 | #define KeyScan_Digit1 (48) 221 | #define KeyScan_Digit2 (49) 222 | #define KeyScan_LetterD (50) 223 | #define KeyScan_LetterR (51) 224 | #define KeyScan_Digit6 (52) 225 | #define KeyScan_LetterU (53) 226 | #define KeyScan_LetterO (54) 227 | #define KeyScan_LetterP (55) 228 | #define KeyScan_OpenSquare (56) 229 | #define KeyScan_CursorUp (57) 230 | #define KeyScan_NumPadPlus (58) 231 | #define KeyScan_NumPadMinus (59) 232 | #define KeyScan_NumPadEnter (60) 233 | #define KeyScan_Insert (61) 234 | #define KeyScan_Home (62) 235 | #define KeyScan_PageUp (63) 236 | #define KeyScan_CapsLock (64) 237 | #define KeyScan_LetterA (65) 238 | #define KeyScan_LetterX (66) 239 | #define KeyScan_LetterF (67) 240 | #define KeyScan_LetterY (68) 241 | #define KeyScan_LetterJ (69) 242 | #define KeyScan_LetterK (70) 243 | #define KeyScan_CommercialAt (71) 244 | #define KeyScan_Colon (72) 245 | #define KeyScan_Return (73) 246 | #define KeyScan_NumPadSlash (74) 247 | #define KeyScan_NumPadDelete (75) 248 | #define KeyScan_NumPadDot (76) 249 | #define KeyScan_NumLock (77) 250 | #define KeyScan_PageDown (78) 251 | #define KeyScan_Tick (79) 252 | #define KeyScan_ShiftLock (80) 253 | #define KeyScan_LetterS (81) 254 | #define KeyScan_LetterC (82) 255 | #define KeyScan_LetterG (83) 256 | #define KeyScan_LetterH (84) 257 | #define KeyScan_LetterN (85) 258 | #define KeyScan_LetterL (86) 259 | #define KeyScan_SemiColon (87) 260 | #define KeyScan_CloseSquare (88) 261 | #define KeyScan_Delete (89) 262 | #define KeyScan_NumPadHash (90) 263 | #define KeyScan_NumPadStar (91) 264 | #define KeyScan_NumPadComma (92) 265 | #define KeyScan_Equals (93) 266 | #define KeyScan_NotFittedLeft (94) 267 | #define KeyScan_NotFittedRight (95) 268 | #define KeyScan_Tab (96) 269 | #define KeyScan_LetterZ (97) 270 | #define KeyScan_Space (98) 271 | #define KeyScan_LetterV (99) 272 | #define KeyScan_LetterB (100) 273 | #define KeyScan_LetterM (101) 274 | #define KeyScan_Comma (102) 275 | #define KeyScan_Dot (103) 276 | #define KeyScan_Slash (104) 277 | #define KeyScan_Copy (105) 278 | #define KeyScan_NumPad0 (106) 279 | #define KeyScan_NumPad1 (107) 280 | #define KeyScan_NumPad3 (108) 281 | #define KeyScan_NoConvert (109) 282 | #define KeyScan_Convert (110) 283 | #define KeyScan_Kana (111) 284 | #define KeyScan_Escape (112) 285 | #define KeyScan_Function1 (113) 286 | #define KeyScan_Function2 (114) 287 | #define KeyScan_Function3 (115) 288 | #define KeyScan_Function5 (116) 289 | #define KeyScan_Function6 (117) 290 | #define KeyScan_Function8 (118) 291 | #define KeyScan_Function9 (119) 292 | #define KeyScan_BackSlash (120) 293 | #define KeyScan_CursorRight (121) 294 | #define KeyScan_NumPad4 (122) 295 | #define KeyScan_NumPad5 (123) 296 | #define KeyScan_NumPad2 (124) 297 | #define KeyScan_AcornLeft (125) 298 | #define KeyScan_AcornRight (126) 299 | #define KeyScan_Menu (127) 300 | #define KeyScan_NoKey (255) 301 | #define KeyScan_CommercialAt_Alt (15) 302 | #define KeyScan_LeftParenthesis (271) 303 | #define KeyScan_RightParenthesis (527) 304 | #define KeyScan_ExclamationMark (783) 305 | #define KeyScan_LowLine_Alt (1039) 306 | #define KeyScan_BrightnessDown (1295) 307 | #define KeyScan_BrightnessUp (1551) 308 | #define KeyScan_QuotationMark (1807) 309 | #define KeyScan_PlusSign (2063) 310 | #define KeyScan_AcuteAccent (2319) 311 | #define KeyScan_YenSign (2575) 312 | #define KeyScan_Colon_Alt (2831) 313 | #define KeyScan_QuestionMark (3087) 314 | #define KeyScan_VerticalLine (3343) 315 | #define KeyScan_DollarSign (3599) 316 | #define KeyScan_EuroSign (3855) 317 | #define KeyScan_LidClosed (4111) 318 | #define KeyScan_Power (4367) 319 | #endif 320 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/Makefile,fe1: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018, Timothy Baldwin 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | include Makefiles:StdTools 18 | 19 | COMPONENT = LinuxSupport 20 | 21 | export: export_${PHASE} 22 | 23 | export_hdrs: 24 | ${MKDIR} .ix.h 25 | ${CP} SocketKVM_Protocol/h .ix.h.SocketKVM_Protocol ${CPFLAGS} 26 | @Echo LinuxSupport header export complete 27 | 28 | export_libs: 29 | @Echo LinuxSupport: no libraries 30 | 31 | export_resources: 32 | @Echo LinuxSupport: no resources 33 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/SocketKVM_Protocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #ifndef __GCC__ 20 | #define __attribute__(X) 21 | #endif 22 | 23 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 24 | #define CONST(x) ((x) << 24) 25 | #else 26 | #define CONST(x) (x) 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | class ule32 { 31 | uint32_t data; 32 | public: 33 | static uint32_t swap(uint32_t v) { 34 | if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) v = __builtin_bswap32(v); 35 | return v; 36 | } 37 | ule32& operator = (uint32_t v) { 38 | data = swap(v); 39 | return *this; 40 | } 41 | operator uint32_t () { 42 | return swap(data); 43 | } 44 | }; 45 | #else 46 | typedef uint32_t ule32; 47 | #endif 48 | 49 | struct version { 50 | int32_t reason; 51 | ule32 version; 52 | } version; 53 | 54 | union report { 55 | enum { 56 | ev_mouse = CONST(0), 57 | ev_keydown = CONST(1), 58 | ev_keyup = CONST(2), 59 | ev_mode_sync = CONST(3), 60 | ev_resize = CONST(4), 61 | ev_close = CONST(5), 62 | ev_version = CONST(6), 63 | } reason; 64 | struct version version; 65 | struct { 66 | int32_t reason; 67 | ule32 x, y, buttons; 68 | } mouse; 69 | struct { 70 | int32_t reason; 71 | ule32 code; 72 | } key; 73 | }; 74 | 75 | union command { 76 | enum { 77 | c_mode_change = CONST(0), 78 | c_set_palette = CONST(1), 79 | c_pointer = CONST(2), 80 | c_suspend = CONST(3), 81 | c_close_ctl = CONST(4), 82 | c_version = CONST(6), 83 | c_activescreen = CONST(7), 84 | c_startscreen = CONST(8), 85 | } reason; 86 | struct version version; 87 | struct { 88 | int32_t reason; 89 | ule32 vidc[16]; 90 | } mode; 91 | struct palette { 92 | int32_t reason; 93 | ule32 colour, index, type; 94 | } palette; 95 | struct pointer { 96 | int32_t reason; 97 | uint8_t width, height, active_x, active_y; 98 | uint8_t visable; 99 | uint8_t data[]; 100 | } pointer; 101 | struct suspend { 102 | int32_t reason; 103 | ule32 delay; 104 | } suspend; 105 | struct close_ctl { 106 | int32_t reason; 107 | int32_t use_message; 108 | } close_ctl; 109 | struct activescreen { 110 | int32_t reason; 111 | ule32 address; 112 | } activescreen; 113 | struct startscreen { 114 | int32_t reason; 115 | ule32 address; 116 | } startscreen; 117 | uint8_t pad[33 * 8]; 118 | }; 119 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/build.mk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # 3 | # Copyright (c) 2013-2018, Timothy Baldwin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | frontend_depends := Unix/SocketKVMFrontends/Keyboard.h Unix/SocketKVMFrontends/frontend_common.h Unix/SocketKVMFrontends/SocketKVM_Protocol.h $(lib_depends) 19 | 20 | include Built/SDL_flags 21 | 22 | all: sdl 23 | 24 | sdl: Built/sdl 25 | ln -sf Built/sdl sdl 26 | 27 | opengl: Built/opengl 28 | ln -sf Built/opengl opengl 29 | 30 | Built/sdl: Unix/SocketKVMFrontends/sdl.cpp Built/sdlkey.h $(frontend_depends) 31 | g++ --std=c++11 -Wall -pthread -g -O2 -IBuilt Unix/SocketKVMFrontends/sdl.cpp $(SDL_FLAGS) -o Built/sdl 32 | 33 | Built/opengl: Unix/SocketKVMFrontends/opengl.cpp $(frontend_depends) 34 | g++ -pthread -g -O2 --std=c++11 Unix/SocketKVMFrontends/opengl.cpp -lGL -lGLU -lglut -o Built/opengl 35 | 36 | Built/sdlkey.h: Unix/SocketKVMFrontends/sdlkey.c $(lib_depends) Unix/SocketKVMFrontends/Keyboard.h Built/SDL_flags $(SDL_DEPS) | Built 37 | gcc -std=gnu99 -Wall -IBuilt Unix/SocketKVMFrontends/sdlkey.c $(SDL_FLAGS) -o Built/sdlkey 38 | Built/sdlkey > $@ 39 | 40 | Built/SDL_flags: Unix/SocketKVMFrontends/build.mk $(call pathsearch sdl2-config) | Built 41 | exec > $@ 42 | if [[ "$$(sdl2-config --version)" != "2.0.12" ]]; then 43 | echo SDL_FLAGS=`sdl2-config --cflags --libs` 44 | else 45 | echo SDL_FLAGS=-Wl,-rpath,$(CURDIR)/Built/SDL/usr/lib -LBuilt/SDL/usr/lib -IBuilt/SDL/usr/include/SDL2 -D_REENTRANT -lSDL2 46 | echo SDL_DEPS=Built/SDL/stamp 47 | echo -n DEBARCH= 48 | dpkg --print-architecture || { gcc Unix/SocketKVMFrontends/identify_abi.c -o Built/idenify_abi.c; Built/idenify_abi.c; } 49 | fi 50 | 51 | Built/SDL/stamp: $(HOME)/Downloads/libsdl2-dev_2.0.9+dfsg1-1_$(DEBARCH).deb $(HOME)/Downloads/libsdl2-2.0-0_2.0.9+dfsg1-1_$(DEBARCH).deb 52 | set -o pipefail 53 | rm -rf Built/SDL 54 | mkdir -p Built/SDL 55 | cd Built/SDL 56 | echo -e '$(foreach t,$^,\n$($(t)) *$(t)\n)' | sha256sum -c 57 | for i in $^; do 58 | ar x "$$i" data.tar.xz 59 | tar xf data.tar.xz 60 | rm data.tar.xz 61 | done 62 | mv usr/lib/*/* usr/lib/ 63 | touch stamp 64 | 65 | define debpkg1 66 | $(HOME)/Downloads/$(1) := $(2) 67 | $(HOME)/Downloads/$(1): 68 | sh Unix/LinuxSupport/download.sh '$(HOME)/Downloads/$(1)' '$(3)$(1)' '$(2)' 69 | endef 70 | 71 | debpkg = $(call debpkg1,$(1),$(2),http://deb.debian.org/debian/pool/main/libs/libsdl2/) 72 | 73 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_amd64.deb,3ea18e9ddf0df52fe9cf37758f2ad364f7be9ece9bdbcd7de00dc98704ebf2a2)) 74 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_amd64.deb,a058eaa5f38e0400fd1ffc6ea275c1cca52893955220ddcf4684c2d64af9aa19)) 75 | 76 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_arm64.deb,f234435019e3178c4f89afe7fd2f38d098a016d0c2aafbadeaf87e8743839098)) 77 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_arm64.deb,9b6095f134e3d65edd789ffc44a5ea727ebf6b30e5bc84af5068769f5499027f)) 78 | 79 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_armel.deb,d18ca3e76d7fee99cad078205f51d119d081b666962044e19ac7808913daab95)) 80 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_armel.deb,38d282189dd6d898248b8b71df5b90b28feebc624f6c8812eb20d4e0e842367d)) 81 | 82 | $(eval $(call debpkg1,libsdl2-dev_2.0.9+dfsg1-1_armhf.deb,f723196925eda4a1bb37a3585163eb57ca38099fa6a0cf382994a7bbfa562fd8,http://raspbian.raspberrypi.org/raspbian/pool/main/libs/libsdl2/)) 83 | $(eval $(call debpkg1,libsdl2-2.0-0_2.0.9+dfsg1-1_armhf.deb,fd46961feb1e227c096afd0ae550329733715f8d00223107508e881998f3c3cb,http://raspbian.raspberrypi.org/raspbian/pool/main/libs/libsdl2/)) 84 | 85 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_i386.deb,5bfffa26614b0fbbff12607a46d7e36e430da06e276a48e0a45d361353f2238c)) 86 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_i386.deb,326b253877d642e0a45dba39fc91498177048b800293ebc9e36b499510cbf1cc)) 87 | 88 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_mips.deb,5de4de3e70f4cf58dad5f3d5d5fb8fd91dc9b9705fd78ce22c4e952c1b9a2d9a)) 89 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_mips.deb,290dae8ca690d97830ef093a8e7ca6c82ca838a8ec38f5aa10aebf0d6eebaf4d)) 90 | 91 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_mips64el.deb,ebaba448fc73ed61979c809772e7bf8c0030e530db7f1cb1fd34d2d70871bcd8)) 92 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_mips64el.deb,6684ba254813657d33eabafdd906de07b738259b4b561344575cfccc8bc250ad)) 93 | 94 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_mipsel.deb,8b3c4d2bedcbb7ae3bb171752ea9f3dea2d27ad86aa8e65854934cffd5e191ae)) 95 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_mipsel.deb,a195df28a75848fcc8d41cfac5b878fcbc9c21f15aab556658ef9cf4a98c1d1a)) 96 | 97 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_ppc64el.deb,b7cd3ae12a0b620e6a6e1dce4e893e5e0f0fd7dfd44f0130ac7c91ef33ae9131)) 98 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_ppc64el.deb,d67bc55a715f538e34e43e0fe0838fffa632be2ce0f79e8bbfabfea58e93d14c)) 99 | 100 | $(eval $(call debpkg,libsdl2-dev_2.0.9+dfsg1-1_s390x.deb,21274c7f6188427b5f753c7fdb15f1ce275d94614435b97b0418e1b9a060b225)) 101 | $(eval $(call debpkg,libsdl2-2.0-0_2.0.9+dfsg1-1_s390x.deb,2fb9893a63c2b442cdddc38f333bfd92636b26ed1e6884f35108960b94f65318)) 102 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/frontend_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2018, Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "SocketKVM_Protocol.h" 31 | #include "Keyboard.h" 32 | 33 | 34 | int sig_fd, sockets[2]; 35 | pid_t pid; 36 | const size_t screen_size = 1024*1024*100; 37 | int screen_fd = -1; 38 | void *pixels = mmap(0, screen_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 39 | std::bitset key_state; 40 | bool swapmouse; 41 | 42 | 43 | inline off_t get_file_size(int fd) { 44 | struct stat s; 45 | s.st_size = 0; 46 | fstat(fd, &s); 47 | return s.st_size; 48 | } 49 | 50 | void run_RISC_OS(char **args) { 51 | 52 | sigset_t sigset; 53 | sigemptyset(&sigset); 54 | sigaddset(&sigset, SIGCHLD); 55 | sigprocmask(SIG_BLOCK, &sigset, nullptr); 56 | sig_fd = signalfd(-1, &sigset, SFD_CLOEXEC | SFD_NONBLOCK); 57 | 58 | socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets); 59 | 60 | pid_t self = getpid(); 61 | pid = fork(); 62 | if (!pid) { 63 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); 64 | int socket = fcntl(sockets[1], F_DUPFD, 31); 65 | char s[40]; 66 | sprintf(s, "RISC_OS_SocketKVM_Socket=%i", socket); 67 | putenv(s); 68 | 69 | sigset_t sigset; 70 | sigemptyset(&sigset); 71 | sigprocmask(SIG_SETMASK, &sigset, nullptr); 72 | 73 | if (getppid() == self) execvp(*args, args); 74 | _exit(1); 75 | } 76 | close(sockets[1]); 77 | } 78 | 79 | void exit_poll() { 80 | struct signalfd_siginfo s; 81 | while(read(sig_fd, &s, sizeof(s)) > 0); 82 | 83 | int status; 84 | if (waitpid(pid, &status, WNOHANG) == pid) exit(WEXITSTATUS(status)); 85 | } 86 | 87 | int read_msg(command &c) { 88 | 89 | char buf[CMSG_SPACE(sizeof(int)) * 2]; 90 | 91 | struct iovec iov = { 92 | .iov_base = &c, 93 | .iov_len = sizeof(c), 94 | }; 95 | 96 | struct msghdr msg = { 97 | msg.msg_control = buf, 98 | msg.msg_controllen = sizeof(buf), 99 | msg.msg_iov = &iov, 100 | msg.msg_iovlen = 1, 101 | }; 102 | 103 | int s = recvmsg(sockets[0], &msg, MSG_DONTWAIT); 104 | 105 | if (s >= 0) for (struct cmsghdr *i = CMSG_FIRSTHDR(&msg); i != NULL; i = CMSG_NXTHDR(&msg, i)) { 106 | if (i->cmsg_level == SOL_SOCKET && i->cmsg_type == SCM_RIGHTS) { 107 | close(screen_fd); 108 | screen_fd = *(int *)CMSG_DATA(i); 109 | mmap(pixels, screen_size, PROT_READ, MAP_FIXED | MAP_SHARED, screen_fd, 0); 110 | } 111 | } 112 | 113 | return s; 114 | } 115 | 116 | void send_report(const report &r) { 117 | write(sockets[0], &r, sizeof(r)); 118 | } 119 | 120 | void report_key(int keycode, bool down) { 121 | 122 | if (swapmouse && (keycode == KeyNo_CentreMouse || keycode == KeyNo_RightMouse)) { 123 | keycode ^= KeyNo_CentreMouse ^ KeyNo_RightMouse; 124 | } 125 | 126 | report r; 127 | r.reason = down ? report::ev_keydown : report::ev_keyup; 128 | r.key.code = keycode; 129 | key_state[keycode] = down; 130 | send_report(r); 131 | } 132 | 133 | void resend_keys() { 134 | report r; 135 | for(int i = 0; i != key_state.size(); ++i) { 136 | if (key_state[i]) { 137 | r.reason = report::ev_keydown; 138 | r.key.code = i; 139 | send_report(r); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/identify_abi.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) { 4 | #if defined(__ARM_PCS_VFP) 5 | puts("armhf"); 6 | #elif defined(__ARMEL__) 7 | puts("armel"); 8 | #elif defined(__i386__) 9 | puts("i386"); 10 | #elif defined(__x86_64__) 11 | puts("amd64"); 12 | #elif defined(__aarch64__) 13 | puts("arm64"); 14 | #endif 15 | } 16 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/opengl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Timothy Baldwin 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of RISC OS Open Ltd nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software 14 | * without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | * POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | #define max_keycode (105) 31 | #include "frontend_common.h" 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | #include 46 | 47 | using std::cerr; 48 | using std::endl; 49 | 50 | #define NUM_SCREENS 3 51 | 52 | #include 53 | 54 | 55 | const int refresh_period = 20; 56 | const int mode_change = 5555; 57 | const int screen_update = 5554; 58 | int log2bpp = 3; 59 | int height = 480; 60 | int width = 640; 61 | int no_updates = 0; 62 | 63 | // Display size 64 | #define SCREEN_WIDTH 2560 65 | #define SCREEN_HEIGHT 1440 66 | 67 | void setupTexture(); 68 | volatile int draw_pixels=1; 69 | void *current_pixels; 70 | 71 | 72 | static unsigned short keycode[256]; 73 | static unsigned short shctrl[256]; 74 | 75 | 76 | 77 | void init_keyboard(){ 78 | for (int i=0;i<256;i++) 79 | { 80 | keycode[i]=0; 81 | shctrl[i]=0; 82 | } 83 | keycode['a']=KeyNo_LetterA; 84 | keycode['b']=KeyNo_LetterB; 85 | keycode['c']=KeyNo_LetterC; 86 | keycode['d']=KeyNo_LetterD; 87 | keycode['e']=KeyNo_LetterE; 88 | keycode['f']=KeyNo_LetterF; 89 | keycode['g']=KeyNo_LetterG; 90 | keycode['h']=KeyNo_LetterH; 91 | keycode['i']=KeyNo_LetterI; 92 | keycode['j']=KeyNo_LetterJ; 93 | keycode['k']=KeyNo_LetterK; 94 | keycode['l']=KeyNo_LetterL; 95 | keycode['m']=KeyNo_LetterM; 96 | keycode['n']=KeyNo_LetterN; 97 | keycode['o']=KeyNo_LetterO; 98 | keycode['p']=KeyNo_LetterP; 99 | keycode['q']=KeyNo_LetterQ; 100 | keycode['r']=KeyNo_LetterR; 101 | keycode['s']=KeyNo_LetterS; 102 | keycode['t']=KeyNo_LetterT; 103 | keycode['u']=KeyNo_LetterU; 104 | keycode['v']=KeyNo_LetterV; 105 | keycode['w']=KeyNo_LetterW; 106 | keycode['x']=KeyNo_LetterX; 107 | keycode['y']=KeyNo_LetterY; 108 | keycode['z']=KeyNo_LetterZ; 109 | keycode[' ']=KeyNo_Space; 110 | 111 | 112 | 113 | 114 | keycode['1'] = keycode['!'] = KeyNo_Digit1;shctrl['!']=1; 115 | keycode['2'] = keycode['@'] = KeyNo_Digit2;shctrl['@']=1; 116 | keycode['3'] = keycode['#'] = KeyNo_Digit3;shctrl['#']=1; 117 | keycode['4'] = keycode['$'] = KeyNo_Digit4;shctrl['$']=1; 118 | keycode['5'] = keycode['%'] = KeyNo_Digit5;shctrl['%']=1; 119 | keycode['6'] = keycode['^'] = KeyNo_Digit6;shctrl['^']=1; 120 | keycode['7'] = keycode['&'] = KeyNo_Digit7;shctrl['&']=1; 121 | keycode['8'] = keycode['*'] = KeyNo_Digit8;shctrl['*']=1; 122 | keycode['9'] = keycode['('] = KeyNo_Digit9;shctrl['(']=1; 123 | keycode['0'] = keycode[')'] = KeyNo_Digit0;shctrl[')']=1; 124 | 125 | 126 | keycode['-'] = keycode['_'] = KeyNo_Minus;shctrl['_']=1; 127 | keycode['='] = keycode['+'] = KeyNo_Equals;shctrl['+']=1; 128 | keycode['\\'] = keycode['|'] = KeyNo_BackSlash;shctrl['|']=1; 129 | keycode['['] = keycode['{'] = KeyNo_OpenSquare;shctrl['{']=1; 130 | keycode[']'] = keycode['}'] = KeyNo_CloseSquare;shctrl['}']=1; 131 | keycode[';'] = keycode[':'] = KeyNo_SemiColon;shctrl[';']=1; 132 | keycode['\''] = keycode['"'] = KeyNo_Tick;shctrl['"']=1; 133 | keycode[','] = keycode['<'] = KeyNo_Comma;shctrl['<']=1; 134 | keycode['.'] = keycode['>'] = KeyNo_Dot;shctrl['>']=1; 135 | keycode['/'] = keycode['?'] = KeyNo_Slash;shctrl['?']=1; 136 | 137 | 138 | for (int k=0;k<26;k++) 139 | { keycode[k+'A']=keycode[k+'a'];shctrl[k+'A']=1; 140 | keycode[k+1]=keycode[k+'a'];} 141 | keycode['\b']=KeyNo_BackSpace; 142 | keycode['\r']=KeyNo_Return; 143 | keycode['\t']=KeyNo_Tab; 144 | keycode[27] = KeyNo_Escape; 145 | } 146 | static int oldscreennumber=0,screennumber=0,display_size=1; 147 | int display_width=SCREEN_WIDTH,display_height=SCREEN_HEIGHT; 148 | static volatile int buttons=0; 149 | bool shiftkey=false; 150 | 151 | void OnMouseClick(int button, int state, int, int) 152 | { 153 | report r; 154 | buttons=button; 155 | 156 | switch (state) { 157 | case GLUT_DOWN: 158 | report_key(KeyNo_LeftMouse + button, true); 159 | break; 160 | case GLUT_UP: 161 | report_key(KeyNo_LeftMouse + button, false); 162 | break; 163 | } 164 | } 165 | 166 | void My_mouse_routine(int x, int y){ 167 | report r; 168 | r.reason = report::ev_mouse; 169 | r.mouse.x = x * width / display_width; 170 | r.mouse.y = height - y * height / display_height; 171 | r.mouse.buttons = buttons; 172 | send_report(r); 173 | 174 | } 175 | 176 | void mouseWheel(int button, int dir, int x, int y) 177 | { 178 | if (dir > 0) 179 | { 180 | // Zoom in 181 | } 182 | else 183 | { 184 | // Zoom out 185 | } 186 | return; 187 | } 188 | 189 | void myupfunc(unsigned char key, int x, int y){ 190 | report_key(keycode[key], false); 191 | } 192 | 193 | void mydownfunc(unsigned char key, int x, int y){ 194 | report_key(keycode[key], true); 195 | if (keycode[key]==0) 196 | cerr << "Key pressed:" << (unsigned int) key << "\n"; 197 | } 198 | 199 | unsigned short special_to_code(int key) { 200 | switch(key) { 201 | case GLUT_KEY_F1: return KeyNo_Function1;// F1 function key. 202 | case GLUT_KEY_F2: return KeyNo_Function2;// F2 function key. 203 | case GLUT_KEY_F3: return KeyNo_Function3;// F3 function key. 204 | case GLUT_KEY_F4: return KeyNo_Function4;// F4 function key. 205 | case GLUT_KEY_F5: return KeyNo_Function5;// F5 function key. 206 | case GLUT_KEY_F6: return KeyNo_Function6;// F6 function key. 207 | case GLUT_KEY_F7: return KeyNo_Function7;// F7 function key. 208 | case GLUT_KEY_F8: return KeyNo_Function8;// F8 function key. 209 | case GLUT_KEY_F9: return KeyNo_Function9;// F9 function key. 210 | case GLUT_KEY_F10: return KeyNo_Function10;// F10 function key. 211 | case GLUT_KEY_F11: return KeyNo_Function11;// F11 function key. 212 | case GLUT_KEY_F12: return KeyNo_Function12; // F12 function key. 213 | case GLUT_KEY_LEFT: return KeyNo_CursorLeft; // Left directional key. 214 | case GLUT_KEY_UP: return KeyNo_CursorUp;// Up directional key. 215 | case GLUT_KEY_RIGHT: return KeyNo_CursorRight;// Right directional key. 216 | case GLUT_KEY_DOWN: return KeyNo_CursorDown;// Down directional key. 217 | case GLUT_KEY_PAGE_UP: return KeyNo_PageUp; // Page up directional key. 218 | case GLUT_KEY_PAGE_DOWN: return KeyNo_PageDown;// Page down directional key. 219 | case GLUT_KEY_HOME: return KeyNo_Home;// Home directional key. 220 | case GLUT_KEY_END: return KeyNo_Break;// End directional key. 221 | case GLUT_KEY_INSERT: return KeyNo_Insert; //Inset directional key. 222 | case 112: return KeyNo_ShiftLeft; 223 | case 113: return KeyNo_ShiftRight; 224 | case 114: return KeyNo_CtrlLeft; 225 | case 115: return KeyNo_CtrlRight; 226 | case 116: return KeyNo_AltLeft; 227 | case 117: return KeyNo_AltRight; 228 | 229 | default: 230 | break; 231 | } 232 | return 0; 233 | } 234 | 235 | void myspecialup(int key, int x, int y) 236 | { 237 | int k = special_to_code(key); 238 | if (k != 0) 239 | report_key(k, false); 240 | else 241 | cerr << " KEYup " << key <<"\n"; 242 | 243 | } 244 | void myspecialdown(int key, int x, int y) 245 | { 246 | int k = special_to_code(key); 247 | if (k != 0) 248 | report_key(k, true); 249 | else 250 | cerr << " KEYdown " << key <<"\n"; 251 | } 252 | 253 | // Setup Texture 254 | void setupTexture() 255 | { 256 | // Create a texture 257 | glTexImage2D(GL_TEXTURE_2D, 0, 3, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, current_pixels); 258 | 259 | // Set up the texture 260 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 261 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 262 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 263 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 264 | 265 | // Enable textures 266 | glEnable(GL_TEXTURE_2D); 267 | draw_pixels=1; 268 | } 269 | 270 | void updateTexture() 271 | { 272 | display_width = glutGet(GLUT_WINDOW_WIDTH); 273 | display_height = glutGet(GLUT_WINDOW_HEIGHT); 274 | 275 | glMatrixMode(GL_PROJECTION); 276 | glLoadIdentity(); 277 | gluOrtho2D(0, display_width, display_height, 0); 278 | glMatrixMode(GL_MODELVIEW); 279 | glViewport(0, 0, display_width, display_height); 280 | // Update Texture 281 | switch(log2bpp) { 282 | case 3: 283 | 284 | glTexSubImage2D(GL_TEXTURE_2D, 0 ,0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, current_pixels); 285 | break; 286 | case 4: 287 | glTexSubImage2D(GL_TEXTURE_2D, 0 ,0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, current_pixels); 288 | break; 289 | default: 290 | glTexSubImage2D(GL_TEXTURE_2D, 0 ,0, 0, width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, current_pixels); 291 | break; 292 | } 293 | 294 | 295 | glBegin( GL_QUADS ); 296 | 297 | glTexCoord2d(0.0, 0.0); glVertex2d(0.0, 0.0); 298 | glTexCoord2d(1.0*width/SCREEN_WIDTH, 0.0); glVertex2d(display_width, 0.0); 299 | glTexCoord2d(1.0*width/SCREEN_WIDTH, 1.0*height/SCREEN_HEIGHT); glVertex2d(display_width, display_height); 300 | glTexCoord2d(0.0, 1.0*height/SCREEN_HEIGHT); glVertex2d(0.0, display_height); 301 | 302 | glEnd(); 303 | } 304 | 305 | void display() 306 | { 307 | // Clear framebuffer 308 | //glClear(GL_COLOR_BUFFER_BIT); 309 | // Draw pixels to texture 310 | updateTexture(); 311 | // Swap buffers! 312 | glutSwapBuffers(); 313 | } 314 | 315 | void reshape_window(GLsizei w, GLsizei h) 316 | { 317 | glClearColor(0.0f, 0.0f, 0.5f, 0.0f); 318 | glMatrixMode(GL_PROJECTION); 319 | glLoadIdentity(); 320 | gluOrtho2D(0, w, h, 0); 321 | glMatrixMode(GL_MODELVIEW); 322 | glViewport(0, 0, w, h); 323 | 324 | // Resize quad 325 | display_width = w; 326 | display_height = h; 327 | draw_pixels=1; 328 | glutPostRedisplay(); 329 | } 330 | 331 | int init_my_GL(int argc, char **argv) 332 | { 333 | // Setup OpenGL 334 | glutInit(&argc, argv); 335 | glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); 336 | 337 | glutInitWindowSize(width, height); 338 | glutInitWindowPosition(320, 320); 339 | glutCreateWindow("RISC OS 5"); 340 | 341 | glutDisplayFunc(display); 342 | glutMouseFunc(OnMouseClick); 343 | glutMotionFunc( My_mouse_routine ); 344 | glutPassiveMotionFunc( My_mouse_routine ); 345 | glutReshapeFunc(reshape_window); 346 | 347 | glutKeyboardUpFunc(myupfunc); 348 | glutKeyboardFunc(mydownfunc); 349 | glutMouseWheelFunc(mouseWheel); 350 | glutSpecialFunc(myspecialdown); 351 | glutSpecialUpFunc(myspecialup); 352 | 353 | setupTexture(); 354 | 355 | return 0; 356 | } 357 | 358 | auto start = std::chrono::steady_clock::now(); 359 | void interact_rule() 360 | { 361 | 362 | report r; 363 | 364 | exit_poll(); 365 | 366 | 367 | command c; 368 | int numscr; 369 | 370 | int s = read_msg(c); 371 | 372 | if (s >= 4) { 373 | 374 | 375 | switch (c.reason) { 376 | case command::c_mode_change: 377 | height = c.mode.vidc[11]; 378 | width = c.mode.vidc[5]; 379 | log2bpp = c.mode.vidc[1]; 380 | cerr << "Set mode " << log2bpp << ' ' << height << ' ' << width << endl; 381 | 382 | switch (log2bpp) { 383 | case 3: 384 | display_size = width*height; 385 | break; 386 | case 4: 387 | display_size = width*height*2; 388 | break; 389 | case 5: 390 | display_size = width*height*4; 391 | break; 392 | } 393 | current_pixels = pixels; 394 | if (width==SCREEN_WIDTH && height == SCREEN_HEIGHT) 395 | glutFullScreen(); 396 | else 397 | glutReshapeWindow(width, height); 398 | 399 | glutPostRedisplay(); 400 | r.reason = report::ev_mode_sync; 401 | write(sockets[0], &r.reason, sizeof(r.reason)); 402 | break; 403 | case command::c_activescreen: 404 | // swap buffer, ensure no unauthorised memory access. 405 | if (c.activescreen.address + display_size <= screen_size) { 406 | current_pixels = pixels + static_cast(c.activescreen.address); 407 | } 408 | break; 409 | case command::c_suspend: 410 | no_updates = c.suspend.delay; 411 | //update_screen(); 412 | break; 413 | case command::c_set_palette: { 414 | /* 415 | SDL_Palette *p; 416 | if (c.palette.type == 0) { 417 | p = palette; 418 | } else if (c.palette.type == 2) { 419 | p = cursor_surface->format->palette; 420 | } else { 421 | break; 422 | } 423 | p->colors[c.palette.index].r = 0xFF & (c.palette.colour >> 8); 424 | p->colors[c.palette.index].g = 0xFF & (c.palette.colour >> 16); 425 | p->colors[c.palette.index].b = 0xFF & (c.palette.colour >> 24); 426 | if (c.palette.type == 2) goto update_cursor; 427 | for (numscr=0;numscrpixels; 436 | int i = c.pointer.height * 8; 437 | do { 438 | int j = 4; 439 | unsigned s = *src++; 440 | do { 441 | *dst++ = s & 3; 442 | s >>= 2; 443 | } while (--j); 444 | } while(--i); 445 | std::memset(dst, 0, (32 - c.pointer.height) * 32); 446 | cursor_active_x = c.pointer.active_x; 447 | cursor_active_y = c.pointer.active_y; 448 | */ 449 | } 450 | update_cursor: { 451 | /* 452 | SDL_Cursor* cursor2 = SDL_CreateColorCursor(cursor_surface, cursor_active_x, cursor_active_y); 453 | SDL_SetCursor(cursor2); 454 | SDL_FreeCursor(cursor); 455 | cursor = cursor2; 456 | */ 457 | break; 458 | } 459 | } 460 | } 461 | auto thismoment = std::chrono::steady_clock::now(); 462 | std::chrono::duration diff = thismoment-start; 463 | if (diff.count() >0.02) { 464 | display(); 465 | start=thismoment; 466 | } 467 | } 468 | 469 | 470 | 471 | int main(int argc, char **argv) { 472 | 473 | struct option opts[] = { 474 | {"chromebook", no_argument, nullptr, 'c'}, 475 | {"swapmouse", no_argument, nullptr, 's'}, 476 | {nullptr, 0, nullptr, 0} 477 | }; 478 | 479 | int opt; 480 | while ((opt = getopt_long(argc, argv, "+cs", opts, nullptr)) != -1) { 481 | switch (opt) { 482 | case 's': 483 | swapmouse = true; 484 | break; 485 | case 'c': 486 | break; 487 | } 488 | } 489 | 490 | 491 | run_RISC_OS(argv + optind); 492 | 493 | int cursor_active_x = 0; 494 | int cursor_active_y = 0; 495 | 496 | current_pixels = pixels; 497 | init_keyboard(); 498 | init_my_GL(argc,argv); 499 | 500 | uint32_t buttons = 0; 501 | glutIdleFunc(interact_rule); 502 | glutMainLoop(); 503 | } 504 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2018, Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "sdlkey.h" 22 | #include "frontend_common.h" 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | using std::cerr; 33 | using std::endl; 34 | 35 | namespace { 36 | 37 | const int refresh_period = 50; 38 | const int mode_change = 5555; 39 | const int screen_update = 5554; 40 | std::atomic updates_pending; 41 | bool use_close_message; 42 | int log2bpp = 3; 43 | int height = 480; 44 | int width = 640; 45 | int window_resize_delay = 2; 46 | int no_updates = 0; 47 | SDL_Window *window; 48 | SDL_Surface *screen; 49 | int client_version; 50 | 51 | void update_screen() { 52 | if (no_updates >= 0) { 53 | no_updates -= refresh_period * updates_pending.exchange(0); 54 | } else { 55 | updates_pending = 0; 56 | } 57 | 58 | static char old[screen_size]; 59 | 60 | size_t s = (height * width) << log2bpp >> 3; 61 | if (no_updates <= 0 && get_file_size(screen_fd) >= s && std::memcmp(old, pixels, s)) { 62 | std::memcpy(old, pixels, s); 63 | SDL_BlitSurface(screen, nullptr, SDL_GetWindowSurface(window), nullptr); 64 | SDL_UpdateWindowSurface(window); 65 | } 66 | } 67 | 68 | void watcher() { 69 | SDL_Event e; 70 | e.type = mode_change; 71 | SDL_Delay(1500); 72 | while(true) { 73 | struct pollfd pfd[] = { 74 | {sig_fd, POLLIN, 0}, 75 | {sockets[0], POLLIN, 0}, 76 | }; 77 | poll(pfd, 2, 1000000000); 78 | SDL_PushEvent(&e); 79 | } 80 | } 81 | 82 | void refresh() { 83 | SDL_Event e; 84 | e.type = screen_update; 85 | while (true) { 86 | if (!updates_pending++) SDL_PushEvent(&e); 87 | SDL_Delay(refresh_period); 88 | } 89 | } 90 | 91 | void set_window_size() { 92 | if (!window_resize_delay) { 93 | int w, h; 94 | SDL_GetWindowSize(window, &w, &h); 95 | if (w != width || h != height) { 96 | SDL_SetWindowSize(window, width, height); 97 | window_resize_delay = 500 / refresh_period; 98 | } 99 | } 100 | } 101 | } 102 | 103 | int main(int argc, char **argv) { 104 | 105 | struct option opts[] = { 106 | {"chromebook", no_argument, nullptr, 'c'}, 107 | {"swapmouse", no_argument, nullptr, 's'}, 108 | {nullptr, 0, nullptr, 0} 109 | }; 110 | 111 | int opt; 112 | while ((opt = getopt_long(argc, argv, "+cs", opts, nullptr)) != -1) { 113 | switch (opt) { 114 | case 's': 115 | swapmouse = true; 116 | break; 117 | case 'c': 118 | sdl2key[SDL_SCANCODE_F10] = KeyNo_Function12; 119 | sdl2key[SDL_SCANCODE_F11] = KeyNo_Function12; 120 | break; 121 | } 122 | } 123 | 124 | run_RISC_OS(argv + optind); 125 | 126 | SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); 127 | SDL_Init(SDL_INIT_VIDEO); 128 | window = SDL_CreateWindow("RISC OS", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); 129 | 130 | 131 | int cursor_active_x = 0; 132 | int cursor_active_y = 0; 133 | SDL_Surface* cursor_surface = SDL_CreateRGBSurface(0, 32, 32, 8, 0, 0, 0, 0); 134 | cursor_surface->format->palette->colors[0].a = 0; 135 | SDL_Cursor* cursor = nullptr; 136 | 137 | 138 | SDL_Palette *palette = SDL_AllocPalette(256); 139 | 140 | new std::thread {refresh}; 141 | //new std::thread {watcher}; 142 | 143 | uint32_t buttons = 0; 144 | while(true) { 145 | report r; 146 | 147 | exit_poll(); 148 | 149 | while (true) { 150 | command c; 151 | 152 | 153 | int s = read_msg(c); 154 | if (s < 4) break; 155 | 156 | switch (c.reason) { 157 | case command::c_mode_change: 158 | height = c.mode.vidc[11]; 159 | width = c.mode.vidc[5]; 160 | log2bpp = c.mode.vidc[1]; 161 | //cerr << "Set mode " << log2bpp << ' ' << height << ' ' << width << endl; 162 | SDL_FreeSurface(screen); 163 | screen = nullptr; 164 | switch (log2bpp) { 165 | case 3: 166 | screen = SDL_CreateRGBSurfaceFrom(pixels, width, height, 8, width, 0, 0, 0, 0); 167 | SDL_SetSurfacePalette(screen, palette); 168 | break; 169 | case 4: 170 | screen = SDL_CreateRGBSurfaceFrom(pixels, width, height, 16, width * 2, 0x1F, 0x1F << 5, 0x1F << 10, 0); 171 | break; 172 | case 5: 173 | screen = SDL_CreateRGBSurfaceFrom(pixels, width, height, 32, width * 4, 0xFF, 0xFF00, 0xFF0000, 0); 174 | break; 175 | } 176 | set_window_size(); 177 | no_updates = std::max(no_updates, 200); 178 | r.reason = report::ev_mode_sync; 179 | write(sockets[0], &r.reason, sizeof(r.reason)); 180 | break; 181 | case command::c_suspend: 182 | no_updates = c.suspend.delay; 183 | update_screen(); 184 | break; 185 | case command::c_set_palette: { 186 | SDL_Palette *p; 187 | if (c.palette.type == 0) { 188 | p = palette; 189 | } else if (c.palette.type == 2) { 190 | p = cursor_surface->format->palette; 191 | } else { 192 | break; 193 | } 194 | p->colors[c.palette.index].r = 0xFF & (c.palette.colour >> 8); 195 | p->colors[c.palette.index].g = 0xFF & (c.palette.colour >> 16); 196 | p->colors[c.palette.index].b = 0xFF & (c.palette.colour >> 24); 197 | if (c.palette.type == 2) goto update_cursor; 198 | SDL_SetSurfacePalette(screen, palette); 199 | break; 200 | } 201 | case command::c_pointer: { 202 | uint8_t *src = c.pointer.data; 203 | uint8_t *dst = (uint8_t *)cursor_surface->pixels; 204 | int i = c.pointer.height * 8; 205 | do { 206 | int j = 4; 207 | unsigned s = *src++; 208 | do { 209 | *dst++ = s & 3; 210 | s >>= 2; 211 | } while (--j); 212 | } while(--i); 213 | std::memset(dst, 0, (32 - c.pointer.height) * 32); 214 | cursor_active_x = c.pointer.active_x; 215 | cursor_active_y = c.pointer.active_y; 216 | } 217 | update_cursor: { 218 | SDL_Cursor* cursor2 = SDL_CreateColorCursor(cursor_surface, cursor_active_x, cursor_active_y); 219 | SDL_SetCursor(cursor2); 220 | SDL_FreeCursor(cursor); 221 | cursor = cursor2; 222 | break; 223 | } 224 | case command::c_close_ctl: 225 | use_close_message = c.close_ctl.use_message; 226 | break; 227 | case command::c_version: { 228 | resend_keys(); 229 | client_version = c.version.version; 230 | report r; 231 | r.reason = report::ev_version; 232 | r.version.version = 1; 233 | send_report(r); 234 | break; 235 | } 236 | } 237 | } 238 | 239 | SDL_Event e; 240 | SDL_WaitEvent(&e); 241 | switch(e.type) { 242 | case mode_change: 243 | break; 244 | case screen_update: 245 | if (window_resize_delay && !--window_resize_delay) set_window_size(); 246 | update_screen(); 247 | break; 248 | case SDL_WINDOWEVENT: 249 | switch(e.window.event) { 250 | case SDL_WINDOWEVENT_RESIZED: { 251 | report r; 252 | r.reason = report::ev_resize; 253 | r.mouse.x = e.window.data1; 254 | r.mouse.y = e.window.data2; 255 | send_report(r); 256 | if (no_updates < 200) no_updates = 200; 257 | window_resize_delay = 1000 / refresh_period; 258 | break; 259 | } 260 | case SDL_WINDOWEVENT_EXPOSED: 261 | SDL_UpdateWindowSurface(window); 262 | break; 263 | } 264 | break; 265 | case SDL_QUIT: 266 | if (use_close_message) { 267 | report r; 268 | r.reason = report::ev_close; 269 | send_report(r); 270 | } else { 271 | kill(pid, SIGTERM); 272 | } 273 | break; 274 | case SDL_KEYDOWN: 275 | report_key(sdl2key[e.key.keysym.scancode], true); 276 | break; 277 | case SDL_KEYUP: 278 | report_key(sdl2key[e.key.keysym.scancode], false); 279 | break; 280 | 281 | case SDL_MOUSEBUTTONDOWN: 282 | report_key(KeyNo_LeftMouse + e.button.button - 1, true); 283 | break; 284 | case SDL_MOUSEBUTTONUP: 285 | report_key(KeyNo_LeftMouse + e.button.button - 1, false); 286 | break; 287 | case SDL_MOUSEMOTION: 288 | buttons = static_cast(e.motion.state); 289 | r.reason = report::ev_mouse; 290 | r.mouse.x = static_cast(e.motion.x); 291 | r.mouse.y = client_version >= 2 ? static_cast(e.motion.y): (height - static_cast(e.motion.y)); 292 | r.mouse.buttons = buttons; 293 | send_report(r); 294 | //std::cerr << "Motion " << r.x << ' ' << r.y << ' ' << r.buttons << std::endl; 295 | break; 296 | } 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /Unix/SocketKVMFrontends/sdlkey.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Timothy Baldwin 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include "Keyboard.h" 21 | 22 | struct keys { int sdl, ro; }; 23 | 24 | struct keys sdl2key[] = { 25 | 26 | {SDL_SCANCODE_A, KeyNo_LetterA}, 27 | {SDL_SCANCODE_B, KeyNo_LetterB}, 28 | {SDL_SCANCODE_C, KeyNo_LetterC}, 29 | {SDL_SCANCODE_D, KeyNo_LetterD}, 30 | {SDL_SCANCODE_E, KeyNo_LetterE}, 31 | {SDL_SCANCODE_F, KeyNo_LetterF}, 32 | {SDL_SCANCODE_G, KeyNo_LetterG}, 33 | {SDL_SCANCODE_H, KeyNo_LetterH}, 34 | {SDL_SCANCODE_I, KeyNo_LetterI}, 35 | {SDL_SCANCODE_J, KeyNo_LetterJ}, 36 | {SDL_SCANCODE_K, KeyNo_LetterK}, 37 | {SDL_SCANCODE_L, KeyNo_LetterL}, 38 | {SDL_SCANCODE_M, KeyNo_LetterM}, 39 | {SDL_SCANCODE_N, KeyNo_LetterN}, 40 | {SDL_SCANCODE_O, KeyNo_LetterO}, 41 | {SDL_SCANCODE_P, KeyNo_LetterP}, 42 | {SDL_SCANCODE_Q, KeyNo_LetterQ}, 43 | {SDL_SCANCODE_R, KeyNo_LetterR}, 44 | {SDL_SCANCODE_S, KeyNo_LetterS}, 45 | {SDL_SCANCODE_T, KeyNo_LetterT}, 46 | {SDL_SCANCODE_U, KeyNo_LetterU}, 47 | {SDL_SCANCODE_V, KeyNo_LetterV}, 48 | {SDL_SCANCODE_W, KeyNo_LetterW}, 49 | {SDL_SCANCODE_X, KeyNo_LetterX}, 50 | {SDL_SCANCODE_Y, KeyNo_LetterY}, 51 | {SDL_SCANCODE_Z, KeyNo_LetterZ}, 52 | {SDL_SCANCODE_0, KeyNo_Digit0}, 53 | {SDL_SCANCODE_1, KeyNo_Digit1}, 54 | {SDL_SCANCODE_2, KeyNo_Digit2}, 55 | {SDL_SCANCODE_3, KeyNo_Digit3}, 56 | {SDL_SCANCODE_4, KeyNo_Digit4}, 57 | {SDL_SCANCODE_5, KeyNo_Digit5}, 58 | {SDL_SCANCODE_6, KeyNo_Digit6}, 59 | {SDL_SCANCODE_7, KeyNo_Digit7}, 60 | {SDL_SCANCODE_8, KeyNo_Digit8}, 61 | {SDL_SCANCODE_9, KeyNo_Digit9}, 62 | 63 | {SDL_SCANCODE_F1, KeyNo_Function1}, 64 | {SDL_SCANCODE_F2, KeyNo_Function2}, 65 | {SDL_SCANCODE_F3, KeyNo_Function3}, 66 | {SDL_SCANCODE_F4, KeyNo_Function4}, 67 | {SDL_SCANCODE_F5, KeyNo_Function5}, 68 | {SDL_SCANCODE_F6, KeyNo_Function6}, 69 | {SDL_SCANCODE_F7, KeyNo_Function7}, 70 | {SDL_SCANCODE_F8, KeyNo_Function8}, 71 | {SDL_SCANCODE_F9, KeyNo_Function9}, 72 | {SDL_SCANCODE_F10, KeyNo_Function10}, 73 | {SDL_SCANCODE_F11, KeyNo_Function11}, 74 | {SDL_SCANCODE_F12, KeyNo_Function12}, 75 | 76 | {SDL_SCANCODE_LSHIFT, KeyNo_ShiftLeft}, 77 | {SDL_SCANCODE_RSHIFT, KeyNo_ShiftRight}, 78 | {SDL_SCANCODE_LCTRL, KeyNo_CtrlLeft}, 79 | {SDL_SCANCODE_RCTRL, KeyNo_CtrlRight}, 80 | {SDL_SCANCODE_LALT, KeyNo_AltLeft}, 81 | {SDL_SCANCODE_RALT, KeyNo_AltRight}, 82 | {SDL_SCANCODE_LGUI, KeyNo_AcornLeft}, 83 | {SDL_SCANCODE_RGUI, KeyNo_AcornRight}, 84 | 85 | {SDL_SCANCODE_GRAVE, KeyNo_BackTick}, 86 | {SDL_SCANCODE_TAB, KeyNo_Tab}, 87 | {SDL_SCANCODE_CAPSLOCK, KeyNo_CapsLock}, 88 | {SDL_SCANCODE_NONUSBACKSLASH, KeyNo_NotFittedLeft}, 89 | {SDL_SCANCODE_SPACE, KeyNo_Space}, 90 | {SDL_SCANCODE_MINUS, KeyNo_Minus}, 91 | {SDL_SCANCODE_EQUALS, KeyNo_Equals}, 92 | {SDL_SCANCODE_BACKSPACE, KeyNo_BackSpace}, 93 | {SDL_SCANCODE_LEFTBRACKET, KeyNo_OpenSquare}, 94 | {SDL_SCANCODE_RIGHTBRACKET, KeyNo_CloseSquare}, 95 | {SDL_SCANCODE_SEMICOLON, KeyNo_SemiColon}, 96 | {SDL_SCANCODE_APOSTROPHE, KeyNo_Tick}, 97 | {SDL_SCANCODE_BACKSLASH, KeyNo_BackSlash}, 98 | {SDL_SCANCODE_RETURN, KeyNo_Return}, 99 | {SDL_SCANCODE_COMMA, KeyNo_Comma}, 100 | {SDL_SCANCODE_PERIOD, KeyNo_Dot}, 101 | {SDL_SCANCODE_SLASH, KeyNo_Slash}, 102 | 103 | {SDL_SCANCODE_PRINTSCREEN, KeyNo_Print}, 104 | {SDL_SCANCODE_SCROLLLOCK, KeyNo_ScrollLock}, 105 | {SDL_SCANCODE_PAUSE, KeyNo_Break}, 106 | {SDL_SCANCODE_F13, KeyNo_Break}, // For chromebook 107 | 108 | {SDL_SCANCODE_INSERT, KeyNo_Insert}, 109 | {SDL_SCANCODE_HOME, KeyNo_Home}, 110 | {SDL_SCANCODE_PAGEUP, KeyNo_PageUp}, 111 | {SDL_SCANCODE_DELETE, KeyNo_Delete}, 112 | {SDL_SCANCODE_END, KeyNo_Copy}, 113 | {SDL_SCANCODE_PAGEDOWN, KeyNo_PageDown}, 114 | 115 | {SDL_SCANCODE_UP, KeyNo_CursorUp}, 116 | {SDL_SCANCODE_RIGHT, KeyNo_CursorRight}, 117 | {SDL_SCANCODE_DOWN, KeyNo_CursorDown}, 118 | {SDL_SCANCODE_LEFT, KeyNo_CursorLeft}, 119 | 120 | {SDL_SCANCODE_NUMLOCKCLEAR, KeyNo_NumLock}, 121 | {SDL_SCANCODE_KP_DIVIDE, KeyNo_NumPadSlash}, 122 | {SDL_SCANCODE_KP_MULTIPLY, KeyNo_NumPadStar}, 123 | {SDL_SCANCODE_KP_MINUS, KeyNo_NumPadMinus}, 124 | {SDL_SCANCODE_KP_7, KeyNo_NumPad7}, 125 | {SDL_SCANCODE_KP_8, KeyNo_NumPad8}, 126 | {SDL_SCANCODE_KP_9, KeyNo_NumPad9}, 127 | {SDL_SCANCODE_KP_PLUS, KeyNo_NumPadPlus}, 128 | {SDL_SCANCODE_KP_4, KeyNo_NumPad4}, 129 | {SDL_SCANCODE_KP_5, KeyNo_NumPad5}, 130 | {SDL_SCANCODE_KP_6, KeyNo_NumPad6}, 131 | {SDL_SCANCODE_KP_1, KeyNo_NumPad1}, 132 | {SDL_SCANCODE_KP_2, KeyNo_NumPad2}, 133 | {SDL_SCANCODE_KP_3, KeyNo_NumPad3}, 134 | {SDL_SCANCODE_KP_ENTER, KeyNo_NumPadEnter}, 135 | {SDL_SCANCODE_KP_0, KeyNo_NumPad0}, 136 | {SDL_SCANCODE_KP_PERIOD, KeyNo_NumPadDot}, 137 | 138 | }; 139 | 140 | int out[SDL_NUM_SCANCODES]; 141 | 142 | int main() { 143 | int max_keycode = 0; 144 | 145 | for(int i = 0; i < sizeof(sdl2key) / sizeof(sdl2key[0]); ++i) { 146 | out[sdl2key[i].sdl] = sdl2key[i].ro; 147 | if (max_keycode < sdl2key[i].ro) max_keycode = sdl2key[i].ro; 148 | } 149 | 150 | printf("int sdl2key[%i] = {\n", SDL_NUM_SCANCODES); 151 | 152 | for(int i = 0; i < SDL_NUM_SCANCODES; ++i) 153 | printf(" %i,\n", out[i]); 154 | 155 | printf("};\n#define max_keycode (%i)\n", max_keycode); 156 | } 157 | -------------------------------------------------------------------------------- /run_RISC_OS: -------------------------------------------------------------------------------- 1 | Unix/LinuxSupport/run_RISC_OS --------------------------------------------------------------------------------