Do core interrupt masking in a less general fashion and save some instructions to decrease size and speed things up a little bit. Small fix to a few places where interrupts would get enabled again where they shouldn't have been (context switching calls when disabled).

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16811 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index fc509ce..d21dc03 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -417,7 +417,7 @@
     not_id   = flash[1]; /* should be 'A' (0x41) and 'R' (0x52) from the "ARCH" marker */
 
     /* disable interrupts, prevent any stray flash access */
-    old_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    old_level = disable_irq_save();
 
     flash[addr1] = 0xAA; /* enter command mode */
     flash[addr2] = 0x55;
@@ -432,7 +432,7 @@
     /* Atmel wants 20ms pause here */
     /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
 
-    set_irq_level(old_level); /* enable interrupts again */
+    restore_irq(old_level); /* enable interrupts again */
 
     /* I assume success if the obtained values are different from
         the normal flash content. This is not perfectly bulletproof, they
@@ -2066,9 +2066,12 @@
         char buf[EEPROM_SIZE];
         int err;
 
-        old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+        old_irq_level = disable_irq_save();
 
         err = eeprom_24cxx_read(0, buf, sizeof buf);
+
+        restore_irq(old_irq_level);
+
         if (err)
             gui_syncsplash(HZ*3, "Eeprom read failure (%d)",err);
         else
@@ -2076,8 +2079,6 @@
             write(fd, buf, sizeof buf);
         }
 
-        set_irq_level(old_irq_level);
-
         close(fd);
     }
 #endif
@@ -2248,7 +2249,7 @@
 
         if(rc == EEPROM_SIZE)
         {
-            old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+            old_irq_level = disable_irq_save();
 
             err = eeprom_24cxx_write(0, buf, sizeof buf);
             if (err)
@@ -2256,7 +2257,7 @@
             else
                 gui_syncsplash(HZ*3, "Eeprom written successfully");
 
-            set_irq_level(old_irq_level);
+            restore_irq(old_irq_level);
         }
         else
         {
diff --git a/apps/main.c b/apps/main.c
index a3a2241..3f83850 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -272,7 +272,7 @@
 {
     kernel_init();
     buffer_init();
-    set_irq_level(0);
+    enable_irq();
     lcd_init();
 #ifdef HAVE_REMOTE_LCD
     lcd_remote_init();
@@ -360,9 +360,9 @@
     
     power_init();
 
-    set_irq_level(0);
+    enable_irq();
 #ifdef CPU_ARM
-    set_fiq_status(FIQ_ENABLED);
+    enable_fiq();
 #endif
     lcd_init();
 #ifdef HAVE_REMOTE_LCD
diff --git a/apps/plugins/wavplay.c b/apps/plugins/wavplay.c
index 6a969f1..bf06787 100644
--- a/apps/plugins/wavplay.c
+++ b/apps/plugins/wavplay.c
@@ -3345,7 +3345,7 @@
 
 void demand_irq_enable(bool on)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     
     if(on)
     {
@@ -3357,7 +3357,7 @@
         IPRA &= 0xfff0;
     }
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 static inline int available(void)
diff --git a/apps/plugins/wavrecord.c b/apps/plugins/wavrecord.c
index ee55763..b509212 100644
--- a/apps/plugins/wavrecord.c
+++ b/apps/plugins/wavrecord.c
@@ -3415,7 +3415,7 @@
 
 void rec_tick_enable(bool on)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     if(on)
     {
@@ -3431,7 +3431,7 @@
         IPRB = (IPRB & 0xff0f) | 0x0080;  /* Reenable IRQ6 */
     }
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 void hijack_interrupts(bool on)
diff --git a/bootloader/iaudio_coldfire.c b/bootloader/iaudio_coldfire.c
index 0f3798d..c1076e9 100644
--- a/bootloader/iaudio_coldfire.c
+++ b/bootloader/iaudio_coldfire.c
@@ -164,7 +164,7 @@
     set_cpu_frequency(CPUFREQ_NORMAL);
     coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
 
-    set_irq_level(0);
+    enable_irq();
     lcd_init();
 #ifdef HAVE_REMOTE_LCD
     lcd_remote_init();
diff --git a/bootloader/iriver_h1x0.c b/bootloader/iriver_h1x0.c
index 6b3527b..4be92eb 100644
--- a/bootloader/iriver_h1x0.c
+++ b/bootloader/iriver_h1x0.c
@@ -435,7 +435,7 @@
     coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
 #endif
 #endif
-    set_irq_level(0);
+    enable_irq();
 
 #ifdef HAVE_EEPROM_SETTINGS
     initialize_eeprom();
diff --git a/bootloader/iriver_h300.c b/bootloader/iriver_h300.c
index 1840966..3349be4 100644
--- a/bootloader/iriver_h300.c
+++ b/bootloader/iriver_h300.c
@@ -175,10 +175,10 @@
     }
 
     /* get rid of a nasty humming sound during boot */
-    mask = set_irq_level(HIGHEST_IRQ_LEVEL);
+    mask = disable_irq_save();
     pcf50606_write(0x3b, 0x00);  /* GPOOD2 high Z */
     pcf50606_write(0x3b, 0x07);  /* GPOOD2 low */
-    set_irq_level(mask);
+    restore_irq(mask);
 
     /* Start with the main backlight OFF. */
     _backlight_init();
@@ -192,7 +192,7 @@
     /* Set up waitstates for the peripherals */
     set_cpu_frequency(0); /* PLL off */
     coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
-    set_irq_level(0);
+    enable_irq();
 
     isp1362_init();
 
diff --git a/bootloader/mrobe500.c b/bootloader/mrobe500.c
index 1dbe7b8..e6dc581 100755
--- a/bootloader/mrobe500.c
+++ b/bootloader/mrobe500.c
@@ -174,8 +174,8 @@
     system_init();

     kernel_init();

     

-    set_irq_level(0);

-    set_fiq_status(FIQ_ENABLED);

+    enable_irq();

+    enable_fiq();

 

     adc_init();

     button_init();

diff --git a/firmware/drivers/audio/uda1380.c b/firmware/drivers/audio/uda1380.c
index ce69ef6..f6a7c73 100644
--- a/firmware/drivers/audio/uda1380.c
+++ b/firmware/drivers/audio/uda1380.c
@@ -203,10 +203,10 @@
 static void reset(void)
 {
 #ifdef IRIVER_H300_SERIES
-    int mask = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int mask = disable_irq_save();
     pcf50606_write(0x3b, 0x00);  /* GPOOD2 high Z */
     pcf50606_write(0x3b, 0x07);  /* GPOOD2 low */
-    set_irq_level(mask);
+    restore_irq(mask);
 #else
     /* RESET signal */
     or_l(1<<29, &GPIO_OUT);
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index b9473be..d38306b 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -465,10 +465,10 @@
     if (flip != flipped) /* not the current setting */
     {
         /* avoid race condition with the button_tick() */
-        int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        int oldlevel = disable_irq_save();
         lastbtn = button_flip(lastbtn);
         flipped = flip;
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
     }
 }
 #endif /* HAVE_LCD_BITMAP */
diff --git a/firmware/drivers/rtc/rtc_pcf50606.c b/firmware/drivers/rtc/rtc_pcf50606.c
index 25b0c70..9b4de44 100644
--- a/firmware/drivers/rtc/rtc_pcf50606.c
+++ b/firmware/drivers/rtc/rtc_pcf50606.c
@@ -30,21 +30,21 @@
 
 int rtc_read_datetime(unsigned char* buf) {
     int rc;
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     
     rc = pcf50606_read_multiple(0x0a, buf, 7);
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
     return rc;
 }
 
 int rtc_write_datetime(unsigned char* buf) {
     int rc;
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     
     rc = pcf50606_write_multiple(0x0a, buf, 7);
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     return rc;
 }
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 47c0d58..be0cfb5 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -270,7 +270,7 @@
 int tick_add_task(void (*f)(void))
 {
     int i;
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     /* Add a task if there is room */
     for(i = 0;i < MAX_NUM_TICK_TASKS;i++)
@@ -278,11 +278,11 @@
         if(tick_funcs[i] == NULL)
         {
             tick_funcs[i] = f;
-            set_irq_level(oldlevel);
+            restore_irq(oldlevel);
             return 0;
         }
     }
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
     panicf("Error! tick_add_task(): out of tasks");
     return -1;
 }
