Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ boot/Makefile.common	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -139,4 +139,5 @@
 	nic/rtl8169 \
 	nic/ar9271 \
+	nic/virtio-net \
 	block/ahci
 
Index: kernel/generic/include/stdbool.h
===================================================================
--- kernel/generic/include/stdbool.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ kernel/generic/include/stdbool.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -41,5 +41,5 @@
 #define true   1
 
-#define __bool_true_false_are_defined 1
+#define __bool_true_false_are_defined  1
 
 #endif
Index: tools/ew.py
===================================================================
--- tools/ew.py	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ tools/ew.py	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -146,4 +146,7 @@
 	return ' -device rtl8139,vlan=0'
 
+def qemu_nic_virtio_options():
+	return ' -device virtio-net,vlan=0'
+
 def qemu_net_options():
 	if is_override('nonet'):
@@ -158,4 +161,6 @@
 		if 'ne2k' in overrides['net'].keys():
 			nic_options += qemu_nic_ne2k_options()
+		if 'virtio-net' in overrides['net'].keys():
+			nic_options += qemu_nic_virtio_options()
 	else:
 		# Use the default NIC
@@ -326,5 +331,5 @@
 def usage():
 	print("%s - emulator wrapper for running HelenOS\n" % os.path.basename(sys.argv[0]))
-	print("%s [-d] [-h] [-net e1k|rtl8139|ne2k] [-nohdd] [-nokvm] [-nonet] [-nosnd] [-nousb] [-noxhci] [-notablet]\n" %
+	print("%s [-d] [-h] [-net e1k|rtl8139|ne2k|virtio-net] [-nohdd] [-nokvm] [-nonet] [-nosnd] [-nousb] [-noxhci] [-notablet]\n" %
 	    os.path.basename(sys.argv[0]))
 	print("-d\tDry run: do not run the emulation, just print the command line.")
@@ -360,4 +365,6 @@
 			elif sys.argv[i] == 'ne2k':
 				overrides['net']['ne2k'] = True
+			elif sys.argv[i] == 'virtio-net':
+				overrides['net']['virtio-net'] = True
 			else:
 				usage()
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -181,4 +181,5 @@
 	drv/nic/rtl8169 \
 	drv/nic/ar9271 \
+	drv/nic/virtio-net \
 	drv/platform/amdm37x \
 	drv/platform/icp \
@@ -251,5 +252,6 @@
 	lib/bithenge \
 	lib/posix \
-	lib/ieee80211
+	lib/ieee80211 \
+	lib/virtio
 
 BASE_BUILDS := $(addsuffix .build,$(BASE_LIBS))
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/Makefile.common	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -165,5 +165,5 @@
 ifneq ($(TEST_SOURCES),)
 	TEST_OUTPUTS = $(TEST_BINARY) $(TEST_BINARY).disasm
-	TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__
+	TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__ $(EXTRA_TEST_CFLAGS)
 	TEST_BINARY_LIBS = $(LIB_PREFIX)/pcut/libpcut.a
 	EXTRA_CLEAN += $(TEST_OUTPUTS) $(TEST_BINARY).map
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -738,6 +738,6 @@
 
 		if (pio_enable_resource(&bus->pio_win,
-		    &hw_resources.resources[0],
-		    (void **) &bus->conf_space)) {
+		    &hw_resources.resources[0], (void **) &bus->conf_space,
+		    NULL, NULL)) {
 			ddf_msg(LVL_ERROR,
 			    "Failed to map configuration space.");
@@ -759,6 +759,6 @@
 
 		if (pio_enable_resource(&bus->pio_win,
-		    &hw_resources.resources[0],
-		    (void **) &bus->conf_addr_reg)) {
+		    &hw_resources.resources[0], (void **) &bus->conf_addr_reg,
+		    NULL, NULL)) {
 			ddf_msg(LVL_ERROR,
 			    "Failed to enable configuration ports.");
@@ -767,6 +767,6 @@
 		}
 		if (pio_enable_resource(&bus->pio_win,
-		    &hw_resources.resources[1],
-		    (void **) &bus->conf_data_reg)) {
+		    &hw_resources.resources[1], (void **) &bus->conf_data_reg,
+		    NULL, NULL)) {
 			ddf_msg(LVL_ERROR,
 			    "Failed to enable configuration ports.");
Index: uspace/drv/nic/virtio-net/Makefile
===================================================================
--- uspace/drv/nic/virtio-net/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/drv/nic/virtio-net/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2018 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = drv nic virtio
+BINARY = virtio-net
+
+SOURCES = \
+	virtio-net.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/virtio-net/virtio-net.c
===================================================================
--- uspace/drv/nic/virtio-net/virtio-net.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/drv/nic/virtio-net/virtio-net.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2018 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "virtio-net.h"
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include <as.h>
+#include <ddf/driver.h>
+#include <ddf/interrupt.h>
+#include <ddf/log.h>
+#include <ops/nic.h>
+#include <pci_dev_iface.h>
+#include <nic/nic.h>
+
+#include <nic.h>
+
+#include <virtio-pci.h>
+
+#define NAME	"virtio-net"
+
+#define VIRTIO_NET_NUM_QUEUES	3
+
+#define RX_QUEUE_1	0
+#define TX_QUEUE_1	1
+#define CT_QUEUE_1	2
+
+#define BUFFER_SIZE	2048
+#define RX_BUF_SIZE	BUFFER_SIZE
+#define TX_BUF_SIZE	BUFFER_SIZE
+#define CT_BUF_SIZE	BUFFER_SIZE
+
+static ddf_dev_ops_t virtio_net_dev_ops;
+
+static errno_t virtio_net_dev_add(ddf_dev_t *dev);
+
+static driver_ops_t virtio_net_driver_ops = {
+	.dev_add = virtio_net_dev_add
+};
+
+static driver_t virtio_net_driver = {
+	.name = NAME,
+	.driver_ops = &virtio_net_driver_ops
+};
+
+/** Allocate DMA buffers
+ *
+ * @param buffers[in]  Number of buffers to allocate.
+ * @param size[in]     Size of each buffer.
+ * @param write[in]    True if the buffers are writable by the driver, false
+ *                     otherwise.
+ * @param buf[out]     Output array holding virtual addresses of the allocated
+ *                     buffers.
+ * @param buf_p[out]   Output array holding physical addresses of the allocated
+ *                     buffers.
+ *
+ * The buffers can be deallocated by virtio_net_teardown_bufs().
+ *
+ * @return  EOK on success or error code.
+ */
+static errno_t virtio_net_setup_bufs(unsigned int buffers, size_t size,
+    bool write, void *buf[], uintptr_t buf_p[])
+{
+	/*
+	 * Allocate all buffers at once in one large chunk.
+	 */
+	void *virt = AS_AREA_ANY;
+	uintptr_t phys;
+	errno_t rc = dmamem_map_anonymous(buffers * size, 0,
+	    write ? AS_AREA_WRITE : AS_AREA_READ, 0, &phys, &virt);
+	if (rc != EOK)
+		return rc;
+
+	ddf_msg(LVL_NOTE, "DMA buffers: %p-%p", virt, virt + buffers * size);
+
+	/*
+	 * Calculate addresses of the individual buffers for easy access.
+	 */
+	for (unsigned i = 0; i < buffers; i++) {
+		buf[i] = virt + i * size;
+		buf_p[i] = phys + i * size;
+	}
+
+	return EOK;
+}
+
+/** Deallocate DMA buffers
+ *
+ * @param buf[in]  Array holding the virtual addresses of the DMA buffers
+ *                 previously allocated by virtio_net_setup_bufs().
+ */
+static void virtio_net_teardown_bufs(void *buf[])
+{
+	if (buf[0]) {
+		dmamem_unmap_anonymous(buf[0]);
+		buf[0] = NULL;
+	}
+}
+
+/** Create free descriptor list from the unused VIRTIO descriptors
+ *
+ * @param vdev[in]   VIRTIO device for which the free list will be created.
+ * @param num[in]    Index of the virtqueue for which the free list will be
+ *                   created.
+ * @param size[in]   Number of descriptors on the free list. The free list will
+ *                   contain descriptors starting from 0 to \a size - 1.
+ * @param head[out]  Variable that will hold the VIRTIO descriptor at the head
+ *                   of the free list.
+ */
+static void virtio_net_create_desc_free_list(virtio_dev_t *vdev, uint16_t num,
+    uint16_t size, uint16_t *head)
+{
+	for (unsigned i = 0; i < size; i++) {
+		virtio_virtq_desc_set(vdev, num, i, 0, 0,
+		    VIRTQ_DESC_F_NEXT, (i + 1 == size) ? -1U : i + 1);
+	}
+	*head = 0;
+}
+
+/** Allocate a descriptor from the free list
+ *
+ * @param vdev[in]      VIRTIO device with the free list.
+ * @param num[in]       Index of the virtqueue with free list.
+ * @param head[in,out]  Head of the free list.
+ *
+ * @return  Allocated descriptor or 0xFFFF if the list is empty.
+ */
+static uint16_t virtio_net_alloc_desc(virtio_dev_t *vdev, uint16_t num,
+    uint16_t *head)
+{
+	virtq_t *q = &vdev->queues[num];
+	fibril_mutex_lock(&q->lock);
+	uint16_t descno = *head;
+	if (descno != (uint16_t) -1U)
+		*head = virtio_virtq_desc_get_next(vdev, num, descno);
+	fibril_mutex_unlock(&q->lock);
+	return descno;
+}
+
+/** Free a descriptor into the free list
+ *
+ * @param vdev[in]      VIRTIO device with the free list.
+ * @param num[in]       Index of the virtqueue with free list.
+ * @param head[in,out]  Head of the free list.
+ * @param descno[in]    The freed descriptor.
+ */
+static void virtio_net_free_desc(virtio_dev_t *vdev, uint16_t num,
+    uint16_t *head, uint16_t descno)
+{
+	virtq_t *q = &vdev->queues[num];
+	fibril_mutex_lock(&q->lock);
+	virtio_virtq_desc_set(vdev, num, descno, 0, 0, VIRTQ_DESC_F_NEXT,
+	    *head);
+	*head = descno;
+	fibril_mutex_unlock(&q->lock);
+}
+
+static void virtio_net_irq_handler(ipc_call_t *icall, ddf_dev_t *dev)
+{
+	nic_t *nic = ddf_dev_data_get(dev);
+	virtio_net_t *virtio_net = nic_get_specific(nic);
+	virtio_dev_t *vdev = &virtio_net->virtio_dev;
+
+	uint16_t descno;
+	uint32_t len;
+	while (virtio_virtq_consume_used(vdev, RX_QUEUE_1, &descno, &len)) {
+		virtio_net_hdr_t *hdr =
+		    (virtio_net_hdr_t *) virtio_net->rx_buf[descno];
+		if (len <= sizeof(*hdr)) {
+			ddf_msg(LVL_WARN,
+			    "RX data length too short, packet dropped");
+			virtio_virtq_produce_available(vdev, RX_QUEUE_1,
+			    descno);
+			continue;
+		}
+
+		nic_frame_t *frame = nic_alloc_frame(nic, len - sizeof(*hdr));
+		if (frame) {
+			memcpy(frame->data, &hdr[1], len - sizeof(*hdr));
+			nic_received_frame(nic, frame);
+		} else {
+			ddf_msg(LVL_WARN,
+			    "Cannot allocate RX frame, packet dropped");
+		}
+
+		virtio_virtq_produce_available(vdev, RX_QUEUE_1, descno);
+	}
+
+	while (virtio_virtq_consume_used(vdev, TX_QUEUE_1, &descno, &len)) {
+		virtio_net_free_desc(vdev, TX_QUEUE_1,
+		    &virtio_net->tx_free_head, descno);
+	}
+	while (virtio_virtq_consume_used(vdev, CT_QUEUE_1, &descno, &len)) {
+		virtio_net_free_desc(vdev, CT_QUEUE_1,
+		    &virtio_net->ct_free_head, descno);
+	}
+}
+
+static errno_t virtio_net_register_interrupt(ddf_dev_t *dev)
+{
+	nic_t *nic = ddf_dev_data_get(dev);
+	virtio_net_t *virtio_net = nic_get_specific(nic);
+	virtio_dev_t *vdev = &virtio_net->virtio_dev;
+
+	hw_res_list_parsed_t res;
+	hw_res_list_parsed_init(&res);
+
+	errno_t rc = nic_get_resources(nic, &res);
+	if (rc != EOK)
+		return rc;
+
+	if (res.irqs.count < 1) {
+		hw_res_list_parsed_clean(&res);
+		rc = EINVAL;
+		return rc;
+	}
+
+	virtio_net->irq = res.irqs.irqs[0];
+	hw_res_list_parsed_clean(&res);
+
+	irq_pio_range_t pio_ranges[] = {
+		{
+			.base = vdev->isr_phys,
+			.size = sizeof(vdev->isr_phys),
+		}
+	};
+
+	irq_cmd_t irq_commands[] = {
+		{
+			.cmd = CMD_PIO_READ_8,
+			.addr = (void *) vdev->isr_phys,
+			.dstarg = 2
+		},
+		{
+			.cmd = CMD_PREDICATE,
+			.value = 1,
+			.srcarg = 2
+		},
+		{
+			.cmd = CMD_ACCEPT
+		}
+	};
+
+	irq_code_t irq_code = {
+		.rangecount = sizeof(pio_ranges) / sizeof(irq_pio_range_t),
+		.ranges = pio_ranges,
+		.cmdcount = sizeof(irq_commands) / sizeof(irq_cmd_t),
+		.cmds = irq_commands
+	};
+
+	return register_interrupt_handler(dev, virtio_net->irq,
+	    virtio_net_irq_handler, &irq_code, &virtio_net->irq_handle);
+}
+
+static errno_t virtio_net_initialize(ddf_dev_t *dev)
+{
+	nic_t *nic = nic_create_and_bind(dev);
+	if (!nic)
+		return ENOMEM;
+
+	virtio_net_t *virtio_net = calloc(1, sizeof(virtio_net_t));
+	if (!virtio_net) {
+		nic_unbind_and_destroy(dev);
+		return ENOMEM;
+	}
+
+	nic_set_specific(nic, virtio_net);
+
+	errno_t rc = virtio_pci_dev_initialize(dev, &virtio_net->virtio_dev);
+	if (rc != EOK)
+		return rc;
+
+	virtio_dev_t *vdev = &virtio_net->virtio_dev;
+	virtio_pci_common_cfg_t *cfg = virtio_net->virtio_dev.common_cfg;
+	virtio_net_cfg_t *netcfg = virtio_net->virtio_dev.device_cfg;
+
+	/*
+	 * Register IRQ
+	 */
+	rc = virtio_net_register_interrupt(dev);
+	if (rc != EOK)
+		goto fail;
+
+	/* Reset the device and negotiate the feature bits */
+	rc = virtio_device_setup_start(vdev,
+	    VIRTIO_NET_F_MAC | VIRTIO_NET_F_CTRL_VQ);
+	if (rc != EOK)
+		goto fail;
+
+	/* Perform device-specific setup */
+
+	/*
+	 * Discover and configure the virtqueues
+	 */
+	uint16_t num_queues = pio_read_le16(&cfg->num_queues);
+	if (num_queues != VIRTIO_NET_NUM_QUEUES) {
+		ddf_msg(LVL_NOTE, "Unsupported number of virtqueues: %u",
+		    num_queues);
+		goto fail;
+	}
+
+	vdev->queues = calloc(sizeof(virtq_t), num_queues);
+	if (!vdev->queues) {
+		rc = ENOMEM;
+		goto fail;
+	}
+
+	rc = virtio_virtq_setup(vdev, RX_QUEUE_1, RX_BUFFERS);
+	if (rc != EOK)
+		goto fail;
+	rc = virtio_virtq_setup(vdev, TX_QUEUE_1, TX_BUFFERS);
+	if (rc != EOK)
+		goto fail;
+	rc = virtio_virtq_setup(vdev, CT_QUEUE_1, CT_BUFFERS);
+	if (rc != EOK)
+		goto fail;
+
+	/*
+	 * Setup DMA buffers
+	 */
+	rc = virtio_net_setup_bufs(RX_BUFFERS, RX_BUF_SIZE, false,
+	    virtio_net->rx_buf, virtio_net->rx_buf_p);
+	if (rc != EOK)
+		goto fail;
+	rc = virtio_net_setup_bufs(TX_BUFFERS, TX_BUF_SIZE, true,
+	    virtio_net->tx_buf, virtio_net->tx_buf_p);
+	if (rc != EOK)
+		goto fail;
+	rc = virtio_net_setup_bufs(CT_BUFFERS, CT_BUF_SIZE, true,
+	    virtio_net->ct_buf, virtio_net->ct_buf_p);
+	if (rc != EOK)
+		goto fail;
+
+	/*
+	 * Give all RX buffers to the NIC
+	 */
+	for (unsigned i = 0; i < RX_BUFFERS; i++) {
+		/*
+		 * Associtate the buffer with the descriptor, set length and
+		 * flags.
+		 */
+		virtio_virtq_desc_set(vdev, RX_QUEUE_1, i,
+		    virtio_net->rx_buf_p[i], RX_BUF_SIZE, VIRTQ_DESC_F_WRITE,
+		    0);
+		/*
+		 * Put the set descriptor into the available ring of the RX
+		 * queue.
+		 */
+		virtio_virtq_produce_available(vdev, RX_QUEUE_1, i);
+	}
+
+	/*
+	 * Put all TX and CT buffers on a free list
+	 */
+	virtio_net_create_desc_free_list(vdev, TX_QUEUE_1, TX_BUFFERS,
+	    &virtio_net->tx_free_head);
+	virtio_net_create_desc_free_list(vdev, CT_QUEUE_1, CT_BUFFERS,
+	    &virtio_net->ct_free_head);
+
+	/*
+	 * Read the MAC address
+	 */
+	nic_address_t nic_addr;
+	for (unsigned i = 0; i < ETH_ADDR; i++)
+		nic_addr.address[i] = pio_read_8(&netcfg->mac[i]);
+	rc = nic_report_address(nic, &nic_addr);
+	if (rc != EOK)
+		goto fail;
+
+	ddf_msg(LVL_NOTE, "MAC address: " PRIMAC, ARGSMAC(nic_addr.address));
+
+	/*
+	 * Enable IRQ
+	 */
+	rc = hw_res_enable_interrupt(ddf_dev_parent_sess_get(dev),
+	    virtio_net->irq);
+	if (rc != EOK) {
+		ddf_msg(LVL_NOTE, "Failed to enable interrupt");
+		goto fail;
+	}
+
+	ddf_msg(LVL_NOTE, "Registered IRQ %d", virtio_net->irq);
+
+	/* Go live */
+	virtio_device_setup_finalize(vdev);
+
+	return EOK;
+
+fail:
+	virtio_net_teardown_bufs(virtio_net->rx_buf);
+	virtio_net_teardown_bufs(virtio_net->tx_buf);
+	virtio_net_teardown_bufs(virtio_net->ct_buf);
+
+	virtio_device_setup_fail(vdev);
+	virtio_pci_dev_cleanup(vdev);
+	return rc;
+}
+
+static void virtio_net_uninitialize(ddf_dev_t *dev)
+{
+	nic_t *nic = ddf_dev_data_get(dev);
+	virtio_net_t *virtio_net = (virtio_net_t *) nic_get_specific(nic);
+
+	virtio_net_teardown_bufs(virtio_net->rx_buf);
+	virtio_net_teardown_bufs(virtio_net->tx_buf);
+	virtio_net_teardown_bufs(virtio_net->ct_buf);
+
+	virtio_device_setup_fail(&virtio_net->virtio_dev);
+	virtio_pci_dev_cleanup(&virtio_net->virtio_dev);
+}
+
+static void virtio_net_send(nic_t *nic, void *data, size_t size)
+{
+	virtio_net_t *virtio_net = nic_get_specific(nic);
+	virtio_dev_t *vdev = &virtio_net->virtio_dev;
+
+	if (size > sizeof(virtio_net) + TX_BUF_SIZE) {
+		ddf_msg(LVL_WARN, "TX data too big, frame dropped");
+		return;
+	}
+
+	uint16_t descno = virtio_net_alloc_desc(vdev, TX_QUEUE_1,
+	    &virtio_net->tx_free_head);
+	if (descno == (uint16_t) -1U) {
+		ddf_msg(LVL_WARN, "No TX buffers available, frame dropped");
+		return;
+	}
+	assert(descno < TX_BUFFERS);
+
+	/* Setup the packed header */
+	virtio_net_hdr_t *hdr = (virtio_net_hdr_t *) virtio_net->tx_buf[descno];
+	memset(hdr, 0, sizeof(virtio_net_hdr_t));
+	hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+	/* Copy packet data into the buffer just past the header */
+	memcpy(&hdr[1], data, size);
+
+	/*
+	 * Set the descriptor, put it into the virtqueue and notify the device
+	 */
+	virtio_virtq_desc_set(vdev, TX_QUEUE_1, descno,
+	    virtio_net->tx_buf_p[descno], sizeof(virtio_net_hdr_t) + size, 0, 0);
+	virtio_virtq_produce_available(vdev, TX_QUEUE_1, descno);
+}
+
+
+static errno_t virtio_net_on_multicast_mode_change(nic_t *nic,
+    nic_multicast_mode_t new_mode, const nic_address_t *address_list,
+    size_t address_count)
+{
+	switch (new_mode) {
+	case NIC_MULTICAST_BLOCKED:
+		nic_report_hw_filtering(nic, -1, 0, -1);
+		return EOK;
+	case NIC_MULTICAST_LIST:
+		nic_report_hw_filtering(nic, -1, 0, -1);
+		return EOK;
+	case NIC_MULTICAST_PROMISC:
+		nic_report_hw_filtering(nic, -1, 0, -1);
+		return EOK;
+	default:
+		return ENOTSUP;
+	}
+	return EOK;
+}
+
+static errno_t virtio_net_on_broadcast_mode_change(nic_t *nic,
+    nic_broadcast_mode_t new_mode)
+{
+	switch (new_mode) {
+	case NIC_BROADCAST_BLOCKED:
+		return ENOTSUP;
+	case NIC_BROADCAST_ACCEPTED:
+		return EOK;
+	default:
+		return ENOTSUP;
+	}
+}
+
+static errno_t virtio_net_dev_add(ddf_dev_t *dev)
+{
+	ddf_msg(LVL_NOTE, "%s %s (handle = %zu)", __func__,
+	    ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
+
+	errno_t rc = virtio_net_initialize(dev);
+	if (rc != EOK)
+		return rc;
+
+	ddf_fun_t *fun = ddf_fun_create(dev, fun_exposed, "port0");
+	if (fun == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+	nic_t *nic = ddf_dev_data_get(dev);
+	nic_set_ddf_fun(nic, fun);
+	ddf_fun_set_ops(fun, &virtio_net_dev_ops);
+
+	nic_set_send_frame_handler(nic, virtio_net_send);
+	nic_set_filtering_change_handlers(nic, NULL,
+	    virtio_net_on_multicast_mode_change,
+	    virtio_net_on_broadcast_mode_change, NULL, NULL);
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding device function");
+		goto uninitialize;
+	}
+
+	rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding function to category");
+		goto unbind;
+	}
+
+	ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
+	    ddf_dev_get_name(dev));
+
+	return EOK;
+
+unbind:
+	ddf_fun_unbind(fun);
+uninitialize:
+	virtio_net_uninitialize(dev);
+error:
+	return rc;
+}
+
+static errno_t virtio_net_get_device_info(ddf_fun_t *fun,
+    nic_device_info_t *info)
+{
+	nic_t *nic = nic_get_from_ddf_fun(fun);
+	if (!nic)
+		return ENOENT;
+
+	str_cpy(info->vendor_name, sizeof(info->vendor_name), "Red Hat, Inc.");
+	str_cpy(info->model_name, sizeof(info->model_name),
+	    "Virtio network device");
+
+	return EOK;
+}
+
+static errno_t virtio_net_get_cable_state(ddf_fun_t *fun,
+    nic_cable_state_t *state)
+{
+	*state = NIC_CS_PLUGGED;
+	return EOK;
+}
+
+static errno_t virtio_net_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	*speed = 1000;
+	*duplex = NIC_CM_FULL_DUPLEX;
+	*role = NIC_ROLE_UNKNOWN;
+	return EOK;
+}
+
+static nic_iface_t virtio_net_nic_iface = {
+	.get_device_info = virtio_net_get_device_info,
+	.get_cable_state = virtio_net_get_cable_state,
+	.get_operation_mode = virtio_net_get_operation_mode,
+};
+
+int main(void)
+{
+	printf("%s: HelenOS virtio-net driver\n", NAME);
+
+	if (nic_driver_init(NAME) != EOK)
+		return 1;
+
+	nic_driver_implement(&virtio_net_driver_ops, &virtio_net_dev_ops,
+	    &virtio_net_nic_iface);
+
+	(void) ddf_log_init(NAME);
+	return ddf_driver_main(&virtio_net_driver);
+}
Index: uspace/drv/nic/virtio-net/virtio-net.h
===================================================================
--- uspace/drv/nic/virtio-net/virtio-net.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/drv/nic/virtio-net/virtio-net.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VIRTIO_NET_H_
+#define _VIRTIO_NET_H_
+
+#include <virtio-pci.h>
+#include <abi/cap.h>
+#include <nic/nic.h>
+
+#define RX_BUFFERS	8
+#define TX_BUFFERS	8
+#define CT_BUFFERS	4
+
+/** Device handles packets with partial checksum. */
+#define VIRTIO_NET_F_CSUM		(1U << 0)
+/** Driver handles packets with partial checksum. */
+#define VIRTIO_NET_F_GUEST_CSUM		(1U << 2)
+/** Device has given MAC address. */
+#define VIRTIO_NET_F_MAC		(1U << 5)
+/** Control channel is available */
+#define VIRTIO_NET_F_CTRL_VQ		(1U << 17)
+
+#define VIRTIO_NET_HDR_GSO_NONE 0
+typedef struct {
+	uint8_t flags;
+	uint8_t gso_type;
+	uint16_t hdr_len;
+	uint16_t gso_size;
+	uint16_t csum_start;
+	uint16_t csum_offset;
+
+	// XXX: QEMU uses the legacy layout for some reason
+#if 0
+	uint16_t num_buffers;
+#endif
+} virtio_net_hdr_t;
+
+typedef struct {
+	uint8_t mac[ETH_ADDR];
+} virtio_net_cfg_t;
+
+typedef struct {
+	virtio_dev_t virtio_dev;
+	void *rx_buf[RX_BUFFERS];
+	uintptr_t rx_buf_p[RX_BUFFERS];
+	void *tx_buf[TX_BUFFERS];
+	uintptr_t tx_buf_p[TX_BUFFERS];
+	void *ct_buf[CT_BUFFERS];
+	uintptr_t ct_buf_p[CT_BUFFERS];
+
+	uint16_t tx_free_head;
+	uint16_t ct_free_head;
+
+	int irq;
+	cap_irq_handle_t irq_handle;
+} virtio_net_t;
+
+#endif
Index: uspace/drv/nic/virtio-net/virtio-net.ma
===================================================================
--- uspace/drv/nic/virtio-net/virtio-net.ma	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/drv/nic/virtio-net/virtio-net.ma	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,2 @@
+10 pci/ven=1af4&dev=1000
+10 pci/ven=1af4&dev=1041
Index: uspace/lib/bithenge/src/helenos/common.h
===================================================================
--- uspace/lib/bithenge/src/helenos/common.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/bithenge/src/helenos/common.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -73,12 +73,4 @@
 }
 
