aboutsummaryrefslogtreecommitdiffstats
path: root/src/interface
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2021-02-28 13:45:58 +0000
committerMichael Brown <mcb30@ipxe.org>2021-02-28 23:28:23 +0000
commitf309d7a7b78eec10621bc71f9401d5b9257f9f39 (patch)
tree118bfa718065739e8f21e776b515c6457a68d221 /src/interface
parent040cdd0c658a49694b17a1c0b5439d0bd7805242 (diff)
downloadipxe-f309d7a7b78eec10621bc71f9401d5b9257f9f39.tar.gz
[linux] Use host glibc system call wrappers
When building as a Linux userspace application, iPXE currently implements its own system calls to the host kernel rather than relying on the host's C library. The output binary is statically linked and has no external dependencies. This matches the general philosophy of other platforms on which iPXE runs, since there are no external libraries available on either BIOS or UEFI bare metal. However, it would be useful for the Linux userspace application to be able to link against host libraries such as libslirp. Modify the build process to perform a two-stage link: first picking out the requested objects in the usual way from blib.a but with relocations left present, then linking again with a helper object to create a standard hosted application. The helper object provides the standard main() entry point and wrappers for the Linux system calls required by the iPXE Linux drivers and interface code. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface')
-rw-r--r--src/interface/linux/linux_api.c373
-rw-r--r--src/interface/linux/linux_console.c2
-rw-r--r--src/interface/linux/linux_entropy.c2
-rw-r--r--src/interface/linux/linux_nap.c2
-rw-r--r--src/interface/linux/linux_pci.c2
-rw-r--r--src/interface/linux/linux_smbios.c2
-rw-r--r--src/interface/linux/linux_time.c2
-rw-r--r--src/interface/linux/linux_timer.c2
-rw-r--r--src/interface/linux/linux_umalloc.c2
-rw-r--r--src/interface/linux/linuxprefix.c38
10 files changed, 419 insertions, 8 deletions
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/interface/linux/linuxprefix.c b/src/interface/linux/linuxprefix.c
new file mode 100644
index 000000000..f38236202
--- /dev/null
+++ b/src/interface/linux/linuxprefix.c
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <ipxe/linux_api.h>
+
+/**
+ * Linux entry point
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Return status code
+ */
+int __asmcall _linux_start ( int argc, char **argv ) {
+
+ /* Store command-line arguments */
+ linux_argc = argc;
+ linux_argv = argv;
+
+ /* Run iPXE */
+ return main();
+}