grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patch 1/3] PCI support (abstract interface)


From: vincent guffens
Subject: [patch 1/3] PCI support (abstract interface)
Date: Tue, 16 May 2006 22:38:12 +0100
User-agent: Mozilla Thunderbird 1.0.8 (X11/20060502)

Hello,

Here is a patch to add pci support to grub2.


2006-05-16  Vincent Guffens  <address@hidden>

        * drivers/: New directory

        * conf/i386-pc.rmk (pkgdata_MODULES): Added pci.mod
        to the list of modules.
        (DRIVERS_CFLAGS): Added.
        (pci_mod_SOURCES): Likewise.
        (pci_mod_CFLAGS): Likewise.
        (pci_mod_LDFLAGS): Likewise.

        * drivers/include/grub/pci.h: New file.
        * drivers/include/grub/list.h: Likewise.
        * drivers/pci/pci.c: Likewise.


diff -rNu grub2/ChangeLog grub2-pci/ChangeLog
--- grub2/ChangeLog     2006-05-14 22:16:16.000000000 +0100
+++ grub2-pci/ChangeLog 2006-05-16 21:51:22.000000000 +0100
@@ -1,3 +1,18 @@
+2006-05-16  Vincent Guffens  <address@hidden>
+
+       * drivers/: New directory.
+
+       * conf/i386-pc.rmk (pkgdata_MODULES): Added pci.mod
+       to the list of modules.
+       (DRIVERS_CFLAGS): Added.
+       (pci_mod_SOURCES): Likewise.
+       (pci_mod_CFLAGS): Likewise.
+       (pci_mod_LDFLAGS): Likewise.
+
+       * drivers/include/grub/pci.h: New file.
+       * drivers/include/grub/list.h: Likewise.
+       * drivers/pci/pci.c: Likewise.
+
 2006-05-14  Yoshinori K. Okuji  <address@hidden>

        * kern/i386/pc/startup.S: Include grub/cpu/linux.h instead of
diff -rNu grub2/conf/i386-pc.rmk grub2-pci/conf/i386-pc.rmk
--- grub2/conf/i386-pc.rmk      2006-05-07 19:28:23.000000000 +0100
+++ grub2-pci/conf/i386-pc.rmk  2006-05-16 21:07:30.000000000 +0100
@@ -3,6 +3,7 @@
 COMMON_ASFLAGS = -nostdinc -fno-builtin
 COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32
 COMMON_LDFLAGS = -melf_i386 -nostdlib
+DRIVERS_CFLAGS = -Idrivers/include -fno-strict-aliasing

 # Images.
 pkgdata_IMAGES = boot.img diskboot.img kernel.img pxeboot.img
@@ -116,7 +117,7 @@
 pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod \
        _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod      \
        vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
-       videotest.mod play.mod
+       videotest.mod play.mod pci.mod

 # For _chain.mod.
 _chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -209,4 +210,9 @@
 videotest_mod_CFLAGS = $(COMMON_CFLAGS)
 videotest_mod_LDFLAGS = $(COMMON_LDFLAGS)

