]> Git Repo - qemu.git/blob - hw/qdev.c
Merge branch 'x86cpu_qom_tcg_v2' of git://github.com/imammedo/qemu
[qemu.git] / hw / qdev.c
1 /*
2  *  Dynamic device configuration and creation.
3  *
4  *  Copyright (c) 2009 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* The theory here is that it should be possible to create a machine without
21    knowledge of specific devices.  Historically board init routines have
22    passed a bunch of arguments to each device, requiring the board know
23    exactly which device it is dealing with.  This file provides an abstract
24    API for device configuration and initialization.  Devices will generally
25    inherit from a particular bus (e.g. PCI or I2C) rather than
26    this API directly.  */
27
28 #include "net.h"
29 #include "qdev.h"
30 #include "sysemu.h"
31 #include "error.h"
32
33 int qdev_hotplug = 0;
34 static bool qdev_hot_added = false;
35 static bool qdev_hot_removed = false;
36
37 /* Register a new device type.  */
38 const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
39 {
40     DeviceClass *dc = DEVICE_GET_CLASS(dev);
41     return dc->vmsd;
42 }
43
44 const char *qdev_fw_name(DeviceState *dev)
45 {
46     DeviceClass *dc = DEVICE_GET_CLASS(dev);
47
48     if (dc->fw_name) {
49         return dc->fw_name;
50     }
51
52     return object_get_typename(OBJECT(dev));
53 }
54
55 bool qdev_exists(const char *name)
56 {
57     return !!object_class_by_name(name);
58 }
59
60 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
61                                      Error **errp);
62
63 static void bus_remove_child(BusState *bus, DeviceState *child)
64 {
65     BusChild *kid;
66
67     QTAILQ_FOREACH(kid, &bus->children, sibling) {
68         if (kid->child == child) {
69             char name[32];
70
71             snprintf(name, sizeof(name), "child[%d]", kid->index);
72             QTAILQ_REMOVE(&bus->children, kid, sibling);
73             object_property_del(OBJECT(bus), name, NULL);
74             g_free(kid);
75             return;
76         }
77     }
78 }
79
80 static void bus_add_child(BusState *bus, DeviceState *child)
81 {
82     char name[32];
83     BusChild *kid = g_malloc0(sizeof(*kid));
84
85     if (qdev_hotplug) {
86         assert(bus->allow_hotplug);
87     }
88
89     kid->index = bus->max_index++;
90     kid->child = child;
91
92     QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
93
94     snprintf(name, sizeof(name), "child[%d]", kid->index);
95     object_property_add_link(OBJECT(bus), name,
96                              object_get_typename(OBJECT(child)),
97                              (Object **)&kid->child,
98                              NULL);
99 }
100
101 void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
102 {
103     dev->parent_bus = bus;
104     bus_add_child(bus, dev);
105 }
106
107 /* Create a new device.  This only initializes the device state structure
108    and allows properties to be set.  qdev_init should be called to
109    initialize the actual device emulation.  */
110 DeviceState *qdev_create(BusState *bus, const char *name)
111 {
112     DeviceState *dev;
113
114     dev = qdev_try_create(bus, name);
115     if (!dev) {
116         if (bus) {
117             hw_error("Unknown device '%s' for bus '%s'\n", name,
118                      object_get_typename(OBJECT(bus)));
119         } else {
120             hw_error("Unknown device '%s' for default sysbus\n", name);
121         }
122     }
123
124     return dev;
125 }
126
127 DeviceState *qdev_try_create(BusState *bus, const char *type)
128 {
129     DeviceState *dev;
130
131     if (object_class_by_name(type) == NULL) {
132         return NULL;
133     }
134     dev = DEVICE(object_new(type));
135     if (!dev) {
136         return NULL;
137     }
138
139     if (!bus) {
140         bus = sysbus_get_default();
141     }
142
143     qdev_set_parent_bus(dev, bus);
144
145     return dev;
146 }
147
148 /* Initialize a device.  Device properties should be set before calling
149    this function.  IRQs and MMIO regions should be connected/mapped after
150    calling this function.
151    On failure, destroy the device and return negative value.
152    Return 0 on success.  */
153 int qdev_init(DeviceState *dev)
154 {
155     DeviceClass *dc = DEVICE_GET_CLASS(dev);
156     int rc;
157
158     assert(dev->state == DEV_STATE_CREATED);
159
160     rc = dc->init(dev);
161     if (rc < 0) {
162         object_unparent(OBJECT(dev));
163         qdev_free(dev);
164         return rc;
165     }
166
167     if (!OBJECT(dev)->parent) {
168         static int unattached_count = 0;
169         gchar *name = g_strdup_printf("device[%d]", unattached_count++);
170
171         object_property_add_child(container_get(qdev_get_machine(),
172                                                 "/unattached"),
173                                   name, OBJECT(dev), NULL);
174         g_free(name);
175     }
176
177     if (qdev_get_vmsd(dev)) {
178         vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
179                                        dev->instance_id_alias,
180                                        dev->alias_required_for_version);
181     }
182     dev->state = DEV_STATE_INITIALIZED;
183     if (dev->hotplugged) {
184         device_reset(dev);
185     }
186     return 0;
187 }
188
189 void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
190                                  int required_for_version)
191 {
192     assert(dev->state == DEV_STATE_CREATED);
193     dev->instance_id_alias = alias_id;
194     dev->alias_required_for_version = required_for_version;
195 }
196
197 void qdev_unplug(DeviceState *dev, Error **errp)
198 {
199     DeviceClass *dc = DEVICE_GET_CLASS(dev);
200
201     if (!dev->parent_bus->allow_hotplug) {
202         error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
203         return;
204     }
205     assert(dc->unplug != NULL);
206
207     qdev_hot_removed = true;
208
209     if (dc->unplug(dev) < 0) {
210         error_set(errp, QERR_UNDEFINED_ERROR);
211         return;
212     }
213 }
214
215 static int qdev_reset_one(DeviceState *dev, void *opaque)
216 {
217     device_reset(dev);
218
219     return 0;
220 }
221
222 static int qbus_reset_one(BusState *bus, void *opaque)
223 {
224     BusClass *bc = BUS_GET_CLASS(bus);
225     if (bc->reset) {
226         return bc->reset(bus);
227     }
228     return 0;
229 }
230
231 void qdev_reset_all(DeviceState *dev)
232 {
233     qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
234 }
235
236 void qbus_reset_all_fn(void *opaque)
237 {
238     BusState *bus = opaque;
239     qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
240 }
241
242 /* can be used as ->unplug() callback for the simple cases */
243 int qdev_simple_unplug_cb(DeviceState *dev)
244 {
245     /* just zap it */
246     object_unparent(OBJECT(dev));
247     qdev_free(dev);
248     return 0;
249 }
250
251
252 /* Like qdev_init(), but terminate program via error_report() instead of
253    returning an error value.  This is okay during machine creation.
254    Don't use for hotplug, because there callers need to recover from
255    failure.  Exception: if you know the device's init() callback can't
256    fail, then qdev_init_nofail() can't fail either, and is therefore
257    usable even then.  But relying on the device implementation that
258    way is somewhat unclean, and best avoided.  */
259 void qdev_init_nofail(DeviceState *dev)
260 {
261     const char *typename = object_get_typename(OBJECT(dev));
262
263     if (qdev_init(dev) < 0) {
264         error_report("Initialization of device %s failed", typename);
265         exit(1);
266     }
267 }
268
269 /* Unlink device from bus and free the structure.  */
270 void qdev_free(DeviceState *dev)
271 {
272     object_delete(OBJECT(dev));
273 }
274
275 void qdev_machine_creation_done(void)
276 {
277     /*
278      * ok, initial machine setup is done, starting from now we can
279      * only create hotpluggable devices
280      */
281     qdev_hotplug = 1;
282 }
283
284 bool qdev_machine_modified(void)
285 {
286     return qdev_hot_added || qdev_hot_removed;
287 }
288
289 BusState *qdev_get_parent_bus(DeviceState *dev)
290 {
291     return dev->parent_bus;
292 }
293
294 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
295 {
296     assert(dev->num_gpio_in == 0);
297     dev->num_gpio_in = n;
298     dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
299 }
300
301 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
302 {
303     assert(dev->num_gpio_out == 0);
304     dev->num_gpio_out = n;
305     dev->gpio_out = pins;
306 }
307
308 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
309 {
310     assert(n >= 0 && n < dev->num_gpio_in);
311     return dev->gpio_in[n];
312 }
313
314 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
315 {
316     assert(n >= 0 && n < dev->num_gpio_out);
317     dev->gpio_out[n] = pin;
318 }
319
320 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
321 {
322     qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
323     if (nd->netdev)
324         qdev_prop_set_netdev(dev, "netdev", nd->netdev);
325     if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
326         object_property_find(OBJECT(dev), "vectors", NULL)) {
327         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
328     }
329     nd->instantiated = 1;
330 }
331
332 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
333 {
334     BusState *bus;
335
336     QLIST_FOREACH(bus, &dev->child_bus, sibling) {
337         if (strcmp(name, bus->name) == 0) {
338             return bus;
339         }
340     }
341     return NULL;
342 }
343
344 int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
345                        qbus_walkerfn *busfn, void *opaque)
346 {
347     BusChild *kid;
348     int err;
349
350     if (busfn) {
351         err = busfn(bus, opaque);
352         if (err) {
353             return err;
354         }
355     }
356
357     QTAILQ_FOREACH(kid, &bus->children, sibling) {
358         err = qdev_walk_children(kid->child, devfn, busfn, opaque);
359         if (err < 0) {
360             return err;
361         }
362     }
363
364     return 0;
365 }
366
367 int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
368                        qbus_walkerfn *busfn, void *opaque)
369 {
370     BusState *bus;
371     int err;
372
373     if (devfn) {
374         err = devfn(dev, opaque);
375         if (err) {
376             return err;
377         }
378     }
379
380     QLIST_FOREACH(bus, &dev->child_bus, sibling) {
381         err = qbus_walk_children(bus, devfn, busfn, opaque);
382         if (err < 0) {
383             return err;
384         }
385     }
386
387     return 0;
388 }
389
390 DeviceState *qdev_find_recursive(BusState *bus, const char *id)
391 {
392     BusChild *kid;
393     DeviceState *ret;
394     BusState *child;
395
396     QTAILQ_FOREACH(kid, &bus->children, sibling) {
397         DeviceState *dev = kid->child;
398
399         if (dev->id && strcmp(dev->id, id) == 0) {
400             return dev;
401         }
402
403         QLIST_FOREACH(child, &dev->child_bus, sibling) {
404             ret = qdev_find_recursive(child, id);
405             if (ret) {
406                 return ret;
407             }
408         }
409     }
410     return NULL;
411 }
412
413 static void qbus_realize(BusState *bus)
414 {
415     const char *typename = object_get_typename(OBJECT(bus));
416     char *buf;
417     int i,len;
418
419     if (bus->name) {
420         /* use supplied name */
421     } else if (bus->parent && bus->parent->id) {
422         /* parent device has id -> use it for bus name */
423         len = strlen(bus->parent->id) + 16;
424         buf = g_malloc(len);
425         snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
426         bus->name = buf;
427     } else {
428         /* no id -> use lowercase bus type for bus name */
429         len = strlen(typename) + 16;
430         buf = g_malloc(len);
431         len = snprintf(buf, len, "%s.%d", typename,
432                        bus->parent ? bus->parent->num_child_bus : 0);
433         for (i = 0; i < len; i++)
434             buf[i] = qemu_tolower(buf[i]);
435         bus->name = buf;
436     }
437
438     if (bus->parent) {
439         QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
440         bus->parent->num_child_bus++;
441         object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
442     } else if (bus != sysbus_get_default()) {
443         /* TODO: once all bus devices are qdevified,
444            only reset handler for main_system_bus should be registered here. */
445         qemu_register_reset(qbus_reset_all_fn, bus);
446     }
447 }
448
449 void qbus_create_inplace(BusState *bus, const char *typename,
450                          DeviceState *parent, const char *name)
451 {
452     object_initialize(bus, typename);
453
454     bus->parent = parent;
455     bus->name = name ? g_strdup(name) : NULL;
456     qbus_realize(bus);
457 }
458
459 BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
460 {
461     BusState *bus;
462
463     bus = BUS(object_new(typename));
464     bus->qom_allocated = true;
465
466     bus->parent = parent;
467     bus->name = name ? g_strdup(name) : NULL;
468     qbus_realize(bus);
469
470     return bus;
471 }
472
473 void qbus_free(BusState *bus)
474 {
475     if (bus->qom_allocated) {
476         object_delete(OBJECT(bus));
477     } else {
478         object_finalize(OBJECT(bus));
479         if (bus->glib_allocated) {
480             g_free(bus);
481         }
482     }
483 }
484
485 static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
486 {
487     BusClass *bc = BUS_GET_CLASS(bus);
488
489     if (bc->get_fw_dev_path) {
490         return bc->get_fw_dev_path(dev);
491     }
492
493     return NULL;
494 }
495
496 static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
497 {
498     int l = 0;
499
500     if (dev && dev->parent_bus) {
501         char *d;
502         l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
503         d = bus_get_fw_dev_path(dev->parent_bus, dev);
504         if (d) {
505             l += snprintf(p + l, size - l, "%s", d);
506             g_free(d);
507         } else {
508             l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
509         }
510     }
511     l += snprintf(p + l , size - l, "/");
512
513     return l;
514 }
515
516 char* qdev_get_fw_dev_path(DeviceState *dev)
517 {
518     char path[128];
519     int l;
520
521     l = qdev_get_fw_dev_path_helper(dev, path, 128);
522
523     path[l-1] = '\0';
524
525     return strdup(path);
526 }
527
528 char *qdev_get_dev_path(DeviceState *dev)
529 {
530     BusClass *bc;
531
532     if (!dev || !dev->parent_bus) {
533         return NULL;
534     }
535
536     bc = BUS_GET_CLASS(dev->parent_bus);
537     if (bc->get_dev_path) {
538         return bc->get_dev_path(dev);
539     }
540
541     return NULL;
542 }
543
544 /**
545  * Legacy property handling
546  */
547
548 static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
549                                      const char *name, Error **errp)
550 {
551     DeviceState *dev = DEVICE(obj);
552     Property *prop = opaque;
553
554     char buffer[1024];
555     char *ptr = buffer;
556
557     prop->info->print(dev, prop, buffer, sizeof(buffer));
558     visit_type_str(v, &ptr, name, errp);
559 }
560
561 static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
562                                      const char *name, Error **errp)
563 {
564     DeviceState *dev = DEVICE(obj);
565     Property *prop = opaque;
566     Error *local_err = NULL;
567     char *ptr = NULL;
568     int ret;
569
570     if (dev->state != DEV_STATE_CREATED) {
571         error_set(errp, QERR_PERMISSION_DENIED);
572         return;
573     }
574
575     visit_type_str(v, &ptr, name, &local_err);
576     if (local_err) {
577         error_propagate(errp, local_err);
578         return;
579     }
580
581     ret = prop->info->parse(dev, prop, ptr);
582     error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
583     g_free(ptr);
584 }
585
586 /**
587  * @qdev_add_legacy_property - adds a legacy property
588  *
589  * Do not use this is new code!  Properties added through this interface will
590  * be given names and types in the "legacy" namespace.
591  *
592  * Legacy properties are string versions of other OOM properties.  The format
593  * of the string depends on the property type.
594  */
595 void qdev_property_add_legacy(DeviceState *dev, Property *prop,
596                               Error **errp)
597 {
598     gchar *name, *type;
599
600     /* Register pointer properties as legacy properties */
601     if (!prop->info->print && !prop->info->parse &&
602         (prop->info->set || prop->info->get)) {
603         return;
604     }
605
606     name = g_strdup_printf("legacy-%s", prop->name);
607     type = g_strdup_printf("legacy<%s>",
608                            prop->info->legacy_name ?: prop->info->name);
609
610     object_property_add(OBJECT(dev), name, type,
611                         prop->info->print ? qdev_get_legacy_property : prop->info->get,
612                         prop->info->parse ? qdev_set_legacy_property : prop->info->set,
613                         NULL,
614                         prop, errp);
615
616     g_free(type);
617     g_free(name);
618 }
619
620 /**
621  * @qdev_property_add_static - add a @Property to a device.
622  *
623  * Static properties access data in a struct.  The actual type of the
624  * property and the field depends on the property type.
625  */
626 void qdev_property_add_static(DeviceState *dev, Property *prop,
627                               Error **errp)
628 {
629     Error *local_err = NULL;
630     Object *obj = OBJECT(dev);
631
632     /*
633      * TODO qdev_prop_ptr does not have getters or setters.  It must
634      * go now that it can be replaced with links.  The test should be
635      * removed along with it: all static properties are read/write.
636      */
637     if (!prop->info->get && !prop->info->set) {
638         return;
639     }
640
641     object_property_add(obj, prop->name, prop->info->name,
642                         prop->info->get, prop->info->set,
643                         prop->info->release,
644                         prop, &local_err);
645
646     if (local_err) {
647         error_propagate(errp, local_err);
648         return;
649     }
650     if (prop->qtype == QTYPE_NONE) {
651         return;
652     }
653
654     if (prop->qtype == QTYPE_QBOOL) {
655         object_property_set_bool(obj, prop->defval, prop->name, &local_err);
656     } else if (prop->info->enum_table) {
657         object_property_set_str(obj, prop->info->enum_table[prop->defval],
658                                 prop->name, &local_err);
659     } else if (prop->qtype == QTYPE_QINT) {
660         object_property_set_int(obj, prop->defval, prop->name, &local_err);
661     }
662     assert_no_error(local_err);
663 }
664
665 static void device_initfn(Object *obj)
666 {
667     DeviceState *dev = DEVICE(obj);
668     ObjectClass *class;
669     Property *prop;
670
671     if (qdev_hotplug) {
672         dev->hotplugged = 1;
673         qdev_hot_added = true;
674     }
675
676     dev->instance_id_alias = -1;
677     dev->state = DEV_STATE_CREATED;
678
679     class = object_get_class(OBJECT(dev));
680     do {
681         for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
682             qdev_property_add_legacy(dev, prop, NULL);
683             qdev_property_add_static(dev, prop, NULL);
684         }
685         class = object_class_get_parent(class);
686     } while (class != object_class_by_name(TYPE_DEVICE));
687     qdev_prop_set_globals(dev);
688
689     object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
690                              (Object **)&dev->parent_bus, NULL);
691 }
692
693 /* Unlink device from bus and free the structure.  */
694 static void device_finalize(Object *obj)
695 {
696     DeviceState *dev = DEVICE(obj);
697     BusState *bus;
698     DeviceClass *dc = DEVICE_GET_CLASS(dev);
699
700     if (dev->state == DEV_STATE_INITIALIZED) {
701         while (dev->num_child_bus) {
702             bus = QLIST_FIRST(&dev->child_bus);
703             qbus_free(bus);
704         }
705         if (qdev_get_vmsd(dev)) {
706             vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
707         }
708         if (dc->exit) {
709             dc->exit(dev);
710         }
711         if (dev->opts) {
712             qemu_opts_del(dev->opts);
713         }
714     }
715     if (dev->parent_bus) {
716         bus_remove_child(dev->parent_bus, dev);
717     }
718 }
719
720 static void device_class_base_init(ObjectClass *class, void *data)
721 {
722     DeviceClass *klass = DEVICE_CLASS(class);
723
724     /* We explicitly look up properties in the superclasses,
725      * so do not propagate them to the subclasses.
726      */
727     klass->props = NULL;
728 }
729
730 void device_reset(DeviceState *dev)
731 {
732     DeviceClass *klass = DEVICE_GET_CLASS(dev);
733
734     if (klass->reset) {
735         klass->reset(dev);
736     }
737 }
738
739 Object *qdev_get_machine(void)
740 {
741     static Object *dev;
742
743     if (dev == NULL) {
744         dev = container_get(object_get_root(), "/machine");
745     }
746
747     return dev;
748 }
749
750 static TypeInfo device_type_info = {
751     .name = TYPE_DEVICE,
752     .parent = TYPE_OBJECT,
753     .instance_size = sizeof(DeviceState),
754     .instance_init = device_initfn,
755     .instance_finalize = device_finalize,
756     .class_base_init = device_class_base_init,
757     .abstract = true,
758     .class_size = sizeof(DeviceClass),
759 };
760
761 static void qbus_initfn(Object *obj)
762 {
763     BusState *bus = BUS(obj);
764
765     QTAILQ_INIT(&bus->children);
766 }
767
768 static void qbus_finalize(Object *obj)
769 {
770     BusState *bus = BUS(obj);
771     BusChild *kid;
772
773     while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
774         DeviceState *dev = kid->child;
775         qdev_free(dev);
776     }
777     if (bus->parent) {
778         QLIST_REMOVE(bus, sibling);
779         bus->parent->num_child_bus--;
780     } else {
781         assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
782         qemu_unregister_reset(qbus_reset_all_fn, bus);
783     }
784     g_free((char *)bus->name);
785 }
786
787 static const TypeInfo bus_info = {
788     .name = TYPE_BUS,
789     .parent = TYPE_OBJECT,
790     .instance_size = sizeof(BusState),
791     .abstract = true,
792     .class_size = sizeof(BusClass),
793     .instance_init = qbus_initfn,
794     .instance_finalize = qbus_finalize,
795 };
796
797 static void qdev_register_types(void)
798 {
799     type_register_static(&bus_info);
800     type_register_static(&device_type_info);
801 }
802
803 type_init(qdev_register_types)
This page took 0.067954 seconds and 4 git commands to generate.