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