@@ -290,7 +290,7 @@
 int tick_remove_task(void (*f)(void))
 {
     int i;
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     /* Remove a task if it is there */
     for(i = 0;i < MAX_NUM_TICK_TASKS;i++)
@@ -298,12 +298,12 @@
         if(tick_funcs[i] == f)
         {
             tick_funcs[i] = NULL;
-            set_irq_level(oldlevel);
+            restore_irq(oldlevel);
             return 0;
         }
     }
     
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
     return -1;
 }
 
@@ -341,7 +341,7 @@
 /* Cancels a timeout callback - can be called from the ISR */
 void timeout_cancel(struct timeout *tmo)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     if (tmo_list != NULL)
     {
@@ -368,7 +368,7 @@
         /* not in list or tmo == NULL */
     }
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 /* Adds a timeout callback - calling with an active timeout resets the
@@ -382,7 +382,7 @@
     if (tmo == NULL)
         return;
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
 
     /* see if this one is already registered */
     curr = tmo_list;
@@ -404,7 +404,7 @@
     tmo->data = data;
     *(long *)&tmo->expires = current_tick + ticks;
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 #endif /* INCLUDE_TIMEOUT_API */
@@ -433,7 +433,7 @@
     while (TIME_BEFORE(USEC_TIMER, stop))
         switch_thread();
 #else
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     sleep_thread(ticks);
     switch_thread();
 #endif
@@ -537,7 +537,7 @@
                              struct queue_sender_list *send,
                              struct thread_entry *owner)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     if(send != NULL && q->send == NULL)
@@ -554,7 +554,7 @@
     }
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     (void)owner;
 }
@@ -618,7 +618,7 @@
 /* Queue must not be available for use during this call */
 void queue_init(struct event_queue *q, bool register_queue)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     if(register_queue)
     {
@@ -645,7 +645,7 @@
         corelock_unlock(&all_queues.cl);
     }
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 /* Queue must not be available for use during this call */
@@ -654,7 +654,7 @@
     int oldlevel;
     int i;
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&all_queues.cl);
     corelock_lock(&q->cl);
 
@@ -697,7 +697,7 @@
     q->write = 0;
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 /* NOTE: multiple threads waiting on a queue head cannot have a well-
@@ -714,7 +714,7 @@
                   "queue_wait->wrong thread\n");
 #endif
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     /* auto-reply */
@@ -734,7 +734,7 @@
             corelock_unlock(&q->cl);
             switch_thread();
 
-            oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+            oldlevel = disable_irq_save();
             corelock_lock(&q->cl);
         }
         /* A message that woke us could now be gone */
@@ -748,7 +748,7 @@
     queue_do_fetch_sender(q->send, rd);
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
@@ -761,7 +761,7 @@
                   "queue_wait_w_tmo->wrong thread\n");
 #endif
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     /* Auto-reply */
@@ -779,7 +779,7 @@
 
         switch_thread();
 
-        oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        oldlevel = disable_irq_save();
         corelock_lock(&q->cl);
     }
 
@@ -798,7 +798,7 @@
     }
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 void queue_post(struct event_queue *q, long id, intptr_t data)
@@ -806,7 +806,7 @@
     int oldlevel;
     unsigned int wr;
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     wr = q->write++ & QUEUE_LENGTH_MASK;
@@ -821,7 +821,7 @@
     wakeup_thread(&q->queue);
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
@@ -832,7 +832,7 @@
     int oldlevel;
     unsigned int wr;
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     wr = q->write++ & QUEUE_LENGTH_MASK;
@@ -875,7 +875,7 @@
     wakeup_thread(&q->queue);
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
     
     return 0;
 }
@@ -887,7 +887,7 @@
     bool in_send;
 
 #if NUM_CORES > 1
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 #endif
 
@@ -895,7 +895,7 @@
 
 #if NUM_CORES > 1
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 #endif
 
     return in_send;
@@ -907,7 +907,7 @@
 {
     if(q->send && q->send->curr_sender)
     {
-        int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        int oldlevel = disable_irq_save();
         corelock_lock(&q->cl);
         /* Double-check locking */
         IF_COP( if(q->send && q->send->curr_sender) )
@@ -916,7 +916,7 @@
         }
 
         corelock_unlock(&q->cl);
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
     }
 }
 
@@ -927,7 +927,7 @@
 
     bool have_msg = false;
 
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     if(q->read != q->write)
@@ -937,7 +937,7 @@
     }
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     return have_msg;
 }
@@ -956,7 +956,7 @@
 {
     int oldlevel;
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     /* Release all threads waiting in the queue for a reply -
@@ -967,14 +967,14 @@
     q->write = 0;
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 void queue_remove_from_head(struct event_queue *q, long id)
 {
     int oldlevel;
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
     corelock_lock(&q->cl);
 
     while(q->read != q->write)
@@ -993,7 +993,7 @@
     }
 
     corelock_unlock(&q->cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 /**
@@ -1012,7 +1012,7 @@
     int i;
 
 #if NUM_CORES > 1
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     corelock_lock(&all_queues.cl);
 #endif
     
@@ -1023,7 +1023,7 @@
 
 #if NUM_CORES > 1
     corelock_unlock(&all_queues.cl);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 #endif
    
     return i;
@@ -1079,7 +1079,7 @@
     IF_PRIO( current->blocker = &m->blocker; )
     current->bqp = &m->queue;
 
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     block_thread(current);
 
     corelock_unlock(&m->cl);
@@ -1118,13 +1118,13 @@
     }
     else
     {
-        const int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        const int oldlevel = disable_irq_save();
         /* Tranfer of owning thread is handled in the wakeup protocol
          * if priorities are enabled otherwise just set it from the
          * queue head. */
         IFN_PRIO( MUTEX_SET_THREAD(m, m->queue); )
         IF_PRIO( unsigned int result = ) wakeup_thread(&m->queue);
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
 
         corelock_unlock(&m->cl);
 
@@ -1219,7 +1219,7 @@
     IF_COP( current->obj_cl = &s->cl; )
     current->bqp = &s->queue;
 
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     block_thread(current);
 
     corelock_unlock(&s->cl);
@@ -1239,9 +1239,9 @@
         /* there should be threads in this queue */
         KERNEL_ASSERT(s->queue != NULL, "semaphore->wakeup\n");
         /* a thread was queued - wake it up */
-        int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        int oldlevel = disable_irq_save();
         IF_PRIO( result = ) wakeup_thread(&s->queue);
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
     }
 
     corelock_unlock(&s->cl);
@@ -1298,7 +1298,7 @@
     IF_COP( current->obj_cl = &e->cl; )
     current->bqp = &e->queues[for_state];
 
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     block_thread(current);
 
     corelock_unlock(&e->cl);
@@ -1323,7 +1323,7 @@
 
     IF_PRIO( result = THREAD_OK; )
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
 
     if(state == STATE_SIGNALED)
     {
@@ -1357,7 +1357,7 @@
             thread_queue_wake(&e->queues[STATE_NONSIGNALED]);
     }
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     corelock_unlock(&e->cl);
 
