diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 7cdf7d3..731b6ea 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -681,6 +681,16 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level)
     }
 }
 
+static void typhoon_alarm_timer(void *opaque)
+{
+    TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
+    int cpu = (uintptr_t)opaque & 3;
+
+    /* Set the ITI bit for this cpu.  */
+    s->cchip.misc |= 1 << (cpu + 4);
+    cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER);
+}
+
 PCIBus *typhoon_init(qemu_irq *p_isa_irq, qemu_irq *p_rtc_irq,
                      CPUState *cpus[3], pci_map_irq_fn sys_map_irq)
 {
@@ -689,14 +699,22 @@ PCIBus *typhoon_init(qemu_irq *p_isa_irq, qemu_irq *p_rtc_irq,
     PCIHostState *p;
     TyphoonState *s;
     PCIBus *b;
-    int region;
+    int i, region;
 
     dev = qdev_create(NULL, "typhoon-pcihost");
     p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
     s = container_of(p, TyphoonState, host);
 
     /* Remember the CPUs so that we can deliver interrupts to them.  */
-    memcpy(s->cchip.cpu, cpus, 4 * sizeof(CPUState *));
+    for (i = 0; i < 4; i++) {
+        CPUState *env = cpus[i];
+        s->cchip.cpu[i] = env;
+        if (env) {
+            env->alarm_timer = qemu_new_timer_ns(rtc_clock,
+                                                 typhoon_alarm_timer,
+                                                 (void *)((uintptr_t)s + i));
+        }
+    }
 
     *p_isa_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
     *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c94becf..72efbbd 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -266,6 +266,10 @@ struct CPUAlphaState {
     uint64_t shadow[8];
     uint64_t scratch[24];
 
+    /* This alarm doesn't exist in real hardware; we wish it did.  */
+    struct QEMUTimer *alarm_timer;
+    uint64_t alarm_expire;
+
 #if TARGET_LONG_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
      * used to emulate 64 bits target on 32 bits hosts
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index c352c24..b693cee 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -113,7 +113,11 @@ DEF_HELPER_2(stq_c_phys, i64, i64, i64)
 
 DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+
 DEF_HELPER_1(halt, void, i64);
+
+DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64)
+DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64)
 #endif
 
 #include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 80656f5..c37fb5f 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1225,6 +1225,21 @@ void helper_halt(uint64_t restart)
         qemu_system_shutdown_request();
     }
 }
+
+uint64_t helper_get_time(void)
+{
+    return qemu_get_clock_ns(rtc_clock);
+}
+
+void helper_set_alarm(uint64_t expire)
+{
+    if (expire) {
+        env->alarm_expire = expire;
+        qemu_mod_timer(env->alarm_timer, expire);
+    } else {
+        qemu_del_timer(env->alarm_timer);
+    }
+}
 #endif
 
 /*****************************************************************************/
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 9edcd74..f34c53e 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1594,6 +1594,9 @@ static int cpu_pr_data(int pr)
         return offsetof(CPUAlphaState, shadow[pr - 32]);
     case 40 ... 63:
         return offsetof(CPUAlphaState, scratch[pr - 40]);
+
+    case 251:
+        return offsetof(CPUAlphaState, alarm_expire);
     }
     return 0;
 }
@@ -1608,6 +1611,12 @@ static void gen_mfpr(int ra, int regno)
         return;
     }
 
+    if (regno == 250) {
+        /* WALL_TIME */
+        gen_helper_get_time(cpu_ir[ra]);
+        return;
+    }
+
     /* The basic registers are data only, and unknown registers
        are read-zero, write-ignore.  */
     if (data == 0) {
@@ -1654,6 +1663,11 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
         gen_helper_halt(tmp);
         return EXIT_PC_STALE;
 
+    case 251:
+        /* ALARM */
+        gen_helper_set_alarm(tmp);
+        break;
+
     default:
         /* The basic registers are data only, and unknown registers
            are read-zero, write-ignore.  */