-static inline void *memchr(const void *s, int c, size_t n)
-{
-	for (size_t i = 0; i < n; i++)
-		if (((char *)s)[i] == c)
-			return (void *)(s + i);
-	return NULL;
-}
-
 static inline errno_t bithenge_parse_int(const char *start, bithenge_int_t *result)
 {
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -41,4 +41,5 @@
 EXTRA_OUTPUT = $(LINKER_SCRIPTS)
 EXTRA_CLEAN = $(LINKER_SCRIPTS)
+EXTRA_TEST_CFLAGS = -Wno-deprecated-declarations
 LIBRARY = libc
 SOVERSION = 0.0
@@ -132,6 +133,8 @@
 	generic/malloc.c \
 	generic/stdio/scanf.c \
+	generic/stdio/sprintf.c \
 	generic/stdio/sscanf.c \
 	generic/stdio/sstream.c \
+	generic/stdio/vsprintf.c \
 	generic/sysinfo.c \
 	generic/ipc.c \
@@ -149,4 +152,5 @@
 	generic/adt/prodcons.c \
 	generic/time.c \
+	generic/tmpfile.c \
 	generic/stdio.c \
 	generic/stdlib.c \
@@ -189,4 +193,5 @@
 	test/fibril/timer.c \
 	test/main.c \
+	test/mem.c \
 	test/io/table.c \
 	test/stdio/scanf.c \
@@ -194,4 +199,5 @@
 	test/qsort.c \
 	test/sprintf.c \
+	test/stdio.c \
 	test/stdlib.c \
 	test/str.c
Index: uspace/lib/c/arch/arm32/include/libarch/fibril_context.h
===================================================================
--- uspace/lib/c/arch/arm32/include/libarch/fibril_context.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/arch/arm32/include/libarch/fibril_context.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -49,5 +49,5 @@
 	uint32_t r7;
 	uint32_t r8;
-	/* r9*/
+	/* r9 */
 	uint32_t tls;
 	uint32_t r10;
@@ -57,3 +57,2 @@
 
 #endif
-
Index: uspace/lib/c/generic/async/client.c
===================================================================
--- uspace/lib/c/generic/async/client.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/async/client.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -190,5 +190,4 @@
 	free(msg);
 }
-
 
 /** Mutex protecting inactive_exch_list and avail_phone_cv.
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/ddi.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -220,8 +220,10 @@
 /** Enable PIO for specified HW resource wrt. to the PIO window.
  *
- * @param win      PIO window. May be NULL if the resources are known to be
- *                 absolute.
- * @param res      Resources specifying the I/O range wrt. to the PIO window.
- * @param virt     Virtual address for application's PIO operations.
+ * @param win        PIO window. May be NULL if the resources are known to be
+ *                   absolute.
+ * @param res        Resources specifying the I/O range wrt. to the PIO window.
+ * @param[out] virt  Virtual address for application's PIO operations.
+ * @param[out] phys  If non-NULL, physical address of the resource
+ * @param[out] size  If non-NULL, size of the enabled resource.
  *
  * @return EOK on success.
@@ -229,8 +231,9 @@
  *
  */