diff --git a/firmware/mp3_playback.c b/firmware/mp3_playback.c
index b2b7205..ed71be2 100644
--- a/firmware/mp3_playback.c
+++ b/firmware/mp3_playback.c
@@ -134,7 +134,7 @@
 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
 void demand_irq_enable(bool on)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     
     if(on)
     {
@@ -144,7 +144,7 @@
     else
         IPRA &= 0xfff0;
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
 
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 273f630..11cbcdc 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -1767,9 +1767,9 @@
                         DEBUGF("New audiobuf_read address: %x (%x)\n",
                                audiobuf+audiobuf_read, audiobuf_read);
 
-                        level = set_irq_level(HIGHEST_IRQ_LEVEL);
+                        level = disable_irq_save();
                         num_rec_bytes = get_unsaved_space();
-                        set_irq_level(level);
+                        restore_irq(level);
                     }
                     else
                     {
@@ -1860,11 +1860,11 @@
                         pause_start_time = record_start_time;
 
                     /* capture all values at one point */
-                    level = set_irq_level(HIGHEST_IRQ_LEVEL);
+                    level = disable_irq_save();
                     save_endpos = audiobuf_write;
                     last_rec_bytes = num_rec_bytes;
                     num_rec_bytes = 0;
-                    set_irq_level(level);
+                    restore_irq(level);
 
                     if (amount_to_save >= 1800)
                     {
@@ -1883,9 +1883,9 @@
                             save_endpos -= audiobuflen;
 
                         last_rec_bytes += offset - 1800;
-                        level = set_irq_level(HIGHEST_IRQ_LEVEL);
+                        level = disable_irq_save();
                         num_rec_bytes += 1800 - offset;
-                        set_irq_level(level);
+                        restore_irq(level);
                     }
 
                     saving_status = NEW_FILE;
diff --git a/firmware/rolo.c b/firmware/rolo.c
index eac45e1..30eba91 100644
--- a/firmware/rolo.c
+++ b/firmware/rolo.c
@@ -271,7 +271,11 @@
 #endif
     adc_close();
 
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+#ifdef CPU_ARM
+    disable_fiq();
+#endif
+    set_irq_level(DISABLE_INTERRUPTS);
+
 #elif CONFIG_CPU == SH7034
     /* Read file length from header and compare to real file length */
     lseek(fd, FIRMWARE_OFFSET_FILE_LENGTH, SEEK_SET);
diff --git a/firmware/target/arm/i2c-pp.c b/firmware/target/arm/i2c-pp.c
index 1cfbfae..450effc 100644
--- a/firmware/target/arm/i2c-pp.c
+++ b/firmware/target/arm/i2c-pp.c
@@ -60,7 +60,7 @@
 
     {
         unsigned int byte;
-        int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+        int old_irq_level = disable_irq_save();
 
         /* clear top 15 bits, left shift 1, or in 0x1 for a read */
         I2C_ADDR = ((addr << 17) >> 16) | 0x1 ;
@@ -69,19 +69,19 @@
 
         I2C_CTRL |= I2C_SEND;
 
-        set_irq_level(old_irq_level);
+        restore_irq(old_irq_level);
         if (pp_i2c_wait_not_busy() < 0)
         {
             return -1;
         }
-        old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+        old_irq_level = disable_irq_save();
 
         byte = I2C_DATA(0);
 
         if (data)
             *data = byte;
 
-        set_irq_level(old_irq_level);
+        restore_irq(old_irq_level);
     }
 
     return 0;
@@ -102,7 +102,7 @@
     }
 
     {
-        int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+        int old_irq_level = disable_irq_save();
 
         /* clear top 15 bits, left shift 1 */
         I2C_ADDR = (addr << 17) >> 16;
@@ -118,7 +118,7 @@
 
         I2C_CTRL |= I2C_SEND;
 
-        set_irq_level(old_irq_level);
+        restore_irq(old_irq_level);
     }
 
     return 0x0;
diff --git a/firmware/target/arm/ipod/backlight-nano_video.c b/firmware/target/arm/ipod/backlight-nano_video.c
index 6d77e2b..647bab9 100644
--- a/firmware/target/arm/ipod/backlight-nano_video.c
+++ b/firmware/target/arm/ipod/backlight-nano_video.c
@@ -43,11 +43,11 @@
     {
         do
         {
-            oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+            oldlevel = disable_irq_save();
             GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x80);
             udelay(10);
             GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x80);
-            set_irq_level(oldlevel);
+            restore_irq(oldlevel);
             udelay(10);
         }
         while (++current_dim < val);
@@ -56,11 +56,11 @@
     {
         do
         {
-            oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+            oldlevel = disable_irq_save();
             GPIO_CLEAR_BITWISE(GPIOD_OUTPUT_VAL, 0x80);
             udelay(200);
             GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x80);
-            set_irq_level(oldlevel);
+            restore_irq(oldlevel);
             udelay(10);
         }
         while (--current_dim > val);
diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c
index d0c82e9..0e1b072 100644
--- a/firmware/target/arm/ipod/video/lcd-video.c
+++ b/firmware/target/arm/ipod/video/lcd-video.c
@@ -110,7 +110,7 @@
 #ifndef BOOTLOADER
 static void lcd_tick(void)
 {
-    /* No set_irq_level - already in interrupt context */
+    /* No core level interrupt mask - already in interrupt context */
 #if NUM_CORES > 1
     corelock_lock(&lcd_state.cl);
 #endif
@@ -143,7 +143,7 @@
 
 static inline void lcd_block_tick(void)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
 #if NUM_CORES > 1
     corelock_lock(&lcd_state.cl);
@@ -152,14 +152,14 @@
 #else
     lcd_state.blocked = true;
 #endif
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 static void lcd_unblock_and_update(void)
 {
     unsigned data;
     bool bcm_is_busy;
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
 #if NUM_CORES > 1
     corelock_lock(&lcd_state.cl);
@@ -184,7 +184,7 @@
 #if NUM_CORES > 1
     corelock_unlock(&lcd_state.cl);
 #endif
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 #else /* BOOTLOADER */
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index 5a9d3b3..433e6e1 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -223,24 +223,24 @@
    will require other measures */
 void pcm_play_lock(void)
 {
-    int status = set_fiq_status(FIQ_DISABLED);
+    int status = disable_fiq_save();
 
     if (++dma_play_data.locked == 1) {
         IIS_IRQTX_REG &= ~IIS_IRQTX;
     }
 
-    set_fiq_status(status);
+    restore_fiq(status);
 }
 
 void pcm_play_unlock(void)
 {
-   int status = set_fiq_status(FIQ_DISABLED);
+   int status = disable_fiq_save();
 
     if (--dma_play_data.locked == 0 && dma_play_data.state != 0) {
         IIS_IRQTX_REG |= IIS_IRQTX;
     }
 
-   set_fiq_status(status);
+   restore_fiq(status);
 }
 
 static void play_start_pcm(void)
@@ -373,22 +373,22 @@
    will require other measures */
 void pcm_rec_lock(void)
 {
-    int status = set_fiq_status(FIQ_DISABLED);
+    int status = disable_fiq_save();
 
     if (++dma_rec_data.locked == 1)
         IIS_IRQRX_REG &= ~IIS_IRQRX;
 
-    set_fiq_status(status);
+    restore_fiq(status);
 }
 
 void pcm_rec_unlock(void)
 {
-    int status = set_fiq_status(FIQ_DISABLED);
+    int status = disable_fiq_save();
 
     if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
         IIS_IRQRX_REG |= IIS_IRQRX;
 
-    set_fiq_status(status);
+    restore_fiq(status);
 }
 
 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
diff --git a/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c b/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c
index b219244..4494742 100644
--- a/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c
+++ b/firmware/target/arm/pnx0101/iriver-ifp7xx/power-ifp7xx.c
@@ -55,11 +55,10 @@
 
 void power_off(void)
 {
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_interrupt(IRQ_FIQ_STATUS);
     GPIO1_CLR = 1 << 16;
     GPIO2_SET = 1;
-    while(1)
-        yield();
+    while(1);
 }
 
 #else
diff --git a/firmware/target/arm/pnx0101/system-pnx0101.c b/firmware/target/arm/pnx0101/system-pnx0101.c
index da94f39..bedcff0 100644
--- a/firmware/target/arm/pnx0101/system-pnx0101.c
+++ b/firmware/target/arm/pnx0101/system-pnx0101.c
@@ -113,7 +113,7 @@
 static void do_set_mem_timings(void) ICODE_ATTR;
 static void do_set_mem_timings(void)
 {
-    int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int old_irq = disable_irq_save();
     while ((EMC.status & 3) != 0);
     EMC.control = 5;
     EMCSTATIC0.waitrd = 6;
@@ -130,7 +130,7 @@
     EMCSTATIC1.config = 0x80081;
 #endif
     EMC.control = 1;
-    set_irq_level(old_irq);
+    restore_irq(old_irq);
 }
 
 static void emc_set_mem_timings(void)
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
index 7f25cb6..00be543 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
@@ -66,27 +66,27 @@
 
 void pcm_apply_settings(void)
 {
-    int oldstatus = set_fiq_status(FIQ_DISABLED);
+    int status = disable_fiq_save();
     _pcm_apply_settings();
-    set_fiq_status(oldstatus);
+    restore_fiq(status);
 }
 
 /* For the locks, DMA interrupt must be disabled because the handler
    manipulates INTMSK and the operation is not atomic */
 void pcm_play_lock(void)
 {
-    int status = set_fiq_status(FIQ_DISABLED);
+    int status = disable_fiq_save();
     if (++dma_play_lock.locked == 1)
         INTMSK |= (1<<19); /* Mask the DMA interrupt */
-    set_fiq_status(status);
+    restore_fiq(status);
 }
 
 void pcm_play_unlock(void)
 {
-    int status = set_fiq_status(FIQ_DISABLED);
+    int status = disable_fiq_save();
     if (--dma_play_lock.locked == 0)
         INTMSK &= ~dma_play_lock.state; /* Unmask the DMA interrupt if enabled */
-    set_fiq_status(status);
+    restore_fiq(status);
 }
 
 void pcm_play_dma_init(void)
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
index 7df20f7..b59e958 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
@@ -66,7 +66,7 @@
             pfn_unregister = NULL;
         }
 
-        oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        oldlevel = disable_irq_save();
 
         TCMPB0 = 0;
         TCNTB0 = (unsigned int)cycles / prescaler;
@@ -77,7 +77,7 @@
         TCFG0 = (TCFG0 & ~0xff) | (prescaler - 1);
         TCFG1 = (TCFG1 & ~0xf) | divider;
 
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
 
         retval = true;
     }
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h
index 774cdbc..3f1dfb1 100644
--- a/firmware/target/arm/system-arm.h
+++ b/firmware/target/arm/system-arm.h
@@ -74,27 +74,7 @@
     return value;
 }
 
