[gPXE-devel] [PATCH 28/33] [linux] Add lpci devices
Piotr Jaroszyński
p.jaroszynski at gmail.com
Sun Aug 15 18:59:33 EDT 2010
Add linux PCI devices used under the hood to make real PCI devices work.
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
src/arch/x86/core/linux/linux_api.c | 15 +
src/drivers/linux/lpci.c | 552 +++++++++++++++++++++++++++++++++++
src/include/gpxe/errfile.h | 1 +
src/include/gpxe/lpci.h | 87 ++++++
src/include/linux_api.h | 6 +
5 files changed, 661 insertions(+), 0 deletions(-)
create mode 100644 src/drivers/linux/lpci.c
create mode 100644 src/include/gpxe/lpci.h
diff --git a/src/arch/x86/core/linux/linux_api.c b/src/arch/x86/core/linux/linux_api.c
index e578687..c557bb1 100644
--- a/src/arch/x86/core/linux/linux_api.c
+++ b/src/arch/x86/core/linux/linux_api.c
@@ -29,6 +29,11 @@ FILE_LICENCE(GPL2_OR_LATER);
#include <asm/unistd.h>
#include <string.h>
+int linux_access(const char *pathname, int mode)
+{
+ return linux_syscall(__NR_access, pathname, mode);
+}
+
int linux_open(const char *pathname, int flags)
{
return linux_syscall(__NR_open, pathname, flags);
@@ -112,3 +117,13 @@ int linux_munmap(void *addr, size_t length)
{
return linux_syscall(__NR_munmap, addr, length);
}
+
+int linux_iopl(int level)
+{
+ return linux_syscall(__NR_iopl, level);
+}
+
+uid_t linux_getuid(void)
+{
+ return linux_syscall(__NR_getuid);
+}
diff --git a/src/drivers/linux/lpci.c b/src/drivers/linux/lpci.c
new file mode 100644
index 0000000..347796e
--- /dev/null
+++ b/src/drivers/linux/lpci.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <gpxe/lpci.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <linux_api.h>
+#include <gpxe/linux.h>
+#include <gpxe/pci.h>
+#include <gpxe/malloc.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/init.h>
+
+/**
+ * @file
+ *
+ * Implementation of the linux PCI devices
+ *
+ * Most of the work is accessing /sys/ intefaces exposed by the linux PCI subsystem.
+ * See linux/Documentation/filesystems/sysfs-pci.txt for details.
+ */
+
+#define UIO_DMA_MEM_SIZE (128 * 1024)
+
+#define UIO_DMA_ID_LEN 10
+
+LIST_HEAD(lpci_devices);
+
+int lpci_ioports_ready = 0;
+
+/** Allocate and initialize an lpci device */
+static struct lpci_device *alloc_lpci_device()
+{
+ struct lpci_device *lpci;
+
+ lpci = zalloc(sizeof(*lpci));
+
+ if (lpci) {
+ lpci->pci_config_fd = -1;
+ INIT_LIST_HEAD(&lpci->iomems);
+ INIT_LIST_HEAD(&lpci->ioports);
+ }
+
+ return lpci;
+}
+
+/** Open the PCI config available via the /sys/ interface */
+static int lpci_open_config(struct lpci_device *lpci)
+{
+ char path[SYS_PATH_LEN];
+
+ if (lpci->pci_config_fd != -1) {
+ DBGC(lpci, "lpci %p config already open('%s') failed (%s)\n", lpci, path, linux_strerror(linux_errno));
+ return -1;
+ }
+
+ snprintf(path, SYS_PATH_LEN, "%sconfig", lpci->sys_path);
+ lpci->pci_config_fd = linux_open(path, O_RDWR);
+
+ if (lpci->pci_config_fd == -1) {
+ DBGC(lpci, "lpci %p open('%s') failed (%s)\n", lpci, path, linux_strerror(linux_errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Close the PCI config */
+static void lpci_close_config(struct lpci_device *lpci)
+{
+ linux_close(lpci->pci_config_fd);
+}
+
+/**
+ * Map a specific I/O resource available via the /sys/ interface
+ *
+ * @v lpci lpci device
+ * @v iores_list List to add the newly mapped I/O resource to
+ * @v rind Index of the resource necessary to find it in /sys/
+ * @v start System address of the resouce
+ * @v len Length of the I/O resource in bytes
+ * @ret rc 0 on success
+ */
+static int lpci_map_iores(struct lpci_device *lpci, struct list_head *iores_list,
+ int rind, unsigned long long start, size_t len)
+{
+ int fd;
+ char path[SYS_PATH_LEN];
+ struct lpci_iores * iores;
+ int rc = 0;
+
+ iores = malloc(sizeof(*iores));
+
+ if (! iores) {
+ return -ENOMEM;
+ }
+
+ iores->start = start;
+ iores->len = len;
+
+ snprintf(path, SYS_PATH_LEN, "%sresource%d", lpci->sys_path, rind);
+ fd = linux_open(path, O_RDWR);
+
+ if (fd == -1) {
+ DBGC(lpci, "lpci %p open('%s', O_RDWR) failed (%s)\n", lpci, path, linux_strerror(linux_errno));
+ rc = fd;
+ goto err_open;
+ }
+ DBGC(lpci, "lpci %p mmapping iores [0x%016llx, 0x%016llx)\n", lpci, start, start + len);
+
+ iores->mapped = linux_mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (iores->mapped == MAP_FAILED) {
+ DBGC(lpci, "lpci %p mmap failed (%s)\n", lpci, linux_strerror(linux_errno));
+ rc = -1;
+ goto err_mmap;
+ }
+
+ list_add(&iores->list, iores_list);
+
+ linux_close(fd);
+
+ DBGC(lpci, "lpci %p mapped iores [0x%016llx, 0x%016llx) to %p\n", lpci, start, start + len, iores->mapped);
+
+ return 0;
+
+err_mmap:
+ linux_close(fd);
+err_open:
+ free(iores);
+
+ return rc;
+}
+
+/** Unmap all I/O resources on the list */
+static void lpci_unmap_iores(struct list_head *iores_list)
+{
+ struct lpci_iores * iores;
+ struct lpci_iores * tmp;
+
+ list_for_each_entry_safe(iores, tmp, iores_list, list) {
+ linux_munmap(iores->mapped, iores->len);
+ list_del(&iores->list);
+ free(iores);
+ }
+}
+
+/** Map I/O resources of the device available via the /sys/ interface */
+static int lpci_map_resources(struct lpci_device *lpci)
+{
+ int fd;
+ char path[SYS_PATH_LEN];
+ char line[SYS_PCI_RESOURCE_LINE_WIDTH];
+ unsigned long long r_start, r_end, r_flags;
+ int r_ind = 0;
+ char * end = line;
+
+ strcpy(path, lpci->sys_path);
+ strcat(path, "resource");
+
+ fd = linux_open(path, O_RDONLY);
+
+ if (fd == -1) {
+ DBGC(lpci, "lpci %p open('%s', O_RDONLY) = %d (%s)\n", lpci, path, fd, linux_strerror(linux_errno));
+ return -1;
+ }
+
+ while (r_ind <= PCI_STD_RESOURCE_END &&
+ linux_read(fd, line, SYS_PCI_RESOURCE_LINE_WIDTH) == SYS_PCI_RESOURCE_LINE_WIDTH) {
+ line[SYS_PCI_RESOURCE_LINE_WIDTH - 1] = 0;
+
+ r_start = strtoull(end, &end, 0);
+ r_end = strtoull(end, &end, 0);
+ r_flags = strtoull(end, &end, 0);
+ end = line;
+
+ if (r_flags & IORESOURCE_MEM) {
+ lpci_map_iores(lpci, &lpci->iomems, r_ind, r_start, r_end - r_start + 1);
+ }
+ /* Doesn't work on x86, see pci_mmap_page_range() in linux/arch/x86/pci/i386.c */
+#if 0
+ if (r_flags & IORESOURCE_IO) {
+ lpci_map_iores(lpci, &lpci->ioports, r_ind, r_start, r_end - r_start + 1);
+ }
+#endif
+
+ ++r_ind;
+ }
+
+ linux_close(fd);
+
+ return 0;
+}
+
+/**
+ * Parse a device id into domain, bus, device and function number
+ *
+ * Accept ids in the following format [domain_hex:]bus_hex:device_hex:function_decimal
+ * hex numbers w/o the '0x' prefix
+ * : can be any string not containing hex digits
+ */
+static int lpci_parse_dev_id(char *id, uint16_t *domain, uint8_t *bus, uint8_t *devfn)
+{
+ unsigned long parts[4];
+ char * p;
+ int i = 0;
+
+ for (p = id ; *p && i < 4 ; ) {
+ if (! isxdigit(*p))
+ ++p;
+ else
+ parts[i++] = strtoul(p, &p, 16);
+ }
+
+ /* parsed all? */
+ if (*p)
+ return -1;
+
+ /* domain present? */
+ if (i == 3) {
+ *domain = 0;
+ } else if (i == 4) {
+ *domain = parts[0];
+ } else {
+ return -1;
+ }
+
+ /* bus < 256 ? */
+ if (parts[i - 3] >= 256)
+ return -1;
+
+ *bus = parts[i - 3];
+
+ /* device < 32 ? */
+ if (parts[i - 2] >= 32)
+ return -1;
+
+ /* function < 8 ? */
+ if (parts[i - 1] >= 8)
+ return -1;
+
+ *devfn = PCI_DEVFN(parts[i - 2], parts[i - 1]);
+
+ return 0;
+}
+
+/** Used to save the old DMA pool to restore it on remove */
+static struct memory_pool *old_dma_pool;
+
+/** The pool to be used while lpci devices are active */
+static struct memory_pool lpci_dma_pool = {
+ .free_blocks = LIST_HEAD_INIT(lpci_dma_pool.free_blocks),
+};
+
+struct uio_dma_mapping *lpci_dma_mapping;
+
+static int uio_dma_fd = -1;
+static struct uio_dma_area *uio_dma_area;
+
+/** Do some basic sanity checks */
+static int lpci_precheck(struct lpci_device *lpci)
+{
+ if (linux_getuid() != 0) {
+ printf("You need to be root to use lpci devices\n");
+ return -EPERM;
+ }
+
+ if (linux_access(lpci->sys_path, O_RDONLY) != 0) {
+ printf("Cannot access '%s': (%s)\n", lpci->sys_path, linux_strerror(linux_errno));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/** Get the UIO-DMA device id from /sys */
+static int lpci_get_uio_dma_id(struct lpci_device *lpci)
+{
+ char path[SYS_PATH_LEN];
+ char buf[UIO_DMA_ID_LEN + 1];
+ int fd;
+ int rc = 0;
+
+ snprintf(path, SYS_PATH_LEN, "%suio_dma_id", lpci->sys_path);
+ fd = linux_open(path, O_RDONLY);
+ if (fd == -1) {
+ DBGC(lpci, "lpci %p open('%s') failed (%s)\n", lpci, path, linux_strerror(linux_errno));
+ return -1;
+ }
+
+ if (linux_read(fd, buf, UIO_DMA_ID_LEN) != UIO_DMA_ID_LEN) {
+ DBGC(lpci, "lpci %p read('%s') failed (%s)\n", lpci, path, linux_strerror(linux_errno));
+ rc = -1;
+ goto close;
+ }
+
+ buf[UIO_DMA_ID_LEN] = '\0';
+
+ lpci->uio_dma_id = strtoul(buf, NULL, 0);
+
+close:
+ linux_close(fd);
+
+ return rc;
+}
+
+/**
+ * Initialize the DMA mappings with UIO-DMA and switch the memory_pool used
+ * by DMA allocations.
+ */
+static int lpci_init_dma(struct lpci_device *lpci)
+{
+ if (uio_dma_fd != -1) {
+ DBG("uio_dma_fd already open\n");
+ return -1;
+ }
+
+ uio_dma_fd = uio_dma_open();
+
+ if (uio_dma_fd == -1) {
+ DBG("lpci uio_dma_open() failed (%s)\n", linux_strerror(linux_errno));
+ goto err_open;
+ }
+
+ /* Use a 32bit mask as some drivers might be assuming it */
+ uio_dma_area = uio_dma_alloc(uio_dma_fd, UIO_DMA_MEM_SIZE, UIO_DMA_CACHE_DISABLE, UIO_DMA_MASK(32), 0);
+ if (! uio_dma_area) {
+ DBG("lpci uio_dma_alloc() failed (%s)\n", linux_strerror(linux_errno));
+ goto err_alloc;
+ }
+
+ lpci_dma_mapping = uio_dma_map(uio_dma_fd, uio_dma_area, lpci->uio_dma_id, UIO_DMA_BIDIRECTIONAL);
+ if (! lpci_dma_mapping) {
+ DBG("lpci uio_dma_map() failed (%s)\n", linux_strerror(linux_errno));
+ goto err_map;
+ }
+
+ if (lpci_dma_mapping->chunk_count != 1) {
+ DBG("lpci uio_dma_map() returned %d chunks, we only support 1\n", lpci_dma_mapping->chunk_count);
+ goto err_chunks;
+ }
+
+ mpopulate(&lpci_dma_pool, lpci_dma_mapping->addr, UIO_DMA_MEM_SIZE);
+ old_dma_pool = set_dma_pool(&lpci_dma_pool);
+
+ return 0;
+
+err_chunks:
+ uio_dma_unmap(uio_dma_fd, lpci_dma_mapping);
+err_map:
+ uio_dma_free(uio_dma_fd, uio_dma_area);
+err_alloc:
+ uio_dma_close(uio_dma_fd);
+ uio_dma_fd = -1;
+err_open:
+ return -1;
+}
+
+/**
+ * Clean up the UIO-DMA mappings and restore the old memory_pool for DMA
+ * allocations.
+ */
+static void lpci_clean_dma()
+{
+ set_dma_pool(old_dma_pool);
+
+ uio_dma_unmap(uio_dma_fd, lpci_dma_mapping);
+ uio_dma_free(uio_dma_fd, uio_dma_area);
+ uio_dma_close(uio_dma_fd);
+}
+
+/** Initialize access to the I/O ports */
+static int lpci_init_ioports()
+{
+ if (lpci_ioports_ready)
+ return 0;
+
+ if (linux_iopl(3) != 0) {
+ DBG("lpci iopl(3) failed (%s)\n", linux_strerror(linux_errno));
+ return -EPERM;
+ }
+ lpci_ioports_ready = 1;
+
+ return 0;
+}
+
+struct linux_driver lpci_driver __linux_driver;
+
+/** Handle a request for an lpci device */
+static int lpci_probe(struct linux_device *device, struct linux_device_request *request)
+{
+ struct linux_setting *dev_setting;
+ uint16_t domain = 0;
+ uint8_t bus = 0;
+ uint8_t devfn = 0;
+ struct lpci_device *lpci;
+ int rc;
+
+ /* Look for the mandatory dev setting */
+ dev_setting = linux_find_setting("dev", &request->settings);
+
+ if (! dev_setting) {
+ printf("lpci missing mandatory dev setting\n");
+ return -EINVAL;
+ }
+
+ dev_setting->applied = 1;
+
+ if (lpci_parse_dev_id(dev_setting->value, &domain, &bus, &devfn)) {
+ printf("lpci missing mandatory dev setting\n");
+ return -ENODEV;
+ }
+
+ lpci = alloc_lpci_device();
+ if (! lpci)
+ return -ENOMEM;
+
+ lpci->settings = &request->settings;
+ lpci->domain = domain;
+ lpci->bus = bus;
+ lpci->devfn = devfn;
+ sprintf(lpci->sys_path, SYS_PCI_DEVICES_PATH "%04x:%02x:%02x.%d/",
+ domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+ linux_set_drvdata(device, lpci);
+
+ rc = lpci_precheck(lpci);
+ if (rc) {
+ goto err_precheck;
+ }
+
+ rc = lpci_get_uio_dma_id(lpci);
+ if (rc) {
+ printf("lpci failed to get UIO-DMA device id. Is the uio-dma-pci driver bound to the device?\n");
+ goto err_uio_dma_id;
+ }
+
+ rc = lpci_open_config(lpci);
+ if (rc) {
+ printf("lpci failed to open PCI config\n");
+ goto err_config;
+ }
+
+ rc = lpci_map_resources(lpci);
+ if (rc) {
+ printf("lpci failed to map I/O resources\n");
+ goto err_map;
+ }
+
+ rc = lpci_init_ioports();
+ if (rc) {
+ printf("lpci ioprts not ready\n");
+ goto err_init_ioports;
+ }
+
+ rc = lpci_init_dma(lpci);
+ if (rc) {
+ printf("lpci DMA memory not ready\n");
+ goto err_init_dma;
+ }
+
+ list_add(&lpci->list, &lpci_devices);
+
+ DBGC(lpci, "lpci %p added device [%04x:%02x:%02x.%d]\n", lpci, domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+ /*
+ * We can handle only one device at the same time.
+ * To support multiple devices time malloc_dma() and phys_to_bus()
+ * conversion would have to know for which device they are being done.
+ */
+ lpci_driver.can_probe = 0;
+
+ return 0;
+
+err_init_dma:
+err_init_ioports:
+err_map:
+ lpci_unmap_iores(&lpci->iomems);
+ lpci_unmap_iores(&lpci->ioports);
+ lpci_close_config(lpci);
+err_uio_dma_id:
+err_precheck:
+err_config:
+ free(lpci);
+
+ return rc;
+}
+
+/** Remove the lpci device */
+static void lpci_remove(struct linux_device *device)
+{
+ struct lpci_device *lpci = linux_get_drvdata(device);
+
+ lpci_clean_dma();
+
+ lpci_unmap_iores(&lpci->iomems);
+ lpci_unmap_iores(&lpci->ioports);
+ lpci_close_config(lpci);
+ list_del(&lpci->list);
+
+ free(lpci);
+}
+
+/** lpci linux_driver */
+struct linux_driver lpci_driver __linux_driver = {
+ .name = "lpci",
+ .probe = lpci_probe,
+ .remove = lpci_remove,
+ .can_probe = 1,
+};
+
+/** Apply lpci settings to corresponding net devices */
+void lpci_apply_settings(void)
+{
+ struct lpci_device *lpci;
+ struct net_device *ndev;
+
+ /* Look for the net_device corresponding to each lpci device */
+ for_each_lpci(lpci) {
+ for_each_netdev(ndev) {
+ if (ndev->dev->desc.bus_type == BUS_TYPE_PCI &&
+ ndev->dev->desc.location == (unsigned int)PCI_BUSDEVFN(lpci->bus, lpci->devfn)) {
+ /* Apply the lpci settings to the net device */
+ linux_apply_settings(lpci->settings, &ndev->settings.settings);
+ }
+ }
+ }
+}
+
+struct startup_fn lpci_apply_settings_startup_fn __startup_fn(STARTUP_LATE) = {
+ .startup = lpci_apply_settings,
+};
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index 9f92470..14f6d91 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -129,6 +129,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_jme ( ERRFILE_DRIVER | 0x005b0000 )
#define ERRFILE_virtio_net ( ERRFILE_DRIVER | 0x005c0000 )
#define ERRFILE_tap ( ERRFILE_DRIVER | 0x005d0000 )
+#define ERRFILE_lpci ( ERRFILE_DRIVER | 0x005e0000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )
diff --git a/src/include/gpxe/lpci.h b/src/include/gpxe/lpci.h
new file mode 100644
index 0000000..370d629
--- /dev/null
+++ b/src/include/gpxe/lpci.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _GPXE_LPCI_H
+#define _GPXE_LPCI_H
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <gpxe/list.h>
+
+#define SYS_PATH_LEN 64 /* enough to contain any path under /sys we need */
+#define SYS_PCI_DEVICES_PATH "/sys/bus/pci/devices/"
+#define SYS_PCI_RESOURCE_LINE_WIDTH (18 * 3 + 1 * 3)
+
+#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
+#define IORESOURCE_IO 0x00000100
+#define IORESOURCE_MEM 0x00000200
+#define IORESOURCE_IRQ 0x00000400
+#define IORESOURCE_DMA 0x00000800
+#define IORESOURCE_BUS 0x00001000
+
+#define PCI_STD_RESOURCE_END 5
+
+/** A linux PCI device
+ *
+ * It is used under the hood to provide I/O and PCI API on linux
+ */
+struct lpci_device {
+ /** Domain number */
+ uint16_t domain;
+ /** Bus number */
+ uint8_t bus;
+ /** Device and function number */
+ uint8_t devfn;
+ /** Base path of the device under /sys/ */
+ char sys_path[SYS_PATH_LEN];
+ /** File descriptor of an opened PCI config file under /sys/ */
+ int pci_config_fd;
+ /** List node */
+ struct list_head list;
+ /** List of mmaped I/O memory */
+ struct list_head iomems;
+ /** List of mmaped I/O ports */
+ struct list_head ioports;
+ /** UIO-DMA device id */
+ uint32_t uio_dma_id;
+ /** Settings list */
+ struct list_head *settings;
+};
+
+/** List of all linux PCI devices */
+extern struct list_head lpci_devices;
+
+/** Iterate over all lpci devices */
+#define for_each_lpci( lpci ) \
+ list_for_each_entry ( (lpci), &lpci_devices, list )
+
+/** An mmaped() I/O resource */
+struct lpci_iores {
+ unsigned long long start;
+ size_t len;
+ void * mapped;
+ struct list_head list;
+};
+
+/** Are ioports ready to be used? */
+extern int lpci_ioports_ready;
+
+/** lpci DMA mapping */
+extern struct uio_dma_mapping * lpci_dma_mapping;
+
+#endif /* _GPXE_LPCI_H */
diff --git a/src/include/linux_api.h b/src/include/linux_api.h
index 6f591d8..1bc1f73 100644
--- a/src/include/linux_api.h
+++ b/src/include/linux_api.h
@@ -47,6 +47,7 @@ typedef uint32_t useconds_t;
extern long linux_syscall(int number, ...);
+extern int linux_access(const char *pathname, int mode);
extern int linux_open(const char *pathname, int flags);
extern int linux_close(int fd);
extern ssize_t linux_read(int fd, void *buf, size_t count);
@@ -67,6 +68,11 @@ extern void *linux_mmap(void *addr, size_t length, int prot, int flags, int fd,
extern void *linux_mremap(void *old_address, size_t old_size, size_t new_size, int flags);
extern int linux_munmap(void *addr, size_t length);
+extern int linux_iopl(int level);
+
+typedef __kernel_uid_t uid_t;
+extern uid_t linux_getuid(void);
+
extern const char *linux_strerror(int errnum);
#endif /* _LINUX_API_H */
--
1.7.1
More information about the gPXE-devel
mailing list