]> Git Repo - qemu.git/blobdiff - vl.c
Drop an unused variable (Samuel Thibault).
[qemu.git] / vl.c
diff --git a/vl.c b/vl.c
index c13b1a1f479af8e1bf19d9622804670ae0842391..1a7f4a34ce385d83b4c32147566a863173cb4c66 100644 (file)
--- a/vl.c
+++ b/vl.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "vl.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/fdc.h"
+#include "hw/audiodev.h"
+#include "hw/isa.h"
+#include "net.h"
+#include "console.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "audio/audio.h"
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -145,7 +160,6 @@ int inet_aton(const char *cp, struct in_addr *ia);
 
 const char *bios_dir = CONFIG_QEMU_SHAREDIR;
 const char *bios_name = NULL;
-char phys_ram_file[1024];
 void *ioport_opaque[MAX_IOPORTS];
 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
@@ -162,12 +176,6 @@ static DisplayState display_state;
 int nographic;
 const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;
-#if defined(TARGET_I386)
-#define MAX_BOOT_DEVICES 3
-#else
-#define MAX_BOOT_DEVICES 1
-#endif
-static char boot_device[MAX_BOOT_DEVICES + 1];
 int ram_size;
 int pit_min_timer_count = 0;
 int nb_nics;
@@ -233,7 +241,7 @@ const char *prom_envs[MAX_PROM_ENVS];
 target_phys_addr_t isa_mem_base = 0;
 PicState2 *isa_pic;
 
-uint32_t default_ioport_readb(void *opaque, uint32_t address)
+static uint32_t default_ioport_readb(void *opaque, uint32_t address)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "unused inb: port=0x%04x\n", address);
@@ -241,7 +249,7 @@ uint32_t default_ioport_readb(void *opaque, uint32_t address)
     return 0xff;
 }
 
-void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
+static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
@@ -249,7 +257,7 @@ void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
 }
 
 /* default is to make two byte accesses */
-uint32_t default_ioport_readw(void *opaque, uint32_t address)
+static uint32_t default_ioport_readw(void *opaque, uint32_t address)
 {
     uint32_t data;
     data = ioport_read_table[0][address](ioport_opaque[address], address);
@@ -258,14 +266,14 @@ uint32_t default_ioport_readw(void *opaque, uint32_t address)
     return data;
 }
 
-void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
+static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
 {
     ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff);
     address = (address + 1) & (MAX_IOPORTS - 1);
     ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff);
 }
 
-uint32_t default_ioport_readl(void *opaque, uint32_t address)
+static uint32_t default_ioport_readl(void *opaque, uint32_t address)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "unused inl: port=0x%04x\n", address);
@@ -273,14 +281,14 @@ uint32_t default_ioport_readl(void *opaque, uint32_t address)
     return 0xffffffff;
 }
 
-void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
+static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
 #endif
 }
 
-void init_ioports(void)
+static void init_ioports(void)
 {
     int i;
 
@@ -952,7 +960,7 @@ QEMUClock *vm_clock;
 
 static QEMUTimer *active_timers[2];
 
-QEMUClock *qemu_new_clock(int type)
+static QEMUClock *qemu_new_clock(int type)
 {
     QEMUClock *clock;
     clock = qemu_mallocz(sizeof(QEMUClock));
@@ -1222,9 +1230,6 @@ static void enable_sigio_timer(int fd)
     /* timer signal */
     sigfillset(&act.sa_mask);
     act.sa_flags = 0;
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
-    act.sa_flags |= SA_ONSTACK;
-#endif
     act.sa_handler = host_alarm_handler;
 
     sigaction(SIGIO, &act, NULL);
@@ -1322,9 +1327,6 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t)
 
     sigfillset(&act.sa_mask);
     act.sa_flags = 0;
-#if defined(TARGET_I386) && defined(USE_CODE_COPY)
-    act.sa_flags |= SA_ONSTACK;
-#endif
     act.sa_handler = host_alarm_handler;
 
     sigaction(SIGALRM, &act, NULL);
@@ -1399,9 +1401,6 @@ static int unix_start_timer(struct qemu_alarm_timer *t)
     /* timer signal */
     sigfillset(&act.sa_mask);
     act.sa_flags = 0;
-#if defined(TARGET_I386) && defined(USE_CODE_COPY)
-    act.sa_flags |= SA_ONSTACK;
-#endif
     act.sa_handler = host_alarm_handler;
 
     sigaction(SIGALRM, &act, NULL);
@@ -1539,7 +1538,7 @@ static void init_timer_alarm(void)
     alarm_timer = t;
 }
 
