symbian-qemu-0.9.1-12/qemu-symbian-svp/devtree.c
changeset 1 2fb8b9db1c86
child 36 a587897e3bb2
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  *  Dynamic device configuration and creation.
       
     3  *
       
     4  *  Copyright (c) 2008 CodeSourcery
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General Public
       
    17  * License along with this library; if not, write to the Free Software
       
    18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    19  */
       
    20 
       
    21 /* FIXME: check all malloc/strdup exit coeds.  Or better still have
       
    22    malloc/strdup abort.  */
       
    23 
       
    24 #include "qemu-common.h"
       
    25 #include "sysemu.h"
       
    26 #include "devtree.h"
       
    27 #include "hw/boards.h"
       
    28 #include "libfdt/libfdt.h"
       
    29 
       
    30 #define BADF(fmt, args...) \
       
    31 do { fprintf(stderr, "error: " fmt , ##args); exit(1);} while (0)
       
    32 
       
    33 /* Assume no device will ever need more than 4 register windows.  */
       
    34 #define MAX_DEV_REGS 4
       
    35 
       
    36 enum QEMUDeicePropetyType {
       
    37     QDEV_PROP_INT,
       
    38     QDEV_PROP_STRING
       
    39 };
       
    40 
       
    41 typedef struct QEMUDeviceProperty {
       
    42     const char *name;
       
    43     enum QEMUDeicePropetyType type;
       
    44     union {
       
    45         int i;
       
    46         char *string;
       
    47     } value;
       
    48     struct QEMUDeviceProperty *next;
       
    49 } QEMUDeviceProperty;
       
    50 
       
    51 struct QEMUDeviceClass {
       
    52     struct QEMUDeviceClass *next;
       
    53     const char *name;
       
    54     void *opaque;
       
    55     QEMUDeviceProperty *properties;
       
    56     int num_irqs;
       
    57     int num_regs;
       
    58     CPUReadMemoryFunc **mem_read[MAX_DEV_REGS];
       
    59     CPUWriteMemoryFunc **mem_write[MAX_DEV_REGS];
       
    60     target_phys_addr_t mem_size[MAX_DEV_REGS];
       
    61     QDEVCreateFn create;
       
    62     SaveStateHandler *save_state;
       
    63     LoadStateHandler *load_state;
       
    64     int savevm_version;
       
    65     unsigned has_chardev:1;
       
    66 };
       
    67 
       
    68 struct QEMUDevice {
       
    69     QEMUDevice *next;
       
    70     QEMUDeviceClass *dc;
       
    71     QEMUDeviceProperty *properties;
       
    72     qemu_irq **irqp;
       
    73     qemu_irq *irq;
       
    74     CharDriverState *chardev;
       
    75     qemu_irq *irq_sink;
       
    76     void *mem_opaque[MAX_DEV_REGS];
       
    77     void *opaque;
       
    78     int irq_sink_count;
       
    79     const void *dt;
       
    80     int node_offset;
       
    81     uint32_t phandle;
       
    82 };
       
    83 
       
    84 const void *machine_devtree;
       
    85 int machine_devtree_size;
       
    86 
       
    87 devtree_ram_region *devtree_ram_map;
       
    88 int devtree_ram_map_size;
       
    89 
       
    90 /* Device (class) registration.  */
       
    91 
       
    92 QEMUDeviceClass *cpu_device_class;
       
    93 
       
    94 static QEMUDeviceClass *all_dc;
       
    95 
       
    96 QEMUDeviceClass *qdev_new(const char *name, QDEVCreateFn create, int nirq)
       
    97 {
       
    98     QEMUDeviceClass *dc = qemu_mallocz(sizeof(*dc));
       
    99 
       
   100     dc->num_irqs = nirq;
       
   101     dc->create = create;
       
   102     dc->name = qemu_strdup(name);
       
   103 
       
   104     dc->next = all_dc;
       
   105     all_dc = dc;
       
   106 
       
   107     return dc;
       
   108 }
       
   109 
       
   110 void qdev_add_chardev(QEMUDeviceClass *dc)
       
   111 {
       
   112     if (dc->has_chardev) {
       
   113         BADF("Device class %s already has a chardev\n", dc->name);
       
   114     }
       
   115     dc->has_chardev = 1;
       
   116 }
       
   117 
       
   118 void qdev_add_property_string(QEMUDeviceClass *dc, const char *name,
       
   119                               const char *def)
       
   120 {
       
   121     QEMUDeviceProperty *p = qemu_mallocz(sizeof(*p));
       
   122 
       
   123     p->name = qemu_strdup(name);
       
   124     p->type = QDEV_PROP_STRING;
       
   125     if (def)
       
   126         p->value.string = qemu_strdup(def);
       
   127     p->next = dc->properties;
       
   128     dc->properties = p;
       
   129 }
       
   130 
       
   131 void qdev_add_property_int(QEMUDeviceClass *dc, const char *name, int def)
       
   132 {
       
   133     QEMUDeviceProperty *p = qemu_mallocz(sizeof(*p));
       
   134 
       
   135     p->name = qemu_strdup(name);
       
   136     p->type = QDEV_PROP_INT;
       
   137     p->value.i = def;
       
   138     p->next = dc->properties;
       
   139     dc->properties = p;
       
   140 }
       
   141 
       
   142 void qdev_add_registers(QEMUDeviceClass *dc, CPUReadMemoryFunc **mem_read,
       
   143                         CPUWriteMemoryFunc **mem_write,
       
   144                         target_phys_addr_t mem_size)
       
   145 {
       
   146     if (dc->num_regs == MAX_DEV_REGS) {
       
   147         BADF("too many regs");
       
   148         return;
       
   149     }
       
   150 
       
   151     dc->mem_read[dc->num_regs] = mem_read;
       
   152     dc->mem_write[dc->num_regs] = mem_write;
       
   153     dc->mem_size[dc->num_regs] = mem_size;
       
   154     dc->num_regs++;
       
   155 }
       
   156 
       
   157 void qdev_add_class_opaque(QEMUDeviceClass *dc, void *opaque)
       
   158 {
       
   159     dc->opaque = opaque;
       
   160 }
       
   161 
       
   162 void qdev_add_savevm(QEMUDeviceClass *dc, int ver,
       
   163                      SaveStateHandler *save_state,
       
   164                      LoadStateHandler *load_state)
       
   165 {
       
   166     dc->savevm_version = ver;
       
   167     dc->save_state = save_state;
       
   168     dc->load_state = load_state;
       
   169 }
       
   170 
       
   171 static QEMUDeviceProperty *qdev_copy_properties(QEMUDeviceProperty *src)
       
   172 {
       
   173     QEMUDeviceProperty *first;
       
   174     QEMUDeviceProperty **p;
       
   175     QEMUDeviceProperty *dest;
       
   176 
       
   177     first = NULL;
       
   178     p = &first;
       
   179     while (src) {
       
   180         dest = qemu_mallocz(sizeof(*dest));
       
   181         dest->name = src->name;
       
   182         dest->type = src->type;
       
   183         switch (src->type) {
       
   184         case QDEV_PROP_INT:
       
   185             dest->value.i = src->value.i;
       
   186             break;
       
   187         case QDEV_PROP_STRING:
       
   188             if (src->value.string)
       
   189                 dest->value.string = qemu_strdup(src->value.string);
       
   190             break;
       
   191         }
       
   192         src = src->next;
       
   193         *p = dest;
       
   194         p = &dest->next;
       
   195     }
       
   196     return first;
       
   197 }
       
   198 
       
   199 
       
   200 /* Device manipulation.  */
       
   201 
       
   202 static QEMUDevice *first_device;
       
   203 
       
   204 static QEMUDevice *qdev_create(QEMUDeviceClass *dc, const void *dt,
       
   205                                int node_offset)
       
   206 {
       
   207     QEMUDevice *dev = qemu_mallocz(sizeof(*dc));
       
   208 
       
   209     dev->dc = dc;
       
   210     dev->properties = qdev_copy_properties(dc->properties);
       
   211     if (dc->num_irqs) {
       
   212         dev->irqp = qemu_mallocz(dc->num_irqs * sizeof(qemu_irq *));
       
   213         dev->irq = qemu_mallocz(dc->num_irqs * sizeof(qemu_irq));
       
   214     }
       
   215     dev->node_offset = node_offset;
       
   216     dev->dt = dt;
       
   217     dev->phandle = fdt_get_phandle(dt, node_offset);
       
   218 
       
   219     dev->next = first_device;
       
   220     first_device = dev;
       
   221 
       
   222     return dev;
       
   223 }
       
   224 
       
   225 /* IRQs are not created/linked until all devices have been created.
       
   226    This function take a pointer to a qemu_irq object, which will be
       
   227    populated later.  */
       
   228 /* FIXME: Should we just have qdev_irq_{raise,lower}?  */
       
   229 void qdev_get_irq(QEMUDevice *dev, int n, qemu_irq *p)
       
   230 {
       
   231     if (n >= dev->dc->num_irqs)
       
   232         BADF("Bad IRQ %d (%d)\n", n, dev->dc->num_irqs);
       
   233     dev->irqp[n] = p;
       
   234 }
       
   235 
       
   236 CharDriverState *qdev_get_chardev(QEMUDevice *dev)
       
   237 {
       
   238     return dev->chardev;
       
   239 }
       
   240 
       
   241 void qdev_create_interrupts(QEMUDevice *dev, qemu_irq_handler handler, 
       
   242                             void *opaque, int n)
       
   243 {
       
   244     dev->irq_sink = qemu_allocate_irqs(handler, opaque, n);
       
   245     dev->irq_sink_count = n;
       
   246 }
       
   247 
       
   248 int qdev_get_property_int(QEMUDevice *dev, const char *name)
       
   249 {
       
   250     QEMUDeviceProperty *p;
       
   251 
       
   252     for (p = dev->properties; p; p = p->next) {
       
   253         if (strcmp(name, p->name) == 0) {
       
   254             if (p->type != QDEV_PROP_INT)
       
   255                 abort();
       
   256             return p->value.i;
       
   257         }
       
   258     }
       
   259     abort();
       
   260 }
       
   261 
       
   262 const char *qdev_get_property_string(QEMUDevice *dev, const char *name)
       
   263 {
       
   264     QEMUDeviceProperty *p;
       
   265 
       
   266     for (p = dev->properties; p; p = p->next) {
       
   267         if (strcmp(name, p->name) == 0) {
       
   268             if (p->type != QDEV_PROP_STRING)
       
   269                 abort();
       
   270             return p->value.string;
       
   271         }
       
   272     }
       
   273     abort();
       
   274 }
       
   275 
       
   276 const char *qdev_get_name(QEMUDevice *dev)
       
   277 {
       
   278     return fdt_get_name(dev->dt, dev->node_offset, NULL);
       
   279 }
       
   280 
       
   281 void *qdev_get_class_opaque(QEMUDevice *dev)
       
   282 {
       
   283     return dev->dc->opaque;
       
   284 }
       
   285 
       
   286 void qdev_set_opaque(QEMUDevice *dev, void *opaque)
       
   287 {
       
   288     dev->opaque = opaque;
       
   289 }
       
   290 
       
   291 void qdev_set_region_opaque(QEMUDevice *dev, int n, void *opaque)
       
   292 {
       
   293     dev->mem_opaque[n] = opaque;
       
   294 }
       
   295 
       
   296 void qdev_set_irq_level(QEMUDevice *dev, int n, int level)
       
   297 {
       
   298     if (n < 0 || n > dev->dc->num_irqs)
       
   299         return;
       
   300 
       
   301     qemu_set_irq(dev->irq[n], level);
       
   302 }
       
   303 
       
   304 /* FDT handling.  */
       
   305 
       
   306 static void invalid_devtree(QEMUDevice *dev, const char *msg)
       
   307 {
       
   308     fprintf(stderr, "devtree: %s: %s\n", dev->dc->name, msg);
       
   309     exit(1);
       
   310 }
       
   311 
       
   312 static const char *fdt_getprop_string(const void *dt, int node,
       
   313                                       const char * name)
       
   314 {
       
   315     const char *p;
       
   316     int len;
       
   317 
       
   318     p = fdt_getprop(dt, node, name, &len);
       
   319     if (!p || len == 0)
       
   320         return NULL;
       
   321     /* Check string is properly terminated.  If the wrong kind of property
       
   322        is used then this may not be true.  */
       
   323     if (p[len - 1] != 0)
       
   324         return NULL;
       
   325     return p;
       
   326 }
       
   327 
       
   328 static void find_properties(QEMUDevice *dev)
       
   329 {
       
   330     const struct fdt_property *p;
       
   331     QEMUDeviceProperty *dp;
       
   332     int len;
       
   333 
       
   334     for (dp = dev->properties; dp; dp = dp->next) {
       
   335         p = fdt_get_property(dev->dt, dev->node_offset, dp->name, &len);
       
   336         if (!p)
       
   337             continue;
       
   338         switch (dp->type) {
       
   339         case QDEV_PROP_INT:
       
   340             if (len != 4) {
       
   341                 invalid_devtree(dev, "Bad integer property");
       
   342                 break;
       
   343             }
       
   344             dp->value.i = fdt32_to_cpu(*(uint32_t *)p->data);
       
   345             break;
       
   346         case QDEV_PROP_STRING:
       
   347             if (len == 0 || p->data[len - 1]) {
       
   348                 invalid_devtree(dev, "Bad string property");
       
   349                 break;
       
   350             }
       
   351             if (dp->value.string)
       
   352                 qemu_free(dp->value.string);
       
   353             dp->value.string = qemu_strdup((const char *)p->data);
       
   354             break;
       
   355         }
       
   356     }
       
   357 }
       
   358 
       
   359 /* We currently assume a fixed address/size.  Enforce that here.  */
       
   360 static void check_cells(const void *dt, int node, int address, int size)
       
   361 {
       
   362     const struct fdt_property *p;
       
   363     int parent;
       
   364     int len;
       
   365     int n;
       
   366 
       
   367     parent = fdt_parent_offset(dt, node);
       
   368     if (node < 0) {
       
   369         fprintf(stderr, "missing parent node for %s\n",
       
   370                 fdt_get_name(dt, node, NULL));
       
   371         exit(1);
       
   372     }
       
   373     p = fdt_get_property(dt, parent, "#address-cells", &len);
       
   374     if (!p || len != 4) {
       
   375         fprintf(stderr,
       
   376                 "Invalid or missing #address-cells for %s\n",
       
   377                 fdt_get_name(dt, node, NULL));
       
   378         exit(1);
       
   379     }
       
   380     n = fdt32_to_cpu(*(uint32_t *)p->data);
       
   381     if (n != address) {
       
   382         fprintf(stderr,
       
   383                 "Incorrect #address-cells for %s (expected %d got %d)\n",
       
   384                 fdt_get_name(dt, node, NULL), address, n);
       
   385         exit(1);
       
   386     }
       
   387     p = fdt_get_property(dt, parent, "#size-cells", &len);
       
   388     if (!p || len != 4) {
       
   389         fprintf(stderr,
       
   390                 "Invalid or missing #size-cells for %s\n",
       
   391                 fdt_get_name(dt, node, NULL));
       
   392         exit(1);
       
   393     }
       
   394     n = fdt32_to_cpu(*(uint32_t *)p->data);
       
   395     if (n != size) {
       
   396         fprintf(stderr,
       
   397                 "Incorrect #size-cells for %s (expected %d got %d)\n",
       
   398                 fdt_get_name(dt, node, NULL), size, n);
       
   399         exit(1);
       
   400     }
       
   401 }
       
   402 
       
   403 static void create_from_node(QEMUDeviceClass *dc, const void *dt, int node)
       
   404 {
       
   405     QEMUDevice *d;
       
   406     const char *propstr;
       
   407     int i;
       
   408 
       
   409     d = qdev_create(dc, dt, node);
       
   410     if (dc->has_chardev) {
       
   411         int n;
       
   412         propstr = fdt_getprop_string(dt, node, "chardev");
       
   413         if (propstr) {
       
   414             i = sscanf(propstr, "serial%d", &n);
       
   415             if (i == 1 && n >= 0 && n < MAX_SERIAL_PORTS)
       
   416                 d->chardev = serial_hds[n];
       
   417         }
       
   418     }
       
   419     find_properties(d);
       
   420     d->dc->create(d);
       
   421     if (dc->savevm_version) {
       
   422         register_savevm(dc->name, -1, dc->savevm_version,
       
   423                         dc->save_state, dc->load_state, d->opaque);
       
   424     }
       
   425     if (dc->num_regs) {
       
   426         const struct fdt_property *p;
       
   427         uint32_t base;
       
   428         uint32_t *data;
       
   429         void *opaque;
       
   430         int iomemtype;
       
   431         int len;
       
   432 
       
   433         check_cells(dt, node, 1, 0);
       
   434         p = fdt_get_property(dt, node, "reg", &len);
       
   435         if (!p || len != dc->num_regs * 4) {
       
   436             invalid_devtree(d, "Missing reg");
       
   437             return;
       
   438         }
       
   439         data = (uint32_t *)p->data;
       
   440         for (i = 0; i < dc->num_regs; i++) {
       
   441             base = fdt32_to_cpu(*data);
       
   442             data++;
       
   443             opaque = d->mem_opaque[i];
       
   444             if (!opaque)
       
   445                 opaque = d->opaque;
       
   446             iomemtype = cpu_register_io_memory(0, dc->mem_read[i],
       
   447                                                dc->mem_write[i], opaque);
       
   448             cpu_register_physical_memory(base, dc->mem_size[i], iomemtype);
       
   449         }
       
   450     }
       
   451 }
       
   452 
       
   453 static void scan_devtree(const void *dt)
       
   454 {
       
   455     QEMUDeviceClass *dc;
       
   456     int node;
       
   457 
       
   458     for (dc = all_dc; dc; dc = dc->next) {
       
   459         node = -1;
       
   460         while (1) {
       
   461             node = fdt_node_offset_by_compatible(dt, node, dc->name);
       
   462             if (node < 0)
       
   463                 break;
       
   464             create_from_node(dc, dt, node);
       
   465         }
       
   466     }
       
   467 }
       
   468 
       
   469 /* Create CPU devices.  These are devices so that they can have interrupts.  */
       
   470 static void create_cpus(const void *dt)
       
   471 {
       
   472     int node = -1;
       
   473 
       
   474     while (1) {
       
   475         node = fdt_node_offset_by_prop_value(dt, node, "device_type",
       
   476                                              "cpu", 4);
       
   477         if (node < 0)
       
   478             break;
       
   479         create_from_node(cpu_device_class, dt, node);
       
   480     }
       
   481 }
       
   482 
       
   483 /* Add RAM.  */
       
   484 static void create_ram(const void *dt)
       
   485 {
       
   486     int node = -1;
       
   487     const struct fdt_property *p;
       
   488     int len;
       
   489     uint32_t base;
       
   490     uint32_t size;
       
   491     uint32_t *data;
       
   492     ram_addr_t offset;
       
   493 
       
   494     while (1) {
       
   495         node = fdt_node_offset_by_prop_value(dt, node, "device_type",
       
   496                                              "memory", 7);
       
   497         if (node < 0)
       
   498             break;
       
   499 
       
   500 
       
   501         check_cells(dt, node, 1, 1);
       
   502         p = fdt_get_property(dt, node, "reg", &len);
       
   503         if (!p || (len % 8) != 0) {
       
   504             fprintf(stderr, "bad memory section %s\n",
       
   505                     fdt_get_name(dt, node, NULL));
       
   506             exit(1);
       
   507         }
       
   508         data = (uint32_t *)p->data;
       
   509         while (len) {
       
   510             base = fdt32_to_cpu(data[0]);
       
   511             size = fdt32_to_cpu(data[1]);
       
   512             data += 2;
       
   513             len -= 8;
       
   514             /* Ignore zero size regions.  */
       
   515             if (size == 0)
       
   516                 continue;
       
   517             offset = qemu_ram_alloc(size);
       
   518             cpu_register_physical_memory(base, size, offset | IO_MEM_RAM);
       
   519 
       
   520             devtree_ram_map_size++;
       
   521             devtree_ram_map = qemu_realloc(devtree_ram_map,
       
   522                 devtree_ram_map_size * sizeof(devtree_ram_region));
       
   523             devtree_ram_map[devtree_ram_map_size - 1].base = base;
       
   524             devtree_ram_map[devtree_ram_map_size - 1].size = size;
       
   525         }
       
   526     }
       
   527     /* FIXME: Merge and sort memory map entries.  */
       
   528     /* Technically there's no reason we have to have RAM.  However in
       
   529        practice it indicates a busted machine description.  */
       
   530     if (!devtree_ram_map) {
       
   531         fprintf(stderr, "No memory regions found\n");
       
   532         exit(1);
       
   533     }
       
   534 }
       
   535 
       
   536 static QEMUDevice *find_device_by_phandle(uint32_t phandle)
       
   537 {
       
   538     QEMUDevice *dev;
       
   539     for (dev = first_device; dev; dev = dev->next) {
       
   540         if (dev->phandle == phandle)
       
   541             return dev;
       
   542     }
       
   543     return NULL;
       
   544 }
       
   545 
       
   546 /* We currently assume #interrupt-cells is 1.  */
       
   547 static void check_interrupt_cells(QEMUDevice *dev)
       
   548 {
       
   549     const struct fdt_property *p;
       
   550     int len;
       
   551 
       
   552     p = fdt_get_property(dev->dt, dev->node_offset, "#interrupt-cells", &len);
       
   553     /* Allow a missing value.  Useful for devices that are pointed to by
       
   554        a qemu,interrupts property.  */
       
   555     if (!p)
       
   556         return;
       
   557     if (len != 4) {
       
   558         invalid_devtree(dev, "Invalid #interrupt-cells");
       
   559     }
       
   560     if (fdt32_to_cpu(*(uint32_t *)p->data) != 1) {
       
   561         invalid_devtree(dev, "#interrupt-cells must be 1");
       
   562     }
       
   563 }
       
   564 
       
   565 static QEMUDevice *find_interrupt_parent(QEMUDevice *dev)
       
   566 {
       
   567     const struct fdt_property *p;
       
   568     QEMUDevice *parent;
       
   569     uint32_t phandle;
       
   570     int len;
       
   571 
       
   572     p = fdt_get_property(dev->dt, dev->node_offset, "interrupt-parent", &len);
       
   573     if (!p)
       
   574         return NULL;
       
   575     if (len != 4) {
       
   576         invalid_devtree(dev, "bad/missing interrupt-parent");
       
   577         return NULL;
       
   578     }
       
   579     phandle = fdt32_to_cpu(*(uint32_t *)p->data);
       
   580 
       
   581     parent = find_device_by_phandle(phandle);
       
   582     if (!parent) {
       
   583         invalid_devtree(dev, "interrupt-parent not found");
       
   584     }
       
   585     check_interrupt_cells(parent);
       
   586     return parent;
       
   587 }
       
   588 
       
   589 static void fixup_irqs(void)
       
   590 {
       
   591     QEMUDevice *dev;
       
   592     QEMUDevice *parent;
       
   593     const struct fdt_property *prop;
       
   594     int len;
       
   595     int i;
       
   596     qemu_irq parent_irq;
       
   597     int is_qemu_irq = 0;
       
   598     uint32_t *data;
       
   599 
       
   600     for (dev = first_device; dev; dev = dev->next) {
       
   601         if (dev->dc->num_irqs) {
       
   602             parent = find_interrupt_parent(dev);
       
   603             if (!parent) {
       
   604                 prop = fdt_get_property(dev->dt, dev->node_offset,
       
   605                                         "qemu,interrupts", &len);
       
   606                 if (!prop) {
       
   607                     invalid_devtree(dev, "missing interrupt-parent");
       
   608                     continue;
       
   609                 }
       
   610                 if (len != dev->dc->num_irqs * 8) {
       
   611                     invalid_devtree(dev, "bad interrupts");
       
   612                     continue;
       
   613                 }
       
   614                 is_qemu_irq = 1;
       
   615             } else {
       
   616                 prop = fdt_get_property(dev->dt, dev->node_offset,
       
   617                                         "interrupts", &len);
       
   618                 if (!prop || len != dev->dc->num_irqs * 4) {
       
   619                     invalid_devtree(dev, "bad/missing interrupts");
       
   620                     continue;
       
   621                 }
       
   622                 is_qemu_irq = 0;
       
   623             }
       
   624             data = (uint32_t *)prop->data;
       
   625             /* FIXME: Need to handle interrupt remapping.  */
       
   626             for (i = 0; i < dev->dc->num_irqs; i++) {
       
   627                 uint32_t parent_irq_num;
       
   628                 if (is_qemu_irq) {
       
   629                     parent = find_device_by_phandle(fdt32_to_cpu(*data));
       
   630                     data++;
       
   631                     if (!parent) {
       
   632                         invalid_devtree(dev, "bad qemu,interrupts");
       
   633                     }
       
   634                     check_interrupt_cells(parent);
       
   635                 }
       
   636                 parent_irq_num = fdt32_to_cpu(*data);
       
   637                 data++;
       
   638                 if (parent_irq_num >= parent->irq_sink_count) {
       
   639                     invalid_devtree(dev, "bad interrupt number");
       
   640                     continue;
       
   641                 }
       
   642                 parent_irq = parent->irq_sink[parent_irq_num];
       
   643                 dev->irq[i] = parent_irq;
       
   644                 if (dev->irqp[i])
       
   645                     *(dev->irqp[i]) = parent_irq;
       
   646             }
       
   647         }
       
   648     }
       
   649 }
       
   650 
       
   651 static void parse_devtree(const char *filename)
       
   652 {
       
   653     FILE *f;
       
   654     void *dt;
       
   655 
       
   656     f = fopen(filename, "rb");
       
   657     if (!f)
       
   658         goto err;
       
   659     fseek(f, 0, SEEK_END);
       
   660     machine_devtree_size = ftell(f);
       
   661     fseek(f, 0, SEEK_SET);
       
   662     dt = qemu_malloc(machine_devtree_size);
       
   663     if (!dt)
       
   664         goto err_close;
       
   665     machine_devtree = dt;
       
   666     if (fread(dt, machine_devtree_size, 1, f) != 1)
       
   667         goto err_close;
       
   668     if (fdt_check_header(dt))
       
   669         goto err_close;
       
   670 
       
   671     create_cpus(dt);
       
   672 
       
   673     create_ram(dt);
       
   674 
       
   675     scan_devtree(dt);
       
   676 
       
   677     fixup_irqs();
       
   678 
       
   679     fclose(f);
       
   680     return;
       
   681 
       
   682 err_close:
       
   683     fclose(f);
       
   684 err:
       
   685     fprintf(stderr, "Failed to load device tree\n");
       
   686     exit(1);
       
   687 }
       
   688 
       
   689 int devtree_get_config_int(const char *name, int def)
       
   690 {
       
   691     const struct fdt_property *p;
       
   692     int len;
       
   693     int node;
       
   694 
       
   695     node = fdt_path_offset(machine_devtree, "/chosen");
       
   696     if (node < 0)
       
   697         return def;
       
   698     p = fdt_get_property(machine_devtree, node, name, &len);
       
   699     if (!p)
       
   700         return def;
       
   701     if (len != 4) {
       
   702         fprintf(stderr, "Expected integer for /chosen/%s\n", name);
       
   703         exit(1);
       
   704     }
       
   705     return fdt32_to_cpu(*(uint32_t *)p->data);
       
   706 }
       
   707 
       
   708 static void devtree_machine_init(ram_addr_t ram_size, int vga_ram_size,
       
   709                             const char *boot_device, DisplayState *ds,
       
   710                             const char *kernel_filename, const char *kernel_cmdline,
       
   711                             const char *initrd_filename, const char *cpu_model)
       
   712 {
       
   713     cpu_device_register();
       
   714     register_devices();
       
   715     parse_devtree(devtree_machine.name);
       
   716     /* FIXME: Get these values from device tree.  */
       
   717     cpu_bootstrap(kernel_filename, kernel_cmdline, initrd_filename);
       
   718 }
       
   719 
       
   720 QEMUMachine devtree_machine = {
       
   721     .name = "",
       
   722     .desc = "Device tree",
       
   723     .init = devtree_machine_init,
       
   724     .max_cpus = 1,
       
   725 };