usb.patch, with conflicts and some warnings fixed
[pintos-anon] / src / devices / pci.c
diff --git a/src/devices/pci.c b/src/devices/pci.c
new file mode 100644 (file)
index 0000000..2df8e2a
--- /dev/null
@@ -0,0 +1,812 @@
+#define PCI_TRANSLATION_ENABLE 1
+
+#include "devices/pci.h"
+#include "threads/init.h"
+#include "threads/malloc.h"
+#include "threads/interrupt.h"
+#include "threads/pte.h"
+#include "threads/io.h"
+#include "pci_lookup.h"
+#include <round.h>
+#include <list.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+extern uint32_t *base_page_dir;
+
+#define PCI_REG_ADDR   0xcf8
+#define PCI_REG_DATA   0xcfc
+#define pci_config_offset(bus, dev, func, reg) (0x80000000 | ((bus) << 16) | ((dev) << 11) | ((func) << 8) | (reg & (~3)))
+
+#define PCI_MAX_DEV_PER_BUS    32
+#define PCI_MAX_FUNC_PER_DEV   8
+
+#define PCI_HEADER_SZ          256
+
+#define PCI_CMD_IO             0x001   /* enable io response */
+#define PCI_CMD_MEMORY         0x002   /* enable memory response */
+#define PCI_CMD_MASTER         0x004   /* enable bus mastering */
+#define PCI_CMD_SPECIAL                0x008   /* enable special cycles */
+#define PCI_CMD_INVALIDATE     0x010   /* memory write + invalidate */
+#define PCI_CMD_PALETTE                0x020   /* palette snooping */
+#define PCI_CMD_PARITY         0x040   /* parity checking */
+#define PCI_CMD_WAIT           0x080   /* address/data stepping */
+#define PCI_CMD_SERR           0x100   /* serr */
+#define PCI_CMD_FASTBACK       0x200   /* back-to-back writing */
+#define PCI_CMD_INTX_DISABLE   0x400   /* emulation disable */
+
+#define PCI_STATUS_CAPLIST     0x10    /* capability list */
+#define PCI_STATUS_66MHZ       0x20    /* 66mhz pci 2.1 bus */
+#define PCI_STATUS_UDF         0x40    /* user definable features */
+#define PCI_STATUS_FASTBACK    0x80    /* fast back to back */
+#define PCI_STATUS_PARITY      0x100   /* parity error detected */
+#define PCI_STATUS_DEVSEL      0x600   /* devsel mask */
+#define PCI_STATUS_DEVSEL_FAST 0
+#define PCI_STATUS_DEVSEL_MED  0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_ABORT   0x0800  /* set on target abort */
+#define PCI_STATUS_REC_ABORT   0x1000  /* master ack of abort */
+#define PCI_STATUS_REC_ABORT_M 0x2000  /* set on master abort */
+#define PCI_STATUS_SERR                0x4000  /* system error */
+#define PCI_STATUS_PARITY2     0x8000  /* set on parity err */
+
+#define PCI_HEADER_NORMAL      0
+#define PCI_HEADER_BRIDGE      1
+#define PCI_HEADER_CARDBUS     2
+
+#define PCI_HEADER_MASK                0x7f
+#define PCI_HEADER_MULTIFUNC   0x80
+
+#define pci_get_reg_offset(x)  (&(((pci_config_header*)(NULL))->x))
+
+#define PCI_VENDOR_INVALID     0xffff
+
+#define PCI_BASEADDR_IO                0x00000001
+#define PCI_BASEADDR_TYPEMASK  0x00000006
+#define PCI_BASEADDR_32BIT     0x00000000
+#define PCI_BASEADDR_64BIT     0x00000004
+#define PCI_BASEADDR_PREFETCH  0x00000008
+#define PCI_BASEADDR_ADDR32    0xfffffff0
+#define PCI_BASEADDR_ADDR64    0xfffffffffffffff0
+#define PCI_BASEADDR_IOPORT    0xfffffffc
+
+#pragma pack(1)
+
+struct pci_config_header
+{
+  uint16_t pci_vendor_id;
+  uint16_t pci_device_id;
+
+  uint16_t pci_command;
+  uint16_t pci_status;
+
+  uint8_t pci_revision;
+
+  /* pci class */
+  uint8_t pci_interface;
+  uint8_t pci_minor;
+  uint8_t pci_major;
+
+  uint8_t pci_cachelinesz;
+  uint8_t pci_latency;
+  uint8_t pci_header;          /* header type */
+  uint8_t pci_bist;            /* self test */
+
+  uint32_t pci_base_reg[6];
+  uint32_t pci_cis;            /* cardbus cis pointer */
+  uint16_t pci_sub_vendor_id;
+  uint16_t pci_sub_id;
+  uint32_t pci_rom_addr;
+  uint8_t pci_capabilities;
+  uint8_t pci_resv[7];
+  uint8_t pci_int_line;
+  uint8_t pci_int_pin;
+  uint8_t pci_min_gnt;
+  uint8_t pci_max_latency;
+};
+
+#pragma pack()
+
+#define PCI_BASE_COUNT         6
+struct pci_dev
+{
+  struct pci_config_header pch;
+  uint8_t bus, dev, func;
+  int base_reg_size[PCI_BASE_COUNT];
+
+  pci_handler_func *irq_handler;
+  void *irq_handler_aux;
+
+  struct list io_ranges;
+  struct list_elem peer;
+  struct list_elem int_peer;
+};
+
+enum pci_io_type
+{ PCI_IO_MEM, PCI_IO_PORT };
+
+/* represents a PCI IO range */
+struct pci_io
+{
+  struct pci_dev *dev;
+  enum pci_io_type type;
+  size_t size; /* bytes in range */
+  union
+  {
+    void *ptr; /* virtual memory address */
+    int port;  /* io port */
+  } addr;
+  struct list_elem peer; /* linkage */
+};
+
+
+static void pci_write_config (int bus, int dev, int func, int reg,
+                             int size, uint32_t data);
+static uint32_t pci_read_config (int bus, int dev, int func, int reg,
+                                int size);
+static void pci_read_all_config (int bus, int dev, int func,
+                                struct pci_config_header *pch);
+static int pci_scan_bus (int bus);
+static int pci_probe (int bus, int dev, int func,
+                     struct pci_config_header *ph);
+static int pci_pci_bridge (struct pci_dev *pd);
+static void pci_power_on (struct pci_dev *pd);
+static void pci_setup_io (struct pci_dev *pd);
+static void pci_interrupt (struct intr_frame *);
+static void pci_print_dev_info (struct pci_dev *pd);
+static void *pci_alloc_mem (void *phys_ptr, int pages);
+
+static struct list devices;
+static struct list int_devices;
+
+/* number of pages that have been allocated to pci devices in the pci zone */
+static int num_pci_pages;
+
+void
+pci_init (void)
+{
+  list_init (&devices);
+  list_init (&int_devices);
+
+  num_pci_pages = 0;
+
+  pci_scan_bus (0);
+  pci_print_stats ();
+}
+
+struct pci_dev *
+pci_get_device (int vendor, int device, int func, int n)
+{
+  struct list_elem *e;
+  int count;
+
+  count = 0;
+  e = list_begin (&devices);
+  while (e != list_end (&devices))
+    {
+      struct pci_dev *pd;
+
+      pd = list_entry (e, struct pci_dev, peer);
+      if (pd->pch.pci_vendor_id == vendor && pd->pch.pci_device_id == device)
+       if (pd->func == func)
+         {
+           if (count == n)
+             return pd;
+           count++;
+         }
+
+      e = list_next (e);
+    }
+
+  return NULL;
+}
+
+struct pci_dev *
+pci_get_dev_by_class (int major, int minor, int iface, int n)
+{
+  struct list_elem *e;
+  int count;
+
+  count = 0;
+  e = list_begin (&devices);
+  while (e != list_end (&devices))
+    {
+      struct pci_dev *pd;
+
+      pd = list_entry (e, struct pci_dev, peer);
+      if (pd->pch.pci_major == major && pd->pch.pci_minor == minor &&
+         pd->pch.pci_interface == iface)
+       {
+         if (count == n)
+           return pd;
+         count++;
+       }
+
+      e = list_next (e);
+    }
+
+  return NULL;
+
+}
+
+struct pci_io *
+pci_io_enum (struct pci_dev *pio, struct pci_io *last)
+{
+  struct list_elem *e;
+
+  if (last != NULL)
+    e = list_next (&last->peer);
+  else
+    e = list_begin (&pio->io_ranges);
+
+  if (e == list_end (&pio->io_ranges))
+    return NULL;
+
+  return list_entry (e, struct pci_io, peer);
+}
+
+void
+pci_register_irq (struct pci_dev *pd, pci_handler_func * f, void *aux)
+{
+  int int_vec;
+  ASSERT (pd != NULL);
+  ASSERT (pd->irq_handler == NULL);
+
+  pd->irq_handler_aux = aux;
+  pd->irq_handler = f;
+  int_vec = pd->pch.pci_int_line + 0x20;
+
+  list_push_back (&int_devices, &pd->int_peer);
+
+  /* ensure that pci interrupt is hooked */
+  if (!intr_is_registered (int_vec))
+    intr_register_ext (int_vec, pci_interrupt, "PCI");
+}
+
+void
+pci_unregister_irq (struct pci_dev *pd)
+{
+  ASSERT (pd != NULL);
+
+  intr_disable ();
+  list_remove (&pd->int_peer);
+  intr_enable ();
+
+  pd->irq_handler = NULL;
+  pd->irq_handler_aux = NULL;
+}
+
+size_t
+pci_io_size (struct pci_io *pio)
+{
+  ASSERT (pio != NULL);
+
+  return pio->size;
+}
+
+void
+pci_reg_write32 (struct pci_io *pio, int reg, uint32_t data)
+{
+  ASSERT (pio != NULL);
+  ASSERT ((unsigned) reg < pio->size);
+
+  if (pio->type == PCI_IO_MEM)
+    {
+      *((uint32_t *) (pio->addr.ptr + reg)) = data;
+    }
+  else if (pio->type == PCI_IO_PORT)
+    {
+      outl (pio->addr.port + reg, data);
+    }
+  else
+    PANIC ("pci: Invalid IO type\n");
+}
+
+void
+pci_reg_write16 (struct pci_io *pio, int reg, uint16_t data)
+{
+  ASSERT (pio != NULL);
+  ASSERT ((unsigned) reg < pio->size);
+
+  if (pio->type == PCI_IO_MEM)
+    {
+      *((uint16_t *) (pio->addr.ptr + reg)) = data;
+    }
+  else if (pio->type == PCI_IO_PORT)
+    {
+      outw (pio->addr.port + reg, data);
+    }
+  else
+    PANIC ("pci: Invalid IO type\n");
+}
+
+void
+pci_reg_write8 (struct pci_io *pio, int reg, uint8_t data)
+{
+  ASSERT (pio != NULL);
+  ASSERT ((unsigned) reg < pio->size);
+
+  if (pio->type == PCI_IO_MEM)
+    {
+      ((uint8_t *) pio->addr.ptr)[reg] = data;
+    }
+  else if (pio->type == PCI_IO_PORT)
+    {
+      outb (pio->addr.port + reg, data);
+    }
+  else
+    PANIC ("pci: Invalid IO type\n");
+}
+
+uint32_t
+pci_reg_read32 (struct pci_io *pio, int reg)
+{
+  uint32_t ret;
+
+  ASSERT (pio != NULL);
+  ASSERT ((unsigned) reg < pio->size);
+
+  if (pio->type == PCI_IO_MEM)
+    {
+      ret = ((uint32_t *) pio->addr.ptr)[reg];
+    }
+  else if (pio->type == PCI_IO_PORT)
+    {
+      ret = inl (pio->addr.port + reg);
+    }
+  else
+    PANIC ("pci: Invalid IO type\n");
+
+  return ret;
+}
+
+uint16_t
+pci_reg_read16 (struct pci_io * pio, int reg)
+{
+  uint16_t ret;
+
+  ASSERT (pio != NULL);
+  ASSERT ((unsigned) reg < pio->size);
+
+  ret = 0;
+  if (pio->type == PCI_IO_MEM)
+    {
+      ret = ((uint16_t *) pio->addr.ptr)[reg];
+    }
+  else if (pio->type == PCI_IO_PORT)
+    {
+      ret = inw (pio->addr.port + reg);
+    }
+  else
+    PANIC ("pci: Invalid IO type\n");
+
+  return ret;
+
+}
+
+uint8_t
+pci_reg_read8 (struct pci_io * pio, int reg)
+{
+  uint8_t ret;
+
+  ASSERT (pio != NULL);
+  ASSERT ((unsigned) reg < pio->size);
+
+  if (pio->type == PCI_IO_MEM)
+    {
+      ret = ((uint8_t *) pio->addr.ptr)[reg];
+    }
+  else if (pio->type == PCI_IO_PORT)
+    {
+      ret = inb (pio->addr.port + reg);
+    }
+  else
+    PANIC ("pci: Invalid IO type\n");
+
+  return ret;
+}
+
+void
+pci_read_in (struct pci_io *pio UNUSED, int off UNUSED, size_t size UNUSED,
+            void *buf UNUSED)
+{
+  PANIC ("pci_read_in: STUB");
+}
+
+void
+pci_write_out (struct pci_io *pio UNUSED, int off UNUSED, size_t size UNUSED,
+              const void *buf UNUSED)
+{
+  PANIC ("pci_write_out: STUB");
+}
+
+static void
+pci_write_config (int bus, int dev, int func, int reg,
+                 int size, uint32_t data)
+{
+  int config_offset;
+
+  config_offset = pci_config_offset (bus, dev, func, reg);
+
+  outl (PCI_REG_ADDR, config_offset);
+
+  switch (size)
+    {
+    case 1:
+      outb (PCI_REG_DATA + (reg & 3), data);
+      break;
+
+    case 2:
+      outw (PCI_REG_DATA + (reg & 3), data);
+      break;
+
+    case 4:
+      outl (PCI_REG_DATA, data);
+      break;
+    }
+}
+
+static uint32_t
+pci_read_config (int bus, int dev, int func, int reg, int size)
+{
+  uint32_t ret;
+  int config_offset;
+
+  config_offset = pci_config_offset (bus, dev, func, reg);
+
+  outl (PCI_REG_ADDR, config_offset);
+
+  switch (size)
+    {
+    case 1:
+      ret = inb (PCI_REG_DATA);
+      break;
+    case 2:
+      ret = inw (PCI_REG_DATA);
+      break;
+    case 4:
+      ret = inl (PCI_REG_DATA);
+      break;
+    default:
+      PANIC ("pci: Strange config read size\n");
+    }
+
+  return ret;
+}
+
+/* read entire configuration header into memory */
+static void
+pci_read_all_config (int bus, int dev, int func,
+                    struct pci_config_header *pch)
+{
+  unsigned int i;
+  for (i = 0; i < ((sizeof (struct pci_config_header) + 3) & ~3) / 4; i++)
+    {
+      ((uint32_t *) pch)[i] = pci_read_config (bus, dev, func, i * 4, 4);
+    }
+}
+
+
+/** scan PCI bus for all devices */
+static int
+pci_scan_bus (int bus)
+{
+  int dev;
+  int max_bus;
+
+  max_bus = 0;
+
+  for (dev = 0; dev < PCI_MAX_DEV_PER_BUS; dev++)
+    {
+      struct pci_config_header pch;
+      int func_cnt, func;
+
+      pci_read_all_config (bus, dev, 0, &pch);
+
+      if (pch.pci_vendor_id == PCI_VENDOR_INVALID)
+       continue;
+
+      func_cnt = 8;
+      if (!(pch.pci_header & PCI_HEADER_MULTIFUNC))
+       {
+         func_cnt = 1;
+       }
+
+      for (func = 0; func < func_cnt; func++)
+       {
+         int retbus;
+         retbus = pci_probe (bus, dev, func, &pch);
+         if (retbus > max_bus)
+           max_bus = retbus;
+       }
+    }
+
+  return max_bus;
+}
+
+/* get all information for a PCI device given bus/dev/func 
+   add pci device to device list if applicable 
+   return a new bus number if new bus is found
+ */
+static int
+pci_probe (int bus, int dev, int func, struct pci_config_header *ph)
+{
+  struct pci_dev *pd;
+
+  if (func != 0)
+    {
+      pci_read_all_config (bus, dev, func, ph);
+      if (ph->pci_vendor_id == PCI_VENDOR_INVALID)
+       return bus;
+    }
+
+  pd = malloc (sizeof (struct pci_dev));
+  memcpy (&pd->pch, ph, sizeof (struct pci_config_header));
+  pd->irq_handler = NULL;
+  pd->irq_handler_aux = NULL;
+  pd->bus = bus;
+  pd->dev = dev;
+  pd->func = func;
+
+  list_init (&pd->io_ranges);
+  list_push_back (&devices, &pd->peer);
+
+
+  if (ph->pci_major == PCI_MAJOR_BRIDGE)
+    {
+      if (ph->pci_minor == PCI_MINOR_PCI)
+       return pci_pci_bridge (pd);
+    }
+
+  pci_setup_io (pd);
+  pci_power_on (pd);
+
+  return bus;
+}
+
+static void
+pci_setup_io (struct pci_dev *pd)
+{
+  int i;
+  for (i = 0; i < PCI_BASE_COUNT; i++)
+    {
+      uint32_t tmp;
+      struct pci_io *pio;
+
+      if (pd->pch.pci_base_reg[i] == 0)
+       {
+         continue;
+       }
+
+      /* determine io granularity.. */
+      pci_write_config (pd->bus, pd->dev, pd->func,
+                       offsetof (struct pci_config_header, pci_base_reg[i]),
+                       4, ~0);
+
+      tmp =
+       pci_read_config (pd->bus, pd->dev, pd->func,
+                        offsetof (struct pci_config_header, pci_base_reg[i]),
+                        4);
+
+      /* configure BAR to the default */
+      pci_write_config (pd->bus, pd->dev, pd->func,
+                       offsetof (struct pci_config_header, pci_base_reg[i]),
+                       4, pd->pch.pci_base_reg[i]);
+
+      pio = malloc (sizeof (struct pci_io));
+      pio->dev = pd;
+
+      if (tmp & PCI_BASEADDR_IO)
+       {
+         pio->type = PCI_IO_PORT;
+         pio->size = (uint16_t) ((~tmp + 1) & 0xffff) + 1;
+         pio->addr.port = pd->pch.pci_base_reg[i] & ~1;
+       }
+      else
+       {
+         uint32_t ofs;
+
+         pio->type = PCI_IO_MEM;
+         pio->size = ROUND_UP ((~tmp + 1), PGSIZE);
+         ofs = (pd->pch.pci_base_reg[i] & 0xfffffff0 & PGMASK);
+         pio->addr.ptr = pci_alloc_mem ((void *) pd->pch.pci_base_reg[i],
+                                        pio->size / PGSIZE);
+         if (pio->addr.ptr == NULL)
+           {
+             printf ("PCI: %d pages for %d:%d.%d failed - may not work\n",
+                     pio->size / PGSIZE, pd->bus, pd->dev, pd->func);
+             free (pio);
+             pio = NULL;
+           }
+         else
+           {
+             pio->addr.ptr = (void *) ((uintptr_t) pio->addr.ptr + ofs);
+           }
+       }
+
+      /* add IO struct to device, if valid */
+      if (pio != NULL)
+       list_push_back (&pd->io_ranges, &pio->peer);
+    }
+
+}
+
+static void
+pci_power_on (struct pci_dev *pd UNUSED)
+{
+  /* STUB */
+}
+
+static int
+pci_pci_bridge (struct pci_dev *pd)
+{
+  int max_bus;
+  uint16_t command;
+
+  /* put bus into offline mode */
+  command = pd->pch.pci_command;
+  command &= ~0x3;
+  pci_write_config (pd->bus, pd->dev, pd->func,
+                   offsetof (struct pci_config_header, pci_command),
+                   2, command);
+  pd->pch.pci_command = command;
+
+  /* set up primary bus */
+  pci_write_config (pd->bus, pd->dev, pd->func, 0x18, 1, pd->bus);
+  /* secondary bus */
+  pci_write_config (pd->bus, pd->dev, pd->func, 0x19, 1, pd->bus + 1);
+
+  /* disable subordinates */
+  pci_write_config (pd->bus, pd->dev, pd->func, 0x1a, 1, 0xff);
+
+  /* scan this new bus */
+  max_bus = pci_scan_bus (pd->bus + 1);
+
+  /* set subordinate to the actual last bus */
+  pci_write_config (pd->bus, pd->dev, pd->func, 0x1a, 1, max_bus);
+
+  /* put online */
+  command |= 0x03;
+  pci_write_config (pd->bus, pd->dev, pd->func,
+                   offsetof (struct pci_config_header, pci_command),
+                   2, command);
+  pd->pch.pci_command = command;
+
+  return max_bus;
+}
+
+/* alert all PCI devices waiting on interrupt line that IRQ fired */
+static void
+pci_interrupt (struct intr_frame *frame)
+{
+  struct list_elem *e;
+  int int_line;
+
+  int_line = frame->vec_no - 0x20;
+  e = list_begin (&int_devices);
+  while (e != list_end (&int_devices))
+    {
+      struct pci_dev *pd;
+
+      pd = list_entry (e, struct pci_dev, int_peer);
+      if (pd->pch.pci_int_line == int_line)
+       pd->irq_handler (pd->irq_handler_aux);
+      e = list_next (e);
+    }
+}
+
+/* display information on all USB devices */
+void
+pci_print_stats (void)
+{
+  struct list_elem *e;
+
+  e = list_begin (&devices);
+  while (e != list_end (&devices))
+    {
+      struct pci_dev *pd;
+
+      pd = list_entry (e, struct pci_dev, peer);
+      pci_print_dev_info (pd);
+
+      e = list_next (e);
+    }
+}
+
+static void
+pci_print_dev_info (struct pci_dev *pd)
+{
+  printf ("PCI Device %d:%d.%d (%x,%x): %s - %s (%s) IRQ %d\n",
+         pd->bus, pd->dev, pd->func,
+         pd->pch.pci_vendor_id,
+         pd->pch.pci_device_id,
+         pci_lookup_vendor (pd->pch.pci_vendor_id),
+         pci_lookup_device (pd->pch.pci_vendor_id, pd->pch.pci_device_id),
+         pci_lookup_class (pd->pch.pci_major, pd->pch.pci_minor,
+                           pd->pch.pci_interface), pd->pch.pci_int_line);
+}
+
+void
+pci_mask_irq (struct pci_dev *pd)
+{
+  intr_irq_mask (pd->pch.pci_int_line);
+}
+
+void
+pci_unmask_irq (struct pci_dev *pd)
+{
+  intr_irq_unmask (pd->pch.pci_int_line);
+}
+
+void
+pci_write_config16 (struct pci_dev *pd, int off, uint16_t data)
+{
+  pci_write_config (pd->bus, pd->dev, pd->func, off, 2, data);
+}
+
+void
+pci_write_config32 (struct pci_dev *pd, int off, uint32_t data)
+{
+  pci_write_config (pd->bus, pd->dev, pd->func, off, 4, data);
+}
+
+void
+pci_write_config8 (struct pci_dev *pd, int off, uint8_t data)
+{
+  pci_write_config (pd->bus, pd->dev, pd->func, off, 1, data);
+}
+
+uint8_t
+pci_read_config8 (struct pci_dev *pd, int off)
+{
+  return pci_read_config (pd->bus, pd->dev, pd->func, off, 1);
+}
+
+uint16_t
+pci_read_config16 (struct pci_dev * pd, int off)
+{
+  return pci_read_config (pd->bus, pd->dev, pd->func, off, 2);
+}
+
+uint32_t
+pci_read_config32 (struct pci_dev * pd, int off)
+{
+  return pci_read_config (pd->bus, pd->dev, pd->func, off, 4);
+}
+
+
+/** allocate PCI memory pages for PCI devices */
+static void *
+pci_alloc_mem (void *phys_ptr, int pages)
+{
+  void *vaddr;
+  int i;
+
+  phys_ptr = (void *) ((uintptr_t) phys_ptr & ~PGMASK);
+
+  /* not enough space to allocate? */
+  if ((unsigned) (num_pci_pages + pages) >= (unsigned) PCI_ADDR_ZONE_PAGES)
+    {
+      return NULL;
+    }
+
+  /* insert into PCI_ZONE */
+  for (i = 0; i < pages; i++)
+    {
+      uint32_t pte_idx = (num_pci_pages + i) % 1024;
+      uint32_t pde_idx = (num_pci_pages + i) / 1024;
+      uint32_t *pt;
+      uint32_t pte;
+
+      pde_idx += pd_no ((void *) PCI_ADDR_ZONE_BEGIN);
+      pte = ((uint32_t) phys_ptr + (i * PGSIZE)) | PTE_P | PTE_W | PTE_CD;
+      pt = (uint32_t *) (ptov (init_page_dir[pde_idx] & ~PGMASK));
+      pt[pte_idx] = pte;
+    }
+
+  vaddr = (void *) (PCI_ADDR_ZONE_BEGIN + (num_pci_pages * PGSIZE));
+  num_pci_pages += pages;
+
+  return vaddr;
+}