-void quit_timers(void)
+static void quit_timers(void)
 {
     alarm_timer->stop(alarm_timer);
     alarm_timer = NULL;
@@ -1832,7 +1831,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr)
     d->mux_cnt++;
 }
 
-CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
 {
     CharDriverState *chr;
     MuxDriver *d;
@@ -3385,7 +3384,8 @@ void qemu_chr_close(CharDriverState *chr)
 /***********************************************************/
 /* network device redirectors */
 
-void hex_dump(FILE *f, const uint8_t *buf, int size)
+__attribute__ (( unused ))
+static void hex_dump(FILE *f, const uint8_t *buf, int size)
 {
     int len, i, j, c;
 
@@ -3733,7 +3733,7 @@ static void smb_exit(void)
 }
 
 /* automatic user mode samba server configuration */
-void net_slirp_smb(const char *exported_dir)
+static void net_slirp_smb(const char *exported_dir)
 {
     char smb_conf[1024];
     char smb_cmdline[1024];
@@ -5127,7 +5127,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
     return NULL;
 }
 
-QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
+static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
 {
     QEMUFile *f;
 
@@ -5361,7 +5361,7 @@ int register_savevm(const char *idstr,
 #define QEMU_VM_FILE_MAGIC   0x5145564d
 #define QEMU_VM_FILE_VERSION 0x00000002
 
-int qemu_savevm_state(QEMUFile *f)
+static int qemu_savevm_state(QEMUFile *f)
 {
     SaveStateEntry *se;
     int len, ret;
@@ -5384,7 +5384,6 @@ int qemu_savevm_state(QEMUFile *f)
         /* record size: filled later */
         len_pos = qemu_ftell(f);
         qemu_put_be32(f, 0);
-
         se->save_state(f, se->opaque);
 
         /* fill record size */
@@ -5415,7 +5414,7 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
     return NULL;
 }
 
-int qemu_loadvm_state(QEMUFile *f)
+static int qemu_loadvm_state(QEMUFile *f)
 {
     SaveStateEntry *se;
     int len, ret, instance_id, record_len, version_id;
@@ -6135,7 +6134,9 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, env->cp15.c1_sys);
     qemu_put_be32(f, env->cp15.c1_coproc);
     qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
-    qemu_put_be32(f, env->cp15.c2_base);
+    qemu_put_be32(f, env->cp15.c2_base0);
+    qemu_put_be32(f, env->cp15.c2_base1);
+    qemu_put_be32(f, env->cp15.c2_mask);
     qemu_put_be32(f, env->cp15.c2_data);
     qemu_put_be32(f, env->cp15.c2_insn);
     qemu_put_be32(f, env->cp15.c3);
@@ -6150,6 +6151,9 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, env->cp15.c9_data);
     qemu_put_be32(f, env->cp15.c13_fcse);
     qemu_put_be32(f, env->cp15.c13_context);
+    qemu_put_be32(f, env->cp15.c13_tls1);
+    qemu_put_be32(f, env->cp15.c13_tls2);
+    qemu_put_be32(f, env->cp15.c13_tls3);
     qemu_put_be32(f, env->cp15.c15_cpar);
 
     qemu_put_be32(f, env->features);
@@ -6168,6 +6172,15 @@ void cpu_save(QEMUFile *f, void *opaque)
         /* TODO: Should use proper FPSCR access functions.  */
         qemu_put_be32(f, env->vfp.vec_len);
         qemu_put_be32(f, env->vfp.vec_stride);
+
+        if (arm_feature(env, ARM_FEATURE_VFP3)) {
+            for (i = 16;  i < 32; i++) {
+                CPU_DoubleU u;
+                u.d = env->vfp.regs[i];
+                qemu_put_be32(f, u.l.upper);
+                qemu_put_be32(f, u.l.lower);
+            }
+        }
     }
 
     if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
@@ -6178,6 +6191,15 @@ void cpu_save(QEMUFile *f, void *opaque)
             qemu_put_be32(f, env->iwmmxt.cregs[i]);
         }
     }