-static inline void enable_fiq(void)
-{
-    /* Clear FIQ disable bit */
-    asm volatile (
-        "mrs     r0, cpsr         \n"\
-        "bic     r0, r0, #0x40    \n"\
-        "msr     cpsr_c, r0         "
-        : : : "r0"
-    );
-}
-
-static inline void disable_fiq(void)
-{
-    /* Set FIQ disable bit */
-    asm volatile (
-        "mrs     r0, cpsr         \n"\
-        "orr     r0, r0, #0x40    \n"\
-        "msr     cpsr_c, r0         "
-        : : : "r0"
-    );
-}
+/* Core-level interrupt masking */
 
 /* This one returns the old status */
 #define IRQ_ENABLED      0x00
@@ -108,8 +88,10 @@
 #define IRQ_FIQ_STATUS   0xc0
 #define HIGHEST_IRQ_LEVEL IRQ_DISABLED
 
-#define set_irq_level(status)  set_interrupt_status((status), IRQ_STATUS)
-#define set_fiq_status(status) set_interrupt_status((status), FIQ_STATUS)
+#define set_irq_level(status) \
+    set_interrupt_status((status), IRQ_STATUS)
+#define set_fiq_status(status) \
+    set_interrupt_status((status), FIQ_STATUS)
 
 static inline int set_interrupt_status(int status, int mask)
 {
@@ -122,10 +104,75 @@
         "orr    %0, %0, %2      \n"
         "msr    cpsr_c, %0      \n"
         : "=&r,r"(cpsr), "=&r,r"(oldstatus)
-        : "r,i"(status & mask), [mask]"i,i"(mask)
-    );
+        : "r,i"(status & mask), [mask]"i,i"(mask));
 
     return oldstatus;
 }
 
+static inline void enable_interrupt(int mask)
+{
+    /* Clear I and/or F disable bit */
+    int tmp;
+    asm volatile (
+        "mrs     %0, cpsr   \n"
+        "bic     %0, %0, %1 \n"
+        "msr     cpsr_c, %0 \n"
+        : "=&r"(tmp) : "i"(mask));
+}
+
+static inline void disable_interrupt(int mask)
+{
+    /* Set I and/or F disable bit */
+    int tmp;
+    asm volatile (
+        "mrs     %0, cpsr   \n"
+        "orr     %0, %0, %1 \n"
+        "msr     cpsr_c, %0 \n"
+        : "=&r"(tmp) : "i"(mask));
+}
+
+#define disable_irq(void) \
+    disable_interrupt(IRQ_STATUS)
+
+#define enable_irq(void) \
+    enable_interrupt(IRQ_STATUS)
+
+#define disable_fiq(void) \
+    disable_interrupt(FIQ_STATUS)
+
+#define enable_fiq(void) \
+    enable_interrupt(FIQ_STATUS)
+
+static inline int disable_interrupt_save(int mask)
+{
+    /* Set I and/or F disable bit and return old cpsr value */
+    int cpsr, tmp;
+    asm volatile (
+        "mrs     %1, cpsr   \n"
+        "orr     %0, %1, %2 \n"
+        "msr     cpsr_c, %0 \n"
+        : "=&r"(tmp), "=&r"(cpsr)
+        : "i"(mask));
+    return cpsr;
+}
+
+#define disable_irq_save() \
+    disable_interrupt_save(IRQ_STATUS)
+
+#define disable_fiq_save() \
+    disable_interrupt_save(FIQ_STATUS)
+
+static inline void restore_interrupt(int cpsr)
+{
+    /* Set cpsr_c from value returned by disable_interrupt_save
+     * or set_interrupt_status */
+    asm volatile ("msr cpsr_c, %0" : : "r"(cpsr));
+}
+
+#define restore_irq(cpsr) \
+    restore_interrupt(cpsr)
+
+#define restore_fiq(cpsr) \
+    restore_interrupt(cpsr)
+
 #endif /* SYSTEM_ARM_H */
diff --git a/firmware/target/arm/tatung/tpj1022/backlight-tpj1022.c b/firmware/target/arm/tatung/tpj1022/backlight-tpj1022.c
index 933ad5e..a466cd9 100644
--- a/firmware/target/arm/tatung/tpj1022/backlight-tpj1022.c
+++ b/firmware/target/arm/tatung/tpj1022/backlight-tpj1022.c
@@ -28,17 +28,17 @@
 void _backlight_on(void)
 {
 #if 0
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     pcf50606_write(0x38, 0xb0); /* Backlight ON, GPO1INV=1, GPO1ACT=011 */
-    set_irq_level(level);
+    restore_irq(level);
 #endif
 }
 
 void _backlight_off(void)
 {
 #if 0
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     pcf50606_write(0x38, 0x80); /* Backlight OFF, GPO1INV=1, GPO1ACT=000 */
-    set_irq_level(level);
+    restore_irq(level);
 #endif
 }
diff --git a/firmware/target/arm/tms320dm320/dsp-dm320.c b/firmware/target/arm/tms320dm320/dsp-dm320.c
index f2ca954..e082cf7 100644
--- a/firmware/target/arm/tms320dm320/dsp-dm320.c
+++ b/firmware/target/arm/tms320dm320/dsp-dm320.c
@@ -85,7 +85,7 @@
 {
     /* If this is called concurrently, we may overlap setting and resetting the
        bit, which causes lost interrupts to the DSP. */
-    int old_level = set_irq_level(IRQ_DISABLED);
+    int old_level = disable_irq_save();
     
     /* The first time you INT0 the DSP, the ROM loader will branch to your RST
        handler. Subsequent times, your INT0 handler will get executed. */
@@ -93,7 +93,7 @@
     nop; nop;
     IO_DSPC_HPIB_CONTROL |= 1 << 7;
     
-    set_irq_level(old_level);
+    restore_irq(old_level);
 }
 
 static void dsp_load(const struct dsp_section *im)
diff --git a/firmware/target/arm/tms320dm320/timer-dm320.c b/firmware/target/arm/tms320dm320/timer-dm320.c
index 482fef9..e1e051d 100644
--- a/firmware/target/arm/tms320dm320/timer-dm320.c
+++ b/firmware/target/arm/tms320dm320/timer-dm320.c
@@ -48,7 +48,7 @@
         pfn_unregister = NULL;
     }
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
 
     /* Increase prescale values starting from 0 to make the cycle count fit */
     while(divider>65535 && prescaler<1024)
@@ -60,7 +60,7 @@
     IO_TIMER0_TMPRSCL = prescaler;
     IO_TIMER0_TMDIV = divider;
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     return true;
 }
diff --git a/firmware/target/coldfire/iaudio/adc-iaudio.c b/firmware/target/coldfire/iaudio/adc-iaudio.c
index 1895cac..5a2de24 100644
--- a/firmware/target/coldfire/iaudio/adc-iaudio.c
+++ b/firmware/target/coldfire/iaudio/adc-iaudio.c
@@ -44,7 +44,7 @@
     int level;
     int data;
 
-    level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    level = disable_irq_save();
 
     pcf50606_write(0x2f, adcc2_parms[channel]);
     data = pcf50606_read(0x30);
@@ -52,7 +52,7 @@
     if (channel == ADC_BATTERY)
         data = get_10bit_voltage(data);
 
-    set_irq_level(level);
+    restore_irq(level);
 
     return (unsigned short)data;
 }
