diff --git a/apps/codecs.c b/apps/codecs.c
index 25cc659..b9b53cf 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -55,7 +55,7 @@
 #define LOGF_ENABLE
 #include "logf.h"
 
-#if (CONFIG_PLATFORM & PLATFORM_SDL)
+#if (CONFIG_PLATFORM & PLATFORM_SDL) && !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 #define PREFIX(_x_) sim_ ## _x_
 #else
 #define PREFIX(_x_) _x_
diff --git a/apps/main.c b/apps/main.c
index 5f2c9e5..66ab714 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -362,7 +362,39 @@ static void init(void)
     sb_skin_init();
     viewportmanager_init();
 
+#if defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
+    disk_init_subsystem();
+    int rc = storage_init();
+    if(rc)
+        panicf("storage error: %d", rc);
+    rc = disk_mount_all();
+    if(rc <= 0)
+    {
+        printf("disk_mount error: %d\n", rc);
+        lcd_clear_display();
+        lcd_puts(0, 0, "No partition");
+        lcd_puts(0, 1, "found.");
+        lcd_puts(0, 2, "Continue ?");
+
+        lcd_update();
+
+        while(true)
+        {
+            int button = get_action(CONTEXT_YESNOSCREEN, HZ*5);
+            switch (button)
+            {
+                case ACTION_YESNO_ACCEPT: goto Lcontinue;
+                case ACTION_NONE: continue;
+                default: exit(1);
+            }
+        }
+
+        Lcontinue:
+        printf("continue without partition !\n");
+    }
+#else /* defined(ROCKBOX_SIMULATE_STORAGE_LAYER) */
     storage_init();
+#endif
     settings_reset();
     settings_load(SETTINGS_ALL);
     settings_apply(true);
diff --git a/apps/plugin.c b/apps/plugin.c
index 9e08951..2f3644b 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -59,7 +59,7 @@
 #include "usbstack/usb_hid.h"
 #endif
 
-#if (CONFIG_PLATFORM & PLATFORM_SDL)
+#if (CONFIG_PLATFORM & PLATFORM_SDL) && !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 #define PREFIX(_x_) sim_ ## _x_
 #else
 #define PREFIX
@@ -936,7 +936,7 @@ static int open_wrapper(const char* pathname, int flags, ...)
 /* we don't have an 'open' function. it's a define. and we need
  * the real file_open, hence PREFIX() doesn't work here */
     int fd;
-#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
+#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
     if (flags & O_CREAT)
     {
         va_list ap;
diff --git a/firmware/SOURCES b/firmware/SOURCES
index ac1a3e1..e703759 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -96,7 +96,8 @@ common/crc32.c
 #ifdef MI4_FORMAT
 common/crc32-mi4.c
 #endif
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || \
+    ((CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(ROCKBOX_SIMULATE_STORAGE_LAYER))
 common/dir_uncached.c
 common/file.c
 common/disk.c
@@ -186,7 +187,8 @@ drivers/touchscreen.c
 
 
 /* Storage */
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || \
+    ((CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(ROCKBOX_SIMULATE_STORAGE_LAYER))
 #if (CONFIG_STORAGE & STORAGE_MMC)
 drivers/ata_mmc.c
 #endif
diff --git a/firmware/common/disk.c b/firmware/common/disk.c
index 6be9b47..0b51386 100644
--- a/firmware/common/disk.c
+++ b/firmware/common/disk.c
@@ -192,7 +192,6 @@ int disk_mount(int drive)
         if (memchr(fat_partition_types, pinfo[i].type,
                    sizeof(fat_partition_types)) == NULL)
             continue;  /* not an accepted partition type */
-
 #ifdef MAX_LOG_SECTOR_SIZE
         int j;
         
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index de579f7..321db5a 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -362,14 +362,12 @@ int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector)
         + rootdirsectors
 #endif
         + fat_bpb->bpb_numfats * fat_bpb->fatsize;
-
     /* Determine FAT type */
     datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
     if (fat_bpb->bpb_secperclus)
         fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
     else
        return -2;
-
 #ifdef TEST_FAT
     /*
       we are sometimes testing with "illegally small" fat32 images,
diff --git a/firmware/export/config/sim.h b/firmware/export/config/sim.h
index 066201a..fff9d49 100644
--- a/firmware/export/config/sim.h
+++ b/firmware/export/config/sim.h
@@ -30,12 +30,14 @@
 
 #undef AMS_OF_SIZE
 
+#if !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 #undef HAVE_MULTIDRIVE
 #undef NUM_DRIVES
 #undef HAVE_HOTSWAP
 #undef HAVE_HOTSWAP_STORAGE_AS_MAIN
 
 #undef CONFIG_STORAGE
+#endif /* !defined(ROCKBOX_SIMULATE_STORAGE_LAYER) */
 
 #undef CONFIG_USBOTG
 
diff --git a/firmware/export/sd.h b/firmware/export/sd.h
index c798f54..f207421 100644
--- a/firmware/export/sd.h
+++ b/firmware/export/sd.h
@@ -36,7 +36,6 @@ void sd_sleepnow(void);
 bool sd_disk_is_active(void);
 int  sd_soft_reset(void);
 int  sd_init(void);
-void sd_close(void);
 int  sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf);
 int  sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf);
 void sd_spin(void);