+
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        qemu_put_be32(f, env->v7m.other_sp);
+        qemu_put_be32(f, env->v7m.vecbase);
+        qemu_put_be32(f, env->v7m.basepri);
+        qemu_put_be32(f, env->v7m.control);
+        qemu_put_be32(f, env->v7m.current_sp);
+        qemu_put_be32(f, env->v7m.exception);
+    }
 }
 
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
@@ -6185,7 +6207,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     CPUARMState *env = (CPUARMState *)opaque;
     int i;
 
-    if (version_id != 0)
+    if (version_id != ARM_CPU_SAVE_VERSION)
         return -EINVAL;
 
     for (i = 0; i < 16; i++) {
@@ -6207,7 +6229,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     env->cp15.c1_sys = qemu_get_be32(f);
     env->cp15.c1_coproc = qemu_get_be32(f);
     env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
-    env->cp15.c2_base = qemu_get_be32(f);
+    env->cp15.c2_base0 = qemu_get_be32(f);
+    env->cp15.c2_base1 = qemu_get_be32(f);
+    env->cp15.c2_mask = qemu_get_be32(f);
     env->cp15.c2_data = qemu_get_be32(f);
     env->cp15.c2_insn = qemu_get_be32(f);
     env->cp15.c3 = qemu_get_be32(f);
@@ -6222,6 +6246,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     env->cp15.c9_data = qemu_get_be32(f);
     env->cp15.c13_fcse = qemu_get_be32(f);
     env->cp15.c13_context = qemu_get_be32(f);
+    env->cp15.c13_tls1 = qemu_get_be32(f);
+    env->cp15.c13_tls2 = qemu_get_be32(f);
+    env->cp15.c13_tls3 = qemu_get_be32(f);
     env->cp15.c15_cpar = qemu_get_be32(f);
 
     env->features = qemu_get_be32(f);
@@ -6240,6 +6267,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         /* TODO: Should use proper FPSCR access functions.  */
         env->vfp.vec_len = qemu_get_be32(f);
         env->vfp.vec_stride = qemu_get_be32(f);
+
+        if (arm_feature(env, ARM_FEATURE_VFP3)) {
+            for (i = 0;  i < 16; i++) {
+                CPU_DoubleU u;
+                u.l.upper = qemu_get_be32(f);
+                u.l.lower = qemu_get_be32(f);
+                env->vfp.regs[i] = u.d;
+            }
+        }
     }
 
     if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
@@ -6251,12 +6287,21 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         }
     }
 
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        env->v7m.other_sp = qemu_get_be32(f);
+        env->v7m.vecbase = qemu_get_be32(f);
+        env->v7m.basepri = qemu_get_be32(f);
+        env->v7m.control = qemu_get_be32(f);
+        env->v7m.current_sp = qemu_get_be32(f);
+        env->v7m.exception = qemu_get_be32(f);
+    }
+
     return 0;
 }
 
 #else
 
-#warning No CPU save/restore functions
+//#warning No CPU save/restore functions
 
 #endif
 
@@ -6609,7 +6654,7 @@ int qemu_register_machine(QEMUMachine *m)
     return 0;
 }
 