diff --git a/firmware/target/coldfire/iaudio/m3/audio-m3.c b/firmware/target/coldfire/iaudio/m3/audio-m3.c
index 4edae48..da8c43c 100644
--- a/firmware/target/coldfire/iaudio/m3/audio-m3.c
+++ b/firmware/target/coldfire/iaudio/m3/audio-m3.c
@@ -33,7 +33,7 @@
         txsrc = (4 << 8); /* recording, iis1RcvData */
 
     IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc;
-    set_irq_level(level);
+    restore_irq(level);
 } /* audio_set_output_source */
 
 void audio_input_mux(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iaudio/m5/audio-m5.c b/firmware/target/coldfire/iaudio/m5/audio-m5.c
index 87a7c35..024621b 100644
--- a/firmware/target/coldfire/iaudio/m5/audio-m5.c
+++ b/firmware/target/coldfire/iaudio/m5/audio-m5.c
@@ -32,7 +32,7 @@
         txsrc = (4 << 8); /* recording, iis1RcvData */
 
     IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc;
-    set_irq_level(level);
+    restore_irq(level);
 } /* audio_set_output_source */
 
 void audio_input_mux(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iaudio/m5/backlight-m5.c b/firmware/target/coldfire/iaudio/m5/backlight-m5.c
index 19bc5bf..3461a33 100644
--- a/firmware/target/coldfire/iaudio/m5/backlight-m5.c
+++ b/firmware/target/coldfire/iaudio/m5/backlight-m5.c
@@ -33,18 +33,18 @@
 
 void _backlight_on(void)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
 
     pcf50606_write(0x39, 0x07);
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 void _backlight_off(void)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
 
     pcf50606_write(0x39, 0x00);
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 void _remote_backlight_on(void)
diff --git a/firmware/target/coldfire/iaudio/m5/power-m5.c b/firmware/target/coldfire/iaudio/m5/power-m5.c
index 939cae0..18401af 100644
--- a/firmware/target/coldfire/iaudio/m5/power-m5.c
+++ b/firmware/target/coldfire/iaudio/m5/power-m5.c
@@ -44,16 +44,16 @@
 void ide_power_enable(bool on)
 {
     /* GPOOD3 */
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     pcf50606_write(0x3c, on ? 0x07 : 0x00);
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 bool ide_powered(void)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     int value = pcf50606_read(0x3c);
-    set_irq_level(level);
+    restore_irq(level);
     return (value & 0x07) != 0;
 }
 
diff --git a/firmware/target/coldfire/iaudio/pcf50606-iaudio.c b/firmware/target/coldfire/iaudio/pcf50606-iaudio.c
index 0614355..14b45e7 100644
--- a/firmware/target/coldfire/iaudio/pcf50606-iaudio.c
+++ b/firmware/target/coldfire/iaudio/pcf50606-iaudio.c
@@ -94,9 +94,9 @@
 
 void pcf50606_reset_timeout(void)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     pcf50606_write(0x08, pcf50606_read(0x08) | 0x02); /* OOCC1 - TOTRST=1 */
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 /* Handles interrupts generated by the pcf50606 */
diff --git a/firmware/target/coldfire/iaudio/x5/audio-x5.c b/firmware/target/coldfire/iaudio/x5/audio-x5.c
index 594ff3b..0ae5f60 100644
--- a/firmware/target/coldfire/iaudio/x5/audio-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/audio-x5.c
@@ -32,7 +32,7 @@
         txsrc = (4 << 8); /* recording, iis1RcvData */
 
     IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc;
-    set_irq_level(level);
+    restore_irq(level);
 } /* audio_set_output_source */
 
 void audio_input_mux(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iaudio/x5/backlight-x5.c b/firmware/target/coldfire/iaudio/x5/backlight-x5.c
index ebb28fb..13ccad5 100644
--- a/firmware/target/coldfire/iaudio/x5/backlight-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/backlight-x5.c
@@ -39,16 +39,16 @@
 #ifndef BOOTLOADER
     _lcd_sleep_timer = 0; /* LCD should be awake already */
 #endif
-    level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    level = disable_irq_save();
     pcf50606_write(0x38, 0xb0); /* Backlight ON, GPO1INV=1, GPO1ACT=011 */
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 void _backlight_off(void)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     pcf50606_write(0x38, 0x80); /* Backlight OFF, GPO1INV=1, GPO1ACT=000 */
-    set_irq_level(level);
+    restore_irq(level);
     lcd_enable(false);
 #ifndef BOOTLOADER
     /* Start LCD sleep countdown */
@@ -66,10 +66,10 @@
 void _backlight_set_brightness(int val)
 {
     /* disable IRQs while bitbanging */
-    int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int old_irq_level = disable_irq_save();
     pcf50606_write(0x35, (val << 1) | 0x01); /* 512Hz, Enable PWM */
     /* enable IRQs again */
-    set_irq_level(old_irq_level);
+    restore_irq(old_irq_level);
 }
 
 void _remote_backlight_on(void)
diff --git a/firmware/target/coldfire/iaudio/x5/ds2411-x5.c b/firmware/target/coldfire/iaudio/x5/ds2411-x5.c
index dc5a188..a9bf20f 100644
--- a/firmware/target/coldfire/iaudio/x5/ds2411-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/ds2411-x5.c
@@ -134,7 +134,7 @@
  */
 int ds2411_read_id(struct ds2411_id *id)
 {
-    int level = set_irq_level(DISABLE_INTERRUPTS); /* Timing sensitive */
+    int level = disable_irq_save(); /* Timing sensitive */
     int i;
     unsigned char crc;
 
@@ -208,7 +208,7 @@
         i = DS2411_NO_PRESENCE;
     }
 
-    set_irq_level(level);
+    restore_irq(level);
 
     return i;
 } /* ds2411_read_id */
diff --git a/firmware/target/coldfire/iaudio/x5/power-x5.c b/firmware/target/coldfire/iaudio/x5/power-x5.c
index 068b25f..f5193aa 100644
--- a/firmware/target/coldfire/iaudio/x5/power-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/power-x5.c
@@ -44,16 +44,16 @@
 void ide_power_enable(bool on)
 {
     /* GPOOD3 */
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     pcf50606_write(0x3c, on ? 0x07 : 0x00);
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 bool ide_powered(void)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     int value = pcf50606_read(0x3c);
-    set_irq_level(level);
+    restore_irq(level);
     return (value & 0x07) != 0;
 }
 
diff --git a/firmware/target/coldfire/iriver/audio-iriver.c b/firmware/target/coldfire/iriver/audio-iriver.c
index 4d22e7c..51917b1 100644
--- a/firmware/target/coldfire/iriver/audio-iriver.c
+++ b/firmware/target/coldfire/iriver/audio-iriver.c
@@ -41,7 +41,7 @@
 
     IIS2CONFIG = (IIS2CONFIG & ~(7 << 8)) | (txsrc_select[source+1] << 8);
 
-    set_irq_level(level);
+    restore_irq(level);
 } /* audio_set_output_source */
 
 void audio_input_mux(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iriver/h100/adc-h100.c b/firmware/target/coldfire/iriver/h100/adc-h100.c
index 40fcc89..7ea7618 100644
--- a/firmware/target/coldfire/iriver/h100/adc-h100.c
+++ b/firmware/target/coldfire/iriver/h100/adc-h100.c
@@ -47,7 +47,7 @@
 
 unsigned short adc_scan(int channel)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     unsigned char data = 0;
     int i;
     
@@ -97,7 +97,7 @@
 
     CS_HI;
 
-    set_irq_level(level);
+    restore_irq(level);
     return data;
 }
 
diff --git a/firmware/target/coldfire/iriver/h100/power-h100.c b/firmware/target/coldfire/iriver/h100/power-h100.c
index 5dc8618..7ecf961 100644
--- a/firmware/target/coldfire/iriver/h100/power-h100.c
+++ b/firmware/target/coldfire/iriver/h100/power-h100.c
@@ -115,8 +115,7 @@
     set_irq_level(DISABLE_INTERRUPTS);
     and_l(~0x00080000, &GPIO1_OUT);
     asm("halt");
-    while(1)
-        yield();
+    while(1);
 }
 
 #endif /* SIMULATOR */
diff --git a/firmware/target/coldfire/iriver/h100/spdif-h100.c b/firmware/target/coldfire/iriver/h100/spdif-h100.c
index beede3f..3806224 100644
--- a/firmware/target/coldfire/iriver/h100/spdif-h100.c
+++ b/firmware/target/coldfire/iriver/h100/spdif-h100.c
@@ -99,7 +99,7 @@
         PDOR3 = 0; /* A write to the FIFO kick-starts playback */
     }
 
