diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-07-07 13:22:53 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-11 00:08:15 +0100 |
| commit | 7861a52adf92a083bb2aed4c35f98d8035dce032 (patch) | |
| tree | 28cd3c40e4c878f730f5df3c1d93bdf91af490c3 /tools | |
| parent | 7fc48e9216ff809da5f8055a50b0be17628ef1df (diff) | |
Setup project skeleton
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/CMakeLists.txt | 37 | ||||
| -rwxr-xr-x | tools/elf2exe.c | 250 | ||||
| m--------- | tools/nwc | 0 | ||||
| -rw-r--r-- | tools/tun2tcp/CMakeLists.txt | 21 | ||||
| -rw-r--r-- | tools/tun2tcp/README.md | 13 | ||||
| -rw-r--r-- | tools/tun2tcp/tun2tcp.c | 160 |
6 files changed, 477 insertions, 4 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index afb5355..682781f 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,9 +1,38 @@ +# wnix, a Unix-like operating system for WebAssembly applications. +# Copyright (C) 2025 Xavier Del Campo Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + cmake_minimum_required(VERSION 3.13) -project(utils) +project(tools) +set(MKPSXISO_NO_LIBFLAC ON) add_subdirectory(mkpsxiso) -add_executable(container "container.c") -add_executable(add-header "add-header.c") +add_subdirectory(nwc) +add_executable(container container.c) +add_executable(add-header add-header.c) +add_executable(elf2exe elf2exe.c) set(cflags -Wall -g3) target_compile_options(container PUBLIC ${cflags}) target_compile_options(add-header PUBLIC ${cflags}) -install(TARGETS container add-header DESTINATION bin) +target_compile_options(elf2exe PUBLIC ${cflags}) +target_compile_definitions(elf2exe + PRIVATE OBJCOPY_PATH=\"mipsel-unknown-elf-objcopy\") +install(TARGETS container add-header elf2exe nwc DESTINATION bin) + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_subdirectory(tun2tcp) +else() + message(STATUS "CMAKE_SYSTEM_NAME (${CMAKE_SYSTEM_NAME}) is not Linux, " + "skipping tun2tcp") +endif() diff --git a/tools/elf2exe.c b/tools/elf2exe.c new file mode 100755 index 0000000..8ce3702 --- /dev/null +++ b/tools/elf2exe.c @@ -0,0 +1,250 @@ +/*
+ * Original source code from PSXSDK, by Giuseppe Gata.
+ * Released under a weak copyleft-like license, pasted below:
+ *
+ * You can use this library for any project, commercial and non-commercial,
+ * open-source and closed-source. But if you modify the library, you must
+ * redistribute the source for the modifications you did to it.
+ * Not doing that constitutes an infringement of this license.
+ * You are not obliged to redistribute the source code of this library if it
+ * was not modified at all by you or anyone related to you.
+ *
+ * There is no advertising clause; you aren't obliged to mention this library
+ * in any documentation of your work using it; however, it would be a nice gesture
+ * if you did so.
+ *
+ * These terms were written to not make people close this work which was released
+ * for all to share. In fact, no use is otherwise restricted.
+ */
+
+/*
+ * elf2exe
+ *
+ * Converts an ELF executable to PS-EXE, using objcopy
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const unsigned char psexe_magic[8] = {'P','S','-','X',' ','E','X','E'};
+const char *psexe_marker_usa = "Sony Computer Entertainment Inc. for North America area";
+const char *psexe_marker_jpn = "Sony Computer Entertainment Inc. for Japan area";
+const char *psexe_marker_eur = "Sony Computer Entertainment Inc. for Europe area";
+char *psexe_marker;
+
+//#define OBJCOPY_PATH "mipsel-unknown-elf-objcopy"
+
+int main(int argc, char *argv[])
+{
+ FILE *objcopy_out, *psexe;
+ char stringbuf[2048];
+ unsigned char charbuf;
+ int x;
+ unsigned int sz;
+ unsigned int gp = 0;
+
+ if(argc < 3)
+ {
+ printf("elf2exe - Converts an ELF executable to PS-EXE\n");
+ printf("usage: elf2exe [elf] [ps-x exe] <options>\n");
+ printf("\n");
+ printf("Options:\n");
+ printf("-mark_jpn - Use Japanese ascii marker (default: USA)\n");
+ printf("-mark_eur - Use European ascii marker (default: USA)\n");
+ printf("-mark=<mark> - Use custom ascii marker <mark>\n");
+ return -1;
+ }
+
+ psexe_marker = (char*)psexe_marker_usa;
+
+ for(x = 3; x < argc; x++)
+ {
+ if(strcmp(argv[x], "-mark_jpn") == 0)
+ psexe_marker = (char*)psexe_marker_jpn;
+
+ if(strcmp(argv[x], "-mark_eur") == 0)
+ psexe_marker = (char*)psexe_marker_eur;
+
+ if(strncmp(argv[x], "-mark=", 6) == 0)
+ {
+ if(strlen(argv[x]) >= 7)
+ psexe_marker = argv[x] + 6;
+ }
+
+ if(strncmp(argv[x], "-gp=", 4) == 0)
+ {
+ if(strlen(argv[x]) >= 5)
+ sscanf(argv[x] + 4, "%x", &gp);
+ }
+ }
+
+/*
+ * Now open the output file
+ */
+
+ psexe = fopen(argv[2], "wb");
+
+ if(psexe == NULL)
+ {
+ printf("Couldn't open %s for writing. Aborting!\n", argv[2]);
+ return -1;
+ }
+
+/*
+ * Write PSEXE magic string
+ */
+ fwrite(psexe_magic, sizeof(char), 8, psexe);
+
+/*
+ * Seek output file to 0x10, Initial Program Counter
+ */
+ fseek(psexe, 0x10, SEEK_SET);
+
+/*
+ * Write initial program counter = 0x80010000
+ */
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x01;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Global Pointer
+ */
+ charbuf = gp & 0xff;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff00) >> 8;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff0000) >> 16;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff000000) >> 24;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Seek output file to 0x18, Text section start address
+ */
+ fseek(psexe, 0x18, SEEK_SET);
+
+/*
+ * Write text section start address = 0
+ */
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x01;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Seek output file to 0x30, Initial Stack Pointer
+ */
+ fseek(psexe, 0x30, SEEK_SET);
+
+/*
+ * Write Initial Stack Pointer = 0x801FFFF0
+ */
+ charbuf = 0xF0;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0xFF;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x1F;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+
+/*
+ * Seek output to 0x4C, ASCII marker
+ */
+ fseek(psexe, 0x4C, SEEK_SET);
+
+ x = 0;
+
+/*
+ * Write ASCII marker string
+ */
+ while(psexe_marker[x])
+ fwrite(&psexe_marker[x++], sizeof(char), 1, psexe);
+
+/*
+ * Run objcopy now
+ */
+ sprintf(stringbuf, OBJCOPY_PATH" -O binary %s %s.bin", argv[1], argv[1]);
+ system(stringbuf);
+
+ sprintf(stringbuf, "%s.bin", argv[1]);
+
+/*
+ * Open objcopy output
+ */
+
+ objcopy_out = fopen(stringbuf, "rb");
+ if(objcopy_out == NULL)
+ {
+ printf("Could not open objcopy output at %s. Check your permissions. Aborting.\n",
+ stringbuf);
+ return -1;
+ }
+
+/*
+ * Seek to 0x800, Program Start
+ * and write the output of objcopy into the PS-X EXE
+ */
+ fseek(psexe, 0x800, SEEK_SET);
+
+ while(!feof(objcopy_out))
+ {
+ x = fgetc(objcopy_out);
+ fputc(x, psexe);
+ }
+
+
+ fclose(objcopy_out);
+
+/*
+ * Get the file size of the PS-X EXE
+ */
+ fseek(psexe, 0, SEEK_END);
+ sz = ftell(psexe);
+ fseek(psexe, 0, SEEK_SET);
+
+ if(sz % 2048 != 0)
+ {
+ fseek(psexe, (((sz / 2048) + 1)*2048) - 1, SEEK_SET);
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ sz = ftell(psexe);
+ }
+
+/*
+ * Write the address of the text section in the header of the PS-X EXE
+ */
+
+ sz -= 0x800;
+
+ fseek(psexe, 0x1C, SEEK_SET);
+
+ charbuf = sz & 0xff;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff00) >> 8;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff0000) >> 16;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff000000) >> 24;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+ fclose(psexe);
+
+/*
+ * Remove objcopy output
+ */
+ sprintf(stringbuf, "%s.bin", argv[1]);
+ remove(stringbuf);
+
+ return 0;
+}
diff --git a/tools/nwc b/tools/nwc -Subproject 1a9ca72b3b88054403995ce71887d09052f4ef4 +Subproject 15d2bb51e092d6dc34fa5fb5c1eb9b64c7c597b diff --git a/tools/tun2tcp/CMakeLists.txt b/tools/tun2tcp/CMakeLists.txt new file mode 100644 index 0000000..674aef6 --- /dev/null +++ b/tools/tun2tcp/CMakeLists.txt @@ -0,0 +1,21 @@ +# wnix, a Unix-like operating system for WebAssembly applications. +# Copyright (C) 2025 Xavier Del Campo Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +cmake_minimum_required(VERSION 3.13) +project(tun2tcp C) +add_executable(${PROJECT_NAME} tun2tcp.c) +target_compile_options(${PROJECT_NAME} PUBLIC ${cflags}) +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/tools/tun2tcp/README.md b/tools/tun2tcp/README.md new file mode 100644 index 0000000..9fcc641 --- /dev/null +++ b/tools/tun2tcp/README.md @@ -0,0 +1,13 @@ +# tun2serial + +```sh +# setcap cap_net_admin+ep ./tun2serial +# sudo ip addr add 10.0.0.1/24 dev tun0 +# sudo ip link set tun0 up +# socat TCP-L:6699 /dev/ttyUSB0,rawer,b1200 +``` + +## Thanks + +- https://backreference.org/2010/03/26/tuntap-interface-tutorial/index.html +- https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/ diff --git a/tools/tun2tcp/tun2tcp.c b/tools/tun2tcp/tun2tcp.c new file mode 100644 index 0000000..4b6615f --- /dev/null +++ b/tools/tun2tcp/tun2tcp.c @@ -0,0 +1,160 @@ + +/* + * wnix, a Unix-like operating system for WebAssembly applications. + * Copyright (C) 2025 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <net/if.h> +#include <linux/if.h> +#include <linux/if_tun.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +static int getport(const char *const s, unsigned short *const port) +{ + char *end; + unsigned long v; + + errno = 0; + v = strtoull(s, &end, 10); + + if (errno || *end || v > USHRT_MAX) + return -1; + + *port = v; + return 0; +} + +int main(int argc, char *argv[]) +{ + static const char path[] = "/dev/net/tun"; + char *s = NULL; + int ret = EXIT_FAILURE, cfd = -1, tfd = -1; + unsigned short port; + + if (argc != 2) + { + fprintf(stderr, "%s <port>\n", *argv); + goto end; + } + else if (getport(argv[1], &port)) + { + fprintf(stderr, "invalid port: %s\n", argv[1]); + goto end; + } + else if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("socket(2)"); + goto end; + } + + const struct sockaddr_in addr = + { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr("127.0.0.1"), + .sin_port = htons(port) + }; + + const struct ifreq ifr = {.ifr_flags = IFF_TUN | IFF_NO_PI}; + + if (connect(cfd, (const struct sockaddr *)&addr, sizeof addr)) + { + perror("connect(2)"); + goto end; + } + else if ((tfd = open(path, O_RDWR)) < 0) + { + fprintf(stderr, "open(2) %s: %s\n", path, strerror(errno)); + goto end; + } + else if (ioctl(tfd, TUNSETIFF, &ifr) < 0) + { + perror("ioctl(2)"); + goto end; + } + else if (!(s = strdup(ifr.ifr_name))) + { + perror("strdup(3)"); + goto end; + } + + fprintf(stderr, "set up TUN device %s\n", s); + unsigned long long total = 0; + + for (;;) + { + char b[1500]; + ssize_t n = read(tfd, &b, sizeof b); + + if (n < 0) + { + perror("read(2)"); + goto end; + } + + fprintf(stderr, "read %zu bytes\n", n); + + size_t rem = n; + + while (rem) + { + const void *p = b; + + fprintf(stderr, "sending %zu bytes\n", rem); + + if ((n = write(cfd, p, rem)) < 0) + { + perror("write(2)"); + goto end; + } + + fprintf(stderr, "sent %zu bytes, total: %llu\n", n, total += n); + + p = (const char *)p + n; + rem -= n; + } + } + + ret = EXIT_SUCCESS; + +end: + + if (cfd >= 0 && close(cfd)) + { + ret = EXIT_FAILURE; + perror("close(2)"); + } + + if (tfd >= 0 && close(tfd)) + { + ret = EXIT_FAILURE; + fprintf(stderr, "close(2) %s: %s\n", path, strerror(errno)); + } + + free(s); + return ret; +} |