diff --git a/firmware/include/dir_uncached.h b/firmware/include/dir_uncached.h
index 5c7ed14..e04ad94 100644
--- a/firmware/include/dir_uncached.h
+++ b/firmware/include/dir_uncached.h
@@ -34,7 +34,7 @@ struct dirinfo {
 #include <stdbool.h>
 #include "file.h"
 
-#if (CONFIG_PLATFORM & PLATFORM_SDL)
+#if (CONFIG_PLATFORM & PLATFORM_SDL) && !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 #define dirent_uncached sim_dirent
 #define DIR_UNCACHED SIM_DIR
 #define opendir_uncached sim_opendir
@@ -56,7 +56,8 @@ struct dirent_uncached {
 #include "fat.h"
 
 typedef struct {
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || \
+    ((CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(ROCKBOX_SIMULATE_STORAGE_LAYER))
     bool busy;
     long startcluster;
     struct fat_dir fatdir;
diff --git a/firmware/include/file.h b/firmware/include/file.h
index 8711124..18eb211 100644
--- a/firmware/include/file.h
+++ b/firmware/include/file.h
@@ -37,7 +37,7 @@
 #define MAX_OPEN_FILES 11
 
 #if !defined(PLUGIN) && !defined(CODEC)
-#if (CONFIG_PLATFORM & PLATFORM_SDL)
+#if (CONFIG_PLATFORM & PLATFORM_SDL) && !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 #define open(x, ...) sim_open(x, __VA_ARGS__)
 #define creat(x,m) sim_creat(x,m)
 #define remove(x) sim_remove(x)
@@ -53,6 +53,20 @@ extern int sim_creat(const char *pathname, mode_t mode);
 extern int sim_open(const char *pathname, int flags, ...);
 #endif
 
+/* Avoid interference with system lseek, read, write */
+#ifdef ROCKBOX_SIMULATE_STORAGE_LAYER
+#define lseek rockbox_lseek
+#define read rockbox_read
+#define write rockbox_write
+#define close rockbox_close
+#define open(x,y,...) file_open(x,y)
+#define file_open rockbox_open
+#define fsync rockbox_fsync
+#define remove rockbox_remove
+#define rename rockbox_rename
+#define ftruncate rockbox_ftruncate
+#endif
+
 typedef int (*open_func)(const char* pathname, int flags, ...);
 typedef ssize_t (*read_func)(int fd, void *buf, size_t count);
 typedef int (*creat_func)(const char *pathname, mode_t mode);
@@ -66,16 +80,13 @@ extern int fsync(int fd);
 extern ssize_t read(int fd, void *buf, size_t count);
 extern off_t lseek(int fildes, off_t offset, int whence);
 extern int file_creat(const char *pathname);
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && !defined(__PCTOOL__)
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && !defined(__PCTOOL__) && !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 /* posix compatibility function */
 static inline int creat(const char *pathname, mode_t mode)
 {
     (void)mode;
     return file_creat(pathname);
 }
-#if !defined(CODEC) && !defined(PLUGIN)
-#define open(x, y, ...) file_open(x,y)
-#endif
 #endif
 extern ssize_t write(int fd, const void *buf, size_t count);
 extern int remove(const char* pathname);
diff --git a/uisimulator/common/SOURCES b/uisimulator/common/SOURCES
index fd256c5..d064100 100644
--- a/uisimulator/common/SOURCES
+++ b/uisimulator/common/SOURCES
@@ -10,7 +10,11 @@ backlight-sim.c
 #endif
 
 io.c
+debug.c
 sim_tasks.c
 /* this is still needed for application since it has some stubs */
 powermgmt-sim.c
 stubs.c
+#if defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
+storage.c
+#endif
diff --git a/uisimulator/common/debug.c b/uisimulator/common/debug.c
new file mode 100644
index 0000000..d33ab31
--- /dev/null
+++ b/uisimulator/common/debug.c
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifndef _MSC_VER
+#include <dirent.h>
+#include <unistd.h>
+#else
+#include "dir-win32.h"
+#endif
+
+#include "debug.h"
+#include "config.h"
+
+#ifdef WIN32
+static unsigned old_cp;
+
+void debug_exit(void)
+{
+    /* Reset console output codepage */
+    SetConsoleOutputCP(old_cp);
+}
+
+void debug_init(void)
+{
+    old_cp = GetConsoleOutputCP();
+    /* Set console output codepage to UTF8. Only works
+     * correctly when the console uses a truetype font. */
+    SetConsoleOutputCP(65001);
+    atexit(debug_exit);
+}
+#else
+void debug_init(void)
+{
+    /* nothing to be done */
+}
+#endif
+
+void debugf(const char *fmt, ...)
+{
+    va_list ap;
+    va_start( ap, fmt );
+    vfprintf( stderr, fmt, ap );
+    va_end( ap );
+}
+
+void ldebugf(const char* file, int line, const char *fmt, ...)
+{
+    va_list ap;
+    va_start( ap, fmt );
+    fprintf( stderr, "%s:%d ", file, line );
+    vfprintf( stderr, fmt, ap );
+    va_end( ap );
+}
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c
index b367eb1..39b6f93 100644
--- a/uisimulator/common/io.c
+++ b/uisimulator/common/io.c
@@ -485,6 +485,7 @@ long sim_filesize(int fd)
 #endif
 }
 
+#if !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
 {
 #ifdef HAVE_MULTIVOLUME
@@ -526,6 +527,7 @@ void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
             *free = 0;
     }
 }
+#endif
 
 int sim_fsync(int fd)
 {
diff --git a/uisimulator/common/storage.c b/uisimulator/common/storage.c
new file mode 100644
index 0000000..abb6070
--- /dev/null
+++ b/uisimulator/common/storage.c
@@ -0,0 +1,244 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2010 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <time.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "debug.h"
+
+#include "storage.h"
+#include "fat.h"
+
+#ifdef HAVE_HOTSWAP
+#define IF_HOTSWAP(a) a
+bool sd_removable(IF_MV_NONVOID(int drive));
+bool sd_present(IF_MV_NONVOID(int drive));
+#else
+#define IF_HOTSWAP(a)
+#endif
+
+/* ugly but allows perfect simulation in all context */
+#define DEFINE_FORWARD_FUNCTION2(subsystem, subsystem_str) \
+    /* xx_init() function, trivial */ \
+    int subsystem##_init(void) \
+    { \
+        return subsystem_init(subsystem_str); \
+    } \
+    /* this gets nasty, hotswap support, in conditional macro of course :) */ \
+    IF_HOTSWAP( \
+        bool subsystem##_removable(IF_MV_NONVOID(int drive)) \
+            { \
+                return subsystem_removable(IF_MV2(drive,) subsystem_str); \
+            } \
+        bool subsystem##_present(IF_MV_NONVOID(int drive)) \
+            { \
+                return subsystem_present(IF_MV2(drive,) subsystem_str); \
+            } \
+        ) \
+    /* read/write support */ \
+    int subsystem##_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) \
+    { \
+        return subsystem_read_sectors(IF_MD2(drive,) start, count, buf, subsystem_str); \
+    } \
+    int subsystem##_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) \
+    { \
+        return subsystem_write_sectors(IF_MD2(drive,) start, count, buf, subsystem_str); \
+    }
+
+/* add another layer, we identify each subsystem using a pointer to a constant string */
+#define DEFINE_FORWARD_FUNCTION(subsystem) \
+    DEFINE_FORWARD_FUNCTION2(subsystem, #subsystem)
+
+/* actual simulation functions */
+
+/* keep a nice table of drives,
+ * consider first driver as fixed, all other as removable but not present,
+ * assign them to the first subsystem which calls init */
+struct drive_t
+{
+    const char *subsystem; /* subsystem */
+    const char *file; /* file used as storage */
+    int file_fd; /* file descriptor */
+    bool removable;
+    unsigned long sec_count; /* sector count */
+};
+
+static struct drive_t drives[NUM_DRIVES];
+static bool first_time_init = true;
+
+/* not nice but allows customization, see definition in target/hosted/system-sdl.c */
+extern const char *sim_root_dir;
+
+#define DEFAULT_SIMULATOR_STOR_FILE     "simdisk.raw"
+
+static int subsystem_init_drive(int drive, const char *file, bool removable, const char *subsystem)
+{
+    drives[drive].subsystem = subsystem;
+    drives[drive].removable = removable;
+    drives[drive].file = file;
+    drives[drive].file_fd = -1;
+    DEBUGF("give drive %d to %s subsystem, map to %s, %sremovable\n", drive, subsystem, file, removable ? "" : "not ");
+
+    if(file != NULL)
+    {
+        /* open file */
+        drives[drive].file_fd = open(file, O_RDWR);
+        if(drives[drive].file_fd == -1)
+        {
+            DEBUGF("  cannot open file: %s\n", strerror(errno));
+            return errno;
+        }
+        /* check that the size is a multiple of SECTOR_SIZE */
+        struct stat st;
+        if(fstat(drives[drive].file_fd, &st))
+        {
+            DEBUGF("  cannot stat file: %s\n", strerror(errno));
+            return errno;
+        }
+        if(st.st_size % SECTOR_SIZE)
+        {
+            DEBUGF("  file size is not a multiple of SECTOR_SIZE (size=%lu, sec=%lu)\n",
+                (unsigned long)st.st_size, SECTOR_SIZE);
+            return -1;
+        }
+        drives[drive].sec_count = st.st_size / SECTOR_SIZE;
+        DEBUGF("  file has %ld sectors (sector size is %ld)\n", drives[drive].sec_count, SECTOR_SIZE);
+    }
+    
+    return 0;
+}
+
+static int subsystem_init(const char *subsystem)
+{
+    int i, rc;
+    
+    if(!first_time_init)
+    {
+        DEBUGF("ignore %s subsystem init", subsystem);
+        return 0;
+    }
+    
+    /* init first drive */
+    rc = subsystem_init_drive(0, sim_root_dir != NULL ? sim_root_dir : DEFAULT_SIMULATOR_STOR_FILE, false, subsystem);
+    if(rc) return rc;
+
+    for(i = 1; i < NUM_DRIVES; i++)
+    {
+        rc = subsystem_init_drive(i, NULL, true, subsystem);
+        if(rc) return rc;
+    }
+
+    return 0;
+}
+
+#ifdef HAVE_HOTSWAP
+static bool subsystem_present(IF_MV2(int drive,) const char *subsystem)
+{
+    (void) subsystem;
+    #ifndef HAVE_MULTIDRIVE
+    int drive = 0;
+    #endif
+    return drives[drive].file_fd != -1;
+}
+
+static bool subsystem_removable(IF_MV2(int drive,) const char *subsystem)
+{
+    (void) subsystem;
+    #ifndef HAVE_MULTIDRIVE
+    int drive = 0;
+    #endif
+    return drives[drive].removable;
+}
+#endif /* HAVE_HOTSWAP */
+
+static int subsystem_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf, const char *subsystem)
+{
+    (void) subsystem;
+    #ifndef HAVE_MULTIDRIVE
+    int drive = 0;
+    #endif
+    if(drives[drive].file_fd == -1)
+        return -1;
+    /* FIXME: check return value */
+    if(lseek(drives[drive].file_fd, start * SECTOR_SIZE, SEEK_SET) == (off_t)-1)
+    {
+        DEBUGF("subsystem lseek failed\n");
+        perror("lseek:");
+        return -1;
+    }
+    int ret = read(drives[drive].file_fd, buf, SECTOR_SIZE * count);
+    if(ret == -1)
+    {
+        DEBUGF("subsystem read failed\n");
+        perror("read:");
+        return -1;
+    }
+    else
+        return 0;
+}
+
+static int subsystem_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf, const char *subsystem)
+{
+    (void) subsystem;
+    #ifndef HAVE_MULTIDRIVE
+    int drive = 0;
+    #endif
+    if(drives[drive].file_fd == -1)
+        return -1;
+    /* FIXME: check return value */
+    if(lseek(drives[drive].file_fd, start * SECTOR_SIZE, SEEK_SET) == (off_t)-1)
+    {
+        DEBUGF("subsystem lseek failed\n");
+        perror("lseek:");
+        return -1;
+    }
+    int ret = write(drives[drive].file_fd, buf, SECTOR_SIZE * count);
+    if(ret == -1)
+    {
+        DEBUGF("subsystem write failed\n");
+        perror("read:");
+        return -1;
+    }
+    else
+        return 0;
+}
+
+/* define everything for each subsystem needed */
+#if (CONFIG_STORAGE & STORAGE_ATA)
+    DEFINE_FORWARD_FUNCTION(ata)
+#endif
+
+#if (CONFIG_STORAGE & STORAGE_MMC)
+    DEFINE_FORWARD_FUNCTION(mmc)
+#endif
+
+#if (CONFIG_STORAGE & STORAGE_SD)
+    DEFINE_FORWARD_FUNCTION(sd)
+#endif
+
+#if (CONFIG_STORAGE & STORAGE_NAND)
+    DEFINE_FORWARD_FUNCTION(nand)
+#endif
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index a9011b9..83c6da1 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -33,8 +33,6 @@
 
 #include "ata.h" /* for volume definitions */
 
-static bool storage_spinning = false;
-
 #if CONFIG_CODEC != SWCODEC
 void audio_set_buffer_margin(int seconds)
 {
@@ -42,6 +40,9 @@ void audio_set_buffer_margin(int seconds)
 }
 #endif
 
+#if !defined(ROCKBOX_SIMULATE_STORAGE_LAYER)
+static bool storage_spinning = false;
+
 int fat_startsector(void)
 {
     return 63;
@@ -128,6 +129,8 @@ void storage_spindown(int s)
     storage_spinning = false;
 }
 
+#endif /* !defined(ROCKBOX_SIMULATE_STORAGE_LAYER) */
+
 void rtc_init(void)
 {
 }
