diff options
29 files changed, 553 insertions, 601 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d890dfb13..6dc577ef1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,9 +14,11 @@ jobs: fetch-depth: 0 - name: Install packages run: | + sudo dpkg --add-architecture i386 sudo apt update sudo apt install -y -o Acquire::Retries=50 \ - mtools syslinux isolinux libc6-dev-i386 valgrind + mtools syslinux isolinux \ + libc6-dev-i386 libc6-dbg:i386 valgrind - name: Build (BIOS) run: | make -j 4 -C src diff --git a/src/Makefile.linux b/src/Makefile.linux new file mode 100644 index 000000000..4a7837916 --- /dev/null +++ b/src/Makefile.linux @@ -0,0 +1,39 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Prefix all iPXE symbols to avoid collisions with platform libraries +# +SYMBOL_PREFIX = _ipxe__ + +# Enable valgrind +# +CFLAGS += -UNVALGRIND + +# Use a two-stage link +# +LDFLAGS += -r -d + +# Source directories +# +SRCDIRS += drivers/linux +SRCDIRS += interface/linux +NON_AUTO_SRCS += interface/linux/linux_api.c + +# Media types +# +NON_AUTO_MEDIA = linux + +# Compiler flags for building host API wrapper +# +LINUX_CFLAGS += -Os -idirafter include -DSYMBOL_PREFIX=$(SYMBOL_PREFIX) + +# Host API wrapper +# +$(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) + $(QM)$(ECHO) " [BUILD] $@" + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ -c $< + +# Rule to generate final binary +# +$(BIN)/%.linux : $(BIN)/%.linux.tmp $(BIN)/linux_api.o + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ $^ diff --git a/src/arch/i386/Makefile.linux b/src/arch/i386/Makefile.linux index 46328c83b..fe4229e94 100644 --- a/src/arch/i386/Makefile.linux +++ b/src/arch/i386/Makefile.linux @@ -1,6 +1,14 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Linker script +# LDSCRIPT = arch/i386/scripts/linux.lds -SRCDIRS += arch/i386/core/linux +# Compiler flags for building host API wrapper +# +LINUX_CFLAGS += -m32 +# Include generic Linux Makefile +# MAKEDEPS += arch/x86/Makefile.linux include arch/x86/Makefile.linux diff --git a/src/arch/i386/core/linux/linux_syscall.S b/src/arch/i386/core/linux/linux_syscall.S deleted file mode 100644 index 38a3e74bd..000000000 --- a/src/arch/i386/core/linux/linux_syscall.S +++ /dev/null @@ -1,45 +0,0 @@ - - .section ".data" - .globl linux_errno - -linux_errno: .int 0 - - .section ".text" - .code32 - .globl linux_syscall - .type linux_syscall, @function - -linux_syscall: - /* Save registers */ - pushl %ebx - pushl %esi - pushl %edi - pushl %ebp - - movl 20(%esp), %eax // C arg1 -> syscall number - movl 24(%esp), %ebx // C arg2 -> syscall arg1 - movl 28(%esp), %ecx // C arg3 -> syscall arg2 - movl 32(%esp), %edx // C arg4 -> syscall arg3 - movl 36(%esp), %esi // C arg5 -> syscall arg4 - movl 40(%esp), %edi // C arg6 -> syscall arg5 - movl 44(%esp), %ebp // C arg7 -> syscall arg6 - - int $0x80 - - /* Restore registers */ - popl %ebp - popl %edi - popl %esi - popl %ebx - - cmpl $-4095, %eax - jae 1f - ret - -1: - negl %eax - movl %eax, linux_errno - movl $-1, %eax - ret - - .size linux_syscall, . - linux_syscall diff --git a/src/arch/i386/core/linux/linuxprefix.S b/src/arch/i386/core/linux/linuxprefix.S deleted file mode 100644 index 398d3cb21..000000000 --- a/src/arch/i386/core/linux/linuxprefix.S +++ /dev/null @@ -1,28 +0,0 @@ -#include <linux/unistd.h> - - .section ".text" - .code32 - .globl _linux_start - .type _linux_start, @function - -_linux_start: - xorl %ebp, %ebp - - popl %esi // save argc - movl %esp, %edi // save argv - - andl $~15, %esp // 16-byte align the stack - - pushl %edi // argv -> C arg2 - pushl %esi // argc -> C arg1 - - call save_args - - /* Our main doesn't use any arguments */ - call main - - movl %eax, %ebx // rc -> syscall arg1 - movl $__NR_exit, %eax - int $0x80 - - .size _linux_start, . - _linux_start diff --git a/src/arch/i386/include/bits/linux_api.h b/src/arch/i386/include/bits/linux_api.h deleted file mode 100644 index dc6e7416e..000000000 --- a/src/arch/i386/include/bits/linux_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _I386_LINUX_API_H -#define _I386_LINUX_API_H - -#define __SYSCALL_mmap __NR_mmap2 - -#endif /* _I386_LINUX_API_H */ diff --git a/src/arch/x86/Makefile.linux b/src/arch/x86/Makefile.linux index 3740cc81a..b60065567 100644 --- a/src/arch/x86/Makefile.linux +++ b/src/arch/x86/Makefile.linux @@ -1,15 +1,10 @@ -MEDIA = linux - -# enable valgrind -CFLAGS += -UNVALGRIND - -SYMBOL_PREFIX = _ipxe__ +# -*- makefile -*- : Force emacs to use Makefile mode +# Include x86 Linux headers +# INCDIRS += arch/x86/include/linux -SRCDIRS += interface/linux -SRCDIRS += drivers/linux -SRCDIRS += arch/x86/core/linux -$(BIN)/%.linux : $(BIN)/%.linux.tmp - $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(CP) $< $@ +# Include generic Linux Makefile +# +MAKEDEPS += Makefile.linux +include Makefile.linux diff --git a/src/arch/x86/core/linux/linux_api.c b/src/arch/x86/core/linux/linux_api.c deleted file mode 100644 index 17b1f3fd4..000000000 --- a/src/arch/x86/core/linux/linux_api.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/** @file - * - * Implementation of most of the linux API. - */ - -#include <linux_api.h> - -#include <stdarg.h> -#include <asm/unistd.h> -#include <string.h> - -int linux_open ( const char *pathname, int flags ) { - return linux_syscall ( __NR_open, pathname, flags ); -} - -int linux_close ( int fd ) { - return linux_syscall ( __NR_close, fd ); -} - -off_t linux_lseek ( int fd, off_t offset, int whence ) { - return linux_syscall ( __NR_lseek, fd, offset, whence ); -} - -__kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ) { - return linux_syscall ( __NR_read, fd, buf, count ); -} - -__kernel_ssize_t linux_write ( int fd, const void *buf, - __kernel_size_t count ) { - return linux_syscall ( __NR_write, fd, buf, count ); -} - -int linux_fcntl ( int fd, int cmd, ... ) { - long arg; - va_list list; - - va_start ( list, cmd ); - arg = va_arg ( list, long ); - va_end ( list ); - - return linux_syscall ( __NR_fcntl, fd, cmd, arg ); -} - -int linux_ioctl ( int fd, int request, ... ) { - void *arg; - va_list list; - - va_start ( list, request ); - arg = va_arg ( list, void * ); - va_end ( list ); - - return linux_syscall ( __NR_ioctl, fd, request, arg ); -} - -int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ) { - return linux_syscall ( __NR_poll, fds, nfds, timeout ); -} - -int linux_nanosleep ( const struct timespec *req, struct timespec *rem ) { - return linux_syscall ( __NR_nanosleep, req, rem ); -} - -int linux_usleep ( useconds_t usec ) { - struct timespec ts = { - .tv_sec = ( ( long ) ( usec / 1000000 ) ), - .tv_nsec = ( ( long ) ( usec % 1000000 ) * 1000UL ), - }; - - return linux_nanosleep ( &ts, NULL ); -} - -int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) { - return linux_syscall ( __NR_gettimeofday, tv, tz ); -} - -void * linux_mmap ( void *addr, __kernel_size_t length, int prot, int flags, - int fd, __kernel_off_t offset ) { - return ( void * ) linux_syscall ( __SYSCALL_mmap, addr, length, prot, - flags, fd, offset ); -} - -void * linux_mremap ( void *old_address, __kernel_size_t old_size, - __kernel_size_t new_size, int flags ) { - return ( void * ) linux_syscall ( __NR_mremap, old_address, old_size, - new_size, flags ); -} - -int linux_munmap ( void *addr, __kernel_size_t length ) { - return linux_syscall ( __NR_munmap, addr, length ); -} - -int linux_socket ( int domain, int type_, int protocol ) { -#ifdef __NR_socket - return linux_syscall ( __NR_socket, domain, type_, protocol ); -#else -#ifndef SOCKOP_socket -# define SOCKOP_socket 1 -#endif - unsigned long sc_args[] = { domain, type_, protocol }; - return linux_syscall ( __NR_socketcall, SOCKOP_socket, sc_args ); -#endif -} - -int linux_bind ( int fd, const struct sockaddr *addr, socklen_t addrlen ) { -#ifdef __NR_bind - return linux_syscall ( __NR_bind, fd, addr, addrlen ); -#else -#ifndef SOCKOP_bind -# define SOCKOP_bind 2 -#endif - unsigned long sc_args[] = { fd, (unsigned long)addr, addrlen }; - return linux_syscall ( __NR_socketcall, SOCKOP_bind, sc_args ); -#endif -} - -ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags, - const struct sockaddr *daddr, socklen_t addrlen ) { -#ifdef __NR_sendto - return linux_syscall ( __NR_sendto, fd, buf, len, flags, - daddr, addrlen ); -#else -#ifndef SOCKOP_sendto -# define SOCKOP_sendto 11 -#endif - unsigned long sc_args[] = { fd, (unsigned long)buf, len, - flags, (unsigned long)daddr, addrlen }; - return linux_syscall ( __NR_socketcall, SOCKOP_sendto, sc_args ); -#endif -} diff --git a/src/arch/x86/core/linux/linux_strerror.c b/src/arch/x86/core/linux/linux_strerror.c deleted file mode 100644 index 24c9b7738..000000000 --- a/src/arch/x86/core/linux/linux_strerror.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE(GPL2_OR_LATER); - -/** @file - * - * linux_strerror implementation - */ - -#include <linux_api.h> -#include <stdio.h> - -/** Error names from glibc */ -static const char *errors[] = { - "Success", - "Operation not permitted", - "No such file or directory", - "No such process", - "Interrupted system call", - "Input/output error", - "No such device or address", - "Argument list too long", - "Exec format error", - "Bad file descriptor", - "No child processes", - "Resource temporarily unavailable", - "Cannot allocate memory", - "Permission denied", - "Bad address", - "Block device required", - "Device or resource busy", - "File exists", - "Invalid cross-device link", - "No such device", - "Not a directory", - "Is a directory", - "Invalid argument", - "Too many open files in system", - "Too many open files", - "Inappropriate ioctl for device", - "Text file busy", - "File too large", - "No space left on device", - "Illegal seek", - "Read-only file system", - "Too many links", - "Broken pipe", - "Numerical argument out of domain", - "Numerical result out of range", - "Resource deadlock avoided", - "File name too long", - "No locks available", - "Function not implemented", - "Directory not empty", - "Too many levels of symbolic links", - "", - "No message of desired type", - "Identifier removed", - "Channel number out of range", - "Level 2 not synchronized", - "Level 3 halted", - "Level 3 reset", - "Link number out of range", - "Protocol driver not attached", - "No CSI structure available", - "Level 2 halted", - "Invalid exchange", - "Invalid request descriptor", - "Exchange full", - "No anode", - "Invalid request code", - "Invalid slot", - "", - "Bad font file format", - "Device not a stream", - "No data available", - "Timer expired", - "Out of streams resources", - "Machine is not on the network", - "Package not installed", - "Object is remote", - "Link has been severed", - "Advertise error", - "Srmount error", - "Communication error on send", - "Protocol error", - "Multihop attempted", - "RFS specific error", - "Bad message", - "Value too large for defined data type", - "Name not unique on network", - "File descriptor in bad state", - "Remote address changed", - "Can not access a needed shared library", - "Accessing a corrupted shared library", - ".lib section in a.out corrupted", - "Attempting to link in too many shared libraries", - "Cannot exec a shared library directly", - "Invalid or incomplete multibyte or wide character", - "Interrupted system call should be restarted", - "Streams pipe error", - "Too many users", - "Socket operation on non-socket", - "Destination address required", - "Message too long", - "Protocol wrong type for socket", - "Protocol not available", - "Protocol not supported", - "Socket type not supported", - "Operation not supported", - "Protocol family not supported", - "Address family not supported by protocol", - "Address already in use", - "Cannot assign requested address", - "Network is down", - "Network is unreachable", - "Network dropped connection on reset", - "Software caused connection abort", - "Connection reset by peer", - "No buffer space available", - "Transport endpoint is already connected", - "Transport endpoint is not connected", - "Cannot send after transport endpoint shutdown", - "Too many references: cannot splice", - "Connection timed out", - "Connection refused", - "Host is down", - "No route to host", - "Operation already in progress", - "Operation now in progress", - "Stale NFS file handle", - "Structure needs cleaning", - "Not a XENIX named type file", - "No XENIX semaphores available", - "Is a named type file", - "Remote I/O error", - "Disk quota exceeded", - "No medium found", - "Wrong medium type", -}; - -const char *linux_strerror(int errnum) -{ - static char errbuf[64]; - static int errors_size = sizeof(errors) / sizeof(*errors); - - if (errnum >= errors_size || errnum < 0) { - snprintf(errbuf, sizeof(errbuf), "Error %#08x", errnum); - return errbuf; - } else { - return errors[errnum]; - } -} diff --git a/src/arch/x86/include/bits/linux_api_platform.h b/src/arch/x86/include/bits/linux_api_platform.h deleted file mode 100644 index 4a9ced5e2..000000000 --- a/src/arch/x86/include/bits/linux_api_platform.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_API_PLATFORM_H -#define _LINUX_API_PLATFORM_H - -extern int linux_errno; - -#endif /* _LINUX_API_PLATFORM_H */ diff --git a/src/arch/x86_64/Makefile.linux b/src/arch/x86_64/Makefile.linux index 154f9d40d..c41ee49df 100644 --- a/src/arch/x86_64/Makefile.linux +++ b/src/arch/x86_64/Makefile.linux @@ -1,6 +1,10 @@ -LDSCRIPT = arch/x86_64/scripts/linux.lds +# -*- makefile -*- : Force emacs to use Makefile mode -SRCDIRS += arch/x86_64/core/linux +# Linker script +# +LDSCRIPT = arch/x86_64/scripts/linux.lds +# Include generic Linux Makefile +# MAKEDEPS += arch/x86/Makefile.linux include arch/x86/Makefile.linux diff --git a/src/arch/x86_64/core/linux/linux_syscall.S b/src/arch/x86_64/core/linux/linux_syscall.S deleted file mode 100644 index d2805f94c..000000000 --- a/src/arch/x86_64/core/linux/linux_syscall.S +++ /dev/null @@ -1,33 +0,0 @@ - - .section ".data" - .globl linux_errno - -linux_errno: .int 0 - - .section ".text" - .code64 - .globl linux_syscall - .type linux_syscall, @function - -linux_syscall: - movq %rdi, %rax // C arg1 -> syscall number - movq %rsi, %rdi // C arg2 -> syscall arg1 - movq %rdx, %rsi // C arg3 -> syscall arg2 - movq %rcx, %rdx // C arg4 -> syscall arg3 - movq %r8, %r10 // C arg5 -> syscall arg4 - movq %r9, %r8 // C arg6 -> syscall arg5 - movq 8(%rsp), %r9 // C arg7 -> syscall arg6 - - syscall - - cmpq $-4095, %rax - jae 1f - ret - -1: - negq %rax - movl %eax, linux_errno - movq $-1, %rax - ret - - .size linux_syscall, . - linux_syscall diff --git a/src/arch/x86_64/core/linux/linuxprefix.S b/src/arch/x86_64/core/linux/linuxprefix.S deleted file mode 100644 index ec8a9decd..000000000 --- a/src/arch/x86_64/core/linux/linuxprefix.S +++ /dev/null @@ -1,25 +0,0 @@ -#include <linux/unistd.h> - - .section ".text" - .code64 - .globl _linux_start - .type _linux_start, @function - -_linux_start: - xorq %rbp, %rbp - - popq %rdi // argc -> C arg1 - movq %rsp, %rsi // argv -> C arg2 - - andq $~15, %rsp // 16-byte align the stack - - call save_args - - /* Our main doesn't use any arguments */ - call main - - movq %rax, %rdi // rc -> syscall arg1 - movq $__NR_exit, %rax - syscall - - .size _linux_start, . - _linux_start diff --git a/src/arch/x86_64/include/bits/linux_api.h b/src/arch/x86_64/include/bits/linux_api.h deleted file mode 100644 index 589fb5808..000000000 --- a/src/arch/x86_64/include/bits/linux_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _X86_64_LINUX_API_H -#define _X86_64_LINUX_API_H - -#define __SYSCALL_mmap __NR_mmap - -#endif /* _X86_64_LINUX_API_H */ diff --git a/src/drivers/linux/af_packet.c b/src/drivers/linux/af_packet.c index 65aafc5b1..9fa6ef2a5 100644 --- a/src/drivers/linux/af_packet.c +++ b/src/drivers/linux/af_packet.c @@ -19,7 +19,7 @@ #include <errno.h> #include <string.h> #include <stdio.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <ipxe/list.h> #include <ipxe/linux.h> #include <ipxe/malloc.h> diff --git a/src/drivers/linux/tap.c b/src/drivers/linux/tap.c index db3b7955b..ff1e08bdb 100644 --- a/src/drivers/linux/tap.c +++ b/src/drivers/linux/tap.c @@ -19,7 +19,7 @@ #include <errno.h> #include <string.h> #include <stdio.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <ipxe/list.h> #include <ipxe/linux.h> #include <ipxe/malloc.h> diff --git a/src/hci/linux_args.c b/src/hci/linux_args.c index 5f903e3b6..12020bd0b 100644 --- a/src/hci/linux_args.c +++ b/src/hci/linux_args.c @@ -18,7 +18,6 @@ FILE_LICENCE(GPL2_OR_LATER); -#include <hci/linux_args.h> #include <getopt.h> #include <string.h> #include <stdio.h> @@ -27,21 +26,8 @@ FILE_LICENCE(GPL2_OR_LATER); #include <ipxe/malloc.h> #include <ipxe/init.h> -/** Saved argc */ -static int saved_argc = 0; -/** Saved argv */ -static char ** saved_argv; - -/** - * Save argc and argv for later access. - * - * To be called by linuxprefix - */ -__asmcall void save_args(int argc, char **argv) -{ - saved_argc = argc; - saved_argv = argv; -} +int linux_argc; +char **linux_argv; /** Supported command-line options */ static struct option options[] = { @@ -138,7 +124,7 @@ void linux_args_parse() while (1) { int option_index = 0; - c = getopt_long(saved_argc, saved_argv, "", options, &option_index); + c = getopt_long(linux_argc, linux_argv, "", options, &option_index); if (c == -1) break; diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h new file mode 100644 index 000000000..ea247a613 --- /dev/null +++ b/src/include/ipxe/linux_api.h @@ -0,0 +1,86 @@ +#ifndef _IPXE_LINUX_API_H +#define _IPXE_LINUX_API_H + +/* + * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>. + * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** @file + * + * Linux host API + * + * This file is included from both the iPXE build environment and the + * host build environment. + * + */ + +#if __STDC_HOSTED__ +#define __asmcall +#define FILE_LICENCE(x) +#endif + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> + +#if ! __STDC_HOSTED__ +#define __KERNEL_STRICT_NAMES +#include <linux/time.h> +#include <linux/mman.h> +#include <linux/fcntl.h> +#include <linux/ioctl.h> +#include <linux/poll.h> +#include <linux/fs.h> +#define MAP_FAILED ( ( void * ) -1 ) +#endif + +struct sockaddr; + +extern int linux_errno; +extern int linux_argc; +extern char **linux_argv; + +extern int __asmcall linux_open ( const char *pathname, int flags, ... ); +extern int __asmcall linux_close ( int fd ); +extern off_t __asmcall linux_lseek ( int fd, off_t offset, int whence ); +extern ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ); +extern ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ); +extern int __asmcall linux_fcntl ( int fd, int cmd, ... ); +extern int __asmcall linux_ioctl ( int fd, unsigned long request, ... ); +extern int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, + int timeout ); +extern int __asmcall linux_nanosleep ( const struct timespec *req, + struct timespec *rem ); +extern int __asmcall linux_usleep ( unsigned int usec ); +extern int __asmcall linux_gettimeofday ( struct timeval *tv, + struct timezone *tz ); +extern void * __asmcall linux_mmap ( void *addr, size_t length, int prot, + int flags, int fd, off_t offset ); +extern void * __asmcall linux_mremap ( void *old_address, size_t old_size, + size_t new_size, int flags, ... ); +extern int __asmcall linux_munmap ( void *addr, size_t length ); +extern int __asmcall linux_socket ( int domain, int type, int protocol ); +extern int __asmcall linux_bind ( int sockfd, const struct sockaddr *addr, + size_t addrlen ); +extern ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, + size_t len, int flags, + const struct sockaddr *dest_addr, + size_t addrlen ); +extern const char * __asmcall linux_strerror ( int linux_errno ); + +#endif /* _IPXE_LINUX_API_H */ diff --git a/src/include/linux_api.h b/src/include/linux_api.h deleted file mode 100644 index fe9fa910f..000000000 --- a/src/include/linux_api.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _LINUX_API_H -#define _LINUX_API_H - -/** * @file - * - * Linux API prototypes. - * Most of the functions map directly to linux syscalls and are the equivalent - * of POSIX functions with the linux_ prefix removed. - */ - -FILE_LICENCE(GPL2_OR_LATER); - -#include <bits/linux_api.h> -#include <bits/linux_api_platform.h> - -#include <stdint.h> - -#define __KERNEL_STRICT_NAMES -#include <linux/types.h> -#include <linux/posix_types.h> -typedef __kernel_pid_t pid_t; -typedef __kernel_suseconds_t suseconds_t; -typedef __kernel_loff_t loff_t; -#include <linux/time.h> -#include <linux/mman.h> -#include <linux/fcntl.h> -#include <linux/ioctl.h> -#include <linux/poll.h> -typedef unsigned long nfds_t; -typedef uint32_t useconds_t; -typedef uint32_t socklen_t; -struct sockaddr; -#define MAP_FAILED ( ( void * ) -1 ) -#define SEEK_SET 0 - -extern long linux_syscall ( int number, ... ); - -extern int linux_open ( const char *pathname, int flags ); -extern int linux_close ( int fd ); -extern off_t linux_lseek ( int fd, off_t offset, int whence ); -extern __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ); -extern __kernel_ssize_t linux_write ( int fd, const void *buf, - __kernel_size_t count ); -extern int linux_fcntl ( int fd, int cmd, ... ); -extern int linux_ioctl ( int fd, int request, ... ); -extern int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ); -extern int linux_nanosleep ( const struct timespec *req, struct timespec *rem ); -extern int linux_usleep ( useconds_t usec ); -extern int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ); -extern void * linux_mmap ( void *addr, __kernel_size_t length, int prot, - int flags, int fd, off_t offset ); -extern void * linux_mremap ( void *old_address, __kernel_size_t old_size, - __kernel_size_t new_size, int flags ); -extern int linux_munmap ( void *addr, __kernel_size_t length ); -extern int linux_socket ( int domain, int type_, int protocol ); -extern int linux_bind ( int fd, const struct sockaddr *addr, - socklen_t addrlen ); -extern ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags, - const struct sockaddr *daddr, socklen_t addrlen ); - -extern const char * linux_strerror ( int errnum ); - -#endif /* _LINUX_API_H */ diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c new file mode 100644 index 000000000..4ab3c6603 --- /dev/null +++ b/src/interface/linux/linux_api.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>. + * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <poll.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <ipxe/linux_api.h> + +/** @file + * + * Linux host API + * + */ + +/** Construct prefixed symbol name */ +#define _C1( x, y ) x ## y +#define _C2( x, y ) _C1 ( x, y ) + +/** Construct prefixed symbol name for iPXE symbols */ +#define IPXE_SYM( symbol ) _C2 ( SYMBOL_PREFIX, symbol ) + +/** Provide a prefixed symbol alias visible to iPXE code */ +#define PROVIDE_IPXE_SYM( symbol ) \ + extern typeof ( symbol ) IPXE_SYM ( symbol ) \ + __attribute__ (( alias ( #symbol) )) + +/** Most recent system call error */ +int linux_errno __attribute__ (( nocommon )); + +/****************************************************************************** + * + * Host entry point + * + ****************************************************************************** + */ + +extern int IPXE_SYM ( _linux_start ) ( int argc, char **argv ); + +/** + * Main entry point + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Exit status + */ +int main ( int argc, char **argv ) { + + return IPXE_SYM ( _linux_start ) ( argc, argv ); +} + +/****************************************************************************** + * + * System call wrappers + * + ****************************************************************************** + */ + +/** + * Wrap open() + * + */ +int __asmcall linux_open ( const char *pathname, int flags, ... ) { + va_list args; + mode_t mode; + int ret; + + va_start ( args, flags ); + mode = va_arg ( args, mode_t ); + va_end ( args ); + ret = open ( pathname, flags, mode ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap close() + * + */ +int __asmcall linux_close ( int fd ) { + int ret; + + ret = close ( fd ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap lseek() + * + */ +off_t __asmcall linux_lseek ( int fd, off_t offset, int whence ) { + off_t ret; + + ret = lseek ( fd, offset, whence ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap read() + * + */ +ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ) { + ssize_t ret; + + ret = read ( fd, buf, count ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap write() + * + */ +ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ) { + ssize_t ret; + + ret = write ( fd, buf, count ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap fcntl() + * + */ +int __asmcall linux_fcntl ( int fd, int cmd, ... ) { + va_list args; + long arg; + int ret; + + va_start ( args, cmd ); + arg = va_arg ( args, long ); + va_end ( args ); + ret = fcntl ( fd, cmd, arg ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap ioctl() + * + */ +int __asmcall linux_ioctl ( int fd, unsigned long request, ... ) { + va_list args; + void *arg; + int ret; + + va_start ( args, request ); + arg = va_arg ( args, void * ); + va_end ( args ); + ret = ioctl ( fd, request, arg ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap poll() + * + */ +int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, + int timeout ) { + int ret; + + ret = poll ( fds, nfds, timeout ); + if ( ret == -1 ) + linux_errno = errno; +} + +/** + * Wrap nanosleep() + * + */ +int __asmcall linux_nanosleep ( const struct timespec *req, + struct timespec *rem ) { + int ret; + + ret = nanosleep ( req, rem ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap usleep() + * + */ +int __asmcall linux_usleep ( unsigned int usec ) { + int ret; + + ret = usleep ( usec ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap gettimeofday() + * + */ +int __asmcall linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) { + int ret; + + ret = gettimeofday ( tv, tz ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap mmap() + * +*/ +void * __asmcall linux_mmap ( void *addr, size_t length, int prot, int flags, + int fd, off_t offset ) { + void *ret; + + ret = mmap ( addr, length, prot, flags, fd, offset ); + if ( ret == MAP_FAILED ) + linux_errno = errno; + return ret; +} + +/** + * Wrap mremap() + * + */ +void * __asmcall linux_mremap ( void *old_address, size_t old_size, + size_t new_size, int flags, ... ) { + va_list args; + void *new_address; + void *ret; + + va_start ( args, flags ); + new_address = va_arg ( args, void * ); + va_end ( args ); + ret = mremap ( old_address, old_size, new_size, flags, new_address ); + if ( ret == MAP_FAILED ) + linux_errno = errno; + return ret; +} + +/** + * Wrap munmap() + * + */ +int __asmcall linux_munmap ( void *addr, size_t length ) { + int ret; + + ret = munmap ( addr, length ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap socket() + * + */ +int __asmcall linux_socket ( int domain, int type, int protocol ) { + int ret; + + ret = socket ( domain, type, protocol ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap bind() + * + */ +int __asmcall linux_bind ( int sockfd, const struct sockaddr *addr, + size_t addrlen ) { + int ret; + + ret = bind ( sockfd, addr, addrlen ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap sendto() + * + */ +ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, size_t len, + int flags, const struct sockaddr *dest_addr, + size_t addrlen ) { + ssize_t ret; + + ret = sendto ( sockfd, buf, len, flags, dest_addr, addrlen ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/****************************************************************************** + * + * C library wrappers + * + ****************************************************************************** + */ + +/** + * Wrap strerror() + * + */ +const char * __asmcall linux_strerror ( int linux_errno ) { + + return strerror ( linux_errno ); +} + +/****************************************************************************** + * + * Symbol aliases + * + ****************************************************************************** + */ + +PROVIDE_IPXE_SYM ( linux_errno ); +PROVIDE_IPXE_SYM ( linux_open ); +PROVIDE_IPXE_SYM ( linux_close ); +PROVIDE_IPXE_SYM ( linux_lseek ); +PROVIDE_IPXE_SYM ( linux_read ); +PROVIDE_IPXE_SYM ( linux_write ); +PROVIDE_IPXE_SYM ( linux_fcntl ); +PROVIDE_IPXE_SYM ( linux_ioctl ); +PROVIDE_IPXE_SYM ( linux_poll ); +PROVIDE_IPXE_SYM ( linux_nanosleep ); +PROVIDE_IPXE_SYM ( linux_usleep ); +PROVIDE_IPXE_SYM ( linux_gettimeofday ); +PROVIDE_IPXE_SYM ( linux_mmap ); +PROVIDE_IPXE_SYM ( linux_mremap ); +PROVIDE_IPXE_SYM ( linux_munmap ); +PROVIDE_IPXE_SYM ( linux_socket ); +PROVIDE_IPXE_SYM ( linux_bind ); +PROVIDE_IPXE_SYM ( linux_sendto ); +PROVIDE_IPXE_SYM ( linux_strerror ); diff --git a/src/interface/linux/linux_console.c b/src/interface/linux/linux_console.c index 5294fca79..d5415b61c 100644 --- a/src/interface/linux/linux_console.c +++ b/src/interface/linux/linux_console.c @@ -28,7 +28,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include <ipxe/init.h> #include <ipxe/keys.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <linux/termios.h> #include <asm/errno.h> diff --git a/src/interface/linux/linux_entropy.c b/src/interface/linux/linux_entropy.c index 0f8e45d36..257e993a0 100644 --- a/src/interface/linux/linux_entropy.c +++ b/src/interface/linux/linux_entropy.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <errno.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <ipxe/entropy.h> /** Entropy source filename */ diff --git a/src/interface/linux/linux_nap.c b/src/interface/linux/linux_nap.c index f1d3cd962..3e77bc7f1 100644 --- a/src/interface/linux/linux_nap.c +++ b/src/interface/linux/linux_nap.c @@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include <ipxe/nap.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> /** @file * diff --git a/src/interface/linux/linux_pci.c b/src/interface/linux/linux_pci.c index 0c140cb89..99c629c19 100644 --- a/src/interface/linux/linux_pci.c +++ b/src/interface/linux/linux_pci.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdio.h> #include <errno.h> #include <byteswap.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <ipxe/linux.h> #include <ipxe/pci.h> diff --git a/src/interface/linux/linux_smbios.c b/src/interface/linux/linux_smbios.c index 6e5174d23..494a60bd9 100644 --- a/src/interface/linux/linux_smbios.c +++ b/src/interface/linux/linux_smbios.c @@ -20,7 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <ipxe/linux.h> #include <ipxe/smbios.h> diff --git a/src/interface/linux/linux_time.c b/src/interface/linux/linux_time.c index 9e99fe9cd..9d410f8e0 100644 --- a/src/interface/linux/linux_time.c +++ b/src/interface/linux/linux_time.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <stddef.h> #include <errno.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> #include <ipxe/time.h> /** diff --git a/src/interface/linux/linux_timer.c b/src/interface/linux/linux_timer.c index 9c5e96f2b..418fd046a 100644 --- a/src/interface/linux/linux_timer.c +++ b/src/interface/linux/linux_timer.c @@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include <stddef.h> #include <ipxe/timer.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> /** @file * diff --git a/src/interface/linux/linux_umalloc.c b/src/interface/linux/linux_umalloc.c index aa0052c53..a7250fa5b 100644 --- a/src/interface/linux/linux_umalloc.c +++ b/src/interface/linux/linux_umalloc.c @@ -29,7 +29,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include <assert.h> #include <ipxe/umalloc.h> -#include <linux_api.h> +#include <ipxe/linux_api.h> /** Special address returned for empty allocations */ #define NOWHERE ((void *)-1) diff --git a/src/include/hci/linux_args.h b/src/interface/linux/linuxprefix.c index ae1ed0526..f38236202 100644 --- a/src/include/hci/linux_args.h +++ b/src/interface/linux/linuxprefix.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com> + * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,19 +13,26 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ -#ifndef _HCI_LINUX_ARGS_H -#define _HCI_LINUX_ARGS_H - -FILE_LICENCE(GPL2_OR_LATER); +#include <stdlib.h> +#include <ipxe/linux_api.h> /** - * Save argc and argv for later access. + * Linux entry point * - * To be called by linuxprefix + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code */ -extern __asmcall void save_args(int argc, char **argv); +int __asmcall _linux_start ( int argc, char **argv ) { + + /* Store command-line arguments */ + linux_argc = argc; + linux_argv = argv; -#endif /* _HCI_LINUX_ARGS_H */ + /* Run iPXE */ + return main(); +} |