mirror of
https://github.com/ipxe/ipxe
synced 2025-12-26 01:22:37 +03:00
[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>
This commit is contained in:
373
src/interface/linux/linux_api.c
Normal file
373
src/interface/linux/linux_api.c
Normal file
@@ -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 );
|
||||
@@ -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>
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER);
|
||||
|
||||
#include <ipxe/nap.h>
|
||||
|
||||
#include <linux_api.h>
|
||||
#include <ipxe/linux_api.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
|
||||
38
src/interface/linux/linuxprefix.c
Normal file
38
src/interface/linux/linuxprefix.c
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user