-    set_irq_level(level);
+    restore_irq(level);
 } /* spdif_set_output_source */
 
 /* Return the last set S/PDIF audio source */
diff --git a/firmware/target/coldfire/iriver/h300/adc-h300.c b/firmware/target/coldfire/iriver/h300/adc-h300.c
index b13d0c7..efe5a9d 100644
--- a/firmware/target/coldfire/iriver/h300/adc-h300.c
+++ b/firmware/target/coldfire/iriver/h300/adc-h300.c
@@ -34,7 +34,7 @@
 
 unsigned short adc_scan(int channel)
 {
-    int level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int level = disable_irq_save();
     unsigned data;
 
     pcf50606_write(0x2f, adcc2_parms[channel]);
@@ -43,6 +43,6 @@
     if (channel == ADC_BATTERY)
         data = (data << 2) | (pcf50606_read(0x31) & 0x03);
 
-    set_irq_level(level);
+    restore_irq(level);
     return data;
 }
diff --git a/firmware/target/coldfire/iriver/h300/backlight-h300.c b/firmware/target/coldfire/iriver/h300/backlight-h300.c
index c0d441a..f042ee5 100644
--- a/firmware/target/coldfire/iriver/h300/backlight-h300.c
+++ b/firmware/target/coldfire/iriver/h300/backlight-h300.c
@@ -51,10 +51,10 @@
 void _backlight_set_brightness(int val)
 {
     /* disable IRQs while bitbanging */
-    int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int old_irq_level = disable_irq_save();
     pcf50606_write(0x35, (val << 1) | 0x01); /* 512Hz, Enable PWM */
     /* enable IRQs again */
-    set_irq_level(old_irq_level);
+    restore_irq(old_irq_level);
 }
 
 void _remote_backlight_on(void)
diff --git a/firmware/target/coldfire/iriver/h300/power-h300.c b/firmware/target/coldfire/iriver/h300/power-h300.c
index 21c723d..a06763e 100644
--- a/firmware/target/coldfire/iriver/h300/power-h300.c
+++ b/firmware/target/coldfire/iriver/h300/power-h300.c
@@ -86,8 +86,7 @@
     set_irq_level(DISABLE_INTERRUPTS);
     and_l(~0x00080000, &GPIO1_OUT);
     asm("halt");
-    while(1)
-        yield();
+    while(1);
 }
 
 #endif /* SIMULATOR */
diff --git a/firmware/target/coldfire/iriver/lcd-remote-iriver.c b/firmware/target/coldfire/iriver/lcd-remote-iriver.c
index cab7cc4..2fe5d6c 100644
--- a/firmware/target/coldfire/iriver/lcd-remote-iriver.c
+++ b/firmware/target/coldfire/iriver/lcd-remote-iriver.c
@@ -478,9 +478,9 @@
             if (!(countdown % 8))
             {
                 /* Determine which type of remote it is */
-                level = set_irq_level(HIGHEST_IRQ_LEVEL);
+                level = disable_irq_save();
                 val = adc_scan(ADC_REMOTEDETECT);
-                set_irq_level(level);
+                restore_irq(level);
 
                 if (val < ADCVAL_H100_LCD_REMOTE_HOLD)
                 {
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index 105ad51..2614946 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -158,7 +158,7 @@
 {
     int level = set_irq_level(DMA_IRQ_LEVEL);
     _pcm_apply_settings(clear_reset);
-    set_irq_level(level);
+    restore_irq(level);
 }
 
 /* This clears the reset bit to enable monitoring immediately if monitoring
@@ -175,7 +175,7 @@
     if (_pcm_apply_settings(!pbm || kick) && kick)
         PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
 
-    set_irq_level(level);
+    restore_irq(level);
 } /* pcm_apply_settings */
 
 void pcm_play_dma_init(void)
diff --git a/firmware/target/coldfire/system-coldfire.c b/firmware/target/coldfire/system-coldfire.c
index 60f7ab1..67c684f 100644
--- a/firmware/target/coldfire/system-coldfire.c
+++ b/firmware/target/coldfire/system-coldfire.c
@@ -351,5 +351,5 @@
     /* Have to be atomic against recording stop initiated by DMA1 */
     int level = set_irq_level(DMA_IRQ_LEVEL);
     DATAINCONTROL = (DATAINCONTROL & (1 << 9)) | value;
-    set_irq_level(level);
+    restore_irq(level);
 }
diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h
index 8e3a2a3..14b3207 100644
--- a/firmware/target/coldfire/system-target.h
+++ b/firmware/target/coldfire/system-target.h
@@ -81,13 +81,54 @@
 {
     int oldlevel;
     /* Read the old level and set the new one */
-    asm volatile ("move.w %%sr, %0 \n"
-                  "bset.l #13, %1  \n" /* Keep supervisor state set */
-                  "move.w %1, %%sr \n"
-                  : "=d"(oldlevel), "+d"(level));
+
+    /* Not volatile - can be removed if oldlevel isn't used */
+    asm          ("move.w %%sr, %0" : "=d"(oldlevel));
+    /* Keep supervisor state set */
+    asm volatile ("move.w %0, %%sr \n" : : "d"(level | 0x2000));
     return oldlevel;
 }
 
+/* Enable all interrupts */
+static inline void enable_irq(void)
+{
+    int tmp;
+    /* Using move.w over the compiler's move.l saves 2 bytes per instance */
+    asm volatile ("move.w %1, %0   \n"
+                  "move.w %0, %%sr \n"
+                  : "=&d"(tmp) : "i"(0x2000));
+}
+
+/* Disable interrupts up to HIGHEST_IRQ_LEVEL */
+static inline void disable_irq(void)
+{
+    int tmp;
+    /* Using move.w over the compiler's move.l saves 2 bytes per instance */
+    asm volatile ("move.w %1, %0   \n"
+                  "move.w %0, %%sr \n"
+                  : "=&d"(tmp)
+                  : "i"(0x2000 | HIGHEST_IRQ_LEVEL));
+}
+
+static inline int disable_irq_save(void)
+{
+    int oldlevel, tmp;
+    /* Using move.w over the compiler's move.l saves 2 bytes per instance */
+    asm volatile ("move.w %%sr, %1 \n"
+                  "move.w %2, %0   \n"
+                  "move.w %0, %%sr \n"
+                  : "=&d"(tmp), "=d"(oldlevel)
+                  : "i"(0x2000 | HIGHEST_IRQ_LEVEL));
+    return oldlevel;
+}
+
+static inline void restore_irq(int oldlevel)
+{
+    /* Restore the sr value returned by disable_irq_save or
+     * set_irq_level */
+    asm volatile ("move.w %0, %%sr" : : "d"(oldlevel));
+}
+
 static inline uint16_t swap16(uint16_t value)
   /*
     result[15..8] = value[ 7..0];
diff --git a/firmware/target/sh/archos/fm_v2/power-fm_v2.c b/firmware/target/sh/archos/fm_v2/power-fm_v2.c
index 94a3633..ac23348 100644
--- a/firmware/target/sh/archos/fm_v2/power-fm_v2.c
+++ b/firmware/target/sh/archos/fm_v2/power-fm_v2.c
@@ -101,9 +101,8 @@
 
 void power_off(void)
 {
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     and_b(~0x20, &PBDRL);
     or_b(0x20, &PBIORL);
-    while(1)
-        yield();
+    while(1);
 }
diff --git a/firmware/target/sh/archos/ondio/power-ondio.c b/firmware/target/sh/archos/ondio/power-ondio.c
index 156516a..87f3657 100644
--- a/firmware/target/sh/archos/ondio/power-ondio.c
+++ b/firmware/target/sh/archos/ondio/power-ondio.c
@@ -66,13 +66,12 @@
 
 void power_off(void)
 {
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
 #ifdef HAVE_BACKLIGHT
     /* Switch off the light on backlight-modded Ondios */
     _backlight_off();
 #endif
     and_b(~0x20, &PBDRL);
     or_b(0x20, &PBIORL);
-    while(1)
-        yield();
+    while(1);
 }
diff --git a/firmware/target/sh/archos/player/power-player.c b/firmware/target/sh/archos/player/power-player.c
index 7d9d0d7..b2f51b9 100644
--- a/firmware/target/sh/archos/player/power-player.c
+++ b/firmware/target/sh/archos/player/power-player.c
@@ -79,9 +79,8 @@
 
 void power_off(void)
 {
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     and_b(~0x08, &PADRH);
     or_b(0x08, &PAIORH);
-    while(1)
-        yield();
+    while(1);
 }