-QEMUMachine *find_machine(const char *name)
+static QEMUMachine *find_machine(const char *name)
 {
     QEMUMachine *m;
 
@@ -6623,7 +6668,7 @@ QEMUMachine *find_machine(const char *name)
 /***********************************************************/
 /* main execution loop */
 
-void gui_update(void *opaque)
+static void gui_update(void *opaque)
 {
     DisplayState *ds = opaque;
     ds->dpy_refresh(ds);
@@ -6907,7 +6952,7 @@ void main_loop_wait(int timeout)
 
 static CPUState *cur_cpu;
 
-int main_loop(void)
+static int main_loop(void)
 {
     int ret, timeout;
 #ifdef CONFIG_PROFILER
@@ -7093,9 +7138,6 @@ static void help(int exitcode)
            "-kernel-kqemu   enable KQEMU full virtualization (default is user mode only)\n"
            "-no-kqemu       disable KQEMU kernel module usage\n"
 #endif
-#ifdef USE_CODE_COPY
-           "-no-code-copy   disable code copy acceleration\n"
-#endif
 #ifdef TARGET_I386
            "-std-vga        simulate a standard VGA card with VESA Bochs Extensions\n"
            "                (default is CL-GD5446 PCI VGA)\n"
@@ -7324,15 +7366,6 @@ const QEMUOption qemu_options[] = {
     { NULL },
 };
 
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
-
-/* this stack is only used during signal handling */
-#define SIGNAL_STACK_SIZE 32768
-
-static uint8_t *signal_stack;
-
-#endif
-
 /* password input */
 
 int qemu_key_check(BlockDriverState *bs, const char *name)
@@ -7380,7 +7413,7 @@ static void read_passwords(void)
 }
 
 /* XXX: currently we cannot use simultaneously different CPUs */
-void register_machines(void)
+static void register_machines(void)
 {
 #if defined(TARGET_I386)
     qemu_register_machine(&pc_machine);
@@ -7402,6 +7435,7 @@ void register_machines(void)
 #else
     qemu_register_machine(&ss5_machine);
     qemu_register_machine(&ss10_machine);
+    qemu_register_machine(&ss600mp_machine);
 #endif
 #elif defined(TARGET_ARM)
     qemu_register_machine(&integratorcp_machine);
@@ -7413,6 +7447,9 @@ void register_machines(void)
     qemu_register_machine(&borzoipda_machine);
     qemu_register_machine(&terrierpda_machine);
     qemu_register_machine(&palmte_machine);
+    qemu_register_machine(&lm3s811evb_machine);
+    qemu_register_machine(&lm3s6965evb_machine);
+    qemu_register_machine(&connex_machine);
 #elif defined(TARGET_SH4)
     qemu_register_machine(&shix_machine);
     qemu_register_machine(&r2d_machine);
@@ -7421,6 +7458,7 @@ void register_machines(void)
 #elif defined(TARGET_M68K)
     qemu_register_machine(&mcf5208evb_machine);
     qemu_register_machine(&an5206_machine);
+    qemu_register_machine(&dummy_m68k_machine);
 #elif defined(TARGET_CRIS)
     qemu_register_machine(&bareetraxfs_machine);
 #else
@@ -7559,14 +7597,16 @@ int main(int argc, char **argv)
     int use_gdbstub;
     const char *gdbstub_port;
 #endif
+    uint32_t boot_devices_bitmap = 0;
     int i, cdrom_index, pflash_index;
-    int snapshot, linux_boot;
+    int snapshot, linux_boot, net_boot;
     const char *initrd_filename;
     const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
     const char *pflash_filename[MAX_PFLASH];
     const char *sd_filename;
     const char *mtd_filename;
     const char *kernel_filename, *kernel_cmdline;
+    const char *boot_devices = "";
     DisplayState *ds = &display_state;
     int cyls, heads, secs, translation;
     char net_clients[MAX_NET_CLIENTS][256];
@@ -7818,20 +7858,34 @@ int main(int argc, char **argv)
                 }
                 break;
             case QEMU_OPTION_boot:
-                if (strlen(optarg) > MAX_BOOT_DEVICES) {
-                    fprintf(stderr, "qemu: too many boot devices\n");
-                    exit(1);
-                }
-                strncpy(boot_device, optarg, MAX_BOOT_DEVICES);
-#if defined(TARGET_SPARC) || defined(TARGET_I386)
-#define BOOTCHARS "acdn"
-#else
-#define BOOTCHARS "acd"
-#endif
-                if (strlen(boot_device) != strspn(boot_device, BOOTCHARS)) {
-                    fprintf(stderr, "qemu: invalid boot device "
-                                    "sequence '%s'\n", boot_device);
-                    exit(1);
+                boot_devices = optarg;
+                /* We just do some generic consistency checks */
+                {
+                    /* Could easily be extended to 64 devices if needed */
+                    const unsigned char *p;
+                    
+                    boot_devices_bitmap = 0;
+                    for (p = boot_devices; *p != '\0'; p++) {
+                        /* Allowed boot devices are:
+                         * a b     : floppy disk drives
+                         * c ... f : IDE disk drives
+                         * g ... m : machine implementation dependant drives
+                         * n ... p : network devices
+                         * It's up to each machine implementation to check
+                         * if the given boot devices match the actual hardware
+                         * implementation and firmware features.
+                         */
+                        if (*p < 'a' || *p > 'q') {
+                            fprintf(stderr, "Invalid boot device '%c'\n", *p);
+                            exit(1);
+                        }
+                        if (boot_devices_bitmap & (1 << (*p - 'a'))) {
+                            fprintf(stderr,
+                                    "Boot device '%c' was given twice\n",*p);
+                            exit(1);
+                        }
+                        boot_devices_bitmap |= 1 << (*p - 'a');
+                    }
                 }
                 break;
             case QEMU_OPTION_fda:
@@ -8136,7 +8190,7 @@ int main(int argc, char **argv)
                         }
                         tm.tm_year -= 1900;
                         tm.tm_mon--;
-                        rtc_start_date = timegm(&tm);
+                        rtc_start_date = mktimegm(&tm);
                         if (rtc_start_date == -1) {
                         date_fail:
                             fprintf(stderr, "Invalid date format. Valid format are:\n"
@@ -8215,23 +8269,24 @@ int main(int argc, char **argv)
         kqemu_allowed = 0;
 #endif
     linux_boot = (kernel_filename != NULL);
-
-    if (!linux_boot &&
-        (!strchr(boot_device, 'n')) &&
-        hd_filename[0] == '\0' &&
-        (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') &&
-        fd_filename[0] == '\0')
+    net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
+
+    /* XXX: this should not be: some embedded targets just have flash */
+    if (!linux_boot && net_boot == 0 &&
+        hd_filename[0] == NULL &&
+        (cdrom_index >= 0 && hd_filename[cdrom_index] == NULL) &&
+        fd_filename[0] == NULL &&
+        pflash_filename[0] == NULL)
         help(1);
 
     /* boot to floppy or the default cd if no hard disk defined yet */
-    if (!boot_device[0]) {
-        if (hd_filename[0] != '\0')
-            boot_device[0] = 'c';
-        else if (fd_filename[0] != '\0')
-            boot_device[0] = 'a';
+    if (!boot_devices[0]) {
+        if (hd_filename[0] != NULL)
+            boot_devices = "c";
+        else if (fd_filename[0] != NULL)
+            boot_devices = "a";
         else
-            boot_device[0] = 'd';
-        boot_device[1] = 0;
+            boot_devices = "d";
     }
     setvbuf(stdout, NULL, _IOLBF, 0);
 
@@ -8271,20 +8326,28 @@ int main(int argc, char **argv)
     }
 
 #ifdef TARGET_I386
-    if (strchr(boot_device, 'n')) {
-       for (i = 0; i < nb_nics; i++) {
+    /* XXX: this should be moved in the PC machine instanciation code */
+    if (net_boot != 0) {
+        int netroms = 0;
+       for (i = 0; i < nb_nics && i < 4; i++) {
            const char *model = nd_table[i].model;
            char buf[1024];
-           if (model == NULL)
-               model = "ne2k_pci";
-           snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
-           if (get_image_size(buf) > 0) {
-               option_rom[nb_option_roms] = strdup(buf);
-               nb_option_roms++;
-               break;
-           }
+            if (net_boot & (1 << i)) {
+                if (model == NULL)
+                    model = "ne2k_pci";
+                snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
+                if (get_image_size(buf) > 0) {
+                    if (nb_option_roms >= MAX_OPTION_ROMS) {
+                        fprintf(stderr, "Too many option ROMs\n");
+                        exit(1);
+                    }
+                    option_rom[nb_option_roms] = strdup(buf);
+                    nb_option_roms++;
+                    netroms++;
+                }
+            }
        }
-       if (i == nb_nics) {
+       if (netroms == 0) {
            fprintf(stderr, "No valid PXE rom found for network device\n");
            exit(1);
        }
@@ -8411,6 +8474,8 @@ int main(int argc, char **argv)
         sdl_display_init(ds, full_screen, no_frame);
 #elif defined(CONFIG_COCOA)
         cocoa_display_init(ds, full_screen);
+#else
+        dumb_display_init(ds);
 #endif
     }
 
@@ -8464,8 +8529,7 @@ int main(int argc, char **argv)
         }
     }
 
-    machine->init(ram_size, vga_ram_size, boot_device,
-                  ds, fd_filename, snapshot,
+    machine->init(ram_size, vga_ram_size, boot_devices, ds,
                   kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
 
     /* init USB devices */
This page took 0.043065 seconds and 4 git commands to generate.