diff --git a/components/dfs/dfs_v1/filesystems/9pfs/dfs_9pfs.c b/components/dfs/dfs_v1/filesystems/9pfs/dfs_9pfs.c index 6e842f51c858..910bfa3d672d 100644 --- a/components/dfs/dfs_v1/filesystems/9pfs/dfs_9pfs.c +++ b/components/dfs/dfs_v1/filesystems/9pfs/dfs_9pfs.c @@ -39,35 +39,48 @@ static rt_list_t _protocol_nodes = RT_LIST_OBJECT_INIT(_protocol_nodes); static struct rt_spinlock _protocol_lock = { 0 }; #ifndef rt_le8_to_cpu -#define rt_le8_to_cpu +#define rt_le8_to_cpu(x) (x) #endif #ifndef rt_cpu_to_le8 -#define rt_cpu_to_le8 +#define rt_cpu_to_le8(x) (x) #endif -#define P9_OF_OPS_GET(width, dir) \ - rt_inline rt_uint##width##_t get_##dir##_##value##width##_of( \ - struct p9_connection *conn, unsigned idx) \ - { \ - rt_uint##width##_t *vp = (void *)&conn->dir##_buffer[idx]; \ - return rt_le##width##_to_cpu(*vp); \ +/* + * The 9P messages are not aligned inside `rx_buffer`/`tx_buffer`, a 64 bit + * field can start at any offset (e.g. the `length` field of an `Rstat` reply + * always starts at P9_MSG_STAT_LEN == 42). Dereferencing a casted pointer + * makes GCC emit `LDRD`/`STRD` on ARMv7-A, which faults on any address that + * is not 8 byte aligned, so always go through an aligned local variable. + */ +#define P9_OF_OPS_GET(width, dir) \ + rt_inline rt_uint##width##_t get_##dir##_##value##width##_of( \ + struct p9_connection *conn, unsigned idx) \ + { \ + rt_uint##width##_t value; \ + \ + rt_memcpy(&value, &conn->dir##_buffer[idx], sizeof(value)); \ + \ + return rt_le##width##_to_cpu(value); \ } -#define P9_OF_OPS_PUT(width, dir) \ - rt_inline void put_##dir##_##value##width##_of( \ - struct p9_connection *conn, unsigned idx, \ - rt_uint##width##_t value) \ - { \ - rt_uint##width##_t *vp = (void *)&conn->dir##_buffer[idx]; \ - *vp = rt_cpu_to_le##width(value); \ +#define P9_OF_OPS_PUT(width, dir) \ + rt_inline void put_##dir##_##value##width##_of( \ + struct p9_connection *conn, unsigned idx, \ + rt_uint##width##_t value) \ + { \ + value = rt_cpu_to_le##width(value); \ + \ + rt_memcpy(&conn->dir##_buffer[idx], &value, sizeof(value)); \ } #define P9_OPS_PUT(width) \ rt_inline rt_off_t put_value##width(struct p9_connection *conn, \ rt_off_t off, rt_uint##width##_t value) \ { \ - ((rt_uint##width##_t *)(conn->tx_buffer + off))[0] = \ - rt_cpu_to_le##width(value); \ + value = rt_cpu_to_le##width(value); \ + \ + rt_memcpy(conn->tx_buffer + off, &value, sizeof(value)); \ + \ return off + sizeof(value); \ } @@ -367,7 +380,7 @@ rt_err_t dfs_9pfs_del_tag(struct p9_protocol *p9p) static int p9_to_fs_err(int rc) { - const int p9_err[] = { + const int p9_err[-P9_MSG_SIZE_TOO_BIG + 1] = { [0] = RT_EOK, [-P9_ERROR] = -EIO, [-P9_UNKNOWN_VERSION] = -ENOSYS, @@ -384,7 +397,12 @@ static int p9_to_fs_err(int rc) [-P9_MSG_SIZE_TOO_BIG] = -ENOSPC, }; - return p9_err[-rc]; + if (rc <= 0 && -rc < (int)(sizeof(p9_err) / sizeof(p9_err[0]))) + { + return p9_err[-rc]; + } + + return -EIO; } static int p9_alloc_fid(struct p9_connection *conn) @@ -547,7 +565,7 @@ rt_inline int p9_walk_subpath(struct p9_connection *conn, const char *path) static int dfs_9pfs_open(struct dfs_file *fd) { - int rc; + int rc = 0; rt_uint32_t size; rt_bool_t is_root; struct p9_connection *conn;