-errno_t pio_enable_resource(pio_window_t *win, hw_resource_t *res, void **virt)
+errno_t pio_enable_resource(pio_window_t *win, hw_resource_t *res, void **virt,
+    uintptr_t *phys, size_t *size)
 {
 	uintptr_t addr;
-	size_t size;
+	size_t sz;
 
 	switch (res->type) {
@@ -242,5 +245,5 @@
 			addr += win->io.base;
 		}
-		size = res->res.io_range.size;
+		sz = res->res.io_range.size;
 		break;
 	case MEM_RANGE:
@@ -251,5 +254,5 @@
 			addr += win->mem.base;
 		}
-		size = res->res.mem_range.size;
+		sz = res->res.mem_range.size;
 		break;
 	default:
@@ -257,5 +260,10 @@
 	}
 
-	return pio_enable((void *) addr, size, virt);
+	if (phys)
+		*phys = addr;
+	if (size)
+		*size = sz;
+
+	return pio_enable((void *) addr, sz, virt);
 }
 
Index: uspace/lib/c/generic/io/printf_core.c
===================================================================
--- uspace/lib/c/generic/io/printf_core.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/io/printf_core.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -39,4 +39,5 @@
 #include <stdio.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <io/printf_core.h>
 #include <ctype.h>
Index: uspace/lib/c/generic/io/snprintf.c
===================================================================
--- uspace/lib/c/generic/io/snprintf.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/io/snprintf.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -35,5 +35,4 @@
 #include <stdarg.h>
 #include <stdio.h>
