diff options
Diffstat (limited to 'qemu/roms/ipxe/src/interface/linux')
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_console.c | 155 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_entropy.c | 97 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_nap.c | 41 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_pci.c | 185 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_smbios.c | 115 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_time.c | 46 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_timer.c | 87 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_uaccess.c | 39 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/interface/linux/linux_umalloc.c | 154 |
9 files changed, 919 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/interface/linux/linux_console.c b/qemu/roms/ipxe/src/interface/linux/linux_console.c new file mode 100644 index 000000000..5105eaa94 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_console.c @@ -0,0 +1,155 @@ +/* + * 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 console implementation. + * + */ + +#include <ipxe/console.h> + +#include <ipxe/init.h> +#include <ipxe/keys.h> +#include <linux_api.h> + +#include <linux/termios.h> +#include <asm/errno.h> + +#include <config/console.h> + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_LINUX ) && CONSOLE_EXPLICIT ( CONSOLE_LINUX ) ) +#undef CONSOLE_LINUX +#define CONSOLE_LINUX ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) +#endif + +static void linux_console_putchar(int c) +{ + /* write to stdout */ + if (linux_write(1, &c, 1) != 1) + DBG("linux_console write failed (%s)\n", linux_strerror(linux_errno)); +} + +static int linux_console_getchar() +{ + char c; + + /* read from stdin */ + if (linux_read(0, &c, 1) < 0) { + DBG("linux_console read failed (%s)\n", linux_strerror(linux_errno)); + return 0; + } + /* backspace seems to be returned as ascii del, map it here */ + if (c == 0x7f) + return KEY_BACKSPACE; + else + return c; +} + +static int linux_console_iskey() +{ + struct pollfd pfd; + pfd.fd = 0; + pfd.events = POLLIN; + + /* poll for data to be read on stdin */ + if (linux_poll(&pfd, 1, 0) == -1) { + DBG("linux_console poll failed (%s)\n", linux_strerror(linux_errno)); + return 0; + } + + if (pfd.revents & POLLIN) + return 1; + else + return 0; +} + +struct console_driver linux_console __console_driver = { + .disabled = 0, + .putchar = linux_console_putchar, + .getchar = linux_console_getchar, + .iskey = linux_console_iskey, + .usage = CONSOLE_LINUX, +}; + +static int linux_tcgetattr(int fd, struct termios *termios_p) +{ + return linux_ioctl(fd, TCGETS, termios_p); +} + +static int linux_tcsetattr(int fd, int optional_actions, const struct termios *termios_p) +{ + unsigned long int cmd; + + switch (optional_actions) + { + case TCSANOW: + cmd = TCSETS; + break; + case TCSADRAIN: + cmd = TCSETSW; + break; + case TCSAFLUSH: + cmd = TCSETSF; + break; + default: + linux_errno = EINVAL; + return -1; + } + + return linux_ioctl(fd, cmd, termios_p); +} + +/** Saved termios attributes */ +static struct termios saved_termios; + +/** Setup the terminal for our use */ +static void linux_console_startup(void) +{ + struct termios t; + + if (linux_tcgetattr(0, &t)) { + DBG("linux_console tcgetattr failed (%s)", linux_strerror(linux_errno)); + return; + } + + saved_termios = t; + + /* Disable canonical mode and echo. Let readline handle that */ + t.c_lflag &= ~(ECHO | ICANON); + /* stop ^C from sending a signal */ + t.c_cc[VINTR] = 0; + + if (linux_tcsetattr(0, TCSAFLUSH, &t)) + DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno)); +} + +/** Restores original terminal attributes on shutdown */ +static void linux_console_shutdown(int flags __unused) +{ + if (linux_tcsetattr(0, TCSAFLUSH, &saved_termios)) + DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno)); +} + +struct startup_fn linux_console_startup_fn __startup_fn(STARTUP_EARLY) = { + .startup = linux_console_startup, + .shutdown = linux_console_shutdown, +}; diff --git a/qemu/roms/ipxe/src/interface/linux/linux_entropy.c b/qemu/roms/ipxe/src/interface/linux/linux_entropy.c new file mode 100644 index 000000000..4671a48da --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_entropy.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Linux entropy source + * + */ + +#include <stdint.h> +#include <errno.h> +#include <linux_api.h> +#include <ipxe/entropy.h> + +/** Entropy source filename */ +static const char entropy_filename[] = "/dev/random"; + +/** Entropy source file handle */ +static int entropy_fd; + +/** + * Enable entropy gathering + * + * @ret rc Return status code + */ +static int linux_entropy_enable ( void ) { + + /* Open entropy source */ + entropy_fd = linux_open ( entropy_filename, O_RDONLY ); + if ( entropy_fd < 0 ) { + DBGC ( &entropy_fd, "ENTROPY could not open %s: %s\n", + entropy_filename, linux_strerror ( linux_errno ) ); + return entropy_fd; + } + + return 0; +} + +/** + * Disable entropy gathering + * + */ +static void linux_entropy_disable ( void ) { + + /* Close entropy source */ + linux_close ( entropy_fd ); +} + +/** + * Get noise sample + * + * @ret noise Noise sample + * @ret rc Return status code + */ +static int linux_get_noise ( noise_sample_t *noise ) { + uint8_t byte; + ssize_t len; + + /* Read a single byte from entropy source */ + len = linux_read ( entropy_fd, &byte, sizeof ( byte ) ); + if ( len < 0 ) { + DBGC ( &entropy_fd, "ENTROPY could not read from %s: %s\n", + entropy_filename, linux_strerror ( linux_errno ) ); + return len; + } + if ( len == 0 ) { + DBGC ( &entropy_fd, "ENTROPY EOF on reading from %s: %s\n", + entropy_filename, linux_strerror ( linux_errno ) ); + return -EPIPE; + } + *noise = byte; + + return 0; +} + +PROVIDE_ENTROPY_INLINE ( linux, min_entropy_per_sample ); +PROVIDE_ENTROPY ( linux, entropy_enable, linux_entropy_enable ); +PROVIDE_ENTROPY ( linux, entropy_disable, linux_entropy_disable ); +PROVIDE_ENTROPY ( linux, get_noise, linux_get_noise ); diff --git a/qemu/roms/ipxe/src/interface/linux/linux_nap.c b/qemu/roms/ipxe/src/interface/linux/linux_nap.c new file mode 100644 index 000000000..f1d3cd962 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_nap.c @@ -0,0 +1,41 @@ +/* + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE(GPL2_OR_LATER); + +#include <ipxe/nap.h> + +#include <linux_api.h> + +/** @file + * + * iPXE CPU sleeping API for linux + * + */ + +/** + * Sleep until next CPU interrupt + * + */ +static void linux_cpu_nap(void) +{ + linux_usleep(0); +} + +PROVIDE_NAP(linux, cpu_nap, linux_cpu_nap); diff --git a/qemu/roms/ipxe/src/interface/linux/linux_pci.c b/qemu/roms/ipxe/src/interface/linux/linux_pci.c new file mode 100644 index 000000000..cbd825c18 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_pci.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2013 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 (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 + * 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <errno.h> +#include <byteswap.h> +#include <linux_api.h> +#include <ipxe/linux.h> +#include <ipxe/pci.h> + +/** @file + * + * iPXE PCI API for Linux + * + */ + +/** + * Open PCI configuration space + * + * @v pci PCI device + * @v flags Access mode flags + * @v where Address within configuration space + * @ret fd File handle, or negative error + */ +static int linux_pci_open ( struct pci_device *pci, int flags, + unsigned long where ) { + char filename[ 22 /* "/proc/bus/pci/xx/xx.x" + NUL */ ]; + int fd; + int rc; + + /* Construct filename */ + snprintf ( filename, sizeof ( filename ), "/proc/bus/pci/%02x/%02x.%x", + PCI_BUS ( pci->busdevfn ), PCI_SLOT ( pci->busdevfn ), + PCI_FUNC ( pci->busdevfn ) ); + + /* Open file */ + fd = linux_open ( filename, flags ); + if ( fd < 0 ) { + DBGC ( pci, "PCI could not open %s: %s\n", filename, + linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_open; + } + + /* Seek to location */ + if ( linux_lseek ( fd, where, SEEK_SET ) < 0 ) { + DBGC ( pci, "PCI could not seek to %s offset %#02lx: %s\n", + filename, where, linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_seek; + } + + return fd; + + err_seek: + linux_close ( fd ); + err_open: + return rc; +} + +/** + * Read from PCI configuration space + * + * @v pci PCI device + * @v where Address within configuration space + * @v value Data buffer + * @v len Length to read + * @ret rc Return status code + */ +int linux_pci_read ( struct pci_device *pci, unsigned long where, + unsigned long *value, size_t len ) { + uint32_t tmp = 0; + int fd; + int check_len; + int rc; + + /* Return "missing device" in case of error */ + *value = -1UL; + + /* Open configuration space */ + fd = linux_pci_open ( pci, O_RDONLY, where ); + if ( fd < 0 ) { + rc = fd; + goto err_open; + } + + /* Read value */ + check_len = linux_read ( fd, &tmp, len ); + if ( check_len < 0 ) { + DBGC ( pci, "PCI could not read from " PCI_FMT " %#02lx+%#zx: " + "%s\n", PCI_ARGS ( pci ), where, len, + linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_read; + } + if ( ( size_t ) check_len != len ) { + DBGC ( pci, "PCI read only %#x bytes from " PCI_FMT + " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ), + where, len ); + rc = -EIO; + goto err_read; + } + + /* Return value */ + *value = le32_to_cpu ( tmp ); + + /* Success */ + rc = 0; + + err_read: + linux_close ( fd ); + err_open: + return rc; +} + +/** + * Write to PCI configuration space + * + * @v pci PCI device + * @v where Address within configuration space + * @v value Value to write + * @v len Length of value + * @ret rc Return status code + */ +int linux_pci_write ( struct pci_device *pci, unsigned long where, + unsigned long value, size_t len ) { + uint32_t tmp; + int fd; + int check_len; + int rc; + + /* Open configuration space */ + fd = linux_pci_open ( pci, O_WRONLY, where ); + if ( fd < 0 ) { + rc = fd; + goto err_open; + } + + /* Prepare value for writing */ + tmp = cpu_to_le32 ( value ); + assert ( len <= sizeof ( tmp ) ); + + /* Write value */ + check_len = linux_write ( fd, &tmp, len ); + if ( check_len < 0 ) { + DBGC ( pci, "PCI could not write to " PCI_FMT " %#02lx+%#zx: " + "%s\n", PCI_ARGS ( pci ), where, len, + linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_write; + } + if ( ( size_t ) check_len != len ) { + DBGC ( pci, "PCI wrote only %#x bytes to " PCI_FMT + " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ), + where, len ); + rc = -EIO; + goto err_write; + } + + /* Success */ + rc = 0; + + err_write: + linux_close ( fd ); + err_open: + return rc; +} diff --git a/qemu/roms/ipxe/src/interface/linux/linux_smbios.c b/qemu/roms/ipxe/src/interface/linux/linux_smbios.c new file mode 100644 index 000000000..6e5174d23 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_smbios.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2013 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <errno.h> +#include <linux_api.h> +#include <ipxe/linux.h> +#include <ipxe/smbios.h> + +/** SMBIOS filename */ +static const char smbios_filename[] = "/dev/mem"; + +/** SMBIOS entry point scan region start address */ +#define SMBIOS_ENTRY_START 0xf0000 + +/** SMBIOS entry point scan region length */ +#define SMBIOS_ENTRY_LEN 0x10000 + +/** SMBIOS mapping alignment */ +#define SMBIOS_ALIGN 0x1000 + +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @ret rc Return status code + */ +static int linux_find_smbios ( struct smbios *smbios ) { + struct smbios_entry entry; + void *entry_mem; + void *smbios_mem; + size_t smbios_offset; + size_t smbios_indent; + size_t smbios_len; + int fd; + int rc; + + /* Open SMBIOS file */ + fd = linux_open ( smbios_filename, O_RDONLY ); + if ( fd < 0 ) { + rc = -ELINUX ( linux_errno ); + DBGC ( smbios, "SMBIOS could not open %s: %s\n", + smbios_filename, linux_strerror ( linux_errno ) ); + goto err_open; + } + + /* Map the region potentially containing the SMBIOS entry point */ + entry_mem = linux_mmap ( NULL, SMBIOS_ENTRY_LEN, PROT_READ, MAP_SHARED, + fd, SMBIOS_ENTRY_START ); + if ( entry_mem == MAP_FAILED ) { + rc = -ELINUX ( linux_errno ); + DBGC ( smbios, "SMBIOS could not mmap %s (%#x+%#x): %s\n", + smbios_filename, SMBIOS_ENTRY_START, SMBIOS_ENTRY_LEN, + linux_strerror ( linux_errno ) ); + goto err_mmap_entry; + } + + /* Scan for the SMBIOS entry point */ + if ( ( rc = find_smbios_entry ( virt_to_user ( entry_mem ), + SMBIOS_ENTRY_LEN, &entry ) ) != 0 ) + goto err_find_entry; + + /* Map the region containing the SMBIOS structures */ + smbios_indent = ( entry.smbios_address & ( SMBIOS_ALIGN - 1 ) ); + smbios_offset = ( entry.smbios_address - smbios_indent ); + smbios_len = ( entry.smbios_len + smbios_indent ); + smbios_mem = linux_mmap ( NULL, smbios_len, PROT_READ, MAP_SHARED, + fd, smbios_offset ); + if ( smbios_mem == MAP_FAILED ) { + rc = -ELINUX ( linux_errno ); + DBGC ( smbios, "SMBIOS could not mmap %s (%#zx+%#zx): %s\n", + smbios_filename, smbios_offset, smbios_len, + linux_strerror ( linux_errno ) ); + goto err_mmap_smbios; + } + + /* Fill in entry point descriptor structure */ + smbios->address = virt_to_user ( smbios_mem + smbios_indent ); + smbios->len = entry.smbios_len; + smbios->count = entry.smbios_count; + smbios->version = SMBIOS_VERSION ( entry.major, entry.minor ); + + /* Unmap the entry point region (no longer required) */ + linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN ); + + return 0; + + linux_munmap ( smbios_mem, smbios_len ); + err_mmap_smbios: + err_find_entry: + linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN ); + err_mmap_entry: + linux_close ( fd ); + err_open: + return rc; +} + +PROVIDE_SMBIOS ( linux, find_smbios, linux_find_smbios ); diff --git a/qemu/roms/ipxe/src/interface/linux/linux_time.c b/qemu/roms/ipxe/src/interface/linux/linux_time.c new file mode 100644 index 000000000..e3cbafec6 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_time.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 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 (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 + * 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Linux time source + * + */ + +#include <stdint.h> +#include <stddef.h> +#include <errno.h> +#include <linux_api.h> +#include <ipxe/time.h> + +/** + * Get current time in seconds + * + * @ret time Time, in seconds + */ +static time_t linux_now ( void ) { + struct timeval now; + + linux_gettimeofday ( &now, NULL ); + return now.tv_sec; +} + +PROVIDE_TIME ( linux, time_now, linux_now ); diff --git a/qemu/roms/ipxe/src/interface/linux/linux_timer.c b/qemu/roms/ipxe/src/interface/linux/linux_timer.c new file mode 100644 index 000000000..7a994517b --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_timer.c @@ -0,0 +1,87 @@ +/* + * 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); + +#include <stddef.h> +#include <ipxe/timer.h> + +#include <linux_api.h> + +/** @file + * + * iPXE timer API for linux + * + */ + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void linux_udelay(unsigned long usecs) +{ + linux_usleep(usecs); +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long linux_ticks_per_sec(void) +{ + return 1000; +} + +/** + * Get current system time in ticks + * + * linux doesn't provide an easy access to jiffies so implement it by measuring + * the time since the first call to this function. + * + * Since this function is used to seed the (non-cryptographic) random + * number generator, we round the start time down to the nearest whole + * second. This minimises the chances of generating identical RNG + * sequences (and hence identical TCP port numbers, etc) on + * consecutive invocations of iPXE. + * + * @ret ticks Current time, in ticks + */ +static unsigned long linux_currticks(void) +{ + static struct timeval start; + static int initialized = 0; + + if (! initialized) { + linux_gettimeofday(&start, NULL); + initialized = 1; + } + + struct timeval now; + linux_gettimeofday(&now, NULL); + + unsigned long ticks = (now.tv_sec - start.tv_sec) * linux_ticks_per_sec(); + ticks += now.tv_usec / (long)(1000000 / linux_ticks_per_sec()); + + return ticks; +} + +PROVIDE_TIMER(linux, udelay, linux_udelay); +PROVIDE_TIMER(linux, currticks, linux_currticks); +PROVIDE_TIMER(linux, ticks_per_sec, linux_ticks_per_sec); diff --git a/qemu/roms/ipxe/src/interface/linux/linux_uaccess.c b/qemu/roms/ipxe/src/interface/linux/linux_uaccess.c new file mode 100644 index 000000000..5ab0b6b65 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_uaccess.c @@ -0,0 +1,39 @@ +/* + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE(GPL2_OR_LATER); + +#include <ipxe/uaccess.h> + +/** @file + * + * iPXE user access API for linux + * + */ + +PROVIDE_UACCESS_INLINE(linux, phys_to_user); +PROVIDE_UACCESS_INLINE(linux, user_to_phys); +PROVIDE_UACCESS_INLINE(linux, virt_to_user); +PROVIDE_UACCESS_INLINE(linux, user_to_virt); +PROVIDE_UACCESS_INLINE(linux, userptr_add); +PROVIDE_UACCESS_INLINE(linux, memcpy_user); +PROVIDE_UACCESS_INLINE(linux, memmove_user); +PROVIDE_UACCESS_INLINE(linux, memset_user); +PROVIDE_UACCESS_INLINE(linux, strlen_user); +PROVIDE_UACCESS_INLINE(linux, memchr_user); diff --git a/qemu/roms/ipxe/src/interface/linux/linux_umalloc.c b/qemu/roms/ipxe/src/interface/linux/linux_umalloc.c new file mode 100644 index 000000000..aa0052c53 --- /dev/null +++ b/qemu/roms/ipxe/src/interface/linux/linux_umalloc.c @@ -0,0 +1,154 @@ +/* + * 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); + +#include <valgrind/memcheck.h> + +/** @file + * + * iPXE user memory allocation API for linux + * + */ + +#include <assert.h> +#include <ipxe/umalloc.h> + +#include <linux_api.h> + +/** Special address returned for empty allocations */ +#define NOWHERE ((void *)-1) + +/** Poison to make the metadata more unique */ +#define POISON 0xa5a5a5a5 +#define min(a,b) (((a)<(b))?(a):(b)) + +/** Metadata stored at the beginning of all allocations */ +struct metadata +{ + unsigned poison; + size_t size; +}; + +#define SIZE_MD (sizeof(struct metadata)) + +/** Simple realloc which passes most of the work to mmap(), mremap() and munmap() */ +static void * linux_realloc(void *ptr, size_t size) +{ + struct metadata md = {0, 0}; + struct metadata * mdptr = NULL; + + DBG2("linux_realloc(%p, %zd)\n", ptr, size); + + /* Check whether we have a valid pointer */ + if (ptr != NULL && ptr != NOWHERE) { + mdptr = ptr - SIZE_MD; + VALGRIND_MAKE_MEM_DEFINED(mdptr, SIZE_MD); + md = *mdptr; + VALGRIND_MAKE_MEM_NOACCESS(mdptr, SIZE_MD); + + /* Check for poison in the metadata */ + if (md.poison != POISON) { + DBG("linux_realloc bad poison: 0x%x (expected 0x%x)\n", md.poison, POISON); + return NULL; + } + } else { + /* Handle NOWHERE as NULL */ + ptr = NULL; + } + + /* + * At this point, ptr is either NULL or pointing to a region allocated by us. + * In the latter case mdptr is pointing to a valid metadata, otherwise it is NULL. + */ + + /* Handle deallocation or allocation of size 0 */ + if (size == 0) { + if (mdptr) { + if (linux_munmap(mdptr, md.size)) + DBG("linux_realloc munmap failed: %s\n", linux_strerror(linux_errno)); + VALGRIND_FREELIKE_BLOCK(ptr, sizeof(*mdptr)); + } + return NOWHERE; + } + + if (ptr) { + char *vbits = NULL; + + if (RUNNING_ON_VALGRIND > 0) + vbits = linux_realloc(NULL, min(size, md.size)); + +/* prevent an unused variable warning when building w/o valgrind support */ +#ifndef NVALGRIND + VALGRIND_GET_VBITS(ptr, vbits, min(size, md.size)); +#endif + + VALGRIND_FREELIKE_BLOCK(ptr, SIZE_MD); + + mdptr = linux_mremap(mdptr, md.size + SIZE_MD, size + SIZE_MD, MREMAP_MAYMOVE); + if (mdptr == MAP_FAILED) { + DBG("linux_realloc mremap failed: %s\n", linux_strerror(linux_errno)); + return NULL; + } + ptr = ((void *)mdptr) + SIZE_MD; + + VALGRIND_MALLOCLIKE_BLOCK(ptr, size, SIZE_MD, 0); +/* prevent an unused variable warning when building w/o valgrind support */ +#ifndef NVALGRIND + VALGRIND_SET_VBITS(ptr, vbits, min(size, md.size)); +#endif + + if (RUNNING_ON_VALGRIND > 0) + linux_realloc(vbits, 0); + } else { + mdptr = linux_mmap(NULL, size + SIZE_MD, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mdptr == MAP_FAILED) { + DBG("linux_realloc mmap failed: %s\n", linux_strerror(linux_errno)); + return NULL; + } + ptr = ((void *)mdptr) + SIZE_MD; + VALGRIND_MALLOCLIKE_BLOCK(ptr, size, SIZE_MD, 0); + } + + /* Update the metadata */ + VALGRIND_MAKE_MEM_DEFINED(mdptr, SIZE_MD); + mdptr->poison = POISON; + mdptr->size = size; + VALGRIND_MAKE_MEM_NOACCESS(mdptr, SIZE_MD); + // VALGRIND_MALLOCLIKE_BLOCK ignores redzones currently, make our own + VALGRIND_MAKE_MEM_NOACCESS(ptr + size, SIZE_MD); + + return ptr; +} + +/** + * Reallocate external memory + * + * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret new_ptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +static userptr_t linux_urealloc(userptr_t old_ptr, size_t new_size) +{ + return (userptr_t)linux_realloc((void *)old_ptr, new_size); +} + +PROVIDE_UMALLOC(linux, urealloc, linux_urealloc); |