diff --git a/firmware/target/sh/archos/recorder/power-recorder.c b/firmware/target/sh/archos/recorder/power-recorder.c
index 2af8df1..1804bcb 100644
--- a/firmware/target/sh/archos/recorder/power-recorder.c
+++ b/firmware/target/sh/archos/recorder/power-recorder.c
@@ -95,9 +95,8 @@
 
 void power_off(void)
 {
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     and_b(~0x10, &PBDRL);
     or_b(0x10, &PBIORL);
-    while(1)
-        yield();
+    while(1);
 }
diff --git a/firmware/target/sh/system-sh.c b/firmware/target/sh/system-sh.c
index eec3ec1..f763e0f 100644
--- a/firmware/target/sh/system-sh.c
+++ b/firmware/target/sh/system-sh.c
@@ -360,7 +360,7 @@
 
 void system_reboot (void)
 {
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
 
     asm volatile ("ldc\t%0,vbr" : : "r"(0));
 
diff --git a/firmware/target/sh/system-target.h b/firmware/target/sh/system-target.h
index 7fb8fec..d641076 100644
--- a/firmware/target/sh/system-target.h
+++ b/firmware/target/sh/system-target.h
@@ -52,11 +52,29 @@
 {
     int i;
     /* Read the old level and set the new one */
-    asm volatile ("stc sr, %0" : "=r" (i));
+
+    /* Not volatile - will be optimized away if the return value isn't used */
+    asm ("stc sr, %0" : "=r" (i));
     asm volatile ("ldc %0, sr" : : "r" (level));
     return i;
 }
 
+static inline void enable_irq(void)
+{
+    int i;
+    asm volatile ("mov %1, %0 \n" /* Save a constant load from RAM */
+                  "ldc %0, sr \n" : "=&r"(i) : "i"(0));
+}
+
+#define disable_irq() \
+    ((void)set_irq_level(HIGHEST_IRQ_LEVEL))
+
+#define disable_irq_save() \
+    set_irq_level(HIGHEST_IRQ_LEVEL)
+
+#define restore_irq(i) \
+    ((void)set_irq_level(i))
+
 static inline uint16_t swap16(uint16_t value)
   /*
     result[15..8] = value[ 7..0];
diff --git a/firmware/test/i2c/main.c b/firmware/test/i2c/main.c
index 0d54da5..e094a0b 100644
--- a/firmware/test/i2c/main.c
+++ b/firmware/test/i2c/main.c
@@ -542,7 +542,7 @@
 
 
 
-    set_irq_level(0);
+    enable_irq();
 
 
 
diff --git a/firmware/test/kernel/main.c b/firmware/test/kernel/main.c
index 99642c8..cc0d93a 100644
--- a/firmware/test/kernel/main.c
+++ b/firmware/test/kernel/main.c
@@ -59,7 +59,7 @@
 
     kernel_init();
 
-    set_irq_level(0);
+    enable_irq();
 
     tick_add_task(testfunc);
     
diff --git a/firmware/thread.c b/firmware/thread.c
index 259a66a..2ac7f6e 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -399,7 +399,7 @@
 {
     PROC_CTL(CURRENT_CORE) = PROC_SLEEP;
     nop; nop; nop;
-    set_irq_level(IRQ_ENABLED);
+    enable_irq();
 }
 #else
 static inline void core_sleep(unsigned int core)
@@ -421,9 +421,6 @@
         "ldr    r1, [%[mbx], #0]           \n"
         "tst    r1, r0, lsr #2             \n"
         "bne    1b                         \n"
-        "mrs    r1, cpsr                   \n" /* Enable IRQ */
-        "bic    r1, r1, #0x80              \n"
-        "msr    cpsr_c, r1                 \n"
         :
         :  [ctl]"r"(&PROC_CTL(CPU)), [mbx]"r"(MBX_BASE), [c]"r"(core)
         : "r0", "r1");
@@ -443,10 +440,8 @@
 
     /* Wait for other processor to finish wake procedure */
     while (MBX_MSG_STAT & (0x1 << core));
-
-    /* Enable IRQ */
-    set_irq_level(IRQ_ENABLED);
 #endif /* ASM/C selection */
+    enable_irq();
 }
 #endif /* NUM_CORES */
 #elif CONFIG_CPU == PP5002
@@ -465,13 +460,11 @@
         "nop                  \n" /* nop's needed because of pipeline */
         "nop                  \n"
         "nop                  \n"
-        "mrs    r0, cpsr      \n" /* Enable IRQ */
-        "bic    r0, r0, #0x80 \n"
-        "msr    cpsr_c, r0    \n"
         :
         : [ctl]"r"(&PROC_CTL(CURRENT_CORE))
         : "r0"
     );
+    enable_irq();
 }
 #else
 /* PP5002 has no mailboxes - emulate using bytes */
@@ -503,9 +496,6 @@
         "ldrb   r0, [%[sem], #0]           \n"
         "cmp    r0, #0                     \n"
         "bne    1b                         \n"
-        "mrs    r0, cpsr                   \n" /* Enable IRQ */
-        "bic    r0, r0, #0x80              \n"
-        "msr    cpsr_c, r0                 \n"
         :
         : [sem]"r"(&core_semaphores[core]), [c]"r"(core),
           [ctl]"r"(&PROC_CTL(CPU))
@@ -530,8 +520,8 @@
     while (core_semaphores[core].intend_wake != 0);
 
     /* Enable IRQ */
-    set_irq_level(IRQ_ENABLED);
 #endif /* ASM/C selection */
+    enable_irq();
 }
 #endif /* NUM_CORES */
 #endif /* PP CPU type */
@@ -578,7 +568,7 @@
         : "r1", "r2", "r3");
 #else /* C version for reference */
     /* Disable interrupts - avoid reentrancy from the tick */
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     /* Signal intent to wake other processor - set stay awake */
     MBX_MSG_SET = 0x11 << othercore;
@@ -593,7 +583,7 @@
 
     /* Done with wake procedure */
     MBX_MSG_CLR = 0x1 << othercore;
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 #endif /* ASM/C selection */
 }
 #elif CONFIG_CPU == PP5002
@@ -631,7 +621,7 @@
     );
 #else /* C version for reference */
     /* Disable interrupts - avoid reentrancy from the tick */
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     /* Signal intent to wake other processor - set stay awake */
     core_semaphores[othercore].intend_wake = 1;
@@ -647,7 +637,7 @@
 
     /* Done with wake procedure */
     core_semaphores[othercore].intend_wake = 0;
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 #endif  /* ASM/C selection */
 }
 #endif /* CPU type */
@@ -775,7 +765,7 @@
 static inline void core_sleep(void)
 {
     #warning TODO: Implement core_sleep
-    set_irq_level(IRQ_ENABLED);
+    enable_irq();
 }
 #elif defined(CPU_TCC780X)
 static inline void core_sleep(void)
@@ -784,11 +774,9 @@
     asm volatile (
         "mov r0, #0                \n"
         "mcr p15, 0, r0, c7, c0, 4 \n" /* Wait for interrupt */
-        "mrs r0, cpsr              \n" /* Unmask IRQ at core level */
-        "bic r0, r0, #0x80         \n"
-        "msr cpsr_c, r0            \n"
         : : : "r0"
     );
+    enable_irq();
 }
 #elif CONFIG_CPU == IMX31L
 static inline void core_sleep(void)
@@ -796,17 +784,15 @@
     asm volatile (
         "mov r0, #0                \n"
         "mcr p15, 0, r0, c7, c0, 4 \n" /* Wait for interrupt */
-        "mrs r0, cpsr              \n" /* Unmask IRQ at core level */
-        "bic r0, r0, #0x80         \n"
-        "msr cpsr_c, r0            \n"
         : : : "r0"
     );
+    enable_irq();
 }
 #else
 static inline void core_sleep(void)
 {
     #warning core_sleep not implemented, battery life will be decreased
-    set_irq_level(0);
+    enable_irq();
 }
 #endif /* CONFIG_CPU == */
 
