diff --git a/arch/x64/arch-cpu.cc b/arch/x64/arch-cpu.cc
index 2d5c916bdd41479007ed0c40287f9adf24bb9aed..2f4601b175f0b7a29c22133df86f9b133864f6e6 100644
--- a/arch/x64/arch-cpu.cc
+++ b/arch/x64/arch-cpu.cc
@@ -11,22 +11,25 @@
 
 namespace sched {
 
-__thread bool in_exception = false;
+__thread unsigned exception_depth = 0;
 
 inline void arch_cpu::enter_exception()
 {
-    if (in_exception) {
-        abort("nested exception");
+    if (exception_depth == nr_exception_stacks - 1) {
+        abort("exception nested too deeply");
     }
-    in_exception = true;
-    auto& s = percpu_exception_stack;
+    auto& s = percpu_exception_stack[exception_depth++];
     set_exception_stack(s, sizeof(s));
 }
 
 inline void arch_cpu::exit_exception()
 {
-    set_exception_stack(&thread::current()->_arch);
-    in_exception = false;
+    if (--exception_depth == 0) {
+        set_exception_stack(&thread::current()->_arch);
+    } else {
+        auto& s = percpu_exception_stack[exception_depth];
+        set_exception_stack(s, sizeof(s));
+    }
 }
 
 exception_guard::exception_guard()
diff --git a/arch/x64/arch-cpu.hh b/arch/x64/arch-cpu.hh
index c33813eef55378ebf862d536740ddb7a8551aed3..644bfcca1c5d5dd2b41fe32c6044343b91cb9aef 100644
--- a/arch/x64/arch-cpu.hh
+++ b/arch/x64/arch-cpu.hh
@@ -41,7 +41,8 @@ struct arch_cpu {
     processor::aligned_task_state_segment atss;
     init_stack initstack;
     // The per-CPU exception stack is used for nested exceptions.
-    char percpu_exception_stack[4096] __attribute__((aligned(16)));
+    static constexpr unsigned nr_exception_stacks = 2;
+    char percpu_exception_stack[nr_exception_stacks][4096] __attribute__((aligned(16)));
     u32 apic_id;
     u32 acpi_id;
     u64 gdt[nr_gdt];
@@ -94,7 +95,7 @@ inline arch_cpu::arch_cpu()
     gdt[gdt_tss] |= (tss_addr & 0xff000000) << 32;
     gdt[gdt_tssx] = tss_addr >> 32;
     // Use the per-CPU stack for early boot faults.
-    set_exception_stack(percpu_exception_stack, sizeof(percpu_exception_stack));
+    set_exception_stack(percpu_exception_stack[0], sizeof(percpu_exception_stack[0]));
 }
 
 inline void arch_cpu::set_ist_entry(unsigned ist, char* base, size_t size)