[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