@@ -1706,14 +1692,14 @@
     while (next != NULL)
     {
         /* Check sleeping threads. Allow interrupts between checks. */
-        set_irq_level(0);
+        enable_irq();
 
         struct thread_entry *curr = next;
 
         next = curr->tmo.next;
 
         /* Lock thread slot against explicit wakeup */
-        set_irq_level(HIGHEST_IRQ_LEVEL);
+        disable_irq();
         LOCK_THREAD(curr);
 
         unsigned state = curr->state;
@@ -1956,7 +1942,7 @@
             check_tmo_threads();
         }
 
-        set_irq_level(HIGHEST_IRQ_LEVEL);
+        disable_irq();
         RTR_LOCK(core);
 
         thread = cores[core].running;
@@ -2018,7 +2004,7 @@
 #endif /* HAVE_PRIORITY_SCHEDULING */
 
             RTR_UNLOCK(core);
-            set_irq_level(0);
+            enable_irq();
             break;
         }
     }
@@ -2212,7 +2198,7 @@
 static struct thread_entry * find_empty_thread_slot(void)
 {
     /* Any slot could be on an interrupt-accessible list */
-    IF_COP( int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); )
+    IF_COP( int oldlevel = disable_irq_save(); )
     struct thread_entry *thread = NULL;
     int n;
 
@@ -2233,7 +2219,7 @@
         UNLOCK_THREAD(t);
     }
 
-    IF_COP( set_irq_level(oldlevel); ) /* Reenable interrups - this slot is
+    IF_COP( restore_irq(oldlevel); ) /* Reenable interrups - this slot is
                                           not accesible to them yet */
     return thread;
 }
@@ -2247,7 +2233,7 @@
 void core_idle(void)
 {
     IF_COP( const unsigned int core = CURRENT_CORE; )
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
     core_sleep(IF_COP(core));
 }
 
@@ -2277,7 +2263,7 @@
         return NULL;
     }
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
 
     /* Munge the stack to make it easy to spot stack overflows */
     stackptr = ALIGN_UP((uintptr_t)stack, sizeof (uintptr_t));
@@ -2338,7 +2324,7 @@
 
     UNLOCK_THREAD(thread);
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     return thread;
 }
@@ -2394,7 +2380,7 @@
         IF_COP( current->obj_cl = &thread->waiter_cl; )
         current->bqp = &thread->queue;
 
-        set_irq_level(HIGHEST_IRQ_LEVEL);
+        disable_irq();
         block_thread(current);
 
         corelock_unlock(&thread->waiter_cl);
@@ -2418,7 +2404,7 @@
     /* Cancel CPU boost if any */
     cancel_cpu_boost();
 
-    set_irq_level(HIGHEST_IRQ_LEVEL);
+    disable_irq();
 
     corelock_lock(&current->waiter_cl);
     LOCK_THREAD(current);
@@ -2503,7 +2489,7 @@
     if (thread == current)
         thread_exit(); /* Current thread - do normal exit */
 
-    oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    oldlevel = disable_irq_save();
 
     corelock_lock(&thread->waiter_cl);
     LOCK_THREAD(thread);
@@ -2521,7 +2507,7 @@
         /* Thread being killed - become a waiter */
         UNLOCK_THREAD(thread);
         corelock_unlock(&thread->waiter_cl);
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
         thread_wait(thread);
         return;
     }
@@ -2543,11 +2529,11 @@
         corelock_unlock(&thread->waiter_cl);
 
         UNLOCK_THREAD(thread);
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
 
         old_core = switch_core(new_core);
 
-        oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        oldlevel = disable_irq_save();
 
         corelock_lock(&thread->waiter_cl);
         LOCK_THREAD(thread);
@@ -2643,7 +2629,7 @@
     /* Removal complete - safe to unlock and reenable interrupts */
     corelock_unlock(&thread->waiter_cl);
     UNLOCK_THREAD(thread);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
 #if NUM_CORES > 1
     if (old_core < NUM_CORES)
@@ -2675,7 +2661,7 @@
 
     /* Thread could be on any list and therefore on an interrupt accessible
        one - disable interrupts */
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     LOCK_THREAD(thread);
 
@@ -2788,7 +2774,7 @@
 
     UNLOCK_THREAD(thread);
 
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 
     return old_base_priority;
 }
@@ -2815,14 +2801,14 @@
  */
 void thread_thaw(struct thread_entry *thread)
 {
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     LOCK_THREAD(thread);
 
     if (thread->state == STATE_FROZEN)
         core_schedule_wakeup(thread);
 
     UNLOCK_THREAD(thread);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 /*---------------------------------------------------------------------------
@@ -2850,14 +2836,14 @@
         return core;
     }
 
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
     LOCK_THREAD(current);
 
     if (current->name == THREAD_DESTRUCT)
     {
         /* Thread being killed - deactivate and let process complete */
         UNLOCK_THREAD(current);
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
         thread_wait(current);
         /* Should never be reached */
         THREAD_PANICF("switch_core->D:*R", current);
diff --git a/firmware/usb.c b/firmware/usb.c
index 2971ab7..c33b62f 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -568,10 +568,10 @@
 #ifdef IRIVER_H300_SERIES
     int irqlevel;
     logf("usb_charging_enable(%s)\n", on ? "on" : "off" );
-    irqlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    irqlevel = disable_irq_save();
     pcf50606_set_usb_charging(on);
     rc = on;
-    (void)set_irq_level(irqlevel);
+    restore_irq(irqlevel);
 #else
     /* TODO: implement it for other targets... */
     (void)on;
diff --git a/flash/bootbox/main.c b/flash/bootbox/main.c
index 5cc4bb6..1f459b7 100644
--- a/flash/bootbox/main.c
+++ b/flash/bootbox/main.c
@@ -156,7 +156,7 @@
     buffer_init();
     lcd_init();
     show_logo();
-    set_irq_level(0);
+    enable_irq();
     adc_init();
     usb_init();
     button_init();
diff --git a/uisimulator/sdl/system-sdl.h b/uisimulator/sdl/system-sdl.h
index c5e7d40..08f702d 100644
--- a/uisimulator/sdl/system-sdl.h
+++ b/uisimulator/sdl/system-sdl.h
@@ -24,6 +24,19 @@
 #define HIGHEST_IRQ_LEVEL 1
 
 int set_irq_level(int level);
+
+#define disable_irq() \
+    ((void)set_irq_level(HIGHEST_IRQ_LEVEL))
+
+#define enable_irq()  \
+    ((void)set_irq_level(0))
+
+#define disable_irq_save() \
+    set_irq_level(HIGHEST_IRQ_LEVEL)
+
+#define restore_irq(level) \
+    ((void)set_irq_level(level))
+
 void sim_enter_irq_handler(void);
 void sim_exit_irq_handler(void);
 bool sim_kernel_init(void);
diff --git a/uisimulator/sdl/thread-sdl.c b/uisimulator/sdl/thread-sdl.c
index 78a66f7..5aae9a4 100644
--- a/uisimulator/sdl/thread-sdl.c
+++ b/uisimulator/sdl/thread-sdl.c
@@ -246,7 +246,7 @@
 {
     struct thread_entry *current = cores[CURRENT_CORE].running;
 
-    set_irq_level(0);
+    enable_irq();
 
     switch (current->state)
     {
@@ -266,9 +266,9 @@
         SDL_SemWait(current->context.s);
         SDL_LockMutex(m);
 
-        oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        oldlevel = disable_irq_save();
         current->state = STATE_RUNNING;
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
         break;
         } /* STATE_BLOCKED: */
 
@@ -280,7 +280,7 @@
         result = SDL_SemWaitTimeout(current->context.s, current->tmo_tick);
         SDL_LockMutex(m);
 
-        oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+        oldlevel = disable_irq_save();
 
         if (current->state == STATE_BLOCKED_W_TMO)
         {
@@ -303,7 +303,7 @@
                 SDL_SemTryWait(current->context.s);
         }
 
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
         break;
         } /* STATE_BLOCKED_W_TMO: */
 
@@ -505,7 +505,7 @@
     SDL_Thread *t;
     SDL_sem *s;
 
-    int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+    int oldlevel = disable_irq_save();
 
     if (thread == NULL)
     {
@@ -547,12 +547,12 @@
     {
         /* Do a graceful exit - perform the longjmp back into the thread
            function to return */
-        set_irq_level(oldlevel);
+        restore_irq(oldlevel);
         longjmp(thread_jmpbufs[current - threads], 1);
     }
 
     SDL_KillThread(t);
-    set_irq_level(oldlevel);
+    restore_irq(oldlevel);
 }
 
 void thread_exit(void)