1 /*- 2 * Copyright (C) 2018 Breno Leitao 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 17 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 19 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 21 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include <sys/cdefs.h> 26 __FBSDID("$FreeBSD$"); 27 28 #include <sys/param.h> 29 #include <sys/kernel.h> 30 #include <sys/systm.h> 31 #include <sys/module.h> 32 #include <sys/types.h> 33 #include <sys/proc.h> 34 35 #include <vm/vm.h> 36 #include <vm/pmap.h> 37 38 #include <machine/bus.h> 39 40 #include <dev/ofw/openfirm.h> 41 #include <dev/ofw/ofw_bus.h> 42 #include <dev/ofw/ofw_bus_subr.h> 43 44 #include "opt_md.h" 45 46 #ifdef MD_ROOT_MEM 47 extern u_char *mfs_root; 48 extern uint32_t mfs_root_size; 49 #else 50 #warning "MD_ROOT_MEM should be set to use ofw initrd as a md device" 51 #endif 52 53 /* bus entry points */ 54 static int ofw_initrd_probe(device_t dev); 55 static int ofw_initrd_attach(device_t dev); 56 static void ofw_initrd_identify(driver_t *driver, device_t parent); 57 58 struct ofw_initrd_softc { 59 device_t sc_dev; 60 vm_paddr_t start; 61 vm_paddr_t end; 62 }; 63 64 static int 65 ofw_initrd_probe(device_t dev) 66 { 67 phandle_t chosen; 68 69 /* limit this device to one unit */ 70 if (device_get_unit(dev) != 0) 71 return (ENXIO); 72 73 chosen = OF_finddevice("/chosen"); 74 if (chosen <= 0) { 75 return (ENXIO); 76 } 77 78 if (!OF_hasprop(chosen, "linux,initrd-start") || 79 !OF_hasprop(chosen, "linux,initrd-end")) 80 return (ENXIO); 81 82 device_set_desc(dev, "OFW initrd memregion loader"); 83 return (BUS_PROBE_DEFAULT); 84 } 85 86 static int 87 ofw_initrd_attach(device_t dev) 88 { 89 struct ofw_initrd_softc *sc; 90 vm_paddr_t start, end; 91 phandle_t chosen; 92 pcell_t cell[2]; 93 ssize_t size; 94 95 sc = device_get_softc(dev); 96 97 chosen = OF_finddevice("/chosen"); 98 if (chosen <= 0) { 99 device_printf(dev, "/chosen not found\n"); 100 return (ENXIO); 101 } 102 103 size = OF_getencprop(chosen, "linux,initrd-start", cell, sizeof(cell)); 104 if (size == 4) 105 start = cell[0]; 106 else if (size == 8) 107 start = (uint64_t)cell[0] << 32 | cell[1]; 108 else { 109 device_printf(dev, "Wrong linux,initrd-start size\n"); 110 return (ENXIO); 111 } 112 113 size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell)); 114 if (size == 4) 115 end = cell[0]; 116 else if (size == 8) 117 end = (uint64_t)cell[0] << 32 | cell[1]; 118 else{ 119 device_printf(dev, "Wrong linux,initrd-end size\n"); 120 return (ENXIO); 121 } 122 123 if (end - start > 0) { 124 mfs_root = (u_char *) PHYS_TO_DMAP(start); 125 mfs_root_size = end - start; 126 127 return (0); 128 } 129 130 return (ENXIO); 131 } 132 133 static void 134 ofw_initrd_identify(driver_t *driver, device_t parent) 135 { 136 if (device_find_child(parent, "initrd", -1) != NULL) 137 return; 138 139 if (BUS_ADD_CHILD(parent, 10, "initrd", -1) == NULL) 140 device_printf(parent, "add ofw_initrd child failed\n"); 141 } 142 143 static device_method_t ofw_initrd_methods[] = { 144 DEVMETHOD(device_identify, ofw_initrd_identify), 145 DEVMETHOD(device_probe, ofw_initrd_probe), 146 DEVMETHOD(device_attach, ofw_initrd_attach), 147 DEVMETHOD_END 148 }; 149 150 static driver_t ofw_initrd_driver = { 151 "ofw_initrd", 152 ofw_initrd_methods, 153 sizeof(struct ofw_initrd_softc) 154 }; 155 156 static devclass_t ofw_initrd_devclass; 157 158 DRIVER_MODULE(ofw_initrd, ofwbus, ofw_initrd_driver, ofw_initrd_devclass, 159 NULL, NULL); 160