+# For pci.mod
+pci_mod_SOURCES = drivers/pci/pci.c
+pci_mod_CFLAGS = $(COMMON_CFLAGS) $(DRIVERS_CFLAGS)
+pci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
diff -rNu grub2/drivers/include/grub/list.h
grub2-pci/drivers/include/grub/list.h
--- grub2/drivers/include/grub/list.h   1970-01-01 01:00:00.000000000 +0100
+++ grub2-pci/drivers/include/grub/list.h       2006-05-16 21:10:58.000000000
+0100
@@ -0,0 +1,86 @@
+/* list.h - A very simple list.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+  If you want a list of struct myitem
+  you do
+
+  struct myitem *item_list;
+
+  where myitem MUST have its next pointer as the FIRST field
+
+  and you can then add, delete the EL item,
+  grub_add_list (&item_list, el);
+  grub_del_list (&item_list, el);
+
+  or call HOOK(item) for each element of the list
+  grub_iterate_list (item_list, hook);
+
+  This brk version will point el to the list item for which
+  HOOK(EL) returns a non-null value
+  grub_iterate_list_brk (item_list, hook, el);
+ */
+
+struct obj {
+  struct obj *next; /* MUST BE FIRST */
+};
+
+#define grub_del_list(list, el) _grub_del_list((struct obj**) list,
(struct obj*) el)
+#define grub_add_list(list, el) _grub_add_list((struct obj**) list,
(struct obj*) el)
+#define grub_find_list(list, el) \
+  (typeof(list)) _grub_find_list((struct obj*) list, (struct obj*) el)
+#define grub_iterate_list(list, func) \
+  {typeof(list) el = list; while (el) {func(el); el=el->next;}}
+#define grub_iterate_list_brk(list, func, it) \
+  {typeof(list) el = list; it = 0; \
+    while (el) {if (func(el)) {it = el; break;} el=el->next; }}
+
+static inline struct obj*  _grub_find_list (struct obj *list, struct
obj *el)
+{
+  struct obj *it = list;
+  for (it = list; it; it=it->next)
+  {
+    if (it == el) return el;
+  }
+  return 0;
+};
+
+static inline void _grub_add_list (struct obj **list, struct obj *el)
+{
+  if ( (!el) || (_grub_find_list (*list, el)) )
+    return;
+
+  el->next = *list;
+  *list = el;
+};
+
+static inline void _grub_del_list (struct obj **list, struct obj *el)
+{
+  struct obj **p;
+  struct obj *q;
+
+  for (p = list, q = *p; q; p = &(q->next), q = q->next)
+    if (q == el)
+      {
+        *p = q->next;
+        break;
+      }
+};
diff -rNu grub2/drivers/include/grub/pci.h
grub2-pci/drivers/include/grub/pci.h
--- grub2/drivers/include/grub/pci.h    1970-01-01 01:00:00.000000000 +0100
+++ grub2-pci/drivers/include/grub/pci.h        2006-05-16 21:10:58.000000000 
+0100
@@ -0,0 +1,119 @@
+/* pci.h Abstract interface for GRUB PCI support.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_PCI_H_
+#define GRUB_PCI_H_
+
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/device.h>
+#include <grub/net.h>
+
+/* Device type advertised by the driver */
+#define GRUB_NET_ETHERNET 0
+
+#define GRUB_PCI_SLOT(devfn)             ((devfn) >> 3)
+#define GRUB_PCI_FUNC(devfn)     ((devfn) & 0x07)
+
+struct grub_pci_ids
+{
+  grub_uint16_t vendor;
+  grub_uint16_t dev_id;
+  const char *name;
+};
+
+struct grub_pci_device;
+
+struct grub_pci_driver
+{
+  struct grub_pci_driver *next;
+  int type;
+  const char *name;
+  grub_err_t (*probe) (struct grub_pci_device *);
+  struct grub_pci_ids *ids;
+  int id_count;
+  grub_uint32_t class;
+};
+
+struct grub_pci_device
+{
+  struct grub_pci_device *next;
+  char *name;
+  grub_uint8_t bus;
+  grub_uint16_t vendor;
+  grub_uint16_t dev_id;
+  grub_uint8_t devfn;
+  grub_uint32_t class;
+  grub_addr_t ioaddr;
+  grub_addr_t membase;
+  grub_addr_t romaddr;
+  grub_uint8_t irq;
+  const struct grub_pci_driver *driver;
+};
+
+typedef struct grub_pci_device *grub_pci_device_t;
+
+struct grub_pci_io_support
+{
+  grub_err_t (*read_config_byte) (grub_pci_device_t, grub_addr_t,
grub_uint8_t *value);
+  grub_err_t (*write_config_byte) (grub_pci_device_t, grub_addr_t,
grub_uint8_t value);
+  grub_err_t (*read_config_word) (grub_pci_device_t, grub_addr_t,
grub_uint16_t *value);
+  grub_err_t (*write_config_word) (grub_pci_device_t, grub_addr_t,
grub_uint16_t value);
+  grub_err_t (*read_config_dword) (grub_pci_device_t, grub_addr_t,
grub_uint32_t *value);
+  grub_err_t (*write_config_dword) (grub_pci_device_t, grub_addr_t,
grub_uint32_t value);
+  grub_addr_t (*bus_base) (unsigned int bus);
+};
+
+struct grub_pci_support
+{
+  /* My name.  */
+  const char *name;
+
+  void (*init)(void);
+  void (*fini)(void);
+
+  void (*adjust) (grub_pci_device_t p);
+
+  /* Base Address Register helper functions. There are up to 6 BARs
+     PCI_BASE_ADDRESS_{[0-5]} in the configuration space of each device */
+  unsigned long (*bar_start) (grub_pci_device_t, unsigned int bar);
+  unsigned long (*bar_size) (grub_pci_device_t, unsigned int bar);
+
+  int (*find_capability) (grub_pci_device_t, int cap);
+
+  /* Call HOOK with each pci device.  */
+  grub_err_t (*iterate) (grub_err_t (*hook) (grub_pci_device_t));
+
+  /* Fill the pci device structure (romaddr, ioaddr, membase, irq)
+     given (bus, devfn, vendor, dev_id, class) */
+  grub_err_t (*init_pdev) (grub_pci_device_t);
+
+  /* Low level io functions.  */
+  struct grub_pci_io_support *io;
+};
+
+extern void grub_set_pci_support (struct grub_pci_support *);
+extern void grub_unset_pci_support (struct grub_pci_support *);
+extern void grub_register_pci_driver (struct grub_pci_driver *drv) ;
+extern void grub_unregister_pci_driver (struct grub_pci_driver *drv);
+
+#endif
+
+
diff -rNu grub2/drivers/pci/pci.c grub2-pci/drivers/pci/pci.c
--- grub2/drivers/pci/pci.c     1970-01-01 01:00:00.000000000 +0100
+++ grub2-pci/drivers/pci/pci.c 2006-05-16 21:11:32.000000000 +0100
@@ -0,0 +1,284 @@
+/* pci.c - abstract PCI support for grub2.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/pci.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/mm.h>
+#include <grub/net.h>
+#include <grub/device.h>
+#include <grub/list.h>
+
+/* This is not a list (there can be only one).  */
+static struct grub_pci_support *grub_pci_support;
+/* Lists of available drivers.  */
+static struct grub_pci_driver *grub_pci_drivers;
+/* Lists of PCI devices driven by GRUB.  */
+static struct grub_pci_device *grub_pci_devices;
+
+/* Add DEV at the head of the PCI device list.  */
+/* This function allocates the memory.          */
+static void grub_register_pci_device (struct grub_pci_device *dev,
+                                      struct grub_pci_driver *drv)
+{
+  grub_pci_device_t ndev = (grub_pci_device_t) grub_malloc (sizeof(*ndev));
+
+  /* TODO: what about the name ? */
+
+  ndev->bus = dev->bus;
+  ndev->vendor = dev->vendor;
+  ndev->dev_id = dev->dev_id;
+  ndev->devfn = dev->devfn;
+  ndev->class = dev->class;
+  ndev->ioaddr = dev->ioaddr;
+  ndev->membase = dev->membase;
+  ndev->romaddr = dev->romaddr;
+  ndev->irq = dev->irq;
+  ndev->driver = drv;
+
+  grub_add_list (&grub_pci_devices, ndev);
+}
+
+/* Unlink DEV from the list of PCI devices.  */
+/* This function frees the memory.           */
+static void grub_unregister_pci_device (struct grub_pci_device *dev)
+{
+  grub_del_list (&grub_pci_devices, dev);
+
+  /* TODO: Don't forget to free the name if used */
+
+  grub_free (dev);
+
+}
+
+void grub_set_pci_support (struct grub_pci_support *pci_s)
+{
+  if (grub_pci_support && grub_pci_support->fini)
+    grub_pci_support->fini ();
+
+  grub_pci_support = pci_s;
+
+  if (pci_s && pci_s->init)
+    pci_s->init ();
+}
+
+void grub_unset_pci_support (struct grub_pci_support *pci_s)
+{
+  if (grub_pci_support == pci_s)
+  {
+    if (pci_s->fini)
+      pci_s->fini ();
+    grub_pci_support = 0;
+  }
+}
+
+static int
+is_alredy_driven (grub_pci_device_t pdev)
+{
+  grub_pci_device_t it;
+  auto int is_pdev_in_list (grub_pci_device_t);
+
+  int is_pdev_in_list (grub_pci_device_t dev)
+  {
+    if ( (dev->bus == pdev->bus) &&
+         (GRUB_PCI_SLOT(dev->devfn) == GRUB_PCI_SLOT(pdev->devfn)) &&
+         (GRUB_PCI_FUNC(dev->dev_id) == GRUB_PCI_FUNC(pdev->dev_id)) )
+      return 1;
+    else
+      return 0;
+  };
+  grub_iterate_list_brk (grub_pci_devices, is_pdev_in_list, it);
+
+  return (it != 0);
+
+}
+
+/* lspci functions.  */
+static grub_err_t
+print_pci_dev_n (grub_pci_device_t pdev)
+{
+  grub_printf ("%02x:%02x.%01x [%04x/%04x] class %04x\n",pdev->bus,
+      GRUB_PCI_SLOT(pdev->devfn), GRUB_PCI_FUNC(pdev->devfn),
+      pdev->vendor, pdev->dev_id, pdev->class >> 8);
+
+  return 0;
+
+};
+
+static grub_err_t
+grub_cmd_lspci (struct grub_arg_list *state __attribute__ ((unused)),
+               int argc __attribute__ ((unused)),
+               char **args __attribute__ ((unused)))
+{
+
+  if (!grub_pci_support)
+    {
+      grub_printf ("No specific PCI support, try \"insmod
pci_etherboot\"\n");
+      return GRUB_ERR_TEST_FAILURE;
+    }
+
+  grub_pci_support->iterate (print_pci_dev_n);
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_lspci_driver (struct grub_arg_list *state __attribute__
((unused)),
+               int argc __attribute__ ((unused)),
+               char **args __attribute__ ((unused)))
+{
+  struct grub_pci_driver *drv= grub_pci_drivers;
+  struct grub_pci_device *dev;
+
+
+  grub_printf ("Available PCI drivers:\n");
+  while (drv)
+  {
+    dev = grub_pci_devices;
+
+    grub_printf ("-> %s:",drv->name);
+    while (dev)
+    {
+        if (dev->driver == drv)
+          grub_printf ("(%02x:%02x.%01x) ",dev->bus,
+              GRUB_PCI_SLOT(dev->devfn), GRUB_PCI_FUNC(dev->devfn));
+        dev=dev->next;
+    }
+    grub_printf ("\n");
+    drv = drv->next;
+  }
+
+  return GRUB_ERR_NONE;
+}
+
+/* Scan driver functions.   */
+static grub_err_t
+scan_driver (grub_pci_device_t pdev)
+{
+  struct grub_pci_driver * drv = grub_pci_drivers;
+  grub_err_t er;
+  int i;
+
+  /* If this device is already driven, do nothing */
+  if (is_alredy_driven (pdev))
+    return GRUB_ERR_TEST_FAILURE;
+
+  while (drv)
+    {
+      for (i=0; i<drv->id_count; i++ )
+        {
+          if ( ((pdev->vendor == drv->ids[i].vendor) &&
+                (pdev->dev_id == drv->ids[i].dev_id)) ||
+               ((pdev->class >> 8) == drv->class) )
+            {
+              grub_pci_support->init_pdev (pdev);
+
+              if ((pdev->class >> 8) != drv->class)
+              {
+                grub_dprintf ("pci","Probing for %s with driver %s\n",
+                    drv->ids[i].name, drv->name);
+              }
+              else
+              {
+                grub_dprintf ("pci","Probing for class %04x with driver
%s\n",
+                    drv->class, drv->name);
+               }
+
+              er = drv->probe (pdev);
+
+              if (er == GRUB_ERR_NONE) {
+                grub_register_pci_device (pdev,drv);
+                return GRUB_ERR_NONE;
+              }
+            }
+        }
+      drv=drv->next;
+    }
+
+  return GRUB_ERR_TEST_FAILURE;
+}
+
+
+/* Add DRV at the head of the driver list.  */
+void grub_register_pci_driver (struct grub_pci_driver *drv)
+{
+  grub_add_list (&grub_pci_drivers, drv);
+  grub_pci_support->iterate (scan_driver);
+}
+
+/* Unlink DRV from the driver list.  */
+void grub_unregister_pci_driver (struct grub_pci_driver *drv)
+{
+  auto int find_used_driver (grub_pci_device_t);
+  grub_pci_device_t dev;
+
+  int find_used_driver (grub_pci_device_t device)
+  {
+    if (device->driver == drv)
+      return 1;
+    else
+      return 0;
+  };
+
+  grub_iterate_list_brk (grub_pci_devices, find_used_driver, dev);
+  while ( dev )
+  {
+    grub_unregister_pci_device (dev);
+    grub_iterate_list_brk (grub_pci_devices, find_used_driver, dev);
+  }
+
+  grub_del_list (&grub_pci_drivers, drv);
+}
+
+
+static grub_err_t
+grub_cmd_scan_pci_device (struct grub_arg_list *state __attribute__
((unused)),
+               int argc __attribute__ ((unused)),
+               char **args __attribute__ ((unused)))
+{
+
+ if (!grub_pci_support)
+   {
+     grub_printf ("No specific PCI support, try \"insmod
pci_etherboot\"\n");
+     return GRUB_ERR_TEST_FAILURE;
+   }
+
+  grub_pci_support->iterate (scan_driver);
+  return GRUB_ERR_NONE;
+}
+
+/* GRUB module functions.   */
+GRUB_MOD_INIT(pci)
+{
+  (void)mod;                   /* To stop warning. */
+  grub_register_command ("lspci", grub_cmd_lspci, GRUB_COMMAND_FLAG_BOTH,
+                        "lspci", "list the PCI devices", 0);
+  grub_register_command ("lspci_driver", grub_cmd_lspci_driver,
GRUB_COMMAND_FLAG_BOTH,
+                        "lspci_driver", "list available PCI drivers and the 
devices they
drive", 0);
+  grub_register_command ("scan_pci_device", grub_cmd_scan_pci_device,
GRUB_COMMAND_FLAG_BOTH,
+                        "scan_pci_device", "Scan the PCI bus for devices for 
which we have
a driver", 0);
+}
+
+GRUB_MOD_FINI(pci)
+{
+  grub_unregister_command ("lspci");
+  grub_unregister_command ("lspci_driver");
+  grub_unregister_command ("scan_pci_device");
+}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]