-#include <io/printf_core.h>
 
 /** Print formatted to the given buffer with limited size.
Index: uspace/lib/c/generic/mem.c
===================================================================
--- uspace/lib/c/generic/mem.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/mem.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -1,5 +1,5 @@
 /*
  * Copyright (c) 2005 Martin Decky
- * Copyright (c) 2008 Jiri Svoboda
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -252,4 +252,27 @@
 }
 
+/** Search memory area.
+ *
+ * @param s Memory area
+ * @param c Character (byte) to search for
+ * @param n Size of memory area in bytes
+ *
+ * @return Pointer to the first occurrence of @a c in the first @a n
+ *         bytes of @a s or @c NULL if not found.
+ */
+void *memchr(const void *s, int c, size_t n)
+{
+	uint8_t *u = (uint8_t *) s;
+	unsigned char uc = (unsigned char) c;
+	size_t i;
+
+	for (i = 0; i < n; i++) {
+		if (u[i] == uc)
+			return (void *) &u[i];
+	}
+
+	return NULL;
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/stdio.c
===================================================================
--- uspace/lib/c/generic/stdio.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/stdio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2017 Jiri Svoboda
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -34,6 +34,50 @@
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
+#include <str.h>
+#include <str_error.h>
+#include <tmpfile.h>
 #include <vfs/vfs.h>
+
+/** Static buffer for tmpnam function */
+static char tmpnam_buf[L_tmpnam];
+
+/** Get stream position.
+ *
+ * @param stream Stream
+ * @param pos Place to store position
+ *
+ * @return Zero on success, non-zero on failure
+ */
+int fgetpos(FILE *stream, fpos_t *pos)
+{
+	off64_t p;
+
+	p = ftell64(stream);
+	if (p < 0)
+		return -1;
+
+	pos->pos = p;
+	return 0;
+}
+
+/** Get stream position.
+ *
+ * @param stream Stream
+ * @param pos Position
+ *
+ * @return Zero on sucess, non-zero on failure
+ */
+int fsetpos(FILE *stream, const fpos_t *pos)
+{
+	int rc;
+
+	rc = fseek64(stream, pos->pos, SEEK_SET);
+	if (rc < 0)
+		return -1;
+
+	return 0;
+}
 
 /** Rename file or directory (C standard) */
@@ -44,4 +88,8 @@
 	rc = vfs_rename_path(old_path, new_path);
 	if (rc != EOK) {
+		/*
+		 * Note that ISO C leaves the value of errno undefined,
+		 * whereas according to UN*X standards, it is set.
+		 */
 		errno = rc;
 		return -1;
@@ -58,4 +106,8 @@
 	rc = vfs_unlink_path(path);
 	if (rc != EOK) {
+		/*
+		 * Note that ISO C leaves the value of errno undefined,
+		 * whereas according to UN*X standards, it is set.
+		 */
 		errno = rc;
 		return -1;
@@ -65,4 +117,60 @@
 }
 
+/** Create a temporary file.
+ *
+ * @return Open stream descriptor or @c NULL on error. In that case
+ *         errno is set (UN*X). Note that ISO C leaves the value of errno
+ *         undefined.
+ */
+FILE *tmpfile(void)
+{
+	int file;
+	FILE *stream;
+
+	file = __tmpfile();
+	if (file < 0) {
+		printf("file is < 0\n");
+		errno = EEXIST;
+		return NULL;
+	}
+
+	stream = fdopen(file, "w+");
+	if (stream == NULL) {
+		printf("stream = NULL\n");
+		vfs_put(file);
+		errno = EACCES;
+		return NULL;
+	}
+
+	return stream;
+}
+
+/** Create name for a temporary file.
+ *
+ * @param s Pointer to array of at least L_tmpnam bytes or @c NULL.
+ * @return The pointer @a s or pointer to internal static buffer on success,
+ *         @c NULL on error.
+ */
+char *tmpnam(char *s)
+{
+	char *p;
+
+	p = (s != NULL) ? s : tmpnam_buf;
+	return __tmpnam(p);
+}
+
+/** Print error message and string representation of @c errno.
+ *
+ * @param s Error message
+ */
+void perror(const char *s)
+{
+	if (s != NULL && *s != '\0')
+		fprintf(stderr, "%s: %s\n", s, str_error(errno));
+	else
+		fprintf(stderr, "%s\n", str_error(errno));
+}
+
+
 /** @}
  */
Index: uspace/lib/c/generic/stdio/sprintf.c
===================================================================
--- uspace/lib/c/generic/stdio/sprintf.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/c/generic/stdio/sprintf.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/** Print formatted to string.
+ *
+ * This function is unsafe, thus it is marked as deprecated. It should never
+ * be used in native HelenOS code.
+ *
+ * @param str Buffer to write to
+ * @param fmt Format string
+ *
+ * @return Number of characters printed on success, negative value on failure
+ */
+int sprintf(char *s, const char *fmt, ...)
+{
+	int rc;
+
+	va_list args;
+	va_start(args, fmt);
+	rc = vsnprintf(s, SIZE_MAX, fmt, args);
+	va_end(args);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/stdio/vsprintf.c
===================================================================
--- uspace/lib/c/generic/stdio/vsprintf.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/c/generic/stdio/vsprintf.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/** Print formatted to string with arguments passed as va_list.
+ *
+ * This function is unsafe, thus it is marked as deprecated. It should never
+ * be used in native HelenOS code.
+ *
+ * @param str Buffer to write to
+ * @param fmt Format string
+ * @param ap Arguments
+ *
+ * @return Number of characters printed on success, negative value on failure
+ */
+int vsprintf(char *s, const char *fmt, va_list ap)
+{
+	return vsnprintf(s, SIZE_MAX, fmt, ap);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/stdlib.c
===================================================================
--- uspace/lib/c/generic/stdlib.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/stdlib.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -195,4 +195,67 @@
 }
 
+/** Compute the absolute value of an integer.
+ *
+ * If the result cannot be represented, the behavior is undefined.
+ *
+ * @param j Integer
+ * @return The absolute value of @a j
+ */
+int abs(int j)
+{
+	int aj;
+
+	if (j < 0) {
+		aj = -j;
+		assert(aj >= 0);
+	} else {
+		aj = j;
+	}
+
+	return aj;
+}
+
+/** Compute the absolute value of a long integer.
+ *
+ * If the result cannot be represented, the behavior is undefined.
+ *
+ * @param j Long integer
+ * @return The absolute value of @a j
+ */
+long labs(long j)
+{
+	long aj;
+
+	if (j < 0) {
+		aj = -j;
+		assert(aj >= 0);
+	} else {
+		aj = j;
+	}
+
+	return aj;
+}
+
+/** Compute the absolute value of a long long integer.
+ *
+ * If the result cannot be represented, the behavior is undefined.
+ *
+ * @param j Long long integer
+ * @return The absolute value of @a j
+ */
+long long llabs(long long j)
+{
+	long long aj;
+
+	if (j < 0) {
+		aj = -j;
+		assert(aj >= 0);
+	} else {
+		aj = j;
+	}
+
+	return aj;
+}
+
 /** Compute quotient and remainder of int division.
  *
Index: uspace/lib/c/generic/tmpfile.c
===================================================================
--- uspace/lib/c/generic/tmpfile.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/c/generic/tmpfile.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file Temporary files
+ */
+
+#include <errno.h>
+#include <fibril_synch.h>
+#include <stdio.h>
+#include <str.h>
+#include <tmpfile.h>
+#include <vfs/vfs.h>
+
+static size_t tmpfile_cnt = 0;
+static FIBRIL_MUTEX_INITIALIZE(tmpfile_lock);
+
+/** Create and open file suitable as temporary file based on template.
+ *
+ * This is designed to allow creating temporary files compatible with POSIX
+ * mk(s)temp and tempnam, as well as for the use of ISO C tmpfile, tmpnam.
+ *
+ * @param templ
+ * @param create If @c false, only construct file name
+ *
+ * @return If @a create is true, open file descriptor on success (and
+ *         @a *templ is filled in with actual file name),
+ *         if @a create is false, zero on success. -1 on failure.
+ */
+int __tmpfile_templ(char *templ, bool create)
+{
+	size_t tsize;
+	char *p;
+	int file;
+	errno_t rc;
+
+	tsize = str_size(templ);
+	if (tsize < 6)
+		return -1;
+
+	p = templ + tsize - 6;
+	if (str_cmp(p, "XXXXXX") != 0)
+		return -1;
+
+	fibril_mutex_lock(&tmpfile_lock);
+
+	while (tmpfile_cnt < 1000000) {
+		snprintf(p, 6 + 1, "%06zu", tmpfile_cnt);
+		if (create) {
+			/* Try creating file */
+			rc = vfs_lookup(templ, WALK_MUST_CREATE |
+			    WALK_REGULAR, &file);
+			if (rc == EOK) {
+				rc = vfs_open(file, MODE_READ | MODE_WRITE);
+				if (rc == EOK) {
+					++tmpfile_cnt;
+					fibril_mutex_unlock(&tmpfile_lock);
+					return file;
+				}
+
+				vfs_put(file);
+			}
+		} else {
+			/* Test if file exists */
+			rc = vfs_lookup(templ, 0, &file);
+			if (rc != EOK) {
+				++tmpfile_cnt;
+				fibril_mutex_unlock(&tmpfile_lock);
+				return 0;
+			}
+
+			vfs_put(file);
+		}
+
+		++tmpfile_cnt;
+	}
+
+	fibril_mutex_unlock(&tmpfile_lock);
+	return -1;
+}
+
+/** Create and open temporary (unnamed) file.
+ *
+ * @return Open file descriptor on success, -1 on failure.
+ */
+int __tmpfile(void)
+{
+	int file;
+	char namebuf[L_tmpnam];
+
+	str_cpy(namebuf, L_tmpnam, "/tmp/tmp.XXXXXX");
+
+	file = __tmpfile_templ(namebuf, true);
+	if (file < 0)
+		return -1;
+
+	(void) vfs_unlink_path(namebuf);
+	return file;
+}
+
+/** Construct temporary file name.
+ *
+ * @param namebuf Buffer that can hold at least L_tmpnam bytes
+ * @return @a namebuf on success, @c NULL on failure
+ */
+char *__tmpnam(char *namebuf)
+{
+	int rc;
+
+	str_cpy(namebuf, L_tmpnam, "/tmp/tmp.XXXXXX");
+
+	rc = __tmpfile_templ(namebuf, false);
+	if (rc < 0)
+		return NULL;
+
+	return namebuf;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -285,12 +285,12 @@
 {
 	size_t abs_size;
-	char *abs = vfs_absolutize(path, &abs_size);
-	if (!abs)
+	char *abs_path = vfs_absolutize(path, &abs_size);
+	if (abs_path == NULL)
 		return ENOMEM;
 
 	int fd;
-	errno_t rc = vfs_lookup(abs, WALK_DIRECTORY, &fd);
+	errno_t rc = vfs_lookup(abs_path, WALK_DIRECTORY, &fd);
 	if (rc != EOK) {
-		free(abs);
+		free(abs_path);
 		return rc;
 	}
@@ -305,5 +305,5 @@
 
 	cwd_fd = fd;
-	cwd_path = abs;
+	cwd_path = abs_path;
 	cwd_size = abs_size;
 
Index: uspace/lib/c/include/adt/hash_table.h
===================================================================
--- uspace/lib/c/include/adt/hash_table.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/adt/hash_table.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -102,5 +102,4 @@
     void *);
 
-
 #endif
 
Index: uspace/lib/c/include/cc.h
===================================================================
--- uspace/lib/c/include/cc.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/cc.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -44,5 +44,4 @@
 #endif
 
-
 #endif
 
Index: uspace/lib/c/include/ddi.h
===================================================================
--- uspace/lib/c/include/ddi.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/ddi.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -40,4 +40,5 @@
 #include <stdint.h>
 #include <sys/time.h>
+#include <byteorder.h>
 #include <abi/ddi/irq.h>
 #include <device/hw_res.h>
@@ -64,5 +65,6 @@
 
 extern errno_t pio_enable_range(addr_range_t *, void **);
-extern errno_t pio_enable_resource(pio_window_t *, hw_resource_t *, void **);
+extern errno_t pio_enable_resource(pio_window_t *, hw_resource_t *, void **,
+    uintptr_t *, size_t *);
 extern errno_t pio_enable(void *, size_t, void **);
 extern errno_t pio_disable(void *, size_t);
@@ -85,4 +87,54 @@
 extern uint64_t pio_read_64(const ioport64_t *);
 
+static inline void pio_write_le16(ioport16_t *reg, uint16_t val)
+{
+	pio_write_16(reg, host2uint16_t_le(val));
+}
+static inline void pio_write_be16(ioport16_t *reg, uint16_t val)
+{
+	pio_write_16(reg, host2uint16_t_be(val));
+}
+static inline void pio_write_le32(ioport32_t *reg, uint32_t val)
+{
+	pio_write_32(reg, host2uint32_t_le(val));
+}
+static inline void pio_write_be32(ioport32_t *reg, uint32_t val)
+{
+	pio_write_32(reg, host2uint32_t_be(val));
+}
+static inline void pio_write_le64(ioport64_t *reg, uint64_t val)
+{
+	pio_write_64(reg, host2uint64_t_le(val));
+}
+static inline void pio_write_be64(ioport64_t *reg, uint64_t val)
+{
+	pio_write_64(reg, host2uint64_t_be(val));
+}
+
+static inline uint16_t pio_read_le16(const ioport16_t *reg)
+{
+	return uint16_t_le2host(pio_read_16(reg));
+}
+static inline uint16_t pio_read_be16(const ioport16_t *reg)
+{
+	return uint16_t_be2host(pio_read_16(reg));
+}
+static inline uint32_t pio_read_le32(const ioport32_t *reg)
+{
+	return uint32_t_le2host(pio_read_32(reg));
+}
+static inline uint32_t pio_read_be32(const ioport32_t *reg)
+{
+	return uint32_t_be2host(pio_read_32(reg));
+}
+static inline uint64_t pio_read_le64(const ioport64_t *reg)
+{
+	return uint64_t_le2host(pio_read_64(reg));
+}
+static inline uint64_t pio_read_be64(const ioport64_t *reg)
+{
+	return uint64_t_be2host(pio_read_64(reg));
+}
+
 static inline uint8_t pio_change_8(ioport8_t *reg, uint8_t val, uint8_t mask,
     useconds_t delay)
Index: uspace/lib/c/include/fibril_synch.h
===================================================================
--- uspace/lib/c/include/fibril_synch.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/fibril_synch.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -67,6 +67,6 @@
 typedef struct {
 	fibril_owner_info_t oi;  /**< Keep this the first thing. */
-	unsigned writers;
-	unsigned readers;
+	unsigned int writers;
+	unsigned int readers;
 	list_t waiters;
 } fibril_rwlock_t;
@@ -145,5 +145,5 @@
 /** A counting semaphore for fibrils. */
 typedef struct {
-	long count;
+	long int count;
 	list_t waiters;
 } fibril_semaphore_t;
Index: uspace/lib/c/include/ipc/common.h
===================================================================
--- uspace/lib/c/include/ipc/common.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/ipc/common.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -50,5 +50,5 @@
 	task_id_t in_task_id;
 	sysarg_t in_phone_hash;
-	unsigned flags;
+	unsigned int flags;
 	struct async_call *label;
 	cap_call_handle_t cap_handle;
Index: uspace/lib/c/include/macros.h
===================================================================
--- uspace/lib/c/include/macros.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/macros.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -38,5 +38,5 @@
 #define min(a, b)  ((a) < (b) ? (a) : (b))
 #define max(a, b)  ((a) > (b) ? (a) : (b))
-#define abs(a)     ((a) >= 0 ? (a) : -(a))
+#define mabs(a)    ((a) >= 0 ? (a) : -(a))
 
 #define ARRAY_SIZE(array)   (sizeof(array) / sizeof(array[0]))
Index: uspace/lib/c/include/mem.h
===================================================================
--- uspace/lib/c/include/mem.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/mem.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2005 Martin Decky
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,4 +50,6 @@
 extern int memcmp(const void *, const void *, size_t)
     __attribute__((nonnull(1, 2)));
+extern void *memchr(const void *, int, size_t)
+    __attribute__((nonnull(1)));
 
 #endif
Index: uspace/lib/c/include/stdbool.h
===================================================================
--- uspace/lib/c/include/stdbool.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/stdbool.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -41,5 +41,5 @@
 #define true   1
 
-#define __bool_true_false_are_defined 1
+#define __bool_true_false_are_defined  1
 
 #endif
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/stdio.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2005 Martin Decky
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -36,33 +37,55 @@
 #define LIBC_STDIO_H_
 
+#include <offset.h>
 #include <stdarg.h>
 #include <io/verify.h>
+#include <_bits/NULL.h>
 #include <_bits/size_t.h>
 #include <_bits/wchar_t.h>
 #include <_bits/wint_t.h>
 
-#define EOF  (-1)
-
-#ifndef SEEK_SET
-#define SEEK_SET  0
-#endif
-
-#ifndef SEEK_CUR
-#define SEEK_CUR  1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END  2
-#endif
-
-/** Default size for stream I/O buffers */
-#define BUFSIZ  4096
-
-/** Recommended size of fixed-size array for holding file names. */
-#define FILENAME_MAX 4096
-
 /** Forward declaration */
 struct _IO_FILE;
 typedef struct _IO_FILE FILE;
+
+/** File position */
+typedef struct {
+	off64_t pos;
+} fpos_t;
+
+#ifndef _HELENOS_SOURCE
+#define _IONBF 0
+#define _IOLBF 1
+#define _IOFBF 2
+#endif
+
+/** Default size for stream I/O buffers */
+#define BUFSIZ  4096
+
+#define EOF  (-1)
+
+/** Max number of files that is guaranteed to be able to open at the same time */
+#define FOPEN_MAX VFS_MAX_OPEN_FILES
+
+/** Recommended size of fixed-size array for holding file names. */
+#define FILENAME_MAX 4096
+
+/** Length of "/tmp/tmp.XXXXXX" + 1 */
+#define L_tmpnam 16
+
+#ifndef SEEK_SET
+#define SEEK_SET  0
+#endif
+
+#ifndef SEEK_CUR
+#define SEEK_CUR  1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END  2
+#endif
+
+/** Minimum number of unique temporary file names */
+#define TMP_MAX 1000000
 
 extern FILE *stdin;
@@ -74,4 +97,5 @@
 extern int fgetc(FILE *);
 extern char *fgets(char *, int, FILE *);
+extern char *gets(char *, size_t) __attribute__((deprecated));
 
 extern int getchar(void);
@@ -104,7 +128,11 @@
 extern int vasprintf(char **, const char *, va_list);
 extern int asprintf(char **, const char *, ...)
-#endif
     _HELENOS_PRINTF_ATTRIBUTE(2, 3);
+#endif
 extern int vsnprintf(char *, size_t, const char *, va_list);
+
+extern int sprintf(char *, const char *, ...)
+    __attribute__((deprecated)) _HELENOS_PRINTF_ATTRIBUTE(2, 3);
+extern int vsprintf(char *, const char *, va_list) __attribute__((deprecated));
 
 /* Formatted input */
@@ -124,4 +152,7 @@
 extern size_t fwrite(const void *, size_t, size_t, FILE *);
 
+extern int fgetpos(FILE *, fpos_t *);
+extern int fsetpos(FILE *, const fpos_t *);
+
 extern int fseek(FILE *, long, int);
 extern void rewind(FILE *);
@@ -133,19 +164,15 @@
 extern void clearerr(FILE *);
 
+extern void perror(const char *);
+
 extern void setvbuf(FILE *, void *, int, size_t);
 extern void setbuf(FILE *, void *);
 
 /* Misc file functions */
+extern int remove(const char *);
 extern int rename(const char *, const char *);
-extern int remove(const char *);
-
-#ifndef _HELENOS_SOURCE
-#define _IONBF 0
-#define _IOLBF 1
-#define _IOFBF 2
-
-extern char *gets(char *, size_t);
-
-#endif
+
+extern FILE *tmpfile(void);
+extern char *tmpnam(char *s) __attribute__((deprecated));
 
 #ifdef _HELENOS_SOURCE
Index: uspace/lib/c/include/stdlib.h
===================================================================
--- uspace/lib/c/include/stdlib.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/stdlib.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -87,4 +87,8 @@
 extern int system(const char *);
 
+extern int abs(int);
+extern long labs(long);
+extern long long llabs(long long);
+
 extern int atoi(const char *);
 extern long atol(const char *);
Index: uspace/lib/c/include/tmpfile.h
===================================================================
--- uspace/lib/c/include/tmpfile.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/c/include/tmpfile.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBC_TMPFILE_H_
+#define LIBC_TMPFILE_H_
+
+#include <stdbool.h>
+
+extern int __tmpfile_templ(char *, bool);
+extern int __tmpfile(void);
+extern char *__tmpnam(char *);
+
+#endif
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -45,5 +45,5 @@
 #include <offset.h>
 
-#define MAX_OPEN_FILES	128
+#define VFS_MAX_OPEN_FILES  128
 
 enum vfs_change_state_type {
Index: uspace/lib/c/test/main.c
===================================================================
--- uspace/lib/c/test/main.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/test/main.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -34,8 +34,10 @@
 PCUT_IMPORT(circ_buf);
 PCUT_IMPORT(fibril_timer);
+PCUT_IMPORT(mem);
 PCUT_IMPORT(odict);
 PCUT_IMPORT(qsort);
 PCUT_IMPORT(scanf);
 PCUT_IMPORT(sprintf);
+PCUT_IMPORT(stdio);
 PCUT_IMPORT(stdlib);
 PCUT_IMPORT(str);
Index: uspace/lib/c/test/mem.c
===================================================================
--- uspace/lib/c/test/mem.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/c/test/mem.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <mem.h>
+#include <pcut/pcut.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(mem);
+
+/** memcpy function */
+PCUT_TEST(memcpy)
+{
+	char buf[5];
+	void *p;
+
+	p = memcpy(buf, "abc\0d", 5);
+	PCUT_ASSERT_TRUE(p == buf);
+
+	PCUT_ASSERT_INT_EQUALS('a', buf[0]);
+	PCUT_ASSERT_INT_EQUALS('b', buf[1]);
+	PCUT_ASSERT_INT_EQUALS('c', buf[2]);
+	PCUT_ASSERT_INT_EQUALS('\0', buf[3]);
+	PCUT_ASSERT_INT_EQUALS('d', buf[4]);
+}
+
+/** memmove function */
+PCUT_TEST(memmove)
+{
+	char buf[] = "abc\0d";
+	void *p;
+
+	p = memmove(buf, buf + 1, 4);
+	PCUT_ASSERT_TRUE(p == buf);
+
+	PCUT_ASSERT_INT_EQUALS('b', buf[0]);
+	PCUT_ASSERT_INT_EQUALS('c', buf[1]);
+	PCUT_ASSERT_INT_EQUALS('\0', buf[2]);
+	PCUT_ASSERT_INT_EQUALS('d', buf[3]);
+	PCUT_ASSERT_INT_EQUALS('d', buf[4]);
+}
+
+/** memcmp function */
+PCUT_TEST(memcmp)
+{
+	const char *s1 = "ab" "\0" "1d";
+	const char *s2 = "ab" "\0" "2d";
+	int c;
+
+	c = memcmp(s1, s2, 3);
+	PCUT_ASSERT_INT_EQUALS(0, c);
+
+	c = memcmp(s1, s2, 4);
+	PCUT_ASSERT_TRUE(c < 0);
+
+	c = memcmp(s2, s1, 4);
+	PCUT_ASSERT_TRUE(c > 0);
+}
+
+/** memchr function */
+PCUT_TEST(memchr)
+{
+	const char *s = "abc\0d";
+	void *p;
+
+	p = memchr(s, 'd', 5);
+	PCUT_ASSERT_TRUE(p == s + 4);
+
+	p = memchr(s, '\0', 5);
+	PCUT_ASSERT_TRUE(p == s + 3);
+
+	p = memchr(s, 'd', 4);
+	PCUT_ASSERT_TRUE(p == NULL);
+}
+
+/** memset function */
+PCUT_TEST(memset)
+{
+	char buf[5];
+	void *p;
+
+	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = 'a';
+	p = memset(buf, 'x', 5);
+	PCUT_ASSERT_TRUE(p == buf);
+
+	PCUT_ASSERT_INT_EQUALS('x', buf[0]);
+	PCUT_ASSERT_INT_EQUALS('x', buf[1]);
+	PCUT_ASSERT_INT_EQUALS('x', buf[2]);
+	PCUT_ASSERT_INT_EQUALS('x', buf[3]);
+	PCUT_ASSERT_INT_EQUALS('x', buf[4]);
+}
+
+PCUT_EXPORT(mem);
Index: uspace/lib/c/test/stdio.c
===================================================================
--- uspace/lib/c/test/stdio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/c/test/stdio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Test stdio module
+ */
+
+#include <errno.h>
+#include <pcut/pcut.h>
+#include <stdio.h>
+#include <str.h>
+#include <tmpfile.h>
+#include <vfs/vfs.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(stdio);
+
+/** remove function */
+PCUT_TEST(remove)
+{
+	char buf[L_tmpnam];
+	char *p;
+	FILE *f;
+	int rc;
+
+	/* Generate unique file name */
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Removing it should fail */
+	rc = remove(buf);
+	PCUT_ASSERT_TRUE(rc != 0);
+
+	f = fopen(buf, "w");
+	PCUT_ASSERT_NOT_NULL(f);
+	fclose(f);
+
+	/* Remove for the first time */
+	rc = remove(buf);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+
+	/* Should fail the second time */
+	rc = remove(buf);
+	PCUT_ASSERT_TRUE(rc != 0);
+}
+
+/** rename function */
+PCUT_TEST(rename)
+{
+	char buf1[L_tmpnam];
+	char buf2[L_tmpnam];
+	char *p;
+	FILE *f;
+	int rc;
+
+	/* Generate first unique file name */
+	p = tmpnam(buf1);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Generate second unique file name */
+	p = tmpnam(buf2);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(buf1, "w");
+	PCUT_ASSERT_NOT_NULL(f);
+	fclose(f);
+
+	/* Rename to the second name */
+	rc = rename(buf1, buf2);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+
+	/* First name should no longer exist */
+	rc = remove(buf1);
+	PCUT_ASSERT_TRUE(rc != 0);
+
+	/* Second can be removed */
+	rc = remove(buf2);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+}
+
+/** tmpfile function */
+PCUT_TEST(tmpfile)
+{
+	FILE *f;
+	char c;
+	size_t n;
+
+	f = tmpfile();
+	PCUT_ASSERT_NOT_NULL(f);
+
+	c = 'x';
+	n = fwrite(&c, sizeof(c), 1, f);
+	PCUT_ASSERT_INT_EQUALS(1, n);
+
+	rewind(f);
+	c = '\0';
+	n = fread(&c, sizeof(c), 1, f);
+	PCUT_ASSERT_INT_EQUALS(1, n);
+	PCUT_ASSERT_INT_EQUALS('x', c);
+
+	fclose(f);
+}
+
+/** tmpnam function with buffer argument */
+PCUT_TEST(tmpnam_buf)
+{
+	char buf[L_tmpnam];
+	char *p;
+	FILE *f;
+
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+	(void) remove(p);
+	fclose(f);
+}
+
+/** tmpnam function called twice */
+PCUT_TEST(tmpnam_twice)
+{
+	char buf1[L_tmpnam];
+	char buf2[L_tmpnam];
+	char *p;
+
+	p = tmpnam(buf1);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	p = tmpnam(buf2);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* We must get two distinct names */
+	PCUT_ASSERT_TRUE(str_cmp(buf1, buf2) != 0);
+}
+
+/** tmpnam function with NULL argument */
+PCUT_TEST(tmpnam_null)
+{
+	char *p;
+	FILE *f;
+
+	p = tmpnam(NULL);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+	(void) remove(p);
+	fclose(f);
+}
+
+/** fgetpos and fsetpos functions */
+PCUT_TEST(fgetpos_setpos)
+{
+	fpos_t pos;
+	int rc;
+	FILE *f;
+
+	f = tmpfile();
+	PCUT_ASSERT_NOT_NULL(f);
+
+	rc = fputs("abc", f);
+	PCUT_ASSERT_TRUE(rc >= 0);
+
+	rc = fgetpos(f, &pos);
+	PCUT_ASSERT_TRUE(rc >= 0);
+
+	rewind(f);
+
+	rc = fsetpos(f, &pos);
+	PCUT_ASSERT_TRUE(rc >= 0);
+
+	(void) fclose(f);
+}
+
+/** perror function with NULL as argument */
+PCUT_TEST(perror_null_msg)
+{
+	errno = EINVAL;
+	perror(NULL);
+}
+
+/** perror function with empty string as argument */
+PCUT_TEST(perror_empty_msg)
+{
+	errno = EINVAL;
+	perror("");
+}
+
+/** perror function with a message argument */
+PCUT_TEST(perror_msg)
+{
+	errno = EINVAL;
+	perror("This is a test");
+}
+
+PCUT_EXPORT(stdio);
Index: uspace/lib/c/test/stdlib.c
===================================================================
--- uspace/lib/c/test/stdlib.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/c/test/stdlib.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -361,4 +361,58 @@
 }
 
+/** abs function of positive number */
+PCUT_TEST(abs_pos)
+{
+	int i;
+
+	i = abs(1);
+	PCUT_ASSERT_TRUE(i == 1);
+}
+
+/** abs function of negative number */
+PCUT_TEST(abs_neg)
+{
+	int i;
+
+	i = abs(-1);
+	PCUT_ASSERT_TRUE(i == 1);
+}
+
+/** labs function of positive number */
+PCUT_TEST(labs_pos)
+{
+	long li;
+
+	li = labs(1);
+	PCUT_ASSERT_TRUE(li == 1);
+}
+
+/** labs function of negative number */
+PCUT_TEST(labs_neg)
+{
+	long li;
+
+	li = labs(-1);
+	PCUT_ASSERT_TRUE(li == 1);
+}
+
+/** llabs function of positive number */
+PCUT_TEST(llabs_pos)
+{
+	long long lli;
+
+	lli = llabs(1);
+	PCUT_ASSERT_TRUE(lli == 1);
+}
+
+/** llabs function of negative number */
+PCUT_TEST(llabs_neg)
+{
+	long long lli;
+
+	lli = llabs(-1);
+	PCUT_ASSERT_TRUE(lli == 1);
+}
+
 /** Integer division */
 PCUT_TEST(div_func)
Index: uspace/lib/drv/include/pci_dev_iface.h
===================================================================
--- uspace/lib/drv/include/pci_dev_iface.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/drv/include/pci_dev_iface.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -42,6 +42,19 @@
 #define PCI_VENDOR_ID	0x00
 #define PCI_DEVICE_ID	0x02
+#define PCI_STATUS 	0x06
 #define PCI_SUB_CLASS	0x0A
 #define PCI_BASE_CLASS	0x0B
+#define PCI_BAR0	0x10
+#define PCI_CAP_PTR	0x34
+
+#define PCI_BAR_COUNT	6
+
+#define PCI_STATUS_CAP_LIST	(1 << 4)
+
+#define PCI_CAP_ID(c)	((c) + 0x0)
+#define PCI_CAP_NEXT(c)	((c) + 0x1)
+
+#define PCI_CAP_PMID		0x1
+#define PCI_CAP_VENDORSPECID	0x9
 
 extern errno_t pci_config_space_read_8(async_sess_t *, uint32_t, uint8_t *);
@@ -52,4 +65,38 @@
 extern errno_t pci_config_space_write_16(async_sess_t *, uint32_t, uint16_t);
 extern errno_t pci_config_space_write_32(async_sess_t *, uint32_t, uint32_t);
+
+static inline errno_t
+pci_config_space_cap_first(async_sess_t *sess, uint8_t *c, uint8_t *id)
+{
+	errno_t rc;
+	uint16_t status;
+
+	rc = pci_config_space_read_16(sess, PCI_STATUS, &status);
+	if (rc != EOK)
+		return rc;
+
+	if (!(status & PCI_STATUS_CAP_LIST)) {
+		*c = 0;
+		return EOK;
+	}
+
+	rc = pci_config_space_read_8(sess, PCI_CAP_PTR, c);
+	if (rc != EOK)
+		return rc;
+	if (!c)
+		return EOK;
+	return pci_config_space_read_8(sess, PCI_CAP_ID(*c), id);
+}
+
+static inline errno_t
+pci_config_space_cap_next(async_sess_t *sess, uint8_t *c, uint8_t *id)
+{
+	errno_t rc = pci_config_space_read_8(sess, PCI_CAP_NEXT(*c), c);
+	if (rc != EOK)
+		return rc;
+	if (!c)
+		return EOK;
+	return pci_config_space_read_8(sess, PCI_CAP_ID(*c), id);
+}
 
 /** PCI device communication interface. */
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -82,5 +82,9 @@
 TEST_SOURCES = \
 	test/main.c \
-	test/scanf.c
+	test/stdio.c \
+	test/stdlib.c \
+	test/unistd.c
+
+EXTRA_TEST_CFLAGS = -Wno-deprecated-declarations
 
 EXPORT_CPPFLAGS = \
Index: uspace/lib/posix/include/posix/stdio.h
===================================================================
--- uspace/lib/posix/include/posix/stdio.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -48,4 +48,6 @@
 extern int fileno(FILE *);
 
+#define P_tmpdir "/tmp"
+
 /* Identifying the Terminal */
 #undef L_ctermid
@@ -59,14 +61,4 @@
     FILE *__restrict__ stream);
 
-/* Error Messages */
-extern void perror(const char *s);
-
-/* File Positioning */
-typedef struct {
-	off64_t offset;
-} fpos_t;
-
-extern int fsetpos(FILE *stream, const fpos_t *pos);
-extern int fgetpos(FILE *__restrict__ stream, fpos_t *__restrict__ pos);
 extern int fseeko(FILE *stream, off_t offset, int whence);
 extern off_t ftello(FILE *stream);
@@ -76,7 +68,4 @@
     _HELENOS_PRINTF_ATTRIBUTE(2, 3);
 extern int vdprintf(int fildes, const char *__restrict__ format, va_list ap);
-extern int sprintf(char *__restrict__ s, const char *__restrict__ format, ...)
-    _HELENOS_PRINTF_ATTRIBUTE(2, 3);
-extern int vsprintf(char *__restrict__ s, const char *__restrict__ format, va_list ap);
 
 /* File Locking */
@@ -90,9 +79,5 @@
 
 /* Temporary Files */
-#undef L_tmpnam
-#define L_tmpnam PATH_MAX
-extern char *tmpnam(char *s);
 extern char *tempnam(const char *dir, const char *pfx);
-extern FILE *tmpfile(void);
 
 #endif /* POSIX_STDIO_H_ */
Index: uspace/lib/posix/include/posix/stdlib.h
===================================================================
--- uspace/lib/posix/include/posix/stdlib.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/include/posix/stdlib.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -42,9 +42,4 @@
 #include <_bits/NULL.h>
 
-/* Absolute Value */
-extern int abs(int i);
-extern long labs(long i);
-extern long long llabs(long long i);
-
 /* Environment Access */
 extern int putenv(char *string);
@@ -63,5 +58,5 @@
 
 /* Legacy Declarations */
-extern char *mktemp(char *tmpl);
+extern char *mktemp(char *tmpl) __attribute__((deprecated));
 extern int bsd_getloadavg(double loadavg[], int nelem);
 
Index: uspace/lib/posix/include/posix/string.h
===================================================================
--- uspace/lib/posix/include/posix/string.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/include/posix/string.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -36,7 +36,4 @@
 #ifndef POSIX_STRING_H_
 #define POSIX_STRING_H_
-
-#include "sys/types.h"
-
 /*
  * TODO: not implemented due to missing locale support
@@ -48,24 +45,7 @@
 
 #include <_bits/NULL.h>
+#include <_bits/size_t.h>
 
-/*
- * These are the same as in HelenOS libc.
- * It would be possible to directly include <str.h> and <mem.h> but
- * it is better not to pollute POSIX namespace with other functions
- * defined in that header.
- *
- * Because libposix is always linked with libc, providing only these
- * forward declarations ought to be enough.
- */
-
-/* From mem.h */
-// #define bzero(ptr, len)  memset((ptr), 0, (len))
-extern void *memset(void *, int, size_t)
-    __attribute__((nonnull(1)));
-extern void *memcpy(void *, const void *, size_t)
-    __attribute__((nonnull(1, 2)));
-extern void *memmove(void *, const void *, size_t)
-    __attribute__((nonnull(1, 2)));
-
+#include "libc/mem.h"
 
 /* Copying and Concatenation */
@@ -80,11 +60,9 @@
 extern char *strndup(const char *s, size_t n);
 
-/* String/Array Comparison */
-extern int memcmp(const void *mem1, const void *mem2, size_t n);
+/* String Comparison */
 extern int strcmp(const char *s1, const char *s2);
 extern int strncmp(const char *s1, const char *s2, size_t n);
 
 /* Search Functions */
-extern void *memchr(const void *mem, int c, size_t n);
 extern char *strchr(const char *s, int c);
 extern char *strrchr(const char *s, int c);
@@ -122,5 +100,4 @@
 #endif
 
-
 #endif  // POSIX_STRING_H_
 
Index: uspace/lib/posix/src/internal/common.h
===================================================================
--- uspace/lib/posix/src/internal/common.h	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/src/internal/common.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -66,5 +66,5 @@
 }
 
-extern aoff64_t posix_pos[MAX_OPEN_FILES];
+extern aoff64_t posix_pos[VFS_MAX_OPEN_FILES];
 
 #endif /* LIBPOSIX_COMMON_H_ */
Index: uspace/lib/posix/src/stdio.c
===================================================================
--- uspace/lib/posix/src/stdio.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/src/stdio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -2,4 +2,5 @@
  * Copyright (c) 2011 Jiri Zarevucky
  * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -38,9 +39,12 @@
 
 #include <assert.h>
-
 #include <errno.h>
-
+#include <stdbool.h>
+#include <tmpfile.h>
+
+#include "posix/fcntl.h"
 #include "posix/stdlib.h"
 #include "posix/string.h"
+#include "posix/sys/stat.h"
 #include "posix/sys/types.h"
 #include "posix/unistd.h"
@@ -169,46 +173,4 @@
 
 /**
- * Write error messages to standard error.
- *
- * @param s Error message.
- */
-void perror(const char *s)
-{
-	if (s == NULL || s[0] == '\0') {
-		fprintf(stderr, "%s\n", strerror(errno));
-	} else {
-		fprintf(stderr, "%s: %s\n", s, strerror(errno));
-	}
-}
-
-/** Restores stream a to position previously saved with fgetpos().
- *
- * @param stream Stream to restore
- * @param pos Position to restore
- * @return Zero on success, non-zero (with errno set) on failure
- */
-int fsetpos(FILE *stream, const fpos_t *pos)
-{
-	return fseek64(stream, pos->offset, SEEK_SET);
-}
-
-/** Saves the stream's position for later use by fsetpos().
- *
- * @param stream Stream to save
- * @param pos Place to store the position
- * @return Zero on success, non-zero (with errno set) on failure
- */
-int fgetpos(FILE *restrict stream, fpos_t *restrict pos)
-{
-	off64_t ret = ftell64(stream);
-	if (ret != -1) {
-		pos->offset = ret;
-		return 0;
-	} else {
-		return -1;
-	}
-}
-
-/**
  * Reposition a file-position indicator in a stream.
  *
@@ -320,35 +282,4 @@
 
 /**
- * Print formatted output to the string.
- *
- * @param s Output string.
- * @param format Format description.
- * @return Either the number of printed characters (excluding null byte) or
- *     negative value on error.
- */
-int sprintf(char *s, const char *restrict format, ...)
-{
-	va_list list;
-	va_start(list, format);
-	int result = vsprintf(s, format, list);
-	va_end(list);
-	return result;
-}
-
-/**
- * Print formatted output to the string.
- *
- * @param s Output string.
- * @param format Format description.
- * @param ap Print arguments.
- * @return Either the number of printed characters (excluding null byte) or
- *     negative value on error.
- */
-int vsprintf(char *s, const char *restrict format, va_list ap)
-{
-	return vsnprintf(s, INT_MAX, format, ap);
-}
-
-/**
  * Acquire file stream for the thread.
  *
@@ -426,32 +357,38 @@
 }
 
-/**
- * Get a unique temporary file name (obsolete).
- *
- * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
- * @return The value of s on success, NULL on failure.
- */
-char *tmpnam(char *s)
-{
-	assert(L_tmpnam >= strlen("/tmp/tnXXXXXX"));
-
-	static char buffer[L_tmpnam + 1];
-	if (s == NULL) {
-		s = buffer;
-	}
-
-	strcpy(s, "/tmp/tnXXXXXX");
-	mktemp(s);
-
-	if (*s == '\0') {
-		/* Errno set by mktemp(). */
-		return NULL;
-	}
-
-	return s;
-}
-
-/**
- * Get an unique temporary file name with additional constraints (obsolete).
+/** Determine if directory is an 'appropriate' temporary directory.
+ *
+ * @param dir Directory path
+ * @return @c true iff directory is appropriate.
+ */
+static bool is_appropriate_tmpdir(const char *dir)
+{
+	struct stat sbuf;
+
+	/* Must not be NULL */
+	if (dir == NULL)
+		return false;
+
+	/* Must not be empty */
+	if (dir[0] == '\0')
+		return false;
+
+	if (stat(dir, &sbuf) != 0)
+		return false;
+
+	/* Must be a directory */
+	if ((sbuf.st_mode & S_IFMT) != S_IFDIR)
+		return false;
+
+	/* Must be writable */
+	if (access(dir, W_OK) != 0)
+		return false;
+
+	return true;
+}
+
+/** Construct unique file name.
+ *
+ * Never use this function.
  *
  * @param dir Path to directory, where the file should be created.
@@ -461,77 +398,34 @@
 char *tempnam(const char *dir, const char *pfx)
 {
-	/* Sequence number of the filename. */
-	static int seq = 0;
-
-	size_t dir_len = strlen(dir);
-	if (dir[dir_len - 1] == '/') {
-		dir_len--;
-	}
-
-	size_t pfx_len = strlen(pfx);
-	if (pfx_len > 5) {
-		pfx_len = 5;
-	}
-
-	char *result = malloc(dir_len + /* slash*/ 1 +
-	    pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
-
-	if (result == NULL) {
-		errno = ENOMEM;
+	const char *dpref;
+	char *d;
+	char *buf;
+	int rc;
+
+	d = getenv("TMPDIR");
+	if (is_appropriate_tmpdir(d))
+		dpref = d;
+	else if (is_appropriate_tmpdir(dir))
+		dpref = dir;
+	else if (is_appropriate_tmpdir(P_tmpdir))
+		dpref = P_tmpdir;
+	else
+		dpref = "/";
+
+	if (dpref[strlen(dpref) - 1] != '/')
+		rc = asprintf(&buf, "%s/%sXXXXXX", dpref, pfx);
+	else
+		rc = asprintf(&buf, "%s%sXXXXXX", dpref, pfx);
+
+	if (rc < 0)
+		return NULL;
+
+	rc = __tmpfile_templ(buf, false);
+	if (rc != 0) {
+		free(buf);
 		return NULL;
 	}
 
-	char *res_ptr = result;
-	strncpy(res_ptr, dir, dir_len);
-	res_ptr += dir_len;
-	strncpy(res_ptr, pfx, pfx_len);
-	res_ptr += pfx_len;
-
-	for (; seq < 1000; ++seq) {
-		snprintf(res_ptr, 8, "%03d.tmp", seq);
-
-		int orig_errno = errno;
-		errno = EOK;
-		/* Check if the file exists. */
-		if (access(result, F_OK) == -1) {
-			if (errno == ENOENT) {
-				errno = orig_errno;
-				break;
-			} else {
-				/* errno set by access() */
-				return NULL;
-			}
-		}
-	}
-
-	if (seq == 1000) {
-		free(result);
-		errno = EINVAL;
-		return NULL;
-	}
-
-	return result;
-}
-
-/**
- * Create and open an unique temporary file.
- * The file is automatically removed when the stream is closed.
- *
- * @param dir Path to directory, where the file should be created.
- * @param pfx Optional prefix up to 5 characters long.
- * @return Newly allocated unique path for temporary file. NULL on failure.
- */
-FILE *tmpfile(void)
-{
-	char filename[] = "/tmp/tfXXXXXX";
-	int fd = mkstemp(filename);
-	if (fd == -1) {
-		/* errno set by mkstemp(). */
-		return NULL;
-	}
-
-	/* Unlink the created file, so that it's removed on close(). */
-	unlink(filename);
-	return fdopen(fd, "w+");
+	return buf;
 }
 
Index: uspace/lib/posix/src/stdlib.c
===================================================================
--- uspace/lib/posix/src/stdlib.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/src/stdlib.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -38,4 +38,5 @@
 
 #include <errno.h>
+#include <tmpfile.h>
 
 #include "posix/fcntl.h"
@@ -49,37 +50,4 @@
 #include "libc/vfs/vfs.h"
 #include "libc/stats.h"
-
-/**
- * Integer absolute value.
- *
- * @param i Input value.
- * @return Absolute value of the parameter.
- */
-int abs(int i)
-{
-	return i < 0 ? -i : i;
-}
-
-/**
- * Long integer absolute value.
- *
- * @param i Input value.
- * @return Absolute value of the parameter.
- */
-long labs(long i)
-{
-	return i < 0 ? -i : i;
-}
-
-/**
- * Long long integer absolute value.
- *
- * @param i Input value.
- * @return Absolute value of the parameter.
- */
-long long llabs(long long i)
-{
-	return i < 0 ? -i : i;
-}
 
 /**
@@ -196,23 +164,26 @@
 int mkstemp(char *tmpl)
 {
-	int fd = -1;
-
-	char *tptr = tmpl + strlen(tmpl) - 6;
-
-	while (fd < 0) {
-		if (*mktemp(tmpl) == '\0') {
-			/* Errno set by mktemp(). */
-			return -1;
-		}
-
-		fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
-
-		if (fd == -1) {
-			/* Restore template to it's original state. */
-			snprintf(tptr, 7, "XXXXXX");
-		}
-	}
-
-	return fd;
+	int tmpl_len;
+	int file;
+
+	tmpl_len = strlen(tmpl);
+	if (tmpl_len < 6) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	char *tptr = tmpl + tmpl_len - 6;
+	if (strcmp(tptr, "XXXXXX") != 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	file = __tmpfile_templ(tmpl, true);
+	if (file < 0) {
+		errno = EIO; // XXX could be more specific
+		return -1;
+	}
+
+	return file;
 }
 
@@ -227,5 +198,8 @@
 char *mktemp(char *tmpl)
 {
-	int tmpl_len = strlen(tmpl);
+	int tmpl_len;
+	int rc;
+
+	tmpl_len = strlen(tmpl);
 	if (tmpl_len < 6) {
 		errno = EINVAL;
@@ -241,26 +215,7 @@
 	}
 
-	static int seq = 0;
-
-	for (; seq < 1000000; ++seq) {
-		snprintf(tptr, 7, "%06d", seq);
-
-		int orig_errno = errno;
-		errno = 0;
-		/* Check if the file exists. */
-		if (access(tmpl, F_OK) == -1) {
-			if (errno == ENOENT) {
-				errno = orig_errno;
-				break;
-			} else {
-				/* errno set by access() */
-				*tmpl = '\0';
-				return tmpl;
-			}
-		}
-	}
-
-	if (seq == 10000000) {
-		errno = EEXIST;
+	rc = __tmpfile_templ(tmpl, false);
+	if (rc != 0) {
+		errno = EIO; // XXX could be more specific
 		*tmpl = '\0';
 		return tmpl;
Index: uspace/lib/posix/src/stdlib/strtold.c
===================================================================
--- uspace/lib/posix/src/stdlib/strtold.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/src/stdlib/strtold.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -52,8 +52,4 @@
 #ifndef HUGE_VALL
 #define HUGE_VALL (+1.0l / +0.0l)
-#endif
-
-#ifndef abs
-#define abs(x) (((x) < 0) ? -(x) : (x))
 #endif
 
Index: uspace/lib/posix/src/string.c
===================================================================
--- uspace/lib/posix/src/string.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/src/string.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -288,27 +288,4 @@
 
 	return 0;
-}
-
-/**
- * Find byte in memory.
- *
- * @param mem Memory area in which to look for the byte.
- * @param c Byte to look for.
- * @param n Maximum number of bytes to be inspected.
- * @return Pointer to the specified byte on success,
- *     NULL pointer otherwise.
- */
-void *memchr(const void *mem, int c, size_t n)
-{
-	assert(mem != NULL);
-
-	const unsigned char *s = mem;
-
-	for (size_t i = 0; i < n; ++i) {
-		if (s[i] == (unsigned char) c) {
-			return (void *) &s[i];
-		}
-	}
-	return NULL;
 }
 
Index: uspace/lib/posix/src/unistd.c
===================================================================
--- uspace/lib/posix/src/unistd.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/src/unistd.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -39,5 +39,7 @@
 #include <errno.h>
 
+#include "posix/dirent.h"
 #include "posix/string.h"
+#include "posix/sys/types.h"
 #include "posix/fcntl.h"
 
@@ -51,5 +53,5 @@
 
 // FIXME: replace with a hash table
-aoff64_t posix_pos[MAX_OPEN_FILES];
+aoff64_t posix_pos[VFS_MAX_OPEN_FILES];
 
 /* Array of environment variable strings (NAME=VALUE). */
@@ -368,8 +370,14 @@
 		 */
 		int fd = open(path, O_RDONLY);
-		if (fd < 0)
-			return -1;
-		close(fd);
-		return 0;
+		if (fd >= 0) {
+			close(fd);
+			return 0;
+		}
+		DIR *dir = opendir(path);
+		if (dir != NULL) {
+			closedir(dir);
+			return 0;
+		}
+		return -1;
 	} else {
 		/* Invalid amode argument. */
Index: uspace/lib/posix/test/main.c
===================================================================
--- uspace/lib/posix/test/main.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/lib/posix/test/main.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2014 Vojtech Horky
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,5 +31,7 @@
 PCUT_INIT;
 
-PCUT_IMPORT(scanf);
+PCUT_IMPORT(stdio);
+PCUT_IMPORT(stdlib);
+PCUT_IMPORT(unistd);
 
 PCUT_MAIN();
Index: pace/lib/posix/test/scanf.c
===================================================================
--- uspace/lib/posix/test/scanf.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ 	(revision )
@@ -1,185 +1,0 @@
-/*
- * Copyright (c) 2014 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-
-#include <errno.h>
-
-#include "posix/stdio.h"
-
-#include <pcut/pcut.h>
-
-#define EPSILON 0.000001
-
-PCUT_INIT;
-
-PCUT_TEST_SUITE(scanf);
-
-
-#ifndef UARCH_sparc64
-
-/*
- * We need some floating point functions for scanf() imlementation
- * that are not yet available for SPARC-64.
- */
-
-PCUT_TEST(int_decimal)
-{
-	int number;
-	int rc = sscanf("4242", "%d", &number);
-	PCUT_ASSERT_INT_EQUALS(1, rc);
-	PCUT_ASSERT_INT_EQUALS(4242, number);
-}
-
-PCUT_TEST(int_negative_decimal)
-{
-	int number;
-	int rc = sscanf("-53", "%d", &number);
-	PCUT_ASSERT_INT_EQUALS(1, rc);
-	PCUT_ASSERT_INT_EQUALS(-53, number);
-}
-
-/*
- * The following tests were copied from stdio/scanf.c where they were
- * commented-out. We ought to convert them to more independent tests
- * eventually.
- */
-
-PCUT_TEST(int_misc)
-{
-	unsigned char uhh;
-	signed char shh;
-	unsigned short uh;
-	short sh;
-	unsigned udef;
-	int sdef;
-	unsigned long ul;
-	long sl;
-	unsigned long long ull;
-	long long sll;
-	void *p;
-
-	int rc = sscanf(
-	    "\n j tt % \t -121314 98765 aqw 0765 0x77 0xABCDEF88 -99 884",
-	    " j tt %%%3hhd%1hhu%3hd %3hu%u aqw%n %lo%llx %p %li %lld",
-	    &shh, &uhh, &sh, &uh, &udef, &sdef, &ul, &ull, &p, &sl, &sll);
-
-	PCUT_ASSERT_INT_EQUALS(10, rc);
-
-	PCUT_ASSERT_INT_EQUALS(-12, shh);
-	PCUT_ASSERT_INT_EQUALS(1, uhh);
-	PCUT_ASSERT_INT_EQUALS(314, sh);
-	PCUT_ASSERT_INT_EQUALS(987, uh);
-	PCUT_ASSERT_INT_EQUALS(65, udef);
-	PCUT_ASSERT_INT_EQUALS(28, sdef);
-	PCUT_ASSERT_INT_EQUALS(0765, ul);
-	PCUT_ASSERT_INT_EQUALS(0x77, ull);
-	PCUT_ASSERT_INT_EQUALS(0xABCDEF88, (long long) (uintptr_t) p);
-	PCUT_ASSERT_INT_EQUALS(-99, sl);
-	PCUT_ASSERT_INT_EQUALS(884, sll);
-}
-
-PCUT_TEST(double_misc)
-{
-	float f;
-	double d;
-	long double ld;
-
-	int rc = sscanf(
-	    "\n \t\t1.0 -0x555.AP10 1234.5678e12",
-	    "%f %lf %Lf",
-	    &f, &d, &ld);
-
-	PCUT_ASSERT_INT_EQUALS(3, rc);
-
-	PCUT_ASSERT_DOUBLE_EQUALS(1.0, f, EPSILON);
-	PCUT_ASSERT_DOUBLE_EQUALS(-0x555.AP10, d, EPSILON);
-	PCUT_ASSERT_DOUBLE_EQUALS(1234.5678e12, ld, EPSILON);
-}
-
-PCUT_TEST(str_misc)
-{
-	char str[20];
-	char *pstr;
-
-	int rc = sscanf(
-	    "\n\n\thello world    \n",
-	    "%5s %ms",
-	    str, &pstr);
-
-	PCUT_ASSERT_INT_EQUALS(2, rc);
-
-	PCUT_ASSERT_STR_EQUALS("hello", str);
-	PCUT_ASSERT_STR_EQUALS("world", pstr);
-
-	free(pstr);
-}
-
-PCUT_TEST(str_matchers)
-{
-	char scanset[20];
-	char *pscanset;
-
-	int rc = sscanf(
-	    "\n\n\th-e-l-l-o world-]    \n",
-	    " %9[-eh-o] %m[^]-]",
-	    scanset, &pscanset);
-
-	PCUT_ASSERT_INT_EQUALS(2, rc);
-
-	PCUT_ASSERT_STR_EQUALS("h-e-l-l-o", scanset);
-	PCUT_ASSERT_STR_EQUALS("world", pscanset);
-
-	free(pscanset);
-}
-
-PCUT_TEST(char_misc)
-{
-	char seq[20];
-	char *pseq;
-
-	int rc = sscanf(
-	    "\n\n\thello world    \n",
-	    " %5c %mc",
-	    seq, &pseq);
-
-	PCUT_ASSERT_INT_EQUALS(2, rc);
-
-	/* Manually terminate the strings. */
-	seq[5] = 0;
-	pseq[1] = 0;
-
-	PCUT_ASSERT_STR_EQUALS("hello", seq);
-	PCUT_ASSERT_STR_EQUALS("w", pseq);
-
-	free(pseq);
-}
-
-#endif
-
-PCUT_EXPORT(scanf);
Index: uspace/lib/posix/test/stdio.c
===================================================================
--- uspace/lib/posix/test/stdio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/posix/test/stdio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include <str.h>
+#include "posix/stdio.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(stdio);
+
+/** tempnam function with directory argument not having trailing slash */
+PCUT_TEST(tempnam_no_slash)
+{
+	char *p;
+	FILE *f;
+
+	p = tempnam("/tmp", "tmp.");
+	PCUT_ASSERT_NOT_NULL(p);
+
+	PCUT_ASSERT_TRUE(str_lcmp(p, "/tmp/tmp.",
+	    str_length("/tmp/tmp.")) == 0);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	(void) remove(p);
+	fclose(f);
+}
+
+/** tempnam function with directory argument having trailing slash */
+PCUT_TEST(tempnam_with_slash)
+{
+	char *p;
+	FILE *f;
+
+	p = tempnam("/tmp/", "tmp.");
+	PCUT_ASSERT_NOT_NULL(p);
+
+	PCUT_ASSERT_TRUE(str_lcmp(p, "/tmp/tmp.",
+	    str_length("/tmp/tmp.")) == 0);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	(void) remove(p);
+	fclose(f);
+}
+
+/** tempnam function with NULL directory argument */
+PCUT_TEST(tempnam_no_dir)
+{
+	char *p;
+	FILE *f;
+
+	p = tempnam(NULL, "tmp.");
+	PCUT_ASSERT_NOT_NULL(p);
+
+	PCUT_ASSERT_TRUE(str_lcmp(p, P_tmpdir "/tmp.",
+	    str_length(P_tmpdir "/tmp.")) == 0);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	(void) remove(p);
+	fclose(f);
+}
+
+PCUT_EXPORT(stdio);
Index: uspace/lib/posix/test/stdlib.c
===================================================================
--- uspace/lib/posix/test/stdlib.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/posix/test/stdlib.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include <str.h>
+#include "posix/fcntl.h"
+#include "posix/stdio.h"
+#include "posix/stdlib.h"
+#include "posix/unistd.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(stdlib);
+
+#define MKSTEMP_TEMPL "/tmp/tmp.XXXXXX"
+#define MKTEMP_BAD_TEMPL "/tmp/tmp.XXXXX"
+#define MKTEMP_SHORT_TEMPL "XXXXX"
+
+/** mktemp function */
+PCUT_TEST(mktemp)
+{
+	int file;
+	char buf[sizeof(MKSTEMP_TEMPL)];
+	char *p;
+
+	str_cpy(buf, sizeof(buf), MKSTEMP_TEMPL);
+
+	p = mktemp(buf);
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(str_lcmp(p, MKSTEMP_TEMPL,
+	    str_length(MKSTEMP_TEMPL) - 6) == 0);
+
+	file = open(p, O_CREAT | O_EXCL | O_RDWR, 0600);
+	PCUT_ASSERT_TRUE(file >= 0);
+	close(file);
+
+	(void) unlink(p);
+}
+
+/** mktemp function called twice should return different names */
+PCUT_TEST(mktemp_twice)
+{
+	char buf1[sizeof(MKSTEMP_TEMPL)];
+	char buf2[sizeof(MKSTEMP_TEMPL)];
+	char *p;
+
+	str_cpy(buf1, sizeof(buf1), MKSTEMP_TEMPL);
+	str_cpy(buf2, sizeof(buf2), MKSTEMP_TEMPL);
+
+	p = mktemp(buf1);
+	PCUT_ASSERT_TRUE(p == buf1);
+	PCUT_ASSERT_TRUE(str_lcmp(p, MKSTEMP_TEMPL,
+	    str_length(MKSTEMP_TEMPL) - 6) == 0);
+
+	p = mktemp(buf2);
+	PCUT_ASSERT_TRUE(p == buf2);
+	PCUT_ASSERT_TRUE(str_lcmp(p, MKSTEMP_TEMPL,
+	    str_length(MKSTEMP_TEMPL) - 6) == 0);
+
+	PCUT_ASSERT_TRUE(str_cmp(buf1, buf2) != 0);
+}
+
+/** mktemp function with malformed template */
+PCUT_TEST(mktemp_bad_templ)
+{
+	char buf[sizeof(MKTEMP_BAD_TEMPL)];
+	char *p;
+
+	str_cpy(buf, sizeof(buf), MKTEMP_BAD_TEMPL);
+
+	p = mktemp(buf);
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(p[0] == '\0');
+}
+
+/** mktemp function with too short template */
+PCUT_TEST(mktemp_short_templ)
+{
+	char buf[sizeof(MKTEMP_SHORT_TEMPL)];
+	char *p;
+
+	str_cpy(buf, sizeof(buf), MKTEMP_SHORT_TEMPL);
+
+	p = mktemp(buf);
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(p[0] == '\0');
+}
+
+/** mkstemp function */
+PCUT_TEST(mkstemp)
+{
+	int file;
+	char buf[sizeof(MKSTEMP_TEMPL)];
+	ssize_t rc;
+	char c;
+
+	str_cpy(buf, sizeof(buf), MKSTEMP_TEMPL);
+
+	file = mkstemp(buf);
+	PCUT_ASSERT_TRUE(file >= 0);
+
+	(void) unlink(buf);
+
+	c = 'x';
+	rc = write(file, &c, sizeof(c));
+	PCUT_ASSERT_TRUE(rc == sizeof(c));
+
+	(void) lseek(file, 0, SEEK_SET);
+	c = '\0';
+	rc = read(file, &c, sizeof(c));
+	PCUT_ASSERT_TRUE(rc == sizeof(c));
+	PCUT_ASSERT_INT_EQUALS('x', c);
+
+	close(file);
+}
+
+PCUT_EXPORT(stdlib);
Index: uspace/lib/posix/test/unistd.c
===================================================================
--- uspace/lib/posix/test/unistd.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/posix/test/unistd.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+#include "posix/fcntl.h"
+#include "posix/stdlib.h"
+#include "posix/unistd.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(unistd);
+
+#define MKSTEMP_TEMPL "/tmp/tmp.XXXXXX"
+#define MKTEMP_BAD_TEMPL "/tmp/tmp.XXXXX"
+#define MKTEMP_SHORT_TEMPL "XXXXX"
+
+/** access function with nonexisting entry */
+PCUT_TEST(access_nonexist)
+{
+	char name[L_tmpnam];
+	char *p;
+	int rc;
+
+	p = tmpnam(name);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	rc = access(name, F_OK);
+	PCUT_ASSERT_INT_EQUALS(-1, rc);
+}
+
+/** access function with file */
+PCUT_TEST(access_file)
+{
+	char name[L_tmpnam];
+	char *p;
+	int file;
+	int rc;
+
+	p = tmpnam(name);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	file = open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
+	PCUT_ASSERT_TRUE(file >= 0);
+
+	rc = access(name, F_OK);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+
+	(void) unlink(name);
+	close(file);
+}
+
+PCUT_EXPORT(unistd);
Index: uspace/lib/virtio/Makefile
===================================================================
--- uspace/lib/virtio/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/virtio/Makefile	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2018 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libvirtio
+LIBS = drv
+
+SOURCES = \
+	virtio.c \
+	virtio-pci.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/virtio/virtio-pci.c
===================================================================
--- uspace/lib/virtio/virtio-pci.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/virtio/virtio-pci.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2018 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file VIRTIO support
+ */
+
+#include "virtio-pci.h"
+
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <pci_dev_iface.h>
+
+static bool check_bar(virtio_dev_t *vdev, uint8_t bar, uint32_t offset,
+    uint32_t length)
+{
+	/* We must ignore the capability if bar is greater than 5 */
+	if (bar >= PCI_BAR_COUNT)
+		return false;
+
+	/* This is not a mapped BAR */
+	if (!vdev->bar[bar].mapped)
+		return false;
+
+	uintptr_t start = (uintptr_t) vdev->bar[bar].mapped_base;
+	if (start + offset < start)
+		return false;
+	if (start + offset > start + vdev->bar[bar].mapped_size)
+		return false;
+	if (start + offset + length < start + offset)
+		return false;
+	if (start + offset + length > start + vdev->bar[bar].mapped_size)
+		return false;
+
+	return true;
+}
+
+static void virtio_pci_common_cfg(virtio_dev_t *vdev, uint8_t bar,
+    uint32_t offset, uint32_t length)
+{
+	if (vdev->common_cfg)
+		return;
+
+	if (!check_bar(vdev, bar, offset, length))
+		return;
+
+	vdev->common_cfg = vdev->bar[bar].mapped_base + offset;
+
+	ddf_msg(LVL_NOTE, "common_cfg=%p", vdev->common_cfg);
+}
+
+static void virtio_pci_notify_cfg(virtio_dev_t *vdev, uint8_t bar,
+    uint32_t offset, uint32_t length, uint32_t multiplier)
+{
+	if (vdev->notify_base)
+		return;
+
+	if (!check_bar(vdev, bar, offset, length))
+		return;
+
+	vdev->notify_base = vdev->bar[bar].mapped_base + offset;
+	vdev->notify_off_multiplier = multiplier;
+
+	ddf_msg(LVL_NOTE, "notify_base=%p, off_multiplier=%u",
+	    vdev->notify_base, vdev->notify_off_multiplier);
+}
+
+static void virtio_pci_isr_cfg(virtio_dev_t *vdev, uint8_t bar, uint32_t offset,
+    uint32_t length)
+{
+	if (vdev->isr)
+		return;
+
+	if (!check_bar(vdev, bar, offset, length))
+		return;
+
+	vdev->isr = vdev->bar[bar].mapped_base + offset;
+	vdev->isr_phys = vdev->bar[bar].phys_base + offset;
+
+	ddf_msg(LVL_NOTE, "isr=%p (phys=%#" PRIxn ")", vdev->isr,
+	    vdev->isr_phys);
+}
+
+static void virtio_pci_device_cfg(virtio_dev_t *vdev, uint8_t bar,
+    uint32_t offset, uint32_t length)
+{
+	if (vdev->device_cfg)
+		return;
+
+	if (!check_bar(vdev, bar, offset, length))
+		return;
+
+	vdev->device_cfg = vdev->bar[bar].mapped_base + offset;
+
+	ddf_msg(LVL_NOTE, "device_cfg=%p", vdev->device_cfg);
+}
+
+static errno_t enable_resources(async_sess_t *pci_sess, virtio_dev_t *vdev)
+{
+	pio_window_t pio_window;
+	errno_t rc = pio_window_get(pci_sess, &pio_window);
+	if (rc != EOK)
+		return rc;
+
+	hw_resource_list_t hw_res;
+	rc = hw_res_get_resource_list(pci_sess, &hw_res);
+	if (rc != EOK)
+		return rc;
+
+	/*
+	 * Enable resources and reconstruct the mapping between BAR and resource
+	 * indices. We are going to need this later when the VIRTIO PCI
+	 * capabilities refer to specific BARs.
+	 *
+	 * XXX: The mapping should probably be provided by the PCI driver
+	 *      itself.
+	 */
+	for (unsigned i = 0, j = 0; i < PCI_BAR_COUNT && j < hw_res.count;
+	    i++) {
+		/* Detect and skip unused BARs */
+		uint32_t bar;
+		rc = pci_config_space_read_32(pci_sess,
+		    PCI_BAR0 + i * sizeof(uint32_t), &bar);
+		if (rc != EOK)
+			return rc;
+		if (!bar)
+			continue;
+
+		hw_resource_t *res = &hw_res.resources[j];
+		rc = pio_enable_resource(&pio_window, res,
+		    &vdev->bar[i].mapped_base, &vdev->bar[i].phys_base,
+		    &vdev->bar[i].mapped_size);
+		if (rc == EOK)
+			vdev->bar[i].mapped = true;
+		j++;
+	}
+
+	return rc;
+}
+
+static errno_t disable_resources(virtio_dev_t *vdev)
+{
+	for (unsigned i = 0; i < PCI_BAR_COUNT; i++) {
+		if (vdev->bar[i].mapped) {
+			errno_t rc = pio_disable(vdev->bar[i].mapped_base,
+			    vdev->bar[i].mapped_size);
+			if (rc != EOK)
+				return rc;
+			vdev->bar[i].mapped = false;
+		}
+	}
+
+	return EOK;
+}
+
+errno_t virtio_pci_dev_initialize(ddf_dev_t *dev, virtio_dev_t *vdev)
+{
+	memset(vdev, 0, sizeof(virtio_dev_t));
+
+	async_sess_t *pci_sess = ddf_dev_parent_sess_get(dev);
+	if (!pci_sess)
+		return ENOENT;
+
+	errno_t rc = enable_resources(pci_sess, vdev);
+	if (rc != EOK)
+		goto error;
+
+	/*
+	 * Find the VIRTIO PCI Capabilities
+	 */
+	uint8_t c;
+	uint8_t cap_vndr;
+	for (rc = pci_config_space_cap_first(pci_sess, &c, &cap_vndr);
+	    (rc == EOK) && c;
+	    rc = pci_config_space_cap_next(pci_sess, &c, &cap_vndr)) {
+		if (cap_vndr != PCI_CAP_VENDORSPECID)
+			continue;
+
+		uint8_t cap_len;
+		rc = pci_config_space_read_8(pci_sess,
+		    VIRTIO_PCI_CAP_CAP_LEN(c), &cap_len);
+		if (rc != EOK)
+			goto error;
+
+		if (cap_len < VIRTIO_PCI_CAP_END(0)) {
+			rc = EINVAL;
+			goto error;
+		}
+
+		uint8_t cfg_type;
+		rc = pci_config_space_read_8(pci_sess,
+		    VIRTIO_PCI_CAP_CFG_TYPE(c), &cfg_type);
+		if (rc != EOK)
+			goto error;
+
+		uint8_t bar;
+		rc = pci_config_space_read_8(pci_sess, VIRTIO_PCI_CAP_BAR(c),
+		    &bar);
+		if (rc != EOK)
+			goto error;
+
+		uint32_t offset;
+		rc = pci_config_space_read_32(pci_sess,
+		    VIRTIO_PCI_CAP_OFFSET(c), &offset);
+		if (rc != EOK)
+			goto error;
+
+		uint32_t length;
+		rc = pci_config_space_read_32(pci_sess,
+		    VIRTIO_PCI_CAP_LENGTH(c), &length);
+		if (rc != EOK)
+			goto error;
+
+		uint32_t multiplier;
+		switch (cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			virtio_pci_common_cfg(vdev, bar, offset, length);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			if (cap_len < VIRTIO_PCI_CAP_END(sizeof(uint32_t))) {
+				rc = EINVAL;
+				goto error;
+			}
+			rc = pci_config_space_read_32(pci_sess,
+			    VIRTIO_PCI_CAP_END(c), &multiplier);
+			if (rc != EOK)
+				goto error;
+			virtio_pci_notify_cfg(vdev, bar, offset, length,
+			    multiplier);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			virtio_pci_isr_cfg(vdev, bar, offset, length);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			virtio_pci_device_cfg(vdev, bar, offset, length);
+			break;
+		case VIRTIO_PCI_CAP_PCI_CFG:
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Check that the configuration is complete */
+	if (!vdev->common_cfg || !vdev->notify_base || !vdev->isr ||
+	    !vdev->device_cfg) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	return rc;
+
+error:
+	(void) disable_resources(vdev);
+	return rc;
+}
+
+errno_t virtio_pci_dev_cleanup(virtio_dev_t *vdev)
+{
+	if (vdev->queues) {
+		for (unsigned i = 0;
+		    i < pio_read_le16(&vdev->common_cfg->num_queues); i++)
+			virtio_virtq_teardown(vdev, i);
+		free(vdev->queues);
+	}
+	return disable_resources(vdev);
+}
+
+/** @}
+ */
Index: uspace/lib/virtio/virtio-pci.h
===================================================================
--- uspace/lib/virtio/virtio-pci.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/virtio/virtio-pci.h	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2018 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file VIRTIO PCI definitions
+ */
+
+#ifndef _VIRTIO_PCI_H_
+#define _VIRTIO_PCI_H_
+
+#include <ddf/driver.h>
+#include <pci_dev_iface.h>
+#include <ddi.h>
+#include <fibril_synch.h>
+
+#define VIRTIO_PCI_CAP_CAP_LEN(c)	((c) + 2)
+#define VIRTIO_PCI_CAP_CFG_TYPE(c)	((c) + 3)
+#define VIRTIO_PCI_CAP_BAR(c)		((c) + 4)
+#define VIRTIO_PCI_CAP_OFFSET(c)	((c) + 8)
+#define VIRTIO_PCI_CAP_LENGTH(c)	((c) + 12)
+#define VIRTIO_PCI_CAP_END(c)		((c) + 16)
+
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+#define VIRTIO_DEV_STATUS_RESET			0
+#define VIRTIO_DEV_STATUS_ACKNOWLEDGE		1
+#define VIRTIO_DEV_STATUS_DRIVER		2
+#define VIRTIO_DEV_STATUS_DRIVER_OK		4
+#define VIRTIO_DEV_STATUS_FEATURES_OK		8
+#define VIRTIO_DEV_STATUS_DEVICE_NEEDS_RESET	64
+#define VIRTIO_DEV_STATUS_FAILED		128
+
+#define VIRTIO_FEATURES_0_31	0
+
+/** Common configuration structure layout according to VIRTIO version 1.0 */
+typedef struct virtio_pci_common_cfg {
+	ioport32_t device_feature_select;
+	const ioport32_t device_feature;
+	ioport32_t driver_feature_select;
+	ioport32_t driver_feature;
+	ioport16_t msix_config;
+	const ioport16_t num_queues;
+	ioport8_t device_status;
+	const ioport8_t config_generation;
+	ioport16_t queue_select;
+	ioport16_t queue_size;
+	ioport16_t queue_msix_vector;
+	ioport16_t queue_enable;
+	const ioport16_t queue_notif_off;
+	ioport64_t queue_desc;
+	ioport64_t queue_avail;
+	ioport64_t queue_used;
+} virtio_pci_common_cfg_t;
+
+/** The buffer continues in the next descriptor */
+#define VIRTQ_DESC_F_NEXT	1
+/** Device write-only buffer */
+#define VIRTQ_DESC_F_WRITE	2
+/** Buffer contains a list of buffer descriptors */
+#define VIRTQ_DESC_F_INDIRECT	4
+
+/** Virtqueue Descriptor structure as per VIRTIO version 1.0 */
+typedef struct virtq_desc {
+	ioport64_t addr;	/**< Buffer physical address */
+	ioport32_t len;		/**< Buffer length */
+	ioport16_t flags;	/**< Buffer flags */
+	ioport16_t next;	/**< Continuation descriptor */
+} virtq_desc_t;
+
+#define VIRTQ_AVAIL_F_NO_INTERRUPT	1
+
+/** Virtqueue Available Ring as per VIRTIO version 1.0 */
+typedef struct virtq_avail {
+	ioport16_t flags;
+	ioport16_t idx;
+	ioport16_t ring[];
+	/*
+	 * We do not define the optional used_event member here in order to be
+	 * able to define ring as a variable-length array.
+	 */
+} virtq_avail_t;
+
+typedef struct virtq_used_elem {
+	ioport32_t id;
+	ioport32_t len;
+} virtq_used_elem_t;
+
+#define VIRTQ_USED_F_NO_NOTIFY	1
+
+/** Virtqueue Used Ring as per VIRTIO version 1.0 */
+typedef struct virtq_used {
+	ioport16_t flags;
+	ioport16_t idx;
+	virtq_used_elem_t ring[];
+	/*
+	 * We do not define the optional avail_event member here in order to be
+	 * able to define ring as a variable-length array.
+	 */
+} virtq_used_t;
+
+typedef struct {
+	void *virt;
+	uintptr_t phys;
+	size_t size;
+
+	/** Mutex protecting access to this virtqueue */
+	fibril_mutex_t lock;
+
+	/**
+	 * Size of the queue which determines the number of descriptors and
+	 * DMA buffers.
+	 */
+	size_t queue_size;
+
+	/** Virtual address of queue size virtq descriptors */
+	virtq_desc_t *desc;
+	/** Virtual address of the available ring */
+	virtq_avail_t *avail;
+	/** Virtual address of the used ring */
+	virtq_used_t *used;
+	uint16_t used_last_idx;
+
+	/** Address of the queue's notification register */
+	ioport16_t *notify;
+} virtq_t;
+
+/** VIRTIO-device specific data associated with the NIC framework nic_t */
+typedef struct {
+	struct {
+		bool mapped;
+		uintptr_t phys_base;
+		void *mapped_base;
+		size_t mapped_size;
+	} bar[PCI_BAR_COUNT];
+
+	/** Commong configuration structure */
+	virtio_pci_common_cfg_t *common_cfg;
+
+	/** Notification base address */
+	void *notify_base;
+	/** Notification offset multiplier */
+	uint32_t notify_off_multiplier;
+
+	/** INT#x interrupt ISR register */
+	ioport8_t *isr;
+	uintptr_t isr_phys;
+
+	/** Device-specific configuration */
+	void *device_cfg;
+
+	/** Virtqueues */
+	virtq_t *queues;
+} virtio_dev_t;
+
+extern void virtio_virtq_desc_set(virtio_dev_t *vdev, uint16_t, uint16_t,
+    uint64_t, uint32_t, uint16_t, uint16_t);
+extern uint16_t virtio_virtq_desc_get_next(virtio_dev_t *vdev, uint16_t,
+    uint16_t);
+
+extern void virtio_virtq_produce_available(virtio_dev_t *, uint16_t, uint16_t);
+extern bool virtio_virtq_consume_used(virtio_dev_t *, uint16_t, uint16_t *,
+    uint32_t *);
+
+extern errno_t virtio_virtq_setup(virtio_dev_t *, uint16_t, uint16_t);
+extern void virtio_virtq_teardown(virtio_dev_t *, uint16_t);
+
+extern errno_t virtio_device_setup_start(virtio_dev_t *, uint32_t);
+extern void virtio_device_setup_fail(virtio_dev_t *);
+extern void virtio_device_setup_finalize(virtio_dev_t *);
+
+extern errno_t virtio_pci_dev_initialize(ddf_dev_t *, virtio_dev_t *);
+extern errno_t virtio_pci_dev_cleanup(virtio_dev_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/virtio/virtio.c
===================================================================
--- uspace/lib/virtio/virtio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
+++ uspace/lib/virtio/virtio.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2018 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file VIRTIO support
+ */
+
+#include "virtio-pci.h"
+
+#include <as.h>
+#include <align.h>
+#include <macros.h>
+
+#include <ddf/log.h>
+#include <libarch/barrier.h>
+
+void virtio_virtq_desc_set(virtio_dev_t *vdev, uint16_t num, uint16_t descno,
+    uint64_t addr, uint32_t len, uint16_t flags, uint16_t next)
+{
+	virtq_desc_t *d = &vdev->queues[num].desc[descno];
+	pio_write_le64(&d->addr, addr);
+	pio_write_le32(&d->len, len);
+	pio_write_le16(&d->flags, flags);
+	pio_write_le16(&d->next, next);
+}
+
+uint16_t virtio_virtq_desc_get_next(virtio_dev_t *vdev, uint16_t num,
+    uint16_t descno)
+{
+	virtq_desc_t *d = &vdev->queues[num].desc[descno];
+	if (!(pio_read_le16(&d->flags) & VIRTQ_DESC_F_NEXT))
+		return (uint16_t) -1U;
+	return pio_read_le16(&d->next);
+}
+
+void virtio_virtq_produce_available(virtio_dev_t *vdev, uint16_t num,
+    uint16_t descno)
+{
+	virtq_t *q = &vdev->queues[num];
+
+	fibril_mutex_lock(&q->lock);
+	uint16_t idx = pio_read_le16(&q->avail->idx);
+	pio_write_le16(&q->avail->ring[idx % q->queue_size], descno);
+	write_barrier();
+	pio_write_le16(&q->avail->idx, idx + 1);
+	write_barrier();
+	pio_write_le16(q->notify, num);
+	fibril_mutex_unlock(&q->lock);
+}
+
+bool virtio_virtq_consume_used(virtio_dev_t *vdev, uint16_t num,
+    uint16_t *descno, uint32_t *len)
+{
+	virtq_t *q = &vdev->queues[num];
+
+	fibril_mutex_lock(&q->lock);
+	uint16_t last_idx = q->used_last_idx % q->queue_size;
+	if (last_idx == (pio_read_le16(&q->used->idx) % q->queue_size)) {
+		fibril_mutex_unlock(&q->lock);
+		return false;
+	}
+
+	*descno = (uint16_t) pio_read_le32(&q->used->ring[last_idx].id);
+	*len = pio_read_le32(&q->used->ring[last_idx].len);
+
+	q->used_last_idx++;
+	fibril_mutex_unlock(&q->lock);
+
+	return true;
+}
+
+errno_t virtio_virtq_setup(virtio_dev_t *vdev, uint16_t num, uint16_t size)
+{
+	virtq_t *q = &vdev->queues[num];
+	virtio_pci_common_cfg_t *cfg = vdev->common_cfg;
+
+	/* Program the queue of our interest */
+	pio_write_le16(&cfg->queue_select, num);
+
+	/* Trim the size of the queue as needed */
+	if (size > pio_read_16(&cfg->queue_size)) {
+		ddf_msg(LVL_ERROR, "Virtq %u: not enough descriptors", num);
+		return ENOMEM;
+	}
+	pio_write_le16(&cfg->queue_size, size);
+	ddf_msg(LVL_NOTE, "Virtq %u: %u descriptors", num, (unsigned) size);
+
+	size_t avail_offset = 0;
+	size_t used_offset = 0;
+
+	/*
+	 * Compute the size of the needed DMA memory and also the offsets of
+	 * the individual components
+	 */
+	size_t mem_size = sizeof(virtq_desc_t[size]);
+	mem_size = ALIGN_UP(mem_size, _Alignof(virtq_avail_t));
+	avail_offset = mem_size;
+	mem_size += sizeof(virtq_avail_t) + sizeof(ioport16_t[size]) +
+	    sizeof(ioport16_t);
+	mem_size = ALIGN_UP(mem_size, _Alignof(virtq_used_t));
+	used_offset = mem_size;
+	mem_size += sizeof(virtq_used_t) + sizeof(virtq_used_elem_t[size]) +
+	    sizeof(ioport16_t);
+
+	/*
+	 * Allocate DMA memory for the virtqueues
+	 */
+	q->virt = AS_AREA_ANY;
+	errno_t rc = dmamem_map_anonymous(mem_size, 0,
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &q->phys, &q->virt);
+	if (rc != EOK) {
+		q->virt = NULL;
+		return rc;
+	}
+
+	fibril_mutex_initialize(&q->lock);
+
+	q->size = mem_size;
+	q->queue_size = size;
+	q->desc = q->virt;
+	q->avail = q->virt + avail_offset;
+	q->used = q->virt + used_offset;
+	q->used_last_idx = 0;
+
+	memset(q->virt, 0, q->size);
+
+	/*
+	 * Write the configured addresses to device's common config
+	 */
+	pio_write_le64(&cfg->queue_desc, q->phys);
+	pio_write_le64(&cfg->queue_avail, q->phys + avail_offset);
+	pio_write_le64(&cfg->queue_used, q->phys + used_offset);
+
+	ddf_msg(LVL_NOTE, "DMA memory for virtq %d: virt=%p, phys=%p, size=%zu",
+	    num, q->virt, (void *) q->phys, q->size);
+
+	/* Determine virtq's notification address */
+	q->notify = vdev->notify_base +
+	    pio_read_le16(&cfg->queue_notif_off) * vdev->notify_off_multiplier;
+
+	ddf_msg(LVL_NOTE, "notification register: %p", q->notify);
+
+	/* Enable the queue */
+	pio_write_le16(&cfg->queue_enable, 1);
+	ddf_msg(LVL_NOTE, "virtq %d set", num);
+
+	return rc;
+}
+
+void virtio_virtq_teardown(virtio_dev_t *vdev, uint16_t num)
+{
+	virtio_pci_common_cfg_t *cfg = vdev->common_cfg;
+
+	/* Disable the queue */
+	pio_write_le16(&cfg->queue_enable, 0);
+
+	virtq_t *q = &vdev->queues[num];
+	if (q->size)
+		dmamem_unmap_anonymous(q->virt);
+}
+
+/**
+ * Perform device initialization as described in section 3.1.1 of the
+ * specification, steps 1 - 6.
+ */
+errno_t virtio_device_setup_start(virtio_dev_t *vdev, uint32_t features)
+{
+	virtio_pci_common_cfg_t *cfg = vdev->common_cfg;
+
+	/* 1. Reset the device */
+	uint8_t status = VIRTIO_DEV_STATUS_RESET;
+	pio_write_8(&cfg->device_status, status);
+
+	/* 2. Acknowledge we found the device */
+	status |= VIRTIO_DEV_STATUS_ACKNOWLEDGE;
+	pio_write_8(&cfg->device_status, status);
+
+	/* 3. We know how to drive the device */
+	status |= VIRTIO_DEV_STATUS_DRIVER;
+	pio_write_8(&cfg->device_status, status);
+
+	/* 4. Read the offered feature flags */
+	pio_write_le32(&cfg->device_feature_select, VIRTIO_FEATURES_0_31);
+	uint32_t device_features = pio_read_le32(&cfg->device_feature);
+
+	ddf_msg(LVL_NOTE, "offered features %x", device_features);
+
+	if (features != (features & device_features))
+		return ENOTSUP;
+	features &= device_features;
+
+	/* 4. Write the accepted feature flags */
+	pio_write_le32(&cfg->driver_feature_select, VIRTIO_FEATURES_0_31);
+	pio_write_le32(&cfg->driver_feature, features);
+
+	ddf_msg(LVL_NOTE, "accepted features %x", features);
+
+	/* 5. Set FEATURES_OK */
+	status |= VIRTIO_DEV_STATUS_FEATURES_OK;
+	pio_write_8(&cfg->device_status, status);
+
+	/* 6. Test if the device supports our feature subset */
+	status = pio_read_8(&cfg->device_status);
+	if (!(status & VIRTIO_DEV_STATUS_FEATURES_OK))
+		return ENOTSUP;
+
+	return EOK;
+}
+
+/**
+ * Perform device initialization as described in section 3.1.1 of the
+ * specification, step 8 (go live).
+ */
+void virtio_device_setup_finalize(virtio_dev_t *vdev)
+{
+	virtio_pci_common_cfg_t *cfg = vdev->common_cfg;
+
+	/* 8. Go live */
+	uint8_t status = pio_read_8(&cfg->device_status);
+	pio_write_8(&cfg->device_status, status | VIRTIO_DEV_STATUS_DRIVER_OK);
+}
+
+void virtio_device_setup_fail(virtio_dev_t *vdev)
+{
+	virtio_pci_common_cfg_t *cfg = vdev->common_cfg;
+
+	uint8_t status = pio_read_8(&cfg->device_status);
+	pio_write_8(&cfg->device_status, status | VIRTIO_DEV_STATUS_FAILED);
+}
+
+/** @}
+ */
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision e768aea1e1c1b71c4e7d59520251bebbdc779f46)
+++ uspace/srv/vfs/vfs_file.c	(revision 81193639c9f3af3b65a6ea46f1f7422d4d3bec12)
@@ -71,10 +71,10 @@
 	fibril_mutex_lock(&vfs_data->lock);
 	if (!vfs_data->files) {
-		vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
+		vfs_data->files = malloc(VFS_MAX_OPEN_FILES * sizeof(vfs_file_t *));
 		if (!vfs_data->files) {
 			fibril_mutex_unlock(&vfs_data->lock);
 			return false;
 		}
-		memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
+		memset(vfs_data->files, 0, VFS_MAX_OPEN_FILES * sizeof(vfs_file_t *));
 	}
 	fibril_mutex_unlock(&vfs_data->lock);
@@ -90,5 +90,5 @@
 		return;
 
-	for (i = 0; i < MAX_OPEN_FILES; i++) {
+	for (i = 0; i < VFS_MAX_OPEN_FILES; i++) {
 		if (vfs_data->files[i])
 			(void) _vfs_fd_free(vfs_data, i);
@@ -199,5 +199,5 @@
 	unsigned int i;
 	if (desc)
-		i = MAX_OPEN_FILES - 1;
+		i = VFS_MAX_OPEN_FILES - 1;
 	else
 		i = 0;
@@ -233,5 +233,5 @@
 			i--;
 		} else {
-			if (i == MAX_OPEN_FILES - 1)
+			if (i == VFS_MAX_OPEN_FILES - 1)
 				break;
 
@@ -261,5 +261,5 @@
 static errno_t _vfs_fd_free_locked(vfs_client_data_t *vfs_data, int fd)
 {
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
+	if ((fd < 0) || (fd >= VFS_MAX_OPEN_FILES) || !vfs_data->files[fd]) {
 		return EBADF;
 	}
@@ -311,5 +311,5 @@
 
 	fibril_mutex_lock(&VFS_DATA->lock);
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES)) {
+	if ((fd < 0) || (fd >= VFS_MAX_OPEN_FILES)) {
 		fibril_mutex_unlock(&VFS_DATA->lock);
 		return EBADF;
@@ -342,5 +342,5 @@
 
 	fibril_mutex_lock(&vfs_data->lock);
-	if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
+	if ((fd >= 0) && (fd < VFS_MAX_OPEN_FILES)) {
 		vfs_file_t *file = vfs_data->files[fd];
 		if (file != NULL) {
