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