OK, I had a look at the hostfs module from arcem, got it to build, then
did some rather improper things with it to make it work with RPCEm.

So, this is the latest version of my patch.  It returns BADDISC if a
disc does not exist, and DISCPROT if a disc is readonly.

The attached hostfs.s will generate a RISC OS error dialog box if one of
these two errors is returned from hostfs.

I have totally zero knowledge of ARM assembly, so hostfs.s is probably a
bit controversial.  I tried to make a routine called "handle_errors" as
a generic error handler, but it all went horribly wrong.  Still, I'm
sure somebody can do a better job.

James
Index: rpc.cfg
===================================================================
--- rpc.cfg	(revision 137)
+++ rpc.cfg	(working copy)
@@ -8,3 +8,13 @@
 cpu_type = SA110
 mem_size = 16
 ipaddress = 172.31.0.1
+hostfs.drive0.name = Boot
+hostfs.drive0.path = ./hostfs
+hostfs.drive0.permissions = read,write
+hostfs.drive1.name = System
+hostfs.drive1.path = /
+hostfs.drive1.permissions = read
+hostfs.drive2.name = Home
+hostfs.drive2.path = ~/rpcemu
+hostfs.drive2.permissions = read,write
+
Index: src/hostfs.c
===================================================================
--- src/hostfs.c	(revision 137)
+++ src/hostfs.c	(working copy)
@@ -28,6 +28,8 @@
 #include "mem.h"
 #include "hostfs.h"
 
+#define WANT_DEFAULT_DISC
+
 typedef int bool;
 
 #define true  ((bool) 1)
@@ -55,11 +57,16 @@
 
 enum FILECORE_ERROR {
   FILECORE_ERROR_BADRENAME   = 0xb0,
+  FILECORE_ERROR_NOPRIV      = 0xba,
   FILECORE_ERROR_TOOMANYOPEN = 0xc0, /* Too many open files */
   FILECORE_ERROR_OPEN        = 0xc2, /* File open */
   FILECORE_ERROR_LOCKED      = 0xc3,
   FILECORE_ERROR_EXISTS      = 0xc4, /* Already exists */
   FILECORE_ERROR_DISCFULL    = 0xc6,
+  FILECORE_ERROR_DISCERR     = 0xc7,
+  FILECORE_ERROR_BADDISC     = 0xc8,
+  FILECORE_ERROR_DISCPROT    = 0xc9,
+  FILECORE_ERROR_NOTFOUND    = 0xd6,
 };
 
 enum RISC_OS_FILE_TYPE {
@@ -74,13 +81,14 @@
   ARMword exec;
   ARMword length;
   ARMword attribs;
+  HOSTFS_Discs *disc_info;
 } risc_os_object_info;
 
 /* TODO Avoid duplicate macro with extnrom.c */
 #define ROUND_UP_TO_4(x) (((x) + 3) & (~3))
 
-char HOSTFS_ROOT[512];
-//#define HOSTFS_ROOT "./hostfs"
+#define MAX_HOSTFS_DISCS 10
+HOSTFS_Discs hostfs_discs[MAX_HOSTFS_DISCS];
 
 #define MAX_OPEN_FILES 255
 
@@ -110,6 +118,72 @@
 }
 #endif
 
+int hostfs_initialise()
+{
+    memset(&hostfs_discs, 0, sizeof(hostfs_discs));
+
+    return 0;
+}
+
+int add_hostfs_disc(const char *name, const char *path, const char *permissions)
+{
+    int i;
+    char *c;
+
+    for (i = 0; i < sizeof(hostfs_discs) / sizeof(HOSTFS_Discs); i++) {
+        if (strlen(hostfs_discs[i].disc_name) == 0) {
+            strncpy(hostfs_discs[i].disc_name, name, sizeof(hostfs_discs[i].disc_name)-1);
+            if (*path == '~')
+                rpcemu_os_expand_home_path(path, hostfs_discs[i].hostfs_root, sizeof(hostfs_discs[i].hostfs_root));
+            else
+                strncpy(hostfs_discs[i].hostfs_root, path, sizeof(hostfs_discs[i].hostfs_root)-1);
+            c = hostfs_discs[i].hostfs_root;
+            while (*c != '\0') {
+                if (*c == '\\') {
+                    *c = '/';
+                }
+                c++;
+            }
+            if (strstr(permissions, "read"))
+                hostfs_discs[i].permissions |= HOSTFS_DISC_READABLE;
+            if (strstr(permissions, "write"))
+                hostfs_discs[i].permissions |= HOSTFS_DISC_WRITEABLE;
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int get_max_hostfs_discs()
+{
+    return MAX_HOSTFS_DISCS;
+}
+
+static HOSTFS_Discs *get_hostfs_disc_info_by_name(const char *disc_name)
+{
+    unsigned int i;
+    for (i = 0; i < sizeof(hostfs_discs) / sizeof(HOSTFS_Discs); i++) {
+       if (strlen(hostfs_discs[i].disc_name) == 0)
+          break;
+       if (strcmp(disc_name, hostfs_discs[i].disc_name) == 0)
+          return &hostfs_discs[i];
+    }
+
+    return NULL;
+}
+
+static HOSTFS_Discs *get_hostfs_disc_info_by_index(int index)
+{
+    if (index >= MAX_HOSTFS_DISCS || index < 0)
+        return NULL;
+
+    if (strlen(hostfs_discs[index].disc_name))
+        return &hostfs_discs[index];
+
+    return NULL;
+}
+
 /**
  * @param buffer_size_needed Required buffer
  */
@@ -257,7 +331,6 @@
 static void
 name_host_to_riscos(const char *object_name, size_t len, char *riscos_name)
 {
-        char *s=riscos_name,*s2=object_name;
   assert(object_name);
   assert(riscos_name);
 
@@ -291,7 +364,8 @@
 static void
 hostfs_read_object_info(const char *host_pathname,
                         char *ro_leaf,
-                        risc_os_object_info *object_info)
+                        risc_os_object_info *object_info,
+                        HOSTFS_Discs *disc_info)
 {
   struct stat info;
   ARMword file_type;
@@ -305,6 +379,7 @@
   assert(ro_leaf);
   assert(object_info);
 
+  object_info->disc_info = disc_info;
   if (stat(host_pathname, &info)) {
     /* Error reading info about the object */
 
@@ -417,7 +492,8 @@
                  int case_sensitive,
                  char *host_name,
                  char *ro_leaf,
-                 risc_os_object_info *object_info)
+                 risc_os_object_info *object_info,
+                 HOSTFS_Discs *disc_info)
 {
   DIR *d;
   struct dirent *entry;
@@ -427,6 +503,7 @@
   assert(host_name && ro_leaf);
   assert(object_info);
 
+  object_info->disc_info = disc_info;
   d = opendir(host_dir_path);
   if (!d) {
     switch (errno) {
@@ -456,7 +533,7 @@
     strcat(entry_path, "/");
     strcat(entry_path, entry->d_name);
 
-    hostfs_read_object_info(entry_path, ro_leaf, object_info);
+    hostfs_read_object_info(entry_path, ro_leaf, object_info, disc_info);
 
     /* Ignore entries we can not read information about,
        or which are neither regular files or directories */
@@ -514,13 +591,20 @@
   char component_name[PATH_MAX]; /* working Host component */
   char *component;
   const char *ro_path_orig = ro_path;
+  char disc_name[80] = "";
+  int disc_index = -1;
+  char *p;
+  char *endptr;
+  HOSTFS_Discs *hostfs_disc_info = NULL;
 
   assert(ro_path);
   assert(host_pathname && ro_leaf);
   assert(object_info);
 
-  assert(ro_path[0] == '$');
+  assert(ro_path[0] == '$' || ro_path[0] == ':');
 
+  object_info->disc_info = NULL;
+
   /* Initialise Host pathname */
   host_pathname[0] = '\0';
 
@@ -532,10 +616,51 @@
   while (*ro_path) {
                 //rpclog("%i %c\n",*ro_path,*ro_path);
     switch (*ro_path) {
+    case ':':
+      p = strchr(ro_path, '$');
+      if (!p) {
+        object_info->type = OBJECT_TYPE_NOT_FOUND;
+        dbug_hostfs("DISC NOT FOUND %s %s\n",host_pathname,ro_leaf);
+        return;
+      }
+      p--;
+      if (*p != '.') {
+        object_info->type = OBJECT_TYPE_NOT_FOUND;
+        dbug_hostfs("DISC NOT FOUND %s %s\n",host_pathname,ro_leaf);
+        return;
+      }
+      ro_path++;
+      memset(disc_name, 0, sizeof(disc_name));
+      strncpy(disc_name, ro_path, p-ro_path>sizeof(disc_name)?sizeof(disc_name)-1:p-ro_path);
+      disc_index = strtoul(disc_name, &endptr, 10);
+      if (disc_name == endptr) {
+          // disc name is a text based name, not an index
+          disc_index = -1;
+      }
+
+
+      ro_path = p;
+      break;
     case '$':
-      strcat(host_pathname, HOSTFS_ROOT);
+#ifdef WANT_DEFAULT_DISC
+      // We have neither have a disc name nor index.  Use the default disc.
+      if (disc_name[0] == '\0' && disc_index == -1)
+      {
+          disc_index = 0;
+      }
+#endif
+      if (disc_index != -1) {
+          hostfs_disc_info = get_hostfs_disc_info_by_index(disc_index);
+      } else {
+          hostfs_disc_info = get_hostfs_disc_info_by_name(disc_name);
+      }
+      if (!hostfs_disc_info) {
+         object_info->type = OBJECT_TYPE_NOT_FOUND;
+         return;
+      }
+      strcat(host_pathname, hostfs_disc_info->hostfs_root);
 
-      hostfs_read_object_info(host_pathname, ro_leaf, object_info);
+      hostfs_read_object_info(host_pathname, ro_leaf, object_info, hostfs_disc_info);
       if (object_info->type == OBJECT_TYPE_NOT_FOUND) {
                 dbug_hostfs("OBJECT NOT FOUND %s %s\n",host_pathname,ro_leaf);
         return;
@@ -552,7 +677,7 @@
         *component = '\0'; /* add terminator */
 
         hostfs_path_scan(host_pathname, component_name, 0,
-                         host_name, ro_leaf, object_info);
+                         host_name, ro_leaf, object_info, hostfs_disc_info);
         if (object_info->type == OBJECT_TYPE_NOT_FOUND) {
           /* This component of the path is invalid */
           /* Return what we have of the host_pathname */
@@ -594,7 +719,7 @@
     *component = '\0'; /* add terminator */
 
     hostfs_path_scan(host_pathname, component_name, preserve_leaf,
-                     host_name, ro_leaf, object_info);
+                     host_name, ro_leaf, object_info, hostfs_disc_info);
     if (object_info->type == OBJECT_TYPE_NOT_FOUND) {
       /* This component of the path is invalid */
       /* Return what we have of the host_pathname */
@@ -935,6 +1060,7 @@
 {
   const unsigned BUFSIZE = MINIMUM_BUFFER_SIZE;
   char ro_path[PATH_MAX], host_pathname[PATH_MAX], ro_leaf[PATH_MAX];
+  char tmp_pathname[PATH_MAX];
   risc_os_object_info object_info;
   char host_path[PATH_MAX];
   FILE *f;
@@ -961,12 +1087,19 @@
   riscos_path_to_host(ro_path, host_path);
   dbug_hostfs("\tPATH2 = %s\n", host_path);
 
-  hostfs_path_process(ro_path, 0, host_pathname, ro_leaf, &object_info);
+  hostfs_path_process(ro_path, 0, tmp_pathname, ro_leaf, &object_info);
   dbug_hostfs("\tro_path = \"%s\"\n", ro_path);
   if (object_info.type != OBJECT_TYPE_NOT_FOUND) {
     dbug_hostfs("\thost_pathname = \"%s\"\n\tro_leaf = \"%s\"\n",
                 host_pathname, ro_leaf);
   }
+  if (!object_info.disc_info) {
+    state->Reg[9] = FILECORE_ERROR_BADDISC;
+	return;
+  } else if (!(object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE)) {
+    state->Reg[9] = FILECORE_ERROR_DISCPROT;
+    return;
+  }
 
   if (object_info.type == OBJECT_TYPE_DIRECTORY) {
     /* This should never occur as RISC OS checks whether a directory exists
@@ -1053,22 +1186,25 @@
     {
       char new_pathname[PATH_MAX];
 
-      path_construct(host_pathname, new_pathname, sizeof(new_pathname),
-                     state->Reg[2], state->Reg[3]);
+      if (object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE)) {
+        path_construct(host_pathname, new_pathname, sizeof(new_pathname),
+                       state->Reg[2], state->Reg[3]);
 
-      if (rename(host_pathname, new_pathname)) {
-        /* TODO handle error in renaming */
-      }
+        if (rename(host_pathname, new_pathname)) {
+          /* TODO handle error in renaming */
+        }
 
-      /* Update timestamp if necessary */
-      if ((state->Reg[2] & 0xfff00000u) == 0xfff00000u) {
-        struct utimbuf t;
+        /* Update timestamp if necessary */
+        if ((state->Reg[2] & 0xfff00000u) == 0xfff00000u) {
+          struct utimbuf t;
 
-        t.modtime = hostfs_adfs2host_time(state->Reg[2], state->Reg[3]);
-        t.actime = t.modtime;
-        utime(new_pathname, &t);
-        /* TODO handle error in utime() */
+          t.modtime = hostfs_adfs2host_time(state->Reg[2], state->Reg[3]);
+          t.actime = t.modtime;
+          utime(new_pathname, &t);
+          /* TODO handle error in utime() */
+        }
       }
+      /* TOD: handle permission error */
     }
 
     /* TODO handle new attribs */
@@ -1131,6 +1267,9 @@
   /* TODO Ensure we do not try to delete the root object: i.e. $ */
 
   hostfs_path_process(ro_path, 0, host_pathname, ro_leaf, &object_info);
+  if (!(object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE))) {
+    return;
+  }
 
   state->Reg[0] = object_info.type;
 
@@ -1170,9 +1309,12 @@
 {
   const unsigned BUFSIZE = MINIMUM_BUFFER_SIZE;
   char ro_path[PATH_MAX];
+  char ro_leaf[PATH_MAX];
   char host_path[PATH_MAX];
+  char tmp_path[PATH_MAX];
   FILE *f;
   ARMword length;
+  risc_os_object_info object_info;
 
   assert(state);
 
@@ -1192,6 +1334,15 @@
   dbug_hostfs("\tPATH = %s\n", ro_path);
   dbug_hostfs("\tPATH2 = %s\n", host_path);
 
+  hostfs_path_process(ro_path, 0, tmp_path, ro_leaf, &object_info);
+  if (!object_info.disc_info) {
+    state->Reg[9] = FILECORE_ERROR_BADDISC;
+	return;
+  } else if (!(object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE)) {
+    state->Reg[9] = FILECORE_ERROR_DISCPROT;
+    return;
+  }
+
   hostfs_ensure_buffer_size(BUFSIZE);
 
   f = fopen(host_path, "wb");
@@ -1221,7 +1372,10 @@
 hostfs_file_8_create_dir(ARMul_State *state)
 {
   char ro_path[PATH_MAX];
+  char ro_leaf[PATH_MAX];
   char host_path[PATH_MAX];
+  char tmp_path[PATH_MAX];
+  risc_os_object_info object_info;
   int s;
 
   assert(state);
@@ -1239,6 +1393,14 @@
   dbug_hostfs("\tPATH = %s\n", ro_path);
   dbug_hostfs("\tPATH2 = %s\n", host_path);
 
+  hostfs_path_process(ro_path, 0, tmp_path, ro_leaf, &object_info);
+  if (!object_info.disc_info) {
+    state->Reg[9] = FILECORE_ERROR_BADDISC;
+	return;
+  } else if (!(object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE)) {
+    state->Reg[9] = FILECORE_ERROR_DISCPROT;
+    return;
+  }
 #if defined __unix || __MACH__
   s = mkdir(host_path, 0755);
 #else
@@ -1472,6 +1634,12 @@
     /* TODO Improve error return */
     state->Reg[3] = 0;
     state->Reg[4] = (uint32_t)-1;
+    if (object_info.disc_info == NULL)
+        state->Reg[9] = FILECORE_ERROR_BADDISC;
+	else if (object_info.type == OBJECT_TYPE_NOT_FOUND)
+        state->Reg[9] = FILECORE_ERROR_NOTFOUND;
+    else
+        state->Reg[9] = FILECORE_ERROR_DISCERR;
     return;
   }
 
@@ -1507,7 +1675,7 @@
       strcat(entry_path, "/");
       strcat(entry_path, entry->d_name);
 
-      hostfs_read_object_info(entry_path, ro_leaf, &object_info);
+      hostfs_read_object_info(entry_path, ro_leaf, &object_info, NULL);
 
       /* Ignore entries we can not read information about,
          or which are neither regular files or directories */
@@ -1547,7 +1715,7 @@
       strcat(entry_path, "/");
       strcat(entry_path, entry->d_name);
 
-      hostfs_read_object_info(entry_path, ro_leaf, &object_info);
+      hostfs_read_object_info(entry_path, ro_leaf, &object_info, NULL);
 
       /* Ignore entries we can not read information about,
          or which are neither regular files or directories */
Index: src/hostfs.h
===================================================================
--- src/hostfs.h	(revision 137)
+++ src/hostfs.h	(working copy)
@@ -6,6 +6,7 @@
 #define HOSTFS_H
 
 //#include "armdefs.h"
+#include "stdint.h"
 #include "rpcemu.h"
 
 #define ARCEM_SWI_CHUNK    0x56ac0
@@ -15,13 +16,26 @@
 #define ARCEM_SWI_NANOSLEEP (ARCEM_SWI_CHUNK + 3)
 #define ARCEM_SWI_NETWORK   (ARCEM_SWI_CHUNK + 4)
 
+#define HOSTFS_DISC_WRITEABLE	1
+#define HOSTFS_DISC_READABLE	2
+
+
 typedef uint32_t ARMword;
+
 typedef struct {
   uint32_t *Reg;
 } ARMul_State;
 
+typedef struct {
+  char disc_name[80];
+  char hostfs_root[512];
+  int permissions;
+} HOSTFS_Discs;
 
 extern void hostfs(ARMul_State *state);
+int hostfs_initialise();
+int add_hostfs_disc(const char *name, const char *path, const char *permissions);
+int get_max_hostfs_discs();
 
 #define ARMul_LoadWordS(state, address) readmeml(address)
 #define ARMul_LoadByte(state, address) readmemb(address)
Index: src/rpcemu.c
===================================================================
--- src/rpcemu.c	(revision 137)
+++ src/rpcemu.c	(working copy)
@@ -19,6 +19,7 @@
 #include "cdrom-iso.h"
 #include "podulerom.h"
 #include "podules.h"
+#include "hostfs.h"
 
 int cdromtype;
 unsigned char flaglookup[16][16];
@@ -59,17 +60,10 @@
 
 int startrpcemu()
 {
-        int c;
         char *p;
         get_executable_name(exname,511);
         p=get_filename(exname);
         *p=0;
-        append_filename(HOSTFS_ROOT,exname,"hostfs",511);
-        for (c=0;c<511;c++)
-        {
-                if (HOSTFS_ROOT[c]=='\\')
-                   HOSTFS_ROOT[c]='/';
-        }
         initmem();
 //printf("Mem inited...\n");
 	loadroms();
@@ -92,7 +86,6 @@
 //printf("About to init video...\n");
         initvideo();
 //printf("Video inited!\n");
-        loadconfig();
         initsound();
         reallocmem(rammask+1);
         initcodeblocks();
@@ -151,6 +144,11 @@
 {
         char fn[512];
         char *p;
+        unsigned int i;
+        char *hostfs_name;
+        char *hostfs_path;
+        char *hostfs_perm;
+        char config_key[80];
         append_filename(fn,exname,"rpc.cfg",511);
         set_config_file(fn);
         p=(char *)get_config_string(NULL,"mem_size",NULL);
@@ -188,6 +186,29 @@
         mousehackon=get_config_int(NULL,"mouse_following",1);
         username=get_config_string(NULL,"username",NULL);
         ipaddress=get_config_string(NULL,"ipaddress",NULL);
+        hostfs_initialise();
+        for (i = 0; i < get_max_hostfs_discs(); i++) {
+                sprintf(config_key, "hostfs.drive%d.name", i);
+                hostfs_name = get_config_string(NULL, config_key, NULL);
+                if (!hostfs_name)
+                        break;
+                sprintf(config_key, "hostfs.drive%d.path", i);
+                hostfs_path = get_config_string(NULL, config_key, NULL);
+                if (!hostfs_name) {
+                        printf("Error: drive %d has no path\n", i);
+                        break;
+                }
+                sprintf(config_key, "hostfs.drive%d.permissions", i);
+                hostfs_perm = get_config_string(NULL, config_key, NULL);
+                if (!hostfs_name) {
+                        printf("Error: drive %d has no permissions\n", i);
+                        break;
+                }
+                if (add_hostfs_disc(hostfs_name, hostfs_path, hostfs_perm) != 0) {
+                        printf("Error: Failed to add hostfs drive %s,%s,%s\n",
+                               hostfs_name, hostfs_path, hostfs_perm);
+                }
+        }
 }
 
 void saveconfig()
Index: src/rpcemu.h
===================================================================
--- src/rpcemu.h	(revision 137)
+++ src/rpcemu.h	(working copy)
@@ -125,6 +125,7 @@
 extern void wakeupsoundthread();
 extern void updateirqs(void);
 extern int quited;
+extern char *rpcemu_os_expand_home_path(const char *path, char *buf, int buflen);
 
 extern char exname[512];
 extern int timetolive;
Index: src/rpc-win.c
===================================================================
--- src/rpc-win.c	(revision 137)
+++ src/rpc-win.c	(working copy)
@@ -31,7 +31,20 @@
 int updatemips=0;
 int vsyncints=0;
 
+char *rpcemu_os_expand_home_path(const char *path, char *buf, int buflen)
+{
+        buf[buflen-1] = '\0';
 
+        if (*path != '~') {
+                strncpy(buf, buflen-1, path);
+        } else {
+                // FIXME: Is this correct?
+                snprintf(buf, buflen, "%s%s", getenv("USERPROFILE"), path+1);
+        }
+
+        return buf;
+}
+
 void domips(void)
 {
         mips=(float)inscount/1000000.0f;
@@ -333,6 +346,7 @@
         ShowWindow (ghwnd, nFunsterStil);
         win_set_window(ghwnd);
         allegro_init();
+        loadconfig();
         install_keyboard();
         install_timer();
         install_mouse();
Index: src/rpc-linux.c
===================================================================
--- src/rpc-linux.c	(revision 137)
+++ src/rpc-linux.c	(working copy)
@@ -10,6 +10,7 @@
 #include "vidc20.h"
 #include "gui.h"
 
+extern void loadconfig();
 
 int mousecapture=0;
 float mips;
@@ -22,6 +23,19 @@
 static uint32_t mipscount;
 float mipstotal;
 
+char *rpcemu_os_expand_home_path(const char *path, char *buf, int buflen)
+{
+        buf[buflen-1] = '\0';
+
+        if (*path != '~') {
+                strncpy(buf, path, buflen-1);
+        } else {
+                snprintf(buf, buflen, "%s%s", getenv("HOME"), path+1);
+        }
+
+        return buf;
+}
+
 void *_soundthread(void *p)
 {
 	int c;
@@ -215,6 +229,8 @@
 
         infocus=1;
         allegro_init();
+	// load config here before anybody needs it.
+	loadconfig();
 
 	LOCK_FUNCTION(close_button_handler);
 	set_close_button_callback(close_button_handler);
Index: src/iomd.h
===================================================================
--- src/iomd.h	(revision 137)
+++ src/iomd.h	(working copy)
@@ -36,8 +36,6 @@
 extern uint8_t readmb(void);
 extern void iomdvsync(int vsync);
 
-extern char HOSTFS_ROOT[512];
-
 extern char discname[2][260];
 extern int drawscre;
 
        @
        @ $Id: hostfs.s,v 1.5 2006/02/13 18:56:02 mhowkins Exp $
        @

        @ ARM constants
        VBIT = 1 << 28

        @ RISC OS constants
        XOS_Write0          = 0x20002
        XOS_CLI             = 0x20005
        XOS_FSControl       = 0x20029
        XOS_ValidateAddress = 0x2003a
        XMessageTrans_ErrorLookup = 0x61506

        FSControl_AddFS    = 12
        FSControl_SelectFS = 14
        FSControl_RemoveFS = 16

        Service_FSRedeclare = 0x40

        @ Constants for ArcEm memory-mapped IO
        AIO_BASE   = 0x03000000
        AIO_HOSTFS = AIO_BASE | (0x001 << 12)

        AIO_HOSTFS_OPEN     = 0x000
        AIO_HOSTFS_GETBYTES = 0x001
        AIO_HOSTFS_PUTBYTES = 0x002
        AIO_HOSTFS_ARGS     = 0x003
        AIO_HOSTFS_CLOSE    = 0x004
        AIO_HOSTFS_FILE     = 0x005
        AIO_HOSTFS_FUNC     = 0x006
        AIO_HOSTFS_GBPB     = 0x007

        ARCEM_SWI_BASE = 0x56ac0

        ArcEm_HostFS = ARCEM_SWI_BASE + 1

        @ Filing system error codes
        FILECORE_ERROR_DISCFULL = 0xc6
        FILECORE_ERROR_BADDISC  = 0xc8
        FILECORE_ERROR_DISCPROT = 0xc9

        @ Filing system properties
        FILING_SYSTEM_NUMBER = 0x99     @ TODO choose unique value
        MAX_OPEN_FILES       = 100      @ TODO choose sensible value



        .global _start

_start:


module_start:

        .int    0               @ Start
        .int    init            @ Initialisation
        .int    final           @ Finalisation
        .int    service         @ Service Call
        .int    title           @ Title String
        .int    help            @ Help String
        .int    table           @ Help and Command keyword table
        .int    ARCEM_SWI_BASE          @ SWI Chunk base
        .int    RM_SWI          @ SWI handler code
        .int    RM_SWI_Table            @ SWI decoding table
        .int    0               @ SWI decoding code


title:
        .string "ArcEmHostFS"

help:
        .string "ArcEm HostFS\t0.03 (01 Feb 2006)"

        .align


        @ Help and Command keyword table
table:
        .string "HostFS"
        .align
        .int    command_hostfs
        .int    0x00000000
        .int    0
        .int    command_hostfs_help

        .byte   0       @ Table terminator

RM_SWI_Table:
        .string "ArcEm"
        .string "Shutdown"
        .string "HostFS"
        .string "Debug"
        .string "IDEFS"
        .byte   0
        .align

RM_SWI:
        MOVS    PC, R14                                 @ do nothing

command_hostfs_help:
        .string "*HostFS selects the HostFS filing system\rSyntax: *HostFS"
        .align


        @ Filing System Information Block
fs_info_block:
        .int    fs_name         @ Filing System name
        .int    fs_text         @ Filing System startup text
        .int    fs_open         @ To Open files (FSEntry_Open)
        .int    fs_getbytes     @ To Get Bytes (FSEntry_GetBytes)
        .int    fs_putbytes     @ To Put Bytes (FSEntry_PutBytes)
        .int    fs_args         @ To Control open files (FSEntry_Args)
        .int    fs_close        @ To Close open files (FSEntry_Close)
        .int    fs_file         @ To perform whole-file ops (FSEntry_File)
        .int    FILING_SYSTEM_NUMBER | (MAX_OPEN_FILES << 8)
                                @ Filing System Information Word
        .int    fs_func         @ To perform various ops (FSEntry_Func)
        .int    fs_gbpb         @ To perform multi-byte ops (FSEntry_GBPB)
        .int    0               @ Extra Filing System Information Word

fs_name:
        .string "HostFS"

fs_text:
        .string "ArcEm Host Filing System jw"
        .align


        /* Entry:
         *   r10 = pointer to environment string
         *   r11 = I/O base or instantiation number
         *   r12 = pointer to private word for this instantiation
         *   r13 = stack pointer (supervisor)
         * Exit:
         *   r7-r11, r13 preserved
         *   other may be corrupted
         */
init:
        @ Declare filing system
        stmfd   sp!, {lr}

        mov     r0, #FSControl_AddFS
        adr     r1, module_start
        mov     r2, #(fs_info_block - module_start)
        mov     r3, r12
        swi     XOS_FSControl

        ldmfd   sp!, {pc}^


final:
        @ Remove filing system
        stmfd   sp!, {lr}

        mov     r0, #FSControl_RemoveFS
        adr     r1, fs_name
        swi     XOS_FSControl
        cmp     pc, #0          @ Clears V (also clears N, Z, and sets C)

        ldmfd   sp!, {pc}


        /* Entry:
         *   r1 = service number
         *   r12 = pointer to private word for this instantiation
         *   r13 = stack pointer
         * Exit:
         *   r1 = can be set to zero if the service is being claimed
         *   r0,r2-r8 can be altered to pass back a result
         *   registers must be preserved if not returning a result
         *   r12 may be corrupted
         */
service:
        teq     r1, #Service_FSRedeclare
        movnes  pc, lr

        teq     r1, #Service_FSRedeclare
        beq     service_fsredeclare

        movs    pc, lr          @ should never reach here

        @ Filing system reinitialise
service_fsredeclare:
        stmfd   sp!, {r0-r3, lr}

        @ Redeclare filing system
        mov     r0, #FSControl_AddFS
        adr     r1, module_start
        mov     r2, #(fs_info_block - module_start)
        mov     r3, r12
        swi     XOS_FSControl

        ldmfd   sp!, {r0-r3, pc}^


        /* Entry (for all *Commands):
         *   r0 = pointer to command tail (read-only)
         *   r1 = number of parameters (as counted by OSCLI)
         *   r12 = pointer to private word for this instantiation
         *   r13 = stack pointer (supervisor)
         *   r14 = return address
         * Exit:
         *   r0 = error pointer (if needed)
         *   r7-r11 preserved
         */

        @ *HostFS
command_hostfs:
        @ Select HostFS as the current Filing System
        stmfd   sp!, {lr}

        mov     r0, #FSControl_SelectFS
        adr     r1, fs_name
        swi     XOS_FSControl

        ldmfd   sp!, {pc}^



        /* FSEntry_Open (Open a file)
         */
fs_open:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_OPEN]
        ldr r9, = AIO_HOSTFS_OPEN

        SWI ArcEm_HostFS

@       movs    pc, lr
        movs    pc, r14


        /* FSEntry_GetBytes (Get bytes from a file)
         */
fs_getbytes:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_GETBYTES]
        ldr     r9, = AIO_HOSTFS_GETBYTES

        SWI ArcEm_HostFS
@       movs    pc, lr
        movs    pc, r14


        /* FSEntry_PutBytes (Put bytes to a file)
         */
fs_putbytes:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_PUTBYTES]

        ldr     r9, = AIO_HOSTFS_PUTBYTES

        SWI ArcEm_HostFS
@       movs    pc, lr
        movs    pc, r14


        /* FSEntry_Args (Control open files)
         */
fs_args:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_ARGS]

        ldr     r9, = AIO_HOSTFS_ARGS

        SWI ArcEm_HostFS
@       movs    pc, lr
        movs    pc, r14


        /* FSEntry_Close (Close an open file)
         */
fs_close:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_CLOSE]

        ldr     r9, = AIO_HOSTFS_CLOSE

        SWI ArcEm_HostFS
@       movs    pc, lr
        movs    pc, r14


        /* FSEntry_File (Whole-file operations)
         */
fs_file:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_FILE]

        ldr     r9, = AIO_HOSTFS_FILE

        SWI ArcEm_HostFS

        teq     r9, #FILECORE_ERROR_DISCFULL
        beq     disc_is_full

        teq     r9, #FILECORE_ERROR_BADDISC
        beq     disc_is_bad

        teq     r9, #FILECORE_ERROR_DISCPROT
        beq     disc_is_protected

        movs    pc, r14
@       movs    pc, lr


        /* FSEntry_Func (Various operations)
         */
fs_func:
        @ Test if operation is FSEntry_Func 10 (Boot filing system)...
        teq     r0, #10
        beq     boot

@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_FUNC]
        ldr r9, = AIO_HOSTFS_FUNC

        SWI ArcEm_HostFS

@       adr     r1, handle_error
        teq     r9, #255
        beq     not_implemented

        teq     r9, #FILECORE_ERROR_DISCFULL
        beq     disc_is_full

        teq     r9, #FILECORE_ERROR_BADDISC
        beq     disc_is_bad

        teq     r9, #FILECORE_ERROR_DISCPROT
        beq     disc_is_protected

@       movs    pc, lr
        movs    pc, r14

boot:
        stmfd   sp!, {lr}
        adr     r0, 1f
        swi     XOS_CLI
        ldmfd   sp!, {pc}       @ Don't preserve flags - return XOS_CLI's error 
(if any)

1:
        .string "Run @.!Boot"
        .align

handle_error:
        teq     r0, #255
        beq     not_implemented

        teq     r0, #FILECORE_ERROR_DISCFULL
        beq     disc_is_full

        teq     r0, #FILECORE_ERROR_BADDISC
        beq     disc_is_bad

        teq     r0, #FILECORE_ERROR_DISCPROT
        beq     disc_is_protected

        orrs    pc, lr, #VBIT

not_implemented:
        stmfd   sp!, {lr}
        adr     r0, err_badfsop
        mov     r1, #0
        mov     r2, #0
        adr     r4, title
        swi     XMessageTrans_ErrorLookup
        ldmfd   sp!, {lr}
        orrs    pc, lr, #VBIT

disc_is_full:
        adr     r0, err_discfull
        orrs    pc, lr, #VBIT

disc_is_bad:
        adr     r0, err_baddisc
        orrs    pc, lr, #VBIT

disc_is_protected:
        adr     r0, err_discprot
        orrs    pc, lr, #VBIT

err_badfsop:
        .int    0x100a0 | (FILING_SYSTEM_NUMBER << 8)
        .string "BadFSOp"
        .align

err_discfull:
        .int    0x10000 | (FILING_SYSTEM_NUMBER << 8) | FILECORE_ERROR_DISCFULL
        .string "Disc full"
        .align

err_baddisc:
        .int    0x10000 | (FILING_SYSTEM_NUMBER << 8) | FILECORE_ERROR_BADDISC
        .string "Bad disc"
        .align

err_discprot:
        .int    0x10000 | (FILING_SYSTEM_NUMBER << 8) | FILECORE_ERROR_DISCPROT
        .string "Locked disc"
        .align


        /* FSEntry_GBPB (Multi-byte operations)
         */
fs_gbpb:
@       ldr     r9, = AIO_HOSTFS
@       str     r9, [r9, #AIO_HOSTFS_GBPB]

        ldr r9, = AIO_HOSTFS_GBPB

        SWI ArcEm_HostFS

@       movs    pc, lr
        movs    pc, r14
_______________________________________________
Rpcemu mailing list
[email protected]
http://www.riscos.info/cgi-bin/mailman/listinfo/rpcemu

Reply via email to