kernel/i386: Add RAM driver for i386.
authorSascha Wildner <saw@online.de>
Sun, 7 Sep 2014 18:11:05 +0000 (20:11 +0200)
committerSascha Wildner <saw@online.de>
Sun, 7 Sep 2014 18:52:23 +0000 (20:52 +0200)
sys/platform/pc32/i386/nexus.c

index 13b93e7..9ede43d 100644 (file)
@@ -51,6 +51,7 @@
 #include <sys/rman.h>
 #include <sys/interrupt.h>
 #include <sys/machintr.h>
+#include <sys/linker.h>
 
 #include <machine/vmparam.h>
 #include <vm/vm.h>
 #include <machine/intr_machdep.h>
 #include <machine_base/apic/ioapic.h>
 #include <machine_base/apic/lapic.h>
+#include <machine/pc/bios.h>
+#include <machine/metadata.h>
 
 #if NPCI > 0
 #include "pcib_if.h"
 #endif
 
+#define ELF_KERN_STR    ("elf"__XSTRING(__ELF_WORD_SIZE)" kernel")
+
 static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
 struct nexus_device {
        struct resource_list    nx_resources;
@@ -623,3 +628,106 @@ nexus_release_msix(device_t dev, device_t child, int irq, int cpuid)
        return 0;
 }
 #endif
+
+/* Placeholder for system RAM. */
+static void
+ram_identify(driver_t *driver, device_t parent)
+{
+       if (resource_disabled("ram", 0))
+               return;
+       if (BUS_ADD_CHILD(parent, parent, 0, "ram", 0) == NULL)
+               panic("%s", __func__);
+}
+
+static int
+ram_probe(device_t dev)
+{
+       device_quiet(dev);
+       device_set_desc(dev, "System RAM");
+       return (0);
+}
+
+static int
+ram_attach(device_t dev)
+{
+       struct bios_smap *smapbase, *smap, *smapend;
+       struct resource *res;
+       vm_paddr_t *p;
+       caddr_t kmdp;
+       uint32_t smapsize;
+       int error, rid;
+
+       device_quiet(dev);
+       device_set_desc(dev, "System RAM");
+
+       /* Retrieve the system memory map from the loader. */
+       kmdp = preload_search_by_type("elf kernel");
+       if (kmdp == NULL)
+               kmdp = preload_search_by_type(ELF_KERN_STR);
+       if (kmdp != NULL)
+               smapbase = (struct bios_smap *)preload_search_info(kmdp,
+                   MODINFO_METADATA | MODINFOMD_SMAP);
+       else
+               smapbase = NULL;
+       if (smapbase != NULL) {
+               smapsize = *((u_int32_t *)smapbase - 1);
+               smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
+
+               rid = 0;
+               for (smap = smapbase; smap < smapend; smap++) {
+                       if (smap->type != SMAP_TYPE_MEMORY ||
+                           smap->length == 0)
+                               continue;
+                       error = bus_set_resource(dev, SYS_RES_MEMORY, rid,
+                           smap->base, smap->length, -1);
+                       if (error)
+                               panic("%s: resource %d failed set with %d",
+                                   __func__, rid, error);
+                       res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+                           0);
+                       if (res == NULL)
+                               panic("%s: resource %d failed to attach",
+                                   __func__, rid);
+                       rid++;
+               }
+               return (0);
+       }
+
+       /*
+        * If the system map is not available, fall back to using
+        * dump_avail[].  We use the dump_avail[] array rather than
+        * phys_avail[] for the memory map as phys_avail[] contains
+        * holes for kernel memory, page 0, the message buffer, and
+        * the dcons buffer.  We test the end address in the loop
+        * instead of the start since the start address for the first
+        * segment is 0.
+        */
+       for (rid = 0, p = dump_avail; p[1] != 0; rid++, p += 2) {
+               error = bus_set_resource(dev, SYS_RES_MEMORY, rid, p[0],
+                   p[1] - p[0], -1);
+               if (error)
+                       panic("%s: resource %d failed set with %d", __func__,
+                           rid, error);
+               res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
+               if (res == NULL)
+                       panic("%s: resource %d failed to attach", __func__,
+                           rid);
+       }
+       return (0);
+}
+static device_method_t ram_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_identify,      ram_identify),
+       DEVMETHOD(device_probe,         ram_probe),
+       DEVMETHOD(device_attach,        ram_attach),
+       { 0, 0 }
+};
+
+static driver_t ram_driver = {
+       "ram",
+       ram_methods,
+       1,              /* no softc */
+};
+
+static devclass_t ram_devclass;
+DRIVER_MODULE(ram, nexus, ram_driver, ram_devclass, NULL, NULL);