summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorguo <[email protected]>2022-12-03 12:07:44 +0800
committerGitHub <[email protected]>2022-12-03 12:07:44 +0800
commitecf2d8215961ca7c539132b62a72df6072cc3e14 (patch)
tree59005f0f74f2593c0435059264f624c862a89f55 /components
parentaaf5462c6d4ae9466a0a8cd2a4bb00cfe1fef2f2 (diff)
sync branch rt-smart. (#6641)
* Synchronize the code of the rt mart branch to the master branch. * TTY device * Add lwP code from rt-smart * Add vnode in DFS, but DFS will be re-write for rt-smart * There are three libcpu for rt-smart: * arm/cortex-a, arm/aarch64 * riscv64 Co-authored-by: Rbb666 <[email protected]> Co-authored-by: zhkag <[email protected]>
Diffstat (limited to 'components')
-rw-r--r--components/dfs/Kconfig11
-rw-r--r--components/dfs/filesystems/devfs/devfs.c100
-rw-r--r--components/dfs/filesystems/elmfat/dfs_elm.c54
-rw-r--r--components/dfs/filesystems/nfs/dfs_nfs.c81
-rw-r--r--components/dfs/filesystems/nfs/rpc/types.h16
-rw-r--r--components/dfs/filesystems/ramfs/dfs_ramfs.c60
-rw-r--r--components/dfs/filesystems/romfs/dfs_romfs.c88
-rw-r--r--components/dfs/filesystems/tmpfs/SConscript9
-rw-r--r--components/dfs/filesystems/tmpfs/dfs_tmpfs.c657
-rw-r--r--components/dfs/filesystems/tmpfs/dfs_tmpfs.h47
-rw-r--r--components/dfs/include/dfs.h22
-rw-r--r--components/dfs/include/dfs_file.h36
-rw-r--r--components/dfs/include/dfs_fs.h2
-rw-r--r--components/dfs/src/dfs.c605
-rw-r--r--components/dfs/src/dfs_file.c412
-rw-r--r--components/dfs/src/dfs_fs.c17
-rw-r--r--components/dfs/src/dfs_posix.c131
-rwxr-xr-xcomponents/drivers/Kconfig108
-rw-r--r--components/drivers/cputime/SConscript3
-rw-r--r--components/drivers/cputime/cputime.c8
-rw-r--r--components/drivers/cputime/cputime_riscv.c39
-rw-r--r--components/drivers/fdt/README.md41
-rw-r--r--components/drivers/fdt/SConscript16
-rw-r--r--components/drivers/fdt/docs/README.md13
-rw-r--r--components/drivers/fdt/docs/api.md434
-rw-r--r--components/drivers/fdt/docs/examples.md81
-rw-r--r--components/drivers/fdt/docs/version.md7
-rw-r--r--components/drivers/fdt/examples/SConscript10
-rw-r--r--components/drivers/fdt/examples/fdt_test.c143
-rw-r--r--components/drivers/fdt/inc/dtb_node.h379
-rw-r--r--components/drivers/fdt/libfdt/SConscript10
-rw-r--r--components/drivers/fdt/libfdt/fdt.c249
-rw-r--r--components/drivers/fdt/libfdt/fdt.h111
-rw-r--r--components/drivers/fdt/libfdt/fdt_addresses.c99
-rw-r--r--components/drivers/fdt/libfdt/fdt_empty_tree.c84
-rw-r--r--components/drivers/fdt/libfdt/fdt_ro.c701
-rw-r--r--components/drivers/fdt/libfdt/fdt_rw.c489
-rw-r--r--components/drivers/fdt/libfdt/fdt_strerror.c100
-rw-r--r--components/drivers/fdt/libfdt/fdt_sw.c286
-rw-r--r--components/drivers/fdt/libfdt/fdt_wip.c137
-rw-r--r--components/drivers/fdt/libfdt/libfdt.h1876
-rw-r--r--components/drivers/fdt/libfdt/libfdt_env.h113
-rw-r--r--components/drivers/fdt/libfdt/libfdt_internal.h95
-rw-r--r--components/drivers/fdt/src/SConscript17
-rw-r--r--components/drivers/fdt/src/dtb_access.c650
-rw-r--r--components/drivers/fdt/src/dtb_addr.c57
-rw-r--r--components/drivers/fdt/src/dtb_base.c537
-rw-r--r--components/drivers/fdt/src/dtb_get.c817
-rw-r--r--components/drivers/fdt/src/dtb_head.c41
-rw-r--r--components/drivers/fdt/src/dtb_load.c105
-rw-r--r--components/drivers/fdt/src/dtb_set.c166
-rw-r--r--components/drivers/include/drivers/cputime.h4
-rw-r--r--components/drivers/include/drivers/gpt.h132
-rw-r--r--components/drivers/include/drivers/lcd.h111
-rw-r--r--components/drivers/include/drivers/mmcsd_card.h4
-rw-r--r--components/drivers/include/drivers/mmcsd_cmd.h3
-rw-r--r--components/drivers/include/drivers/mmcsd_core.h23
-rw-r--r--components/drivers/include/drivers/mmcsd_host.h53
-rw-r--r--components/drivers/include/drivers/rt_dev_bus.h18
-rw-r--r--components/drivers/include/drivers/serial.h2
-rw-r--r--components/drivers/include/drivers/serial_v2.h2
-rw-r--r--components/drivers/include/ipc/pipe.h8
-rw-r--r--components/drivers/include/ipc/waitqueue.h2
-rw-r--r--components/drivers/include/rtdevice.h4
-rw-r--r--components/drivers/ipc/completion.c5
-rw-r--r--components/drivers/ipc/dataqueue.c4
-rw-r--r--components/drivers/ipc/pipe.c283
-rw-r--r--components/drivers/ipc/waitqueue.c26
-rw-r--r--components/drivers/ipc/workqueue.c8
-rw-r--r--components/drivers/misc/SConscript12
-rw-r--r--components/drivers/misc/rt_dev_bus.c80
-rw-r--r--components/drivers/misc/rt_null.c74
-rw-r--r--components/drivers/misc/rt_random.c159
-rw-r--r--components/drivers/misc/rt_zero.c75
-rw-r--r--components/drivers/sdio/SConscript1
-rw-r--r--components/drivers/sdio/block_dev.c408
-rw-r--r--components/drivers/sdio/gpt.c561
-rw-r--r--components/drivers/sdio/mmc.c634
-rw-r--r--components/drivers/sdio/mmcsd_core.c88
-rw-r--r--components/drivers/sdio/sd.c1
-rw-r--r--components/drivers/sdio/sdio.c6
-rw-r--r--components/drivers/serial/serial.c43
-rw-r--r--components/drivers/serial/serial_v2.c31
-rw-r--r--components/drivers/tty/SConscript10
-rw-r--r--components/drivers/tty/console.c325
-rw-r--r--components/drivers/tty/include/console.h19
-rw-r--r--components/drivers/tty/include/tty.h490
-rw-r--r--components/drivers/tty/include/tty_ldisc.h56
-rw-r--r--components/drivers/tty/n_tty.c2041
-rw-r--r--components/drivers/tty/pty.c374
-rw-r--r--components/drivers/tty/tty.c424
-rw-r--r--components/drivers/tty/tty_ioctl.c109
-rw-r--r--components/drivers/tty/tty_ldisc.c181
-rw-r--r--components/drivers/virtio/SConscript11
-rw-r--r--components/drivers/virtio/virtio.c324
-rw-r--r--components/drivers/virtio/virtio.h156
-rw-r--r--components/drivers/virtio/virtio_blk.c253
-rw-r--r--components/drivers/virtio/virtio_blk.h105
-rw-r--r--components/drivers/virtio/virtio_console.c778
-rw-r--r--components/drivers/virtio/virtio_console.h97
-rw-r--r--components/drivers/virtio/virtio_gpu.c934
-rw-r--r--components/drivers/virtio/virtio_gpu.h412
-rw-r--r--components/drivers/virtio/virtio_input.c449
-rw-r--r--components/drivers/virtio/virtio_input.h145
-rw-r--r--components/drivers/virtio/virtio_input_event_codes.h932
-rw-r--r--components/drivers/virtio/virtio_mmio.h67
-rw-r--r--components/drivers/virtio/virtio_net.c314
-rw-r--r--components/drivers/virtio/virtio_net.h119
-rw-r--r--components/drivers/virtio/virtio_queue.h97
-rw-r--r--components/fal/src/fal_rtt.c18
-rw-r--r--components/finsh/cmd.c2
-rw-r--r--components/finsh/msh.c212
-rw-r--r--components/finsh/msh_file.c31
-rw-r--r--components/libc/compilers/common/ctime.c234
-rw-r--r--components/libc/compilers/common/include/sys/signal.h8
-rw-r--r--components/libc/compilers/common/include/sys/time.h13
-rw-r--r--components/libc/compilers/musl/fcntl.h24
-rw-r--r--components/libc/posix/io/mman/mman.c1
-rw-r--r--components/libc/posix/io/poll/poll.c28
-rw-r--r--components/libc/posix/io/stdio/libc.c17
-rw-r--r--components/libc/posix/io/termios/termios.h94
-rw-r--r--components/lwp/Kconfig77
-rw-r--r--components/lwp/SConscript39
-rw-r--r--components/lwp/arch/aarch64/common/reloc.c28
-rw-r--r--components/lwp/arch/aarch64/cortex-a/lwp_arch.c77
-rw-r--r--components/lwp/arch/aarch64/cortex-a/lwp_arch.h45
-rw-r--r--components/lwp/arch/aarch64/cortex-a/lwp_gcc.S593
-rw-r--r--components/lwp/arch/arm/arm926/lwp_gcc.S81
-rw-r--r--components/lwp/arch/arm/common/reloc.c120
-rw-r--r--components/lwp/arch/arm/cortex-a/lwp_arch.c138
-rw-r--r--components/lwp/arch/arm/cortex-a/lwp_arch.h49
-rw-r--r--components/lwp/arch/arm/cortex-a/lwp_gcc.S379
-rw-r--r--components/lwp/arch/arm/cortex-a9/lwp_gcc.S70
-rw-r--r--components/lwp/arch/arm/cortex-m3/lwp_gcc.S124
-rw-r--r--components/lwp/arch/arm/cortex-m3/lwp_iar.S123
-rw-r--r--components/lwp/arch/arm/cortex-m3/lwp_rvds.S135
-rw-r--r--components/lwp/arch/arm/cortex-m4/lwp_gcc.S124
-rw-r--r--components/lwp/arch/arm/cortex-m4/lwp_iar.S123
-rw-r--r--components/lwp/arch/arm/cortex-m4/lwp_rvds.S135
-rw-r--r--components/lwp/arch/arm/cortex-m7/lwp_gcc.S124
-rw-r--r--components/lwp/arch/arm/cortex-m7/lwp_iar.S123
-rw-r--r--components/lwp/arch/arm/cortex-m7/lwp_rvds.S135
-rw-r--r--components/lwp/arch/risc-v/rv64/SConscript11
-rw-r--r--components/lwp/arch/risc-v/rv64/lwp_arch.c264
-rw-r--r--components/lwp/arch/risc-v/rv64/lwp_arch.h70
-rw-r--r--components/lwp/arch/risc-v/rv64/lwp_gcc.S337
-rw-r--r--components/lwp/arch/risc-v/rv64/reloc.c108
-rw-r--r--components/lwp/arch/x86/i386/SConscript11
-rw-r--r--components/lwp/arch/x86/i386/lwp_arch.c371
-rw-r--r--components/lwp/arch/x86/i386/lwp_arch.h49
-rw-r--r--components/lwp/arch/x86/i386/lwp_gcc.S73
-rw-r--r--components/lwp/arch/x86/i386/reloc.c41
-rw-r--r--components/lwp/ioremap.c120
-rw-r--r--components/lwp/ioremap.h26
-rw-r--r--components/lwp/lwp.c1393
-rw-r--r--components/lwp/lwp.h287
-rw-r--r--components/lwp/lwp_arch_comm.h53
-rw-r--r--components/lwp/lwp_avl.c227
-rw-r--r--components/lwp/lwp_avl.h46
-rw-r--r--components/lwp/lwp_dbg.c119
-rw-r--r--components/lwp/lwp_elf.h3520
-rw-r--r--components/lwp/lwp_futex.c252
-rw-r--r--components/lwp/lwp_ipc.c1153
-rw-r--r--components/lwp/lwp_ipc.h64
-rw-r--r--components/lwp/lwp_ipc_internal.h38
-rw-r--r--components/lwp/lwp_mem.c220
-rw-r--r--components/lwp/lwp_mem.h21
-rw-r--r--components/lwp/lwp_memheap.c576
-rw-r--r--components/lwp/lwp_memheap.h61
-rw-r--r--components/lwp/lwp_mm.c40
-rw-r--r--components/lwp/lwp_mm.h16
-rw-r--r--components/lwp/lwp_mm_area.c122
-rw-r--r--components/lwp/lwp_mm_area.h53
-rw-r--r--components/lwp/lwp_pid.c1117
-rw-r--r--components/lwp/lwp_pid.h52
-rw-r--r--components/lwp/lwp_pmutex.c413
-rw-r--r--components/lwp/lwp_setsid.c27
-rw-r--r--components/lwp/lwp_shm.c416
-rw-r--r--components/lwp/lwp_shm.h31
-rw-r--r--components/lwp/lwp_signal.c606
-rw-r--r--components/lwp/lwp_signal.h39
-rw-r--r--components/lwp/lwp_syscall.c4356
-rw-r--r--components/lwp/lwp_syscall.h89
-rw-r--r--components/lwp/lwp_tid.c132
-rw-r--r--components/lwp/lwp_user_mm.c623
-rw-r--r--components/lwp/lwp_user_mm.h55
-rw-r--r--components/lwp/page.c424
-rw-r--r--components/lwp/page.h40
-rw-r--r--components/lwp/syscall_data.h32
-rw-r--r--components/net/netdev/src/netdev.c53
-rw-r--r--components/net/sal/dfs_net/dfs_net.c51
-rw-r--r--components/net/sal/impl/af_inet_lwip.c8
-rw-r--r--components/net/sal/include/sal_socket.h51
-rw-r--r--components/net/sal/socket/net_sockets.c99
-rw-r--r--components/net/sal/src/sal_socket.c94
-rw-r--r--components/utilities/resource/SConscript8
-rw-r--r--components/utilities/resource/resource_id.c62
-rw-r--r--components/utilities/resource/resource_id.h31
-rw-r--r--components/utilities/rt-link/src/rtlink_dev.c12
199 files changed, 40922 insertions, 3722 deletions
diff --git a/components/dfs/Kconfig b/components/dfs/Kconfig
index 28cb892e3e..527c3ba77a 100644
--- a/components/dfs/Kconfig
+++ b/components/dfs/Kconfig
@@ -135,17 +135,26 @@ if RT_USING_DFS
config RT_USING_DFS_DEVFS
bool "Using devfs for device objects"
- default n
+ default y
config RT_USING_DFS_ROMFS
bool "Enable ReadOnly file system on flash"
default n
+ config RT_USING_DFS_CROMFS
+ bool "Enable readonly compressed file system on flash"
+ default n
+ # select PKG_USING_ZLIB
+
config RT_USING_DFS_RAMFS
bool "Enable RAM file system"
select RT_USING_MEMHEAP
default n
+ config RT_USING_DFS_TMPFS
+ bool "Enable TMP file system"
+ default n
+
config RT_USING_DFS_NFS
bool "Using NFS v3 client file system"
depends on RT_USING_LWIP
diff --git a/components/dfs/filesystems/devfs/devfs.c b/components/dfs/filesystems/devfs/devfs.c
index 8e58fb9f53..5181a95391 100644
--- a/components/dfs/filesystems/devfs/devfs.c
+++ b/components/dfs/filesystems/devfs/devfs.c
@@ -7,7 +7,7 @@
* Date Author Notes
* 2018-02-11 Bernard Ignore O_CREAT flag in open.
*/
-
+#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
@@ -37,7 +37,7 @@ int dfs_device_fs_ioctl(struct dfs_fd *file, int cmd, void *args)
RT_ASSERT(file != RT_NULL);
/* get device handler */
- dev_id = (rt_device_t)file->data;
+ dev_id = (rt_device_t)file->vnode->data;
RT_ASSERT(dev_id != RT_NULL);
/* close device handler */
@@ -56,7 +56,7 @@ int dfs_device_fs_read(struct dfs_fd *file, void *buf, size_t count)
RT_ASSERT(file != RT_NULL);
/* get device handler */
- dev_id = (rt_device_t)file->data;
+ dev_id = (rt_device_t)file->vnode->data;
RT_ASSERT(dev_id != RT_NULL);
/* read device data */
@@ -74,7 +74,7 @@ int dfs_device_fs_write(struct dfs_fd *file, const void *buf, size_t count)
RT_ASSERT(file != RT_NULL);
/* get device handler */
- dev_id = (rt_device_t)file->data;
+ dev_id = (rt_device_t)file->vnode->data;
RT_ASSERT(dev_id != RT_NULL);
/* read device data */
@@ -90,12 +90,18 @@ int dfs_device_fs_close(struct dfs_fd *file)
rt_device_t dev_id;
RT_ASSERT(file != RT_NULL);
+ RT_ASSERT(file->vnode->ref_count > 0);
+
+ if (file->vnode->ref_count > 1)
+ {
+ return 0;
+ }
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
{
struct device_dirent *root_dirent;
- root_dirent = (struct device_dirent *)file->data;
+ root_dirent = (struct device_dirent *)file->vnode->data;
RT_ASSERT(root_dirent != RT_NULL);
/* release dirent */
@@ -104,14 +110,14 @@ int dfs_device_fs_close(struct dfs_fd *file)
}
/* get device handler */
- dev_id = (rt_device_t)file->data;
+ dev_id = (rt_device_t)file->vnode->data;
RT_ASSERT(dev_id != RT_NULL);
/* close device handler */
result = rt_device_close(dev_id);
if (result == RT_EOK)
{
- file->data = RT_NULL;
+ file->vnode->data = RT_NULL;
return RT_EOK;
}
@@ -124,8 +130,14 @@ int dfs_device_fs_open(struct dfs_fd *file)
rt_err_t result;
rt_device_t device;
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ file->pos = 0;
+ return 0;
+ }
/* open root directory */
- if ((file->path[0] == '/') && (file->path[1] == '\0') &&
+ if ((file->vnode->path[0] == '/') && (file->vnode->path[1] == '\0') &&
(file->flags & O_DIRECTORY))
{
struct rt_object *object;
@@ -174,29 +186,45 @@ int dfs_device_fs_open(struct dfs_fd *file)
}
/* set data */
- file->data = root_dirent;
+ file->vnode->data = root_dirent;
return RT_EOK;
}
+#ifdef RT_USING_DEV_BUS
+ else if (file->flags & O_CREAT)
+ {
+ if (!(file->flags & O_DIRECTORY))
+ {
+ return -ENOSYS;
+ }
+ /* regester bus device */
+ if (rt_device_bus_create(&file->vnode->path[1], 0) == RT_NULL)
+ {
+ return -EEXIST;
+ }
+ }
+#endif
- device = rt_device_find(&file->path[1]);
+ device = rt_device_find(&file->vnode->path[1]);
if (device == RT_NULL)
+ {
return -ENODEV;
+ }
#ifdef RT_USING_POSIX_DEVIO
if (device->fops)
{
/* use device fops */
- file->fops = device->fops;
- file->data = (void *)device;
+ file->vnode->fops = device->fops;
+ file->vnode->data = (void *)device;
/* use fops */
- if (file->fops->open)
+ if (file->vnode->fops->open)
{
- result = file->fops->open(file);
+ result = file->vnode->fops->open(file);
if (result == RT_EOK || result == -RT_ENOSYS)
{
- file->type = FT_DEVICE;
+ file->vnode->type = FT_DEVICE;
return 0;
}
}
@@ -207,17 +235,36 @@ int dfs_device_fs_open(struct dfs_fd *file)
result = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
if (result == RT_EOK || result == -RT_ENOSYS)
{
- file->data = device;
- file->type = FT_DEVICE;
+ file->vnode->data = device;
+ file->vnode->type = FT_DEVICE;
return RT_EOK;
}
}
- file->data = RT_NULL;
+ file->vnode->data = RT_NULL;
/* open device failed. */
return -EIO;
}
+int dfs_device_fs_unlink(struct dfs_filesystem *fs, const char *path)
+{
+#ifdef RT_USING_DEV_BUS
+ rt_device_t dev_id;
+
+ dev_id = rt_device_find(&path[1]);
+ if (dev_id == RT_NULL)
+ {
+ return -1;
+ }
+ if (dev_id->type != RT_Device_Class_Bus)
+ {
+ return -1;
+ }
+ rt_device_bus_destroy(dev_id);
+#endif
+ return RT_EOK;
+}
+
int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
{
/* stat root directory */
@@ -253,6 +300,8 @@ int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat
st->st_mode |= S_IFBLK;
else if (dev_id->type == RT_Device_Class_Pipe)
st->st_mode |= S_IFIFO;
+ else if (dev_id->type == RT_Device_Class_Bus)
+ st->st_mode |= S_IFDIR;
else
st->st_mode |= S_IFREG;
@@ -273,7 +322,7 @@ int dfs_device_fs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t co
struct dirent *d;
struct device_dirent *root_dirent;
- root_dirent = (struct device_dirent *)file->data;
+ root_dirent = (struct device_dirent *)file->vnode->data;
RT_ASSERT(root_dirent != RT_NULL);
/* make integer count */
@@ -287,7 +336,14 @@ int dfs_device_fs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t co
object = (rt_object_t)root_dirent->devices[root_dirent->read_index + index];
d = dirp + index;
- d->d_type = DT_REG;
+ if ((((rt_device_t)object)->type) == RT_Device_Class_Bus)
+ {
+ d->d_type = DT_DIR;
+ }
+ else
+ {
+ d->d_type = DT_REG;
+ }
d->d_namlen = RT_NAME_MAX;
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
rt_strncpy(d->d_name, object->name, RT_NAME_MAX);
@@ -327,7 +383,7 @@ static const struct dfs_filesystem_ops _device_fs =
RT_NULL, /*unmount*/
RT_NULL, /*mkfs*/
RT_NULL, /*statfs*/
- RT_NULL, /*unlink*/
+ dfs_device_fs_unlink,
dfs_device_fs_stat,
RT_NULL, /*rename*/
};
diff --git a/components/dfs/filesystems/elmfat/dfs_elm.c b/components/dfs/filesystems/elmfat/dfs_elm.c
index adcb3e0ac5..f32ab53285 100644
--- a/components/dfs/filesystems/elmfat/dfs_elm.c
+++ b/components/dfs/filesystems/elmfat/dfs_elm.c
@@ -191,7 +191,7 @@ int dfs_elm_unmount(struct dfs_filesystem *fs)
return RT_EOK;
}
-int dfs_elm_mkfs(rt_device_t dev_id)
+int dfs_elm_mkfs(rt_device_t dev_id, const char *fs_name)
{
#define FSM_STATUS_INIT 0
#define FSM_STATUS_USE_TEMP_DRIVER 1
@@ -330,9 +330,21 @@ int dfs_elm_open(struct dfs_fd *file)
#if (FF_VOLUMES > 1)
int vol;
- struct dfs_filesystem *fs = (struct dfs_filesystem *)file->data;
+ struct dfs_filesystem *fs = file->vnode->fs;
extern int elm_get_vol(FATFS * fat);
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ if (file->vnode->type == FT_DIRECTORY
+ && !(file->flags & O_DIRECTORY))
+ {
+ return -ENOENT;
+ }
+ file->pos = 0;
+ return 0;
+ }
+
if (fs == NULL)
return -ENOENT;
@@ -344,9 +356,9 @@ int dfs_elm_open(struct dfs_fd *file)
if (drivers_fn == RT_NULL)
return -ENOMEM;
- rt_snprintf(drivers_fn, 256, "%d:%s", vol, file->path);
+ rt_snprintf(drivers_fn, 256, "%d:%s", vol, file->vnode->path);
#else
- drivers_fn = file->path;
+ drivers_fn = file->vnode->path;
#endif
if (file->flags & O_DIRECTORY)
@@ -423,7 +435,8 @@ int dfs_elm_open(struct dfs_fd *file)
if (result == FR_OK)
{
file->pos = fd->fptr;
- file->size = f_size(fd);
+ file->vnode->size = f_size(fd);
+ file->vnode->type = FT_REGULAR;
file->data = fd;
if (file->flags & O_APPEND)
@@ -448,10 +461,15 @@ int dfs_elm_close(struct dfs_fd *file)
{
FRESULT result;
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ return 0;
+ }
result = FR_OK;
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
{
- DIR *dir;
+ DIR *dir = RT_NULL;
dir = (DIR *)(file->data);
RT_ASSERT(dir != RT_NULL);
@@ -459,9 +477,9 @@ int dfs_elm_close(struct dfs_fd *file)
/* release memory */
rt_free(dir);
}
- else if (file->type == FT_REGULAR)
+ else if (file->vnode->type == FT_REGULAR)
{
- FIL *fd;
+ FIL *fd = RT_NULL;
fd = (FIL *)(file->data);
RT_ASSERT(fd != RT_NULL);
@@ -504,6 +522,10 @@ int dfs_elm_ioctl(struct dfs_fd *file, int cmd, void *args)
fd->fptr = fptr;
return elm_result_to_dfs(result);
}
+ case F_GETLK:
+ return 0;
+ case F_SETLK:
+ return 0;
}
return -ENOSYS;
}
@@ -514,7 +536,7 @@ int dfs_elm_read(struct dfs_fd *file, void *buf, size_t len)
FRESULT result;
UINT byte_read;
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
{
return -EISDIR;
}
@@ -537,7 +559,7 @@ int dfs_elm_write(struct dfs_fd *file, const void *buf, size_t len)
FRESULT result;
UINT byte_write;
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
{
return -EISDIR;
}
@@ -548,7 +570,7 @@ int dfs_elm_write(struct dfs_fd *file, const void *buf, size_t len)
result = f_write(fd, buf, len, &byte_write);
/* update position and file size */
file->pos = fd->fptr;
- file->size = f_size(fd);
+ file->vnode->size = f_size(fd);
if (result == FR_OK)
return byte_write;
@@ -567,10 +589,10 @@ int dfs_elm_flush(struct dfs_fd *file)
return elm_result_to_dfs(result);
}
-int dfs_elm_lseek(struct dfs_fd *file, rt_off_t offset)
+int dfs_elm_lseek(struct dfs_fd *file, off_t offset)
{
FRESULT result = FR_OK;
- if (file->type == FT_REGULAR)
+ if (file->vnode->type == FT_REGULAR)
{
FIL *fd;
@@ -586,10 +608,10 @@ int dfs_elm_lseek(struct dfs_fd *file, rt_off_t offset)
return fd->fptr;
}
}
- else if (file->type == FT_DIRECTORY)
+ else if (file->vnode->type == FT_DIRECTORY)
{
/* which is a directory */
- DIR *dir;
+ DIR *dir = RT_NULL;
dir = (DIR *)(file->data);
RT_ASSERT(dir != RT_NULL);
diff --git a/components/dfs/filesystems/nfs/dfs_nfs.c b/components/dfs/filesystems/nfs/dfs_nfs.c
index 284d8d42af..5b16875c29 100644
--- a/components/dfs/filesystems/nfs/dfs_nfs.c
+++ b/components/dfs/filesystems/nfs/dfs_nfs.c
@@ -559,12 +559,11 @@ int nfs_read(struct dfs_fd *file, void *buf, size_t count)
nfs_file *fd;
nfs_filesystem *nfs;
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
return -EISDIR;
-
- RT_ASSERT(file->data != NULL);
- struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->data));
+ RT_ASSERT(file->vnode->data != NULL);
+ struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->vnode->data));
nfs = (struct nfs_filesystem *)(dfs_nfs->data);
fd = (nfs_file *)(nfs->data);
RT_ASSERT(fd != NULL);
@@ -629,11 +628,11 @@ int nfs_write(struct dfs_fd *file, const void *buf, size_t count)
nfs_file *fd;
nfs_filesystem *nfs;
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
return -EISDIR;
- RT_ASSERT(file->data != NULL);
- struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->data));
+ RT_ASSERT(file->vnode->data != NULL);
+ struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->vnode->data));
nfs = (struct nfs_filesystem *)(dfs_nfs->data);
fd = (nfs_file *)(nfs->data);
RT_ASSERT(fd != NULL);
@@ -676,11 +675,10 @@ int nfs_write(struct dfs_fd *file, const void *buf, size_t count)
file->pos = fd->offset;
/* update file size */
if (fd->size < fd->offset) fd->size = fd->offset;
- file->size = fd->size;
+ file->vnode->size = fd->size;
}
xdr_free((xdrproc_t)xdr_WRITE3res, (char *)&res);
- }
- while (count > 0);
+ } while (count > 0);
xdr_free((xdrproc_t)xdr_WRITE3res, (char *)&res);
@@ -692,11 +690,11 @@ int nfs_lseek(struct dfs_fd *file, off_t offset)
nfs_file *fd;
nfs_filesystem *nfs;
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
return -EISDIR;
- RT_ASSERT(file->data != NULL);
- struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->data));
+ RT_ASSERT(file->vnode->data != NULL);
+ struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->vnode->data));
nfs = (struct nfs_filesystem *)(dfs_nfs->data);
fd = (nfs_file *)(nfs->data);
RT_ASSERT(fd != NULL);
@@ -714,11 +712,18 @@ int nfs_lseek(struct dfs_fd *file, off_t offset)
int nfs_close(struct dfs_fd *file)
{
nfs_filesystem *nfs;
- RT_ASSERT(file->data != NULL);
- struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->data));
+ RT_ASSERT(file->vnode->data != NULL);
+ struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->vnode->data));
+
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ return 0;
+ }
+
nfs = (struct nfs_filesystem *)(dfs_nfs->data);
- if (file->type == FT_DIRECTORY)
+ if (file->vnode->type == FT_DIRECTORY)
{
struct nfs_dir *dir;
@@ -727,7 +732,7 @@ int nfs_close(struct dfs_fd *file)
xdr_free((xdrproc_t)xdr_READDIR3res, (char *)&dir->res);
rt_free(dir);
}
- else if (file->type == FT_REGULAR)
+ else if (file->vnode->type == FT_REGULAR)
{
struct nfs_file *fd;
@@ -744,24 +749,42 @@ int nfs_close(struct dfs_fd *file)
int nfs_open(struct dfs_fd *file)
{
nfs_filesystem *nfs;
- RT_ASSERT(file->data != NULL);
- struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->data));
+ RT_ASSERT(file->vnode->data != NULL);
+ struct dfs_filesystem *dfs_nfs = file->vnode->fs;
nfs = (struct nfs_filesystem *)(dfs_nfs->data);
RT_ASSERT(nfs != NULL);
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ if (file->vnode->type == FT_DIRECTORY
+ && !(file->flags & O_DIRECTORY))
+ {
+ return -ENOENT;
+ }
+ file->pos = 0;
+ return 0;
+ }
+
if (file->flags & O_DIRECTORY)
{
nfs_dir *dir;
if (file->flags & O_CREAT)
{
- if (nfs_mkdir(nfs, file->path, 0755) < 0)
+ if (nfs_mkdir(nfs, file->vnode->path, 0755) < 0)
+ {
return -EAGAIN;
+ }
}
/* open directory */
- dir = nfs_opendir(nfs, file->path);
- if (dir == NULL) return -ENOENT;
+ dir = nfs_opendir(nfs, file->vnode->path);
+ if (dir == NULL)
+ {
+ return -ENOENT;
+ }
+ file->vnode->type = FT_DIRECTORY;
nfs->data = dir;
}
else
@@ -772,8 +795,10 @@ int nfs_open(struct dfs_fd *file)
/* create file */
if (file->flags & O_CREAT)
{
- if (nfs_create(nfs, file->path, 0664) < 0)
+ if (nfs_create(nfs, file->vnode->path, 0664) < 0)
+ {
return -EAGAIN;
+ }
}
/* open file (get file handle ) */
@@ -781,7 +806,7 @@ int nfs_open(struct dfs_fd *file)
if (fp == NULL)
return -ENOMEM;
- handle = get_handle(nfs, file->path);
+ handle = get_handle(nfs, file->vnode->path);
if (handle == NULL)
{
rt_free(fp);
@@ -805,7 +830,8 @@ int nfs_open(struct dfs_fd *file)
/* set private file */
nfs->data = fp;
- file->size = fp->size;
+ file->vnode->size = fp->size;
+ file->vnode->type = FT_REGULAR;
}
return 0;
@@ -1085,9 +1111,8 @@ int nfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
nfs_filesystem *nfs;
char *name;
-
- RT_ASSERT(file->data != NULL);
- struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->data));
+ RT_ASSERT(file->vnode->data != NULL);
+ struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem *)(file->vnode->data));
nfs = (struct nfs_filesystem *)(dfs_nfs->data);
dir = (nfs_dir *)(nfs->data);
RT_ASSERT(dir != NULL);
diff --git a/components/dfs/filesystems/nfs/rpc/types.h b/components/dfs/filesystems/nfs/rpc/types.h
index 043bfab896..9c4ccd3838 100644
--- a/components/dfs/filesystems/nfs/rpc/types.h
+++ b/components/dfs/filesystems/nfs/rpc/types.h
@@ -47,7 +47,15 @@
#include <string.h>
#include <stdint.h>
+
+#ifndef RT_USING_MINILIBC
+typedef unsigned int u_int;
+typedef unsigned char u_char;
+typedef unsigned long u_long;
+#else
#include <sys/types.h>
+#include <stdint.h>
+#endif
typedef long long int64_t;
typedef unsigned long long uint64_t;
@@ -55,6 +63,14 @@ typedef unsigned long long uint64_t;
typedef int bool_t;
typedef int enum_t;
+#if !defined(RT_USING_NEWLIB) && !defined(RT_USING_MUSL)
+typedef unsigned long dev_t;
+#endif
+
+#if !defined(RT_USING_NEWLIB) && !defined(RT_USING_MINILIBC) && !defined(RT_USING_MUSL)
+typedef rt_int32_t ssize_t;
+#endif
+
/* This needs to be changed to uint32_t in the future */
typedef unsigned long rpcprog_t;
typedef unsigned long rpcvers_t;
diff --git a/components/dfs/filesystems/ramfs/dfs_ramfs.c b/components/dfs/filesystems/ramfs/dfs_ramfs.c
index 781626633f..f31b76f0e2 100644
--- a/components/dfs/filesystems/ramfs/dfs_ramfs.c
+++ b/components/dfs/filesystems/ramfs/dfs_ramfs.c
@@ -97,13 +97,13 @@ int dfs_ramfs_read(struct dfs_fd *file, void *buf, size_t count)
rt_size_t length;
struct ramfs_dirent *dirent;
- dirent = (struct ramfs_dirent *)file->data;
+ dirent = (struct ramfs_dirent *)file->vnode->data;
RT_ASSERT(dirent != NULL);
- if (count < file->size - file->pos)
+ if (count < file->vnode->size - file->pos)
length = count;
else
- length = file->size - file->pos;
+ length = file->vnode->size - file->pos;
if (length > 0)
rt_memcpy(buf, &(dirent->data[file->pos]), length);
@@ -119,13 +119,13 @@ int dfs_ramfs_write(struct dfs_fd *fd, const void *buf, size_t count)
struct ramfs_dirent *dirent;
struct dfs_ramfs *ramfs;
- dirent = (struct ramfs_dirent *)fd->data;
+ dirent = (struct ramfs_dirent *)fd->vnode->data;
RT_ASSERT(dirent != NULL);
ramfs = dirent->fs;
RT_ASSERT(ramfs != NULL);
- if (count + fd->pos > fd->size)
+ if (count + fd->pos > fd->vnode->size)
{
rt_uint8_t *ptr;
ptr = rt_memheap_realloc(&(ramfs->memheap), dirent->data, fd->pos + count);
@@ -139,7 +139,7 @@ int dfs_ramfs_write(struct dfs_fd *fd, const void *buf, size_t count)
/* update dirent and file size */
dirent->data = ptr;
dirent->size = fd->pos + count;
- fd->size = dirent->size;
+ fd->vnode->size = dirent->size;
}
if (count > 0)
@@ -153,7 +153,7 @@ int dfs_ramfs_write(struct dfs_fd *fd, const void *buf, size_t count)
int dfs_ramfs_lseek(struct dfs_fd *file, off_t offset)
{
- if (offset <= (off_t)file->size)
+ if (offset <= (off_t)file->vnode->size)
{
file->pos = offset;
@@ -165,7 +165,13 @@ int dfs_ramfs_lseek(struct dfs_fd *file, off_t offset)
int dfs_ramfs_close(struct dfs_fd *file)
{
- file->data = NULL;
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ return 0;
+ }
+
+ file->vnode->data = NULL;
return RT_EOK;
}
@@ -177,7 +183,19 @@ int dfs_ramfs_open(struct dfs_fd *file)
struct ramfs_dirent *dirent;
struct dfs_filesystem *fs;
- fs = (struct dfs_filesystem *)file->data;
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ if (file->vnode->type == FT_DIRECTORY
+ && !(file->flags & O_DIRECTORY))
+ {
+ return -ENOENT;
+ }
+ file->pos = 0;
+ return 0;
+ }
+
+ fs = file->vnode->fs;
ramfs = (struct dfs_ramfs *)fs->data;
RT_ASSERT(ramfs != NULL);
@@ -190,7 +208,7 @@ int dfs_ramfs_open(struct dfs_fd *file)
}
/* open directory */
- dirent = dfs_ramfs_lookup(ramfs, file->path, &size);
+ dirent = dfs_ramfs_lookup(ramfs, file->vnode->path, &size);
if (dirent == NULL)
return -ENOENT;
if (dirent == &(ramfs->root)) /* it's root directory */
@@ -200,10 +218,11 @@ int dfs_ramfs_open(struct dfs_fd *file)
return -ENOENT;
}
}
+ file->vnode->type = FT_DIRECTORY;
}
else
{
- dirent = dfs_ramfs_lookup(ramfs, file->path, &size);
+ dirent = dfs_ramfs_lookup(ramfs, file->vnode->path, &size);
if (dirent == &(ramfs->root)) /* it's root directory */
{
return -ENOENT;
@@ -225,15 +244,18 @@ int dfs_ramfs_open(struct dfs_fd *file)
}
/* remove '/' separator */
- name_ptr = file->path;
+ name_ptr = file->vnode->path;
while (*name_ptr == '/' && *name_ptr)
- name_ptr ++;
+ {
+ name_ptr++;
+ }
strncpy(dirent->name, name_ptr, RAMFS_NAME_MAX);
rt_list_init(&(dirent->list));
dirent->data = NULL;
dirent->size = 0;
dirent->fs = ramfs;
+ file->vnode->type = FT_DIRECTORY;
/* add to the root directory */
rt_list_insert_after(&(ramfs->root.list), &(dirent->list));
@@ -256,12 +278,16 @@ int dfs_ramfs_open(struct dfs_fd *file)
}
}
- file->data = dirent;
- file->size = dirent->size;
+ file->vnode->data = dirent;
+ file->vnode->size = dirent->size;
if (file->flags & O_APPEND)
- file->pos = file->size;
+ {
+ file->pos = file->vnode->size;
+ }
else
+ {
file->pos = 0;
+ }
return 0;
}
@@ -299,7 +325,7 @@ int dfs_ramfs_getdents(struct dfs_fd *file,
struct ramfs_dirent *dirent;
struct dfs_ramfs *ramfs;
- dirent = (struct ramfs_dirent *)file->data;
+ dirent = (struct ramfs_dirent *)file->vnode->data;
ramfs = dirent->fs;
RT_ASSERT(ramfs != RT_NULL);
diff --git a/components/dfs/filesystems/romfs/dfs_romfs.c b/components/dfs/filesystems/romfs/dfs_romfs.c
index 981e5f2ee8..bdce2a8bb2 100644
--- a/components/dfs/filesystems/romfs/dfs_romfs.c
+++ b/components/dfs/filesystems/romfs/dfs_romfs.c
@@ -34,7 +34,28 @@ int dfs_romfs_unmount(struct dfs_filesystem *fs)
int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args)
{
- return -EIO;
+ int ret = RT_EOK;
+ struct romfs_dirent *dirent;
+
+ dirent = (struct romfs_dirent *)file->vnode->data;
+ RT_ASSERT(dirent != NULL);
+
+ switch (cmd)
+ {
+ case RT_FIOGETADDR:
+ {
+ *(rt_ubase_t*)args = (rt_ubase_t)dirent->data;
+ break;
+ }
+ case RT_FIOFTRUNCATE:
+ {
+ break;
+ }
+ default:
+ ret = -RT_EINVAL;
+ break;
+ }
+ return ret;
}
rt_inline int check_dirent(struct romfs_dirent *dirent)
@@ -112,9 +133,6 @@ struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const ch
else
{
/* return file dirent */
- if (subpath != NULL)
- break; /* not the end of path */
-
return &dirent[index];
}
}
@@ -133,7 +151,7 @@ int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count)
rt_size_t length;
struct romfs_dirent *dirent;
- dirent = (struct romfs_dirent *)file->data;
+ dirent = (struct romfs_dirent *)file->vnode->data;
RT_ASSERT(dirent != NULL);
if (check_dirent(dirent) != 0)
@@ -141,10 +159,10 @@ int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count)
return -EIO;
}
- if (count < file->size - file->pos)
+ if (count < file->vnode->size - file->pos)
length = count;
else
- length = file->size - file->pos;
+ length = file->vnode->size - file->pos;
if (length > 0)
rt_memcpy(buf, &(dirent->data[file->pos]), length);
@@ -157,7 +175,7 @@ int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count)
int dfs_romfs_lseek(struct dfs_fd *file, off_t offset)
{
- if (offset >= 0 && (rt_size_t)offset <= file->size)
+ if (offset <= file->vnode->size)
{
file->pos = offset;
return file->pos;
@@ -168,7 +186,12 @@ int dfs_romfs_lseek(struct dfs_fd *file, off_t offset)
int dfs_romfs_close(struct dfs_fd *file)
{
- file->data = NULL;
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ return RT_EOK;
+ }
+ file->vnode->data = NULL;
return RT_EOK;
}
@@ -179,34 +202,63 @@ int dfs_romfs_open(struct dfs_fd *file)
struct romfs_dirent *root_dirent;
struct dfs_filesystem *fs;
- fs = (struct dfs_filesystem *)file->data;
+ if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
+ {
+ return -EINVAL;
+ }
+
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ if (file->vnode->type == FT_DIRECTORY
+ && !(file->flags & O_DIRECTORY))
+ {
+ return -ENOENT;
+ }
+ file->pos = 0;
+ return 0;
+ }
+
+ fs = file->vnode->fs;
root_dirent = (struct romfs_dirent *)fs->data;
if (check_dirent(root_dirent) != 0)
+ {
return -EIO;
+ }
if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
+ {
return -EINVAL;
+ }
- dirent = dfs_romfs_lookup(root_dirent, file->path, &size);
+ dirent = dfs_romfs_lookup(root_dirent, file->vnode->path, &size);
if (dirent == NULL)
+ {
return -ENOENT;
+ }
/* entry is a directory file type */
if (dirent->type == ROMFS_DIRENT_DIR)
{
if (!(file->flags & O_DIRECTORY))
+ {
return -ENOENT;
+ }
+ file->vnode->type = FT_DIRECTORY;
}
else
{
/* entry is a file, but open it as a directory */
if (file->flags & O_DIRECTORY)
+ {
return -ENOENT;
+ }
+ file->vnode->type = FT_REGULAR;
}
- file->data = dirent;
- file->size = size;
+ file->vnode->data = dirent;
+ file->vnode->size = size;
file->pos = 0;
return RT_EOK;
@@ -222,7 +274,9 @@ int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
dirent = dfs_romfs_lookup(root_dirent, path, &size);
if (dirent == NULL)
+ {
return -ENOENT;
+ }
st->st_dev = 0;
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
@@ -248,9 +302,11 @@ int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
struct dirent *d;
struct romfs_dirent *dirent, *sub_dirent;
- dirent = (struct romfs_dirent *)file->data;
+ dirent = (struct romfs_dirent *)file->vnode->data;
if (check_dirent(dirent) != 0)
+ {
return -EIO;
+ }
RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
/* enter directory */
@@ -259,10 +315,12 @@ int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
/* make integer count */
count = (count / sizeof(struct dirent));
if (count == 0)
+ {
return -EINVAL;
+ }
index = 0;
- for (index = 0; index < count && (rt_size_t)file->pos < file->size; index ++)
+ for (index = 0; index < count && file->pos < file->vnode->size; index++)
{
d = dirp + index;
diff --git a/components/dfs/filesystems/tmpfs/SConscript b/components/dfs/filesystems/tmpfs/SConscript
new file mode 100644
index 0000000000..c94a9bcff0
--- /dev/null
+++ b/components/dfs/filesystems/tmpfs/SConscript
@@ -0,0 +1,9 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_TMPFS'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/dfs/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/filesystems/tmpfs/dfs_tmpfs.c
new file mode 100644
index 0000000000..a2eebe00f3
--- /dev/null
+++ b/components/dfs/filesystems/tmpfs/dfs_tmpfs.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-24 flybreak the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <dfs.h>
+#include <dfs_fs.h>
+#include <dfs_file.h>
+
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#include <lwp_user_mm.h>
+#endif
+
+#include "dfs_tmpfs.h"
+
+#define DBG_TAG "tmpfs"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static int _path_separate(const char *path, char *parent_path, char *file_name)
+{
+ const char *path_p, *path_q;
+
+ RT_ASSERT(path[0] == '/');
+
+ file_name[0] = '\0';
+ path_p = path_q = &path[1];
+__next_dir:
+ while (*path_q != '/' && *path_q != '\0')
+ {
+ path_q++;
+ }
+ if (path_q != path_p) /*sub dir*/
+ {
+ if (*path_q != '\0')
+ {
+ path_q++;
+ path_p = path_q;
+ goto __next_dir;
+ }
+ else /* Last level dir */
+ {
+ rt_memcpy(parent_path, path, path_p - path - 1);
+ parent_path[path_p - path - 1] = '\0';
+ rt_memcpy(file_name, path_p, path_q - path_p);
+ file_name[path_q - path_p] = '\0';
+ }
+ }
+ if (parent_path[0] == 0)
+ {
+ parent_path[0] = '/';
+ parent_path[1] = '\0';
+ }
+ LOG_D("parent_path: %s", parent_path);
+ LOG_D("file_name: %s", file_name);
+
+ return 0;
+}
+
+static int _get_subdir(const char *path, char *name)
+{
+ const char *subpath = path;
+ while (*subpath == '/' && *subpath)
+ subpath ++;
+ while (*subpath != '/' && *subpath)
+ {
+ *name = *subpath;
+ name ++;
+ subpath ++;
+ }
+ return 0;
+}
+
+static int _free_subdir(struct tmpfs_file *dfile)
+{
+ struct tmpfs_file *file;
+ rt_list_t *list, *temp_list;
+
+ RT_DEFINE_SPINLOCK(lock);
+
+ RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
+
+ rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
+ {
+ file = rt_list_entry(list, struct tmpfs_file, sibling);
+ if (file->type == TMPFS_TYPE_DIR)
+ {
+ _free_subdir(file);
+ }
+ if (file->data != NULL)
+ {
+ /* TODO: fix for rt-smart */
+ rt_free(file->data);
+ }
+ rt_hw_spin_lock(&lock);
+ rt_list_remove(&(file->sibling));
+ rt_hw_spin_unlock(&lock);
+ rt_free(file);
+ }
+ return 0;
+}
+
+int dfs_tmpfs_mount(struct dfs_filesystem *fs,
+ unsigned long rwflag,
+ const void *data)
+{
+ struct tmpfs_sb *superblock;
+
+ superblock = rt_calloc(1, sizeof(struct tmpfs_sb));
+ superblock->df_size = sizeof(struct tmpfs_sb);
+ superblock->magic = TMPFS_MAGIC;
+ rt_list_init(&superblock->sibling);
+
+ superblock->root.name[0] = '/';
+ superblock->root.sb = superblock;
+ superblock->root.type = TMPFS_TYPE_DIR;
+ rt_list_init(&superblock->root.sibling);
+ rt_list_init(&superblock->root.subdirs);
+
+ fs->data = superblock;
+
+ return RT_EOK;
+}
+
+int dfs_tmpfs_unmount(struct dfs_filesystem *fs)
+{
+ struct tmpfs_sb *superblock;
+
+ superblock = (struct tmpfs_sb *)fs->data;
+ RT_ASSERT(superblock != NULL);
+
+ _free_subdir(&(superblock->root));
+ rt_free(superblock);
+
+ fs->data = NULL;
+
+ return RT_EOK;
+}
+
+int dfs_tmpfs_statfs(struct dfs_filesystem *fs, struct statfs *buf)
+{
+ struct tmpfs_sb *superblock;
+
+ superblock = (struct tmpfs_sb *)fs->data;
+ RT_ASSERT(superblock != NULL);
+ RT_ASSERT(buf != NULL);
+
+ buf->f_bsize = 512;
+ buf->f_blocks = (superblock->df_size + 511) / 512;
+ buf->f_bfree = 1;
+
+ return RT_EOK;
+}
+
+int dfs_tmpfs_ioctl(struct dfs_fd *file, int cmd, void *args)
+{
+ struct tmpfs_file *d_file;
+ struct tmpfs_sb *superblock;
+
+ d_file = (struct tmpfs_file *)file->vnode->data;
+ RT_ASSERT(d_file != NULL);
+
+ superblock = d_file->sb;
+ RT_ASSERT(superblock != NULL);
+
+ switch (cmd)
+ {
+#ifdef RT_USING_LWP
+ case RT_FIOMMAP2:
+ {
+ struct dfs_mmap2_args *mmap2 = (struct dfs_mmap2_args *)args;
+ if (mmap2)
+ {
+ if (mmap2->length > file->vnode->size)
+ {
+ return -RT_ENOMEM;
+ }
+
+ LOG_D("tmpfile mmap ptr:%x , size:%d\n", d_file->data, mmap2->length);
+ mmap2->ret = lwp_map_user_phy(lwp_self(), RT_NULL, d_file->data, mmap2->length, 0);
+ }
+ return RT_EOK;
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+ return -EIO;
+}
+
+struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock,
+ const char *path,
+ rt_size_t *size)
+{
+ const char *subpath, *curpath, *filename = RT_NULL;
+ char subdir_name[TMPFS_NAME_MAX];
+ struct tmpfs_file *file, *curfile;
+ rt_list_t *list;
+
+ RT_DEFINE_SPINLOCK(lock);
+
+ subpath = path;
+ while (*subpath == '/' && *subpath)
+ subpath ++;
+ if (! *subpath) /* is root directory */
+ {
+ *size = 0;
+ return &(superblock->root);
+ }
+
+ curpath = subpath;
+ curfile = &superblock->root;
+
+find_subpath:
+ while (*subpath != '/' && *subpath)
+ subpath ++;
+
+ if (! *subpath) /* is last directory */
+ filename = curpath;
+ else
+ subpath ++; /* skip '/' */
+
+ memset(subdir_name, 0, TMPFS_NAME_MAX);
+ _get_subdir(curpath, subdir_name);
+
+ rt_hw_spin_lock(&lock);
+
+ rt_list_for_each(list, &curfile->subdirs)
+ {
+ file = rt_list_entry(list, struct tmpfs_file, sibling);
+ if (filename) /* find file */
+ {
+ if (rt_strcmp(file->name, filename) == 0)
+ {
+ *size = file->size;
+
+ rt_hw_spin_unlock(&lock);
+ return file;
+ }
+ }
+ else if (rt_strcmp(file->name, subdir_name) == 0)
+ {
+ *size = file->size;
+ curpath = subpath;
+ curfile = file;
+ rt_hw_spin_unlock(&lock);
+ goto find_subpath;
+ }
+ }
+ rt_hw_spin_unlock(&lock);
+ /* not found */
+ return NULL;
+}
+
+int dfs_tmpfs_read(struct dfs_fd *file, void *buf, size_t count)
+{
+ rt_size_t length;
+ struct tmpfs_file *d_file;
+
+ d_file = (struct tmpfs_file *)file->vnode->data;
+ RT_ASSERT(d_file != NULL);
+
+ if (count < file->vnode->size - file->pos)
+ length = count;
+ else
+ length = file->vnode->size - file->pos;
+
+ if (length > 0)
+ memcpy(buf, &(d_file->data[file->pos]), length);
+
+ /* update file current position */
+ file->pos += length;
+
+ return length;
+}
+
+
+int dfs_tmpfs_write(struct dfs_fd *fd, const void *buf, size_t count)
+{
+ struct tmpfs_file *d_file;
+ struct tmpfs_sb *superblock;
+
+ d_file = (struct tmpfs_file *)fd->vnode->data;
+ RT_ASSERT(d_file != NULL);
+
+ superblock = d_file->sb;
+ RT_ASSERT(superblock != NULL);
+
+ if (count + fd->pos > fd->vnode->size)
+ {
+ rt_uint8_t *ptr;
+ ptr = rt_realloc(d_file->data, fd->pos + count);
+ if (ptr == NULL)
+ {
+ rt_set_errno(-ENOMEM);
+ return 0;
+ }
+
+ superblock->df_size += (fd->pos - d_file->size + count);
+ /* update d_file and file size */
+ d_file->data = ptr;
+ d_file->size = fd->pos + count;
+ fd->vnode->size = d_file->size;
+ LOG_D("tmpfile ptr:%x, size:%d", ptr, d_file->size);
+ }
+
+ if (count > 0)
+ memcpy(d_file->data + fd->pos, buf, count);
+
+ /* update file current position */
+ fd->pos += count;
+
+ return count;
+}
+
+int dfs_tmpfs_lseek(struct dfs_fd *file, off_t offset)
+{
+ if (offset <= (off_t)file->vnode->size)
+ {
+ file->pos = offset;
+
+ return file->pos;
+ }
+
+ return -EIO;
+}
+
+int dfs_tmpfs_close(struct dfs_fd *file)
+{
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ return 0;
+ }
+
+ file->vnode->data = NULL;
+
+ return RT_EOK;
+}
+
+int dfs_tmpfs_open(struct dfs_fd *file)
+{
+ rt_size_t size;
+ struct tmpfs_sb *superblock;
+ struct tmpfs_file *d_file, *p_file;
+ struct dfs_filesystem *fs;
+ char parent_path[DFS_PATH_MAX],file_name[TMPFS_NAME_MAX];
+
+ RT_DEFINE_SPINLOCK(lock);
+
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if (file->vnode->ref_count > 1)
+ {
+ if (file->vnode->type == FT_DIRECTORY
+ && !(file->flags & O_DIRECTORY))
+ {
+ return -ENOENT;
+ }
+ file->pos = 0;
+ return 0;
+ }
+
+ fs = file->vnode->fs;
+
+ superblock = (struct tmpfs_sb *)fs->data;
+ RT_ASSERT(superblock != NULL);
+
+ /* find file */
+ d_file = dfs_tmpfs_lookup(superblock, file->vnode->path, &size);
+ if (d_file == NULL && !(file->flags & O_CREAT))
+ return -ENOENT;
+
+ /* Creates a new file. */
+ if (file->flags & O_CREAT)
+ {
+ if (d_file != NULL)
+ return -EEXIST;
+
+ /* find parent file */
+ _path_separate(file->vnode->path, parent_path, file_name);
+ if (file_name[0] == '\0') /* it's root dir */
+ return -ENOENT;
+
+ /* open parent directory */
+ p_file = dfs_tmpfs_lookup(superblock, parent_path, &size);
+ if (p_file == NULL)
+ return -ENOENT;
+
+ /* create a file entry */
+ d_file = (struct tmpfs_file *)rt_calloc(1, sizeof(struct tmpfs_file));
+ if (d_file == NULL)
+ {
+ return -ENOMEM;
+ }
+ superblock->df_size += sizeof(struct tmpfs_file);
+
+ strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
+
+ rt_list_init(&(d_file->subdirs));
+ rt_list_init(&(d_file->sibling));
+ d_file->data = NULL;
+ d_file->size = 0;
+ d_file->sb = superblock;
+ if (file->flags & O_DIRECTORY)
+ {
+ d_file->type = TMPFS_TYPE_DIR;
+ }
+ else
+ {
+ d_file->type = TMPFS_TYPE_FILE;
+ }
+ rt_hw_spin_lock(&lock);
+ rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
+ rt_hw_spin_unlock(&lock);
+ }
+ /* Creates a new file.
+ * If the file is existing, it is truncated and overwritten.
+ */
+ if (file->flags & O_TRUNC)
+ {
+ d_file->size = 0;
+ if (d_file->data != NULL)
+ {
+ /* ToDo: fix for rt-smart. */
+ rt_free(d_file->data);
+ d_file->data = NULL;
+ }
+ }
+
+ /* fill file */
+ if (d_file->type == TMPFS_TYPE_DIR)
+ {
+ if (file->flags & O_DIRECTORY)
+ file->vnode->type = FT_DIRECTORY;
+ else
+ return -ENOMEM;
+ }
+ else
+ {
+ if (file->flags & O_DIRECTORY)
+ {
+ return -ENOMEM;
+ }
+ file->vnode->type = FT_DEVICE;
+ }
+
+ file->vnode->data = d_file;
+ file->vnode->size = d_file->size;
+ if (file->flags & O_APPEND)
+ {
+ file->pos = file->vnode->size;
+ }
+ else
+ {
+ file->pos = 0;
+ }
+
+ return 0;
+}
+
+int dfs_tmpfs_stat(struct dfs_filesystem *fs,
+ const char *path,
+ struct stat *st)
+{
+ rt_size_t size;
+ struct tmpfs_file *d_file;
+ struct tmpfs_sb *superblock;
+
+ superblock = (struct tmpfs_sb *)fs->data;
+ d_file = dfs_tmpfs_lookup(superblock, path, &size);
+
+ if (d_file == NULL)
+ return -ENOENT;
+
+ st->st_dev = 0;
+ st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ if (d_file->type == TMPFS_TYPE_DIR)
+ {
+ st->st_mode &= ~S_IFREG;
+ st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ }
+
+ st->st_size = d_file->size;
+ st->st_mtime = 0;
+
+ return RT_EOK;
+}
+
+int dfs_tmpfs_getdents(struct dfs_fd *file,
+ struct dirent *dirp,
+ uint32_t count)
+{
+ rt_size_t index, end;
+ struct dirent *d;
+ struct tmpfs_file *d_file, *n_file;
+ rt_list_t *list;
+ struct tmpfs_sb *superblock;
+
+ d_file = (struct tmpfs_file *)file->vnode->data;
+
+ superblock = d_file->sb;
+ RT_ASSERT(superblock != RT_NULL);
+
+ /* make integer count */
+ count = (count / sizeof(struct dirent));
+ if (count == 0)
+ return -EINVAL;
+
+ end = file->pos + count;
+ index = 0;
+ count = 0;
+
+ rt_list_for_each(list, &d_file->subdirs)
+ {
+ n_file = rt_list_entry(list, struct tmpfs_file, sibling);
+ if (index >= (rt_size_t)file->pos)
+ {
+ d = dirp + count;
+ if (d_file->type == TMPFS_TYPE_FILE)
+ {
+ d->d_type = DT_REG;
+ }
+ if (d_file->type == TMPFS_TYPE_DIR)
+ {
+ d->d_type = DT_DIR;
+ }
+ d->d_namlen = RT_NAME_MAX;
+ d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
+ rt_strncpy(d->d_name, n_file->name, TMPFS_NAME_MAX);
+
+ count += 1;
+ file->pos += 1;
+ }
+ index += 1;
+ if (index >= end)
+ {
+ break;
+ }
+ }
+
+ return count * sizeof(struct dirent);
+}
+
+int dfs_tmpfs_unlink(struct dfs_filesystem *fs, const char *path)
+{
+ rt_size_t size;
+ struct tmpfs_sb *superblock;
+ struct tmpfs_file *d_file;
+
+ RT_DEFINE_SPINLOCK(lock);
+
+ superblock = (struct tmpfs_sb *)fs->data;
+ RT_ASSERT(superblock != NULL);
+
+ d_file = dfs_tmpfs_lookup(superblock, path, &size);
+ if (d_file == NULL)
+ return -ENOENT;
+
+ rt_hw_spin_lock(&lock);
+ rt_list_remove(&(d_file->sibling));
+ rt_hw_spin_unlock(&lock);
+
+ if (d_file->data != NULL)
+ rt_free(d_file->data);
+ rt_free(d_file);
+
+ return RT_EOK;
+}
+
+int dfs_tmpfs_rename(struct dfs_filesystem *fs,
+ const char *oldpath,
+ const char *newpath)
+{
+ struct tmpfs_file *d_file, *p_file;
+ struct tmpfs_sb *superblock;
+ rt_size_t size;
+ char parent_path[DFS_PATH_MAX],file_name[TMPFS_NAME_MAX];
+
+ RT_DEFINE_SPINLOCK(lock);
+
+ superblock = (struct tmpfs_sb *)fs->data;
+ RT_ASSERT(superblock != NULL);
+
+ d_file = dfs_tmpfs_lookup(superblock, newpath, &size);
+ if (d_file != NULL)
+ return -EEXIST;
+
+ d_file = dfs_tmpfs_lookup(superblock, oldpath, &size);
+ if (d_file == NULL)
+ return -ENOENT;
+
+ /* find parent file */
+ _path_separate(newpath, parent_path, file_name);
+ if (file_name[0] == '\0') /* it's root dir */
+ return -ENOENT;
+ /* open parent directory */
+ p_file = dfs_tmpfs_lookup(superblock, parent_path, &size);
+ RT_ASSERT(p_file != NULL);
+
+ rt_hw_spin_lock(&lock);
+ rt_list_remove(&(d_file->sibling));
+ rt_hw_spin_unlock(&lock);
+
+ strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
+
+ rt_hw_spin_lock(&lock);
+ rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
+ rt_hw_spin_unlock(&lock);
+
+ return RT_EOK;
+}
+
+static const struct dfs_file_ops _tmp_fops =
+{
+ dfs_tmpfs_open,
+ dfs_tmpfs_close,
+ dfs_tmpfs_ioctl,
+ dfs_tmpfs_read,
+ dfs_tmpfs_write,
+ NULL, /* flush */
+ dfs_tmpfs_lseek,
+ dfs_tmpfs_getdents,
+};
+
+static const struct dfs_filesystem_ops _tmpfs =
+{
+ "tmp",
+ DFS_FS_FLAG_DEFAULT,
+ &_tmp_fops,
+
+ dfs_tmpfs_mount,
+ dfs_tmpfs_unmount,
+ NULL, /* mkfs */
+ dfs_tmpfs_statfs,
+
+ dfs_tmpfs_unlink,
+ dfs_tmpfs_stat,
+ dfs_tmpfs_rename,
+};
+
+int dfs_tmpfs_init(void)
+{
+ /* register tmp file system */
+ dfs_register(&_tmpfs);
+
+ return 0;
+}
diff --git a/components/dfs/filesystems/tmpfs/dfs_tmpfs.h b/components/dfs/filesystems/tmpfs/dfs_tmpfs.h
new file mode 100644
index 0000000000..37911bfd1b
--- /dev/null
+++ b/components/dfs/filesystems/tmpfs/dfs_tmpfs.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-24 flybreak the first version
+ */
+
+#ifndef __DFS_TMPFS_H__
+#define __DFS_TMPFS_H__
+
+#include <rtthread.h>
+
+#define TMPFS_NAME_MAX 32
+#define TMPFS_MAGIC 0x0B0B0B0B
+
+#define TMPFS_TYPE_FILE 0x00
+#define TMPFS_TYPE_DIR 0x01
+
+struct tmpfs_sb;
+
+struct tmpfs_file
+{
+ rt_uint32_t type; /* file type */
+ char name[TMPFS_NAME_MAX]; /* file name */
+ rt_list_t subdirs; /* file subdir list */
+ rt_list_t sibling; /* file sibling list */
+ struct tmpfs_sb *sb; /* superblock ptr */
+ rt_uint8_t *data; /* file date ptr */
+ rt_size_t size; /* file size */
+};
+
+
+struct tmpfs_sb
+{
+ rt_uint32_t magic; /* TMPFS_MAGIC */
+ struct tmpfs_file root; /* root dir */
+ rt_size_t df_size; /* df size */
+ rt_list_t sibling; /* sb sibling list */
+};
+
+int dfs_tmpfs_init(void);
+
+#endif
+
diff --git a/components/dfs/include/dfs.h b/components/dfs/include/dfs.h
index 678ff0e377..b2575fbf4d 100644
--- a/components/dfs/include/dfs.h
+++ b/components/dfs/include/dfs.h
@@ -37,8 +37,8 @@ extern "C" {
/*
* skip stdin/stdout/stderr normally
*/
-#ifndef DFS_FD_OFFSET
-#define DFS_FD_OFFSET 3
+#ifndef DFS_STDIO_OFFSET
+#define DFS_STDIO_OFFSET 3
#endif
#ifndef DFS_PATH_MAX
@@ -87,11 +87,27 @@ struct dfs_fdtable *dfs_fdtable_get(void);
void dfs_lock(void);
void dfs_unlock(void);
+void dfs_fd_lock(void);
+void dfs_fd_unlock(void);
+
+void dfs_fm_lock(void);
+void dfs_fm_unlock(void);
+
#ifdef DFS_USING_POSIX
/* FD APIs */
+int fdt_fd_new(struct dfs_fdtable *fdt);
+struct dfs_fd *fdt_fd_get(struct dfs_fdtable* fdt, int fd);
+void fdt_fd_release(struct dfs_fdtable* fdt, int fd);
int fd_new(void);
+int fd_associate(struct dfs_fdtable *fdt, int fd, struct dfs_fd *file);
struct dfs_fd *fd_get(int fd);
-void fd_put(struct dfs_fd *fd);
+int fd_get_fd_index(struct dfs_fd *file);
+void fd_release(int fd);
+
+void fd_init(struct dfs_fd *fd);
+
+struct dfs_fdtable *dfs_fdtable_get(void);
+struct dfs_fdtable *dfs_fdtable_get_global(void);
#endif /* DFS_USING_POSIX */
#ifdef __cplusplus
diff --git a/components/dfs/include/dfs_file.h b/components/dfs/include/dfs_file.h
index df1013d69c..7258127331 100644
--- a/components/dfs/include/dfs_file.h
+++ b/components/dfs/include/dfs_file.h
@@ -36,24 +36,47 @@ struct dfs_file_ops
/* file descriptor */
#define DFS_FD_MAGIC 0xfdfd
-struct dfs_fd
+
+struct dfs_fnode
{
- uint16_t magic; /* file descriptor magic number */
uint16_t type; /* Type (regular or socket) */
char *path; /* Name (below mount point) */
+ char *fullpath; /* Full path is hash key */
int ref_count; /* Descriptor reference count */
+ rt_list_t list; /* The node of vnode hash table */
struct dfs_filesystem *fs;
const struct dfs_file_ops *fops;
+ uint32_t flags; /* self flags, is dir etc.. */
- uint32_t flags; /* Descriptor flags */
size_t size; /* Size in bytes */
+ void *data; /* Specific file system data */
+};
+
+struct dfs_fd
+{
+ uint16_t magic; /* file descriptor magic number */
+ uint32_t flags; /* Descriptor flags */
+ int ref_count; /* Descriptor reference count */
off_t pos; /* Current file position */
+ struct dfs_fnode *vnode; /* file node struct */
+ void *data; /* Specific fd data */
+};
- void *data; /* Specific file system data */
+struct dfs_mmap2_args
+{
+ void *addr;
+ size_t length;
+ int prot;
+ int flags;
+ off_t pgoffset;
+
+ void *ret;
};
+void dfs_fnode_mgr_init(void);
+int dfs_file_is_open(const char *pathname);
int dfs_file_open(struct dfs_fd *fd, const char *path, int flags);
int dfs_file_close(struct dfs_fd *fd);
int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args);
@@ -67,9 +90,12 @@ int dfs_file_lseek(struct dfs_fd *fd, off_t offset);
int dfs_file_stat(const char *path, struct stat *buf);
int dfs_file_rename(const char *oldpath, const char *newpath);
int dfs_file_ftruncate(struct dfs_fd *fd, off_t length);
+int dfs_file_mmap2(struct dfs_fd *fd, struct dfs_mmap2_args *mmap2);
/* 0x5254 is just a magic number to make these relatively unique ("RT") */
-#define RT_FIOFTRUNCATE 0x52540000U
+#define RT_FIOFTRUNCATE 0x52540000U
+#define RT_FIOGETADDR 0x52540001U
+#define RT_FIOMMAP2 0x52540002U
#ifdef __cplusplus
}
diff --git a/components/dfs/include/dfs_fs.h b/components/dfs/include/dfs_fs.h
index 0a13040c21..985017afe0 100644
--- a/components/dfs/include/dfs_fs.h
+++ b/components/dfs/include/dfs_fs.h
@@ -37,7 +37,7 @@ struct dfs_filesystem_ops
int (*unmount) (struct dfs_filesystem *fs);
/* make a file system */
- int (*mkfs) (rt_device_t devid);
+ int (*mkfs) (rt_device_t dev_id, const char *fs_name);
int (*statfs) (struct dfs_filesystem *fs, struct statfs *buf);
int (*unlink) (struct dfs_filesystem *fs, const char *pathname);
diff --git a/components/dfs/src/dfs.c b/components/dfs/src/dfs.c
index f1d7571c0c..f3f9c2354b 100644
--- a/components/dfs/src/dfs.c
+++ b/components/dfs/src/dfs.c
@@ -28,12 +28,14 @@ struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX];
/* device filesystem lock */
static struct rt_mutex fslock;
+static struct rt_mutex fdlock;
#ifdef DFS_USING_WORKDIR
char working_directory[DFS_PATH_MAX] = {"/"};
#endif
static struct dfs_fdtable _fdtab;
+static int fd_alloc(struct dfs_fdtable *fdt, int startfd);
/**
* @addtogroup DFS
@@ -54,6 +56,9 @@ int dfs_init(void)
return 0;
}
+ /* init vnode hash table */
+ dfs_fnode_mgr_init();
+
/* clear filesystem operations table */
rt_memset((void *)filesystem_operation_table, 0, sizeof(filesystem_operation_table));
/* clear filesystem table */
@@ -63,6 +68,7 @@ int dfs_init(void)
/* create device filesystem lock */
rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_PRIO);
+ rt_mutex_init(&fdlock, "fdlock", RT_IPC_FLAG_PRIO);
#ifdef DFS_USING_WORKDIR
/* set current working directory */
@@ -70,6 +76,13 @@ int dfs_init(void)
working_directory[0] = '/';
#endif
+#ifdef RT_USING_DFS_TMPFS
+ {
+ extern int dfs_tmpfs_init(void);
+ dfs_tmpfs_init();
+ }
+#endif
+
#ifdef RT_USING_DFS_DEVFS
{
extern int devfs_init(void);
@@ -79,6 +92,13 @@ int dfs_init(void)
dfs_mount(NULL, "/dev", "devfs", 0, 0);
}
+#if defined(RT_USING_DEV_BUS) && defined(RT_USING_DFS_TMPFS)
+ mkdir("/dev/shm", 0x777);
+ if (dfs_mount(RT_NULL, "/dev/shm", "tmp", 0, 0) != 0)
+ {
+ rt_kprintf("Dir /dev/shm mount failed!\n");
+ }
+#endif
#endif
init_ok = RT_TRUE;
@@ -107,6 +127,21 @@ void dfs_lock(void)
}
}
+void dfs_fd_lock(void)
+{
+ rt_err_t result = -RT_EBUSY;
+
+ while (result == -RT_EBUSY)
+ {
+ result = rt_mutex_take(&fdlock, RT_WAITING_FOREVER);
+ }
+
+ if (result != RT_EOK)
+ {
+ RT_ASSERT(0);
+ }
+}
+
/**
* this function will lock device file system.
*
@@ -118,51 +153,95 @@ void dfs_unlock(void)
}
#ifdef DFS_USING_POSIX
-static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
+
+void dfs_fd_unlock(void)
{
- int idx;
+ rt_mutex_release(&fdlock);
+}
- /* find an empty fd entry */
- for (idx = startfd; idx < (int)fdt->maxfd; idx++)
+static int fd_slot_expand(struct dfs_fdtable *fdt, int fd)
+{
+ int nr;
+ int index;
+ struct dfs_fd **fds = NULL;
+
+ if (fd < fdt->maxfd)
{
- if (fdt->fds[idx] == RT_NULL)
- break;
- if (fdt->fds[idx]->ref_count == 0)
- break;
+ return fd;
+ }
+ if (fd >= DFS_FD_MAX)
+ {
+ return -1;
}
- /* allocate a larger FD container */
- if (idx == (int)fdt->maxfd && fdt->maxfd < DFS_FD_MAX)
+ nr = ((fd + 4) & ~3);
+ if (nr > DFS_FD_MAX)
{
- int cnt, index;
- struct dfs_fd **fds;
+ nr = DFS_FD_MAX;
+ }
+ fds = (struct dfs_fd **)rt_realloc(fdt->fds, nr * sizeof(struct dfs_fd *));
+ if (!fds)
+ {
+ return -1;
+ }
- /* increase the number of FD with 4 step length */
- cnt = fdt->maxfd + 4;
- cnt = cnt > DFS_FD_MAX ? DFS_FD_MAX : cnt;
+ /* clean the new allocated fds */
+ for (index = fdt->maxfd; index < nr; index++)
+ {
+ fds[index] = NULL;
+ }
+ fdt->fds = fds;
+ fdt->maxfd = nr;
- fds = (struct dfs_fd **)rt_realloc(fdt->fds, cnt * sizeof(struct dfs_fd *));
- if (fds == NULL) goto __exit; /* return fdt->maxfd */
+ return fd;
+}
+
+static int fd_slot_alloc(struct dfs_fdtable *fdt, int startfd)
+{
+ int idx;
- /* clean the new allocated fds */
- for (index = (int)fdt->maxfd; index < cnt; index ++)
+ /* find an empty fd slot */
+ for (idx = startfd; idx < (int)fdt->maxfd; idx++)
+ {
+ if (fdt->fds[idx] == RT_NULL)
{
- fds[index] = NULL;
+ return idx;
}
+ }
- fdt->fds = fds;
- fdt->maxfd = cnt;
+ idx = fdt->maxfd;
+ if (idx < startfd)
+ {
+ idx = startfd;
}
+ if (fd_slot_expand(fdt, idx) < 0)
+ {
+ return -1;
+ }
+ return idx;
+}
+static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
+{
+ int idx;
+ struct dfs_fd *fd = NULL;
+
+ idx = fd_slot_alloc(fdt, startfd);
/* allocate 'struct dfs_fd' */
- if (idx < (int)fdt->maxfd && fdt->fds[idx] == RT_NULL)
+ if (idx < 0)
{
- fdt->fds[idx] = (struct dfs_fd *)rt_calloc(1, sizeof(struct dfs_fd));
- if (fdt->fds[idx] == RT_NULL)
- idx = fdt->maxfd;
+ return -1;
}
+ fd = (struct dfs_fd *)rt_calloc(1, sizeof(struct dfs_fd));
+ if (!fd)
+ {
+ return -1;
+ }
+ fd->ref_count = 1;
+ fd->magic = DFS_FD_MAGIC;
+ fd->vnode = NULL;
+ fdt->fds[idx] = fd;
-__exit:
return idx;
}
@@ -172,34 +251,32 @@ __exit:
*
* @return -1 on failed or the allocated file descriptor.
*/
-int fd_new(void)
+int fdt_fd_new(struct dfs_fdtable *fdt)
{
- struct dfs_fd *d;
int idx;
- struct dfs_fdtable *fdt;
- fdt = dfs_fdtable_get();
/* lock filesystem */
- dfs_lock();
+ dfs_fd_lock();
/* find an empty fd entry */
- idx = fd_alloc(fdt, 0);
+ idx = fd_alloc(fdt, DFS_STDIO_OFFSET);
/* can't find an empty fd entry */
- if (idx == (int)fdt->maxfd)
+ if (idx < 0)
{
- idx = -(1 + DFS_FD_OFFSET);
LOG_E("DFS fd new is failed! Could not found an empty fd entry.");
- goto __result;
}
- d = fdt->fds[idx];
- d->ref_count = 1;
- d->magic = DFS_FD_MAGIC;
+ dfs_fd_unlock();
+ return idx;
+}
-__result:
- dfs_unlock();
- return idx + DFS_FD_OFFSET;
+int fd_new(void)
+{
+ struct dfs_fdtable *fdt = NULL;
+
+ fdt = dfs_fdtable_get();
+ return fdt_fd_new(fdt);
}
/**
@@ -211,69 +288,119 @@ __result:
* @return NULL on on this file descriptor or the file descriptor structure
* pointer.
*/
-struct dfs_fd *fd_get(int fd)
+
+struct dfs_fd *fdt_fd_get(struct dfs_fdtable* fdt, int fd)
{
struct dfs_fd *d;
- struct dfs_fdtable *fdt;
-#ifdef RT_USING_POSIX_STDIO
- if ((0 <= fd) && (fd <= 2))
- fd = libc_stdio_get_console();
-#endif /* RT_USING_POSIX_STDIO */
-
- fdt = dfs_fdtable_get();
- fd = fd - DFS_FD_OFFSET;
if (fd < 0 || fd >= (int)fdt->maxfd)
+ {
return NULL;
+ }
- dfs_lock();
+ dfs_fd_lock();
d = fdt->fds[fd];
/* check dfs_fd valid or not */
if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
{
- dfs_unlock();
+ dfs_fd_unlock();
return NULL;
}
- /* increase the reference count */
- d->ref_count ++;
- dfs_unlock();
+ dfs_fd_unlock();
return d;
}
+struct dfs_fd *fd_get(int fd)
+{
+ struct dfs_fdtable *fdt;
+
+ fdt = dfs_fdtable_get();
+ return fdt_fd_get(fdt, fd);
+}
+
/**
* @ingroup Fd
*
* This function will put the file descriptor.
*/
-void fd_put(struct dfs_fd *fd)
+void fdt_fd_release(struct dfs_fdtable* fdt, int fd)
{
- RT_ASSERT(fd != NULL);
+ struct dfs_fd *fd_slot = NULL;
- dfs_lock();
+ RT_ASSERT(fdt != NULL);
- fd->ref_count --;
+ dfs_fd_lock();
- /* clear this fd entry */
- if (fd->ref_count == 0)
+ if ((fd < 0) || (fd >= fdt->maxfd))
{
- int index;
- struct dfs_fdtable *fdt;
+ dfs_fd_unlock();
+ return;
+ }
+
+ fd_slot = fdt->fds[fd];
+ if (fd_slot == NULL)
+ {
+ dfs_fd_unlock();
+ return;
+ }
+ fdt->fds[fd] = NULL;
- fdt = dfs_fdtable_get();
- for (index = 0; index < (int)fdt->maxfd; index ++)
+ /* check fd */
+ RT_ASSERT(fd_slot->magic == DFS_FD_MAGIC);
+
+ fd_slot->ref_count--;
+
+ /* clear this fd entry */
+ if (fd_slot->ref_count == 0)
+ {
+ struct dfs_fnode *vnode = fd_slot->vnode;
+ if (vnode)
{
- if (fdt->fds[index] == fd)
- {
- rt_free(fd);
- fdt->fds[index] = 0;
- break;
- }
+ vnode->ref_count--;
}
+ rt_free(fd_slot);
}
- dfs_unlock();
+ dfs_fd_unlock();
+}
+
+void fd_release(int fd)
+{
+ struct dfs_fdtable *fdt;
+
+ fdt = dfs_fdtable_get();
+ fdt_fd_release(fdt, fd);
+}
+
+int sys_dup(int oldfd)
+{
+ int newfd = -1;
+ struct dfs_fdtable *fdt = NULL;
+
+ dfs_fd_lock();
+ /* check old fd */
+ fdt = dfs_fdtable_get();
+ if ((oldfd < 0) || (oldfd >= fdt->maxfd))
+ {
+ goto exit;
+ }
+ if (!fdt->fds[oldfd])
+ {
+ goto exit;
+ }
+ /* get a new fd */
+ newfd = fd_slot_alloc(fdt, DFS_STDIO_OFFSET);
+ if (newfd >= 0)
+ {
+ fdt->fds[newfd] = fdt->fds[oldfd];
+ /* inc ref_count */
+ fdt->fds[newfd]->ref_count++;
+ }
+exit:
+ dfs_fd_unlock();
+ return newfd;
}
#endif /* DFS_USING_POSIX */
@@ -320,9 +447,9 @@ int fd_is_open(const char *pathname)
for (index = 0; index < fdt->maxfd; index++)
{
fd = fdt->fds[index];
- if (fd == NULL || fd->fops == NULL || fd->path == NULL) continue;
+ if (fd == NULL || fd->vnode->fops == NULL || fd->vnode->path == NULL) continue;
- if (fd->fs == fs && strcmp(fd->path, mountpath) == 0)
+ if (fd->vnode->fs == fs && strcmp(fd->vnode->path, mountpath) == 0)
{
/* found file in file descriptor table */
rt_free(fullpath);
@@ -339,6 +466,139 @@ int fd_is_open(const char *pathname)
return -1;
}
+int sys_dup2(int oldfd, int newfd)
+{
+ struct dfs_fdtable *fdt = NULL;
+ int ret = 0;
+ int retfd = -1;
+
+ dfs_fd_lock();
+ /* check old fd */
+ fdt = dfs_fdtable_get();
+ if ((oldfd < 0) || (oldfd >= fdt->maxfd))
+ {
+ goto exit;
+ }
+ if (!fdt->fds[oldfd])
+ {
+ goto exit;
+ }
+ if (newfd < 0)
+ {
+ goto exit;
+ }
+ if (newfd >= fdt->maxfd)
+ {
+ newfd = fd_slot_expand(fdt, newfd);
+ if (newfd < 0)
+ {
+ goto exit;
+ }
+ }
+ if (fdt->fds[newfd] == fdt->fds[oldfd])
+ {
+ /* ok, return newfd */
+ retfd = newfd;
+ goto exit;
+ }
+
+ if (fdt->fds[newfd])
+ {
+ ret = dfs_file_close(fdt->fds[newfd]);
+ if (ret < 0)
+ {
+ goto exit;
+ }
+ fd_release(newfd);
+ }
+
+ fdt->fds[newfd] = fdt->fds[oldfd];
+ /* inc ref_count */
+ fdt->fds[newfd]->ref_count++;
+ retfd = newfd;
+exit:
+ dfs_fd_unlock();
+ return retfd;
+}
+
+static int fd_get_fd_index_form_fdt(struct dfs_fdtable *fdt, struct dfs_fd *file)
+{
+ int fd = -1;
+
+ if (file == RT_NULL)
+ {
+ return -1;
+ }
+
+ dfs_fd_lock();
+
+ for(int index = 0; index < (int)fdt->maxfd; index++)
+ {
+ if(fdt->fds[index] == file)
+ {
+ fd = index;
+ break;
+ }
+ }
+
+ dfs_fd_unlock();
+
+ return fd;
+}
+
+int fd_get_fd_index(struct dfs_fd *file)
+{
+ struct dfs_fdtable *fdt;
+
+ fdt = dfs_fdtable_get();
+ return fd_get_fd_index_form_fdt(fdt, file);
+}
+
+int fd_associate(struct dfs_fdtable *fdt, int fd, struct dfs_fd *file)
+{
+ int retfd = -1;
+
+ if (!file)
+ {
+ return retfd;
+ }
+ if (!fdt)
+ {
+ return retfd;
+ }
+
+ dfs_fd_lock();
+ /* check old fd */
+ if ((fd < 0) || (fd >= fdt->maxfd))
+ {
+ goto exit;
+ }
+
+ if (fdt->fds[fd])
+ {
+ goto exit;
+ }
+ /* inc ref_count */
+ file->ref_count++;
+ fdt->fds[fd] = file;
+ retfd = fd;
+exit:
+ dfs_fd_unlock();
+ return retfd;
+}
+
+void fd_init(struct dfs_fd *fd)
+{
+ if (fd)
+ {
+ fd->magic = DFS_FD_MAGIC;
+ fd->ref_count = 1;
+ fd->pos = 0;
+ fd->vnode = NULL;
+ fd->data = NULL;
+ }
+}
+
/**
* this function will return a sub-path name under directory.
*
@@ -383,7 +643,13 @@ char *dfs_normalize_path(const char *directory, const char *filename)
#ifdef DFS_USING_WORKDIR
if (directory == NULL) /* shall use working directory */
+ {
+#ifdef RT_USING_LWP
+ directory = lwp_getcwd();
+#else
directory = &working_directory[0];
+#endif
+ }
#else
if ((directory == NULL) && (filename[0] != '/'))
{
@@ -422,14 +688,14 @@ char *dfs_normalize_path(const char *directory, const char *filename)
if (c == '.')
{
- if (!src[1]) src ++; /* '.' and ends */
+ if (!src[1]) src++; /* '.' and ends */
else if (src[1] == '/')
{
/* './' case */
src += 2;
while ((*src == '/') && (*src != '\0'))
- src ++;
+ src++;
continue;
}
else if (src[1] == '.')
@@ -446,7 +712,7 @@ char *dfs_normalize_path(const char *directory, const char *filename)
src += 3;
while ((*src == '/') && (*src != '\0'))
- src ++;
+ src++;
goto up_one;
}
}
@@ -454,15 +720,15 @@ char *dfs_normalize_path(const char *directory, const char *filename)
/* copy up the next '/' and erase all '/' */
while ((c = *src++) != '\0' && c != '/')
- *dst ++ = c;
+ *dst++ = c;
if (c == '/')
{
- *dst ++ = '/';
+ *dst++ = '/';
while (c == '/')
c = *src++;
- src --;
+ src--;
}
else if (!c)
break;
@@ -470,20 +736,25 @@ char *dfs_normalize_path(const char *directory, const char *filename)
continue;
up_one:
- dst --;
- if (dst < dst0)
+ /* keep the topmost root directory */
+ if (dst - dst0 != 1 || dst[-1] != '/')
{
- rt_free(fullpath);
- return NULL;
+ dst--;
+
+ if (dst < dst0)
+ {
+ rt_free(fullpath);
+ return NULL;
+ }
}
while (dst0 < dst && dst[-1] != '/')
- dst --;
+ dst--;
}
*dst = '\0';
/* remove '/' in the end of path if exist */
- dst --;
+ dst--;
if ((dst != fullpath) && (*dst == '/'))
*dst = '\0';
@@ -519,6 +790,27 @@ struct dfs_fdtable *dfs_fdtable_get(void)
return fdt;
}
+#ifdef RT_USING_LWP
+struct dfs_fdtable *dfs_fdtable_get_pid(int pid)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct dfs_fdtable *fdt = RT_NULL;
+
+ lwp = lwp_from_pid(pid);
+ if (lwp)
+ {
+ fdt = &lwp->fdt;
+ }
+
+ return fdt;
+}
+#endif
+
+struct dfs_fdtable *dfs_fdtable_get_global(void)
+{
+ return &_fdtab;
+}
+
#ifdef RT_USING_FINSH
int list_fd(void)
{
@@ -532,28 +824,97 @@ int list_fd(void)
rt_kprintf("fd type ref magic path\n");
rt_kprintf("-- ------ --- ----- ------\n");
- for (index = 0; index < (int)fd_table->maxfd; index ++)
+ for (index = 0; index < (int)fd_table->maxfd; index++)
{
struct dfs_fd *fd = fd_table->fds[index];
- if (fd && fd->fops)
+ if (fd && fd->vnode->fops)
{
- rt_kprintf("%2d ", index + DFS_FD_OFFSET);
- if (fd->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
- else if (fd->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
- else if (fd->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
- else if (fd->type == FT_USER) rt_kprintf("%-7.7s ", "user");
- else if (fd->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
+ rt_kprintf("%2d ", index);
+ if (fd->vnode->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
+ else if (fd->vnode->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
+ else if (fd->vnode->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
+ else if (fd->vnode->type == FT_USER) rt_kprintf("%-7.7s ", "user");
+ else if (fd->vnode->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
else rt_kprintf("%-8.8s ", "unknown");
- rt_kprintf("%3d ", fd->ref_count);
+ rt_kprintf("%3d ", fd->vnode->ref_count);
rt_kprintf("%04x ", fd->magic);
- if (fd->fs && fd->fs->path && rt_strlen(fd->fs->path) > 1)
+ if (fd->vnode->path)
{
- rt_kprintf("%s", fd->fs->path);
+ rt_kprintf("%s\n", fd->vnode->path);
}
- if (fd->path)
+ else
{
- rt_kprintf("%s\n", fd->path);
+ rt_kprintf("\n");
+ }
+ }
+ }
+ dfs_unlock();
+
+ return 0;
+}
+
+#ifdef RT_USING_LWP
+static int lsofp(int pid)
+{
+ int index;
+ struct dfs_fdtable *fd_table = RT_NULL;
+
+ if (pid == (-1))
+ {
+ fd_table = dfs_fdtable_get();
+ if (!fd_table) return -1;
+ }
+ else
+ {
+ fd_table = dfs_fdtable_get_pid(pid);
+ if (!fd_table)
+ {
+ rt_kprintf("PID %s is not a applet(lwp)\n", pid);
+ return -1;
+ }
+ }
+
+ rt_kprintf("--- -- ------ ------ ----- ---------- ---------- ---------- ------\n");
+
+ rt_enter_critical();
+ for (index = 0; index < (int)fd_table->maxfd; index++)
+ {
+ struct dfs_fd *fd = fd_table->fds[index];
+
+ if (fd && fd->vnode->fops)
+ {
+ if(pid == (-1))
+ {
+ rt_kprintf(" K ");
+ }
+ else
+ {
+ rt_kprintf("%3d ", pid);
+ }
+
+ rt_kprintf("%2d ", index);
+ if (fd->vnode->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
+ else if (fd->vnode->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
+ else if (fd->vnode->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
+ else if (fd->vnode->type == FT_USER) rt_kprintf("%-7.7s ", "user");
+ else if (fd->vnode->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
+ else rt_kprintf("%-8.8s ", "unknown");
+ rt_kprintf("%6d ", fd->vnode->ref_count);
+ rt_kprintf("%04x 0x%.8x ", fd->magic, (int)(size_t)fd->vnode);
+
+ if(fd->vnode == RT_NULL)
+ {
+ rt_kprintf("0x%.8x 0x%.8x ", (int)0x00000000, (int)(size_t)fd);
+ }
+ else
+ {
+ rt_kprintf("0x%.8x 0x%.8x ", (int)(size_t)(fd->vnode->data), (int)(size_t)fd);
+ }
+
+ if (fd->vnode->path)
+ {
+ rt_kprintf("%s \n", fd->vnode->path);
}
else
{
@@ -561,10 +922,50 @@ int list_fd(void)
}
}
}
- dfs_unlock();
+ rt_exit_critical();
+
+ return 0;
+}
+
+int lsof(int argc, char *argv[])
+{
+ rt_kprintf("PID fd type fd-ref magic vnode vnode/data addr path \n");
+
+ if (argc == 1)
+ {
+ struct rt_list_node *node, *list;
+ struct lwp_avl_struct *pids = lwp_get_pid_ary();
+
+ lsofp(-1);
+
+ for (int index = 0; index < RT_LWP_MAX_NR; index++)
+ {
+ struct rt_lwp *lwp = (struct rt_lwp *)pids[index].data;
+
+ if (lwp)
+ {
+ list = &lwp->t_grp;
+ for (node = list->next; node != list; node = node->next)
+ {
+ lsofp(lwp_to_pid(lwp));
+ }
+ }
+ }
+ }
+ else if (argc == 3)
+ {
+ if (argv[1][0] == '-' && argv[1][1] == 'p')
+ {
+ int pid = atoi(argv[2]);
+ lsofp(pid);
+ }
+ }
return 0;
}
-#endif /* RT_USING_FINSH */
+MSH_CMD_EXPORT(lsof, list open files);
+#endif /* RT_USING_LWP */
+#endif
/*@}*/
+
diff --git a/components/dfs/src/dfs_file.c b/components/dfs/src/dfs_file.c
index a798bd3c59..1f6f0d1e29 100644
--- a/components/dfs/src/dfs_file.c
+++ b/components/dfs/src/dfs_file.c
@@ -14,6 +14,78 @@
#include <dfs.h>
#include <dfs_file.h>
#include <dfs_private.h>
+#include <unistd.h>
+
+#define DFS_FNODE_HASH_NR 128
+
+struct dfs_fnode_mgr
+{
+ struct rt_mutex lock;
+ rt_list_t head[DFS_FNODE_HASH_NR];
+};
+
+static struct dfs_fnode_mgr dfs_fm;
+
+void dfs_fm_lock(void)
+{
+ rt_mutex_take(&dfs_fm.lock, RT_WAITING_FOREVER);
+}
+
+void dfs_fm_unlock(void)
+{
+ rt_mutex_release(&dfs_fm.lock);
+}
+
+void dfs_fnode_mgr_init(void)
+{
+ int i = 0;
+
+ rt_mutex_init(&dfs_fm.lock, "dfs_mgr", RT_IPC_FLAG_PRIO);
+ for (i = 0; i < DFS_FNODE_HASH_NR; i++)
+ {
+ rt_list_init(&dfs_fm.head[i]);
+ }
+}
+
+/* BKDR Hash Function */
+static unsigned int bkdr_hash(const char *str)
+{
+ unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
+ unsigned int hash = 0;
+
+ while (*str)
+ {
+ hash = hash * seed + (*str++);
+ }
+
+ return (hash % DFS_FNODE_HASH_NR);
+}
+
+static struct dfs_fnode *dfs_fnode_find(const char *path, rt_list_t **hash_head)
+{
+ struct dfs_fnode *vnode = NULL;
+ int hash = bkdr_hash(path);
+ rt_list_t *hh;
+
+ hh = dfs_fm.head[hash].next;
+
+ if (hash_head)
+ {
+ *hash_head = &dfs_fm.head[hash];
+ }
+
+ while (hh != &dfs_fm.head[hash])
+ {
+ vnode = rt_container_of(hh, struct dfs_fnode, list);
+ if (rt_strcmp(path, vnode->fullpath) == 0)
+ {
+ /* found */
+ return vnode;
+ }
+ hh = hh->next;
+ }
+ return NULL;
+}
/**
* @addtogroup FileApi
@@ -22,6 +94,34 @@
/*@{*/
/**
+ * This function will return whether this file has been opend.
+ *
+ * @param pathname the file path name.
+ *
+ * @return 0 on file has been open successfully, -1 on open failed.
+ */
+int dfs_file_is_open(const char *pathname)
+{
+ char *fullpath = NULL;
+ struct dfs_fnode *vnode = NULL;
+ int ret = 0;
+
+ fullpath = dfs_normalize_path(NULL, pathname);
+
+ dfs_fm_lock();
+ vnode = dfs_fnode_find(fullpath, NULL);
+ if (vnode)
+ {
+ ret = 1;
+ }
+ dfs_fm_unlock();
+
+ rt_free(fullpath);
+ return ret;
+}
+
+
+/**
* this function will open a file which specified by path with specified flags.
*
* @param fd the file descriptor pointer to return the corresponding result.
@@ -35,6 +135,8 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
struct dfs_filesystem *fs;
char *fullpath;
int result;
+ struct dfs_fnode *vnode = NULL;
+ rt_list_t *hash_head;
/* parameter check */
if (fd == NULL)
@@ -49,56 +151,101 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
LOG_D("open file:%s", fullpath);
- /* find filesystem */
- fs = dfs_filesystem_lookup(fullpath);
- if (fs == NULL)
+ dfs_fm_lock();
+ /* vnode find */
+ vnode = dfs_fnode_find(fullpath, &hash_head);
+ if (vnode)
{
+ vnode->ref_count++;
+ fd->pos = 0;
+ fd->vnode = vnode;
+ dfs_fm_unlock();
rt_free(fullpath); /* release path */
-
- return -ENOENT;
}
+ else
+ {
+ /* find filesystem */
+ fs = dfs_filesystem_lookup(fullpath);
+ if (fs == NULL)
+ {
+ dfs_fm_unlock();
+ rt_free(fullpath); /* release path */
+ return -ENOENT;
+ }
+
+ vnode = rt_calloc(1, sizeof(struct dfs_fnode));
+ if (!vnode)
+ {
+ dfs_fm_unlock();
+ rt_free(fullpath); /* release path */
+ return -ENOMEM;
+ }
+ vnode->ref_count = 1;
- LOG_D("open in filesystem:%s", fs->ops->name);
- fd->fs = fs; /* set file system */
- fd->fops = fs->ops->fops; /* set file ops */
+ LOG_D("open in filesystem:%s", fs->ops->name);
+ vnode->fs = fs; /* set file system */
+ vnode->fops = fs->ops->fops; /* set file ops */
- /* initialize the fd item */
- fd->type = FT_REGULAR;
- fd->flags = flags;
- fd->size = 0;
- fd->pos = 0;
- fd->data = fs;
+ /* initialize the fd item */
+ vnode->type = FT_REGULAR;
+ vnode->flags = 0;
- if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
- {
- if (dfs_subdir(fs->path, fullpath) == NULL)
- fd->path = rt_strdup("/");
+ if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
+ {
+ if (dfs_subdir(fs->path, fullpath) == NULL)
+ vnode->path = rt_strdup("/");
+ else
+ vnode->path = rt_strdup(dfs_subdir(fs->path, fullpath));
+ LOG_D("Actual file path: %s", vnode->path);
+ }
else
- fd->path = rt_strdup(dfs_subdir(fs->path, fullpath));
- rt_free(fullpath);
- LOG_D("Actual file path: %s", fd->path);
- }
- else
- {
- fd->path = fullpath;
- }
+ {
+ vnode->path = fullpath;
+ }
+ vnode->fullpath = fullpath;
- /* specific file system open routine */
- if (fd->fops->open == NULL)
- {
- /* clear fd */
- rt_free(fd->path);
- fd->path = NULL;
+ /* specific file system open routine */
+ if (vnode->fops->open == NULL)
+ {
+ dfs_fm_unlock();
+ /* clear fd */
+ if (vnode->path != vnode->fullpath)
+ {
+ rt_free(vnode->fullpath);
+ }
+ rt_free(vnode->path);
+ rt_free(vnode);
- return -ENOSYS;
+ return -ENOSYS;
+ }
+
+ fd->pos = 0;
+ fd->vnode = vnode;
+
+ /* insert vnode to hash */
+ rt_list_insert_after(hash_head, &vnode->list);
}
- if ((result = fd->fops->open(fd)) < 0)
+ fd->flags = flags;
+
+ if ((result = vnode->fops->open(fd)) < 0)
{
- /* clear fd */
- rt_free(fd->path);
- fd->path = NULL;
+ vnode->ref_count--;
+ if (vnode->ref_count == 0)
+ {
+ /* remove from hash */
+ rt_list_remove(&vnode->list);
+ /* clear fd */
+ if (vnode->path != vnode->fullpath)
+ {
+ rt_free(vnode->fullpath);
+ }
+ rt_free(vnode->path);
+ fd->vnode = NULL;
+ rt_free(vnode);
+ }
+ dfs_fm_unlock();
LOG_D("%s open failed", fullpath);
return result;
@@ -107,9 +254,10 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
fd->flags |= DFS_F_OPEN;
if (flags & O_DIRECTORY)
{
- fd->type = FT_DIRECTORY;
+ fd->vnode->type = FT_DIRECTORY;
fd->flags |= DFS_F_DIRECTORY;
}
+ dfs_fm_unlock();
LOG_D("open successful");
return 0;
@@ -124,20 +272,52 @@ int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
*/
int dfs_file_close(struct dfs_fd *fd)
{
+ struct dfs_fnode *vnode = NULL;
int result = 0;
if (fd == NULL)
+ {
return -ENXIO;
+ }
- if (fd->fops->close != NULL)
- result = fd->fops->close(fd);
+ if (fd->ref_count == 1)
+ {
+ dfs_fm_lock();
+ vnode = fd->vnode;
- /* close fd error, return */
- if (result < 0)
- return result;
+ if (vnode->ref_count <= 0)
+ {
+ dfs_fm_unlock();
+ return -ENXIO;
+ }
- rt_free(fd->path);
- fd->path = NULL;
+ if (vnode->fops->close != NULL)
+ {
+ result = vnode->fops->close(fd);
+ }
+
+ /* close fd error, return */
+ if (result < 0)
+ {
+ dfs_fm_unlock();
+ return result;
+ }
+
+ if (vnode->ref_count == 1)
+ {
+ /* remove from hash */
+ rt_list_remove(&vnode->list);
+ fd->vnode = NULL;
+
+ if (vnode->path != vnode->fullpath)
+ {
+ rt_free(vnode->fullpath);
+ }
+ rt_free(vnode->path);
+ rt_free(vnode);
+ }
+ dfs_fm_unlock();
+ }
return result;
}
@@ -154,10 +334,12 @@ int dfs_file_close(struct dfs_fd *fd)
int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
{
if (fd == NULL)
+ {
return -EINVAL;
+ }
/* regular file system fd */
- if (fd->type == FT_REGULAR)
+ if (fd->vnode->type == FT_REGULAR || fd->vnode->type == FT_DEVICE)
{
switch (cmd)
{
@@ -176,8 +358,10 @@ int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
}
}
- if (fd->fops->ioctl != NULL)
- return fd->fops->ioctl(fd, cmd, args);
+ if (fd->vnode->fops->ioctl != NULL)
+ {
+ return fd->vnode->fops->ioctl(fd, cmd, args);
+ }
return -ENOSYS;
}
@@ -197,13 +381,19 @@ int dfs_file_read(struct dfs_fd *fd, void *buf, size_t len)
int result = 0;
if (fd == NULL)
+ {
return -EINVAL;
+ }
- if (fd->fops->read == NULL)
+ if (fd->vnode->fops->read == NULL)
+ {
return -ENOSYS;
+ }
- if ((result = fd->fops->read(fd, buf, len)) < 0)
+ if ((result = fd->vnode->fops->read(fd, buf, len)) < 0)
+ {
fd->flags |= DFS_F_EOF;
+ }
return result;
}
@@ -220,11 +410,20 @@ int dfs_file_read(struct dfs_fd *fd, void *buf, size_t len)
int dfs_file_getdents(struct dfs_fd *fd, struct dirent *dirp, size_t nbytes)
{
/* parameter check */
- if (fd == NULL || fd->type != FT_DIRECTORY)
+ if (fd == NULL)
+ {
+ return -EINVAL;
+ }
+
+ if (fd->vnode->type != FT_DIRECTORY)
+ {
return -EINVAL;
+ }
- if (fd->fops->getdents != NULL)
- return fd->fops->getdents(fd, dirp, nbytes);
+ if (fd->vnode->fops->getdents != NULL)
+ {
+ return fd->vnode->fops->getdents(fd, dirp, nbytes);
+ }
return -ENOSYS;
}
@@ -249,17 +448,17 @@ int dfs_file_unlink(const char *path)
return -EINVAL;
}
- /* get filesystem */
- if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
+ /* Check whether file is already open */
+ if (dfs_file_is_open(fullpath))
{
- result = -ENOENT;
+ result = -EBUSY;
goto __exit;
}
- /* Check whether file is already open */
- if (fd_is_open(fullpath) == 0)
+ /* get filesystem */
+ if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
{
- result = -EBUSY;
+ result = -ENOENT;
goto __exit;
}
@@ -294,12 +493,16 @@ __exit:
int dfs_file_write(struct dfs_fd *fd, const void *buf, size_t len)
{
if (fd == NULL)
+ {
return -EINVAL;
+ }
- if (fd->fops->write == NULL)
+ if (fd->vnode->fops->write == NULL)
+ {
return -ENOSYS;
+ }
- return fd->fops->write(fd, buf, len);
+ return fd->vnode->fops->write(fd, buf, len);
}
/**
@@ -314,10 +517,10 @@ int dfs_file_flush(struct dfs_fd *fd)
if (fd == NULL)
return -EINVAL;
- if (fd->fops->flush == NULL)
+ if (fd->vnode->fops->flush == NULL)
return -ENOSYS;
- return fd->fops->flush(fd);
+ return fd->vnode->fops->flush(fd);
}
/**
@@ -335,10 +538,10 @@ int dfs_file_lseek(struct dfs_fd *fd, off_t offset)
if (fd == NULL)
return -EINVAL;
- if (fd->fops->lseek == NULL)
+ if (fd->vnode->fops->lseek == NULL)
return -ENOSYS;
- result = fd->fops->lseek(fd, offset);
+ result = fd->vnode->fops->lseek(fd, offset);
/* update current position */
if (result >= 0)
@@ -425,11 +628,10 @@ int dfs_file_stat(const char *path, struct stat *buf)
*/
int dfs_file_rename(const char *oldpath, const char *newpath)
{
- int result;
- struct dfs_filesystem *oldfs, *newfs;
- char *oldfullpath, *newfullpath;
+ int result = RT_EOK;
+ struct dfs_filesystem *oldfs = NULL, *newfs = NULL;
+ char *oldfullpath = NULL, *newfullpath = NULL;
- result = RT_EOK;
newfullpath = NULL;
oldfullpath = NULL;
@@ -440,6 +642,12 @@ int dfs_file_rename(const char *oldpath, const char *newpath)
goto __exit;
}
+ if (dfs_file_is_open((const char *)oldfullpath))
+ {
+ result = -EBUSY;
+ goto __exit;
+ }
+
newfullpath = dfs_normalize_path(NULL, newpath);
if (newfullpath == NULL)
{
@@ -473,8 +681,14 @@ int dfs_file_rename(const char *oldpath, const char *newpath)
}
__exit:
- rt_free(oldfullpath);
- rt_free(newfullpath);
+ if (oldfullpath)
+ {
+ rt_free(oldfullpath);
+ }
+ if (newfullpath)
+ {
+ rt_free(newfullpath);
+ }
/* not at same file system, return EXDEV */
return result;
@@ -494,28 +708,52 @@ int dfs_file_ftruncate(struct dfs_fd *fd, off_t length)
int result;
/* fd is null or not a regular file system fd, or length is invalid */
- if (fd == NULL || fd->type != FT_REGULAR || length < 0)
+ if (fd == NULL || fd->vnode->type != FT_REGULAR || length < 0)
return -EINVAL;
- if (fd->fops->ioctl == NULL)
+ if (fd->vnode->fops->ioctl == NULL)
return -ENOSYS;
- result = fd->fops->ioctl(fd, RT_FIOFTRUNCATE, (void*)&length);
+ result = fd->vnode->fops->ioctl(fd, RT_FIOFTRUNCATE, (void*)&length);
/* update current size */
if (result == 0)
- fd->size = length;
+ fd->vnode->size = length;
return result;
}
+int dfs_file_mmap2(struct dfs_fd *fd, struct dfs_mmap2_args *mmap2)
+{
+ int ret = 0;
+
+ if (fd && mmap2)
+ {
+ if (fd->vnode->type != FT_DEVICE || !fd->vnode->fops->ioctl)
+ {
+ rt_set_errno(EINVAL);
+ }
+ else if (fd->vnode->type == FT_DEVICE && fd->vnode->fops->ioctl)
+ {
+ ret = fd->vnode->fops->ioctl(fd, RT_FIOMMAP2, mmap2);
+ if (ret != 0)
+ {
+ ret = ret > 0? ret : -ret;
+ rt_set_errno(ret);
+ }
+ }
+ }
+
+ return ret;
+}
+
#ifdef RT_USING_FINSH
#include <finsh.h>
-static struct dfs_fd fd;
-static struct dirent dirent;
void ls(const char *pathname)
{
+ struct dfs_fd fd;
+ struct dirent dirent;
struct stat stat;
int length;
char *fullpath, *path;
@@ -537,6 +775,7 @@ void ls(const char *pathname)
path = (char *)pathname;
}
+ fd_init(&fd);
/* list directory */
if (dfs_file_open(&fd, path, O_DIRECTORY) == 0)
{
@@ -595,9 +834,11 @@ FINSH_FUNCTION_EXPORT(rm, remove files or directories);
void cat(const char *filename)
{
- uint32_t length;
+ struct dfs_fd fd;
+ int length = 0;
char buffer[81];
+ fd_init(&fd);
if (dfs_file_open(&fd, filename, O_RDONLY) < 0)
{
rt_kprintf("Open %s failed\n", filename);
@@ -607,15 +848,15 @@ void cat(const char *filename)
do
{
- rt_memset(buffer, 0, sizeof(buffer));
- length = dfs_file_read(&fd, buffer, sizeof(buffer) - 1);
+ rt_memset(buffer, 0x0, sizeof(buffer));
+ length = dfs_file_read(&fd, (void *)buffer, sizeof(buffer) - 1);
if (length > 0)
{
- rt_kprintf("%s", buffer);
+ buffer[length] = '\0';
+ rt_device_t out_device = rt_console_get_device();
+ rt_device_write(out_device, 0, (void *)buffer, sizeof(buffer));
}
- }
- while (length > 0);
- rt_kprintf("\n");
+ } while (length > 0);
dfs_file_close(&fd);
}
@@ -625,6 +866,7 @@ FINSH_FUNCTION_EXPORT(cat, print file);
#define BUF_SZ 4096
static void copyfile(const char *src, const char *dst)
{
+ struct dfs_fd fd;
struct dfs_fd src_fd;
rt_uint8_t *block_ptr;
rt_int32_t read_bytes;
@@ -637,6 +879,7 @@ static void copyfile(const char *src, const char *dst)
return;
}
+ fd_init(&src_fd);
if (dfs_file_open(&src_fd, src, O_RDONLY) < 0)
{
rt_free(block_ptr);
@@ -644,6 +887,7 @@ static void copyfile(const char *src, const char *dst)
return;
}
+ fd_init(&fd);
if (dfs_file_open(&fd, dst, O_WRONLY | O_CREAT) < 0)
{
rt_free(block_ptr);
diff --git a/components/dfs/src/dfs_fs.c b/components/dfs/src/dfs_fs.c
index 2abad9dfeb..7724afc7bc 100644
--- a/components/dfs/src/dfs_fs.c
+++ b/components/dfs/src/dfs_fs.c
@@ -241,7 +241,7 @@ int dfs_mount(const char *device_name,
for (ops = &filesystem_operation_table[0];
ops < &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; ops++)
- if ((*ops != NULL) && (strcmp((*ops)->name, filesystemtype) == 0))
+ if ((*ops != NULL) && (strncmp((*ops)->name, filesystemtype, strlen((*ops)->name)) == 0))
break;
dfs_unlock();
@@ -273,6 +273,7 @@ int dfs_mount(const char *device_name,
{
struct dfs_fd fd;
+ fd_init(&fd);
if (dfs_file_open(&fd, fullpath, O_RDONLY | O_DIRECTORY) < 0)
{
rt_free(fullpath);
@@ -312,6 +313,9 @@ int dfs_mount(const char *device_name,
fs->path = fullpath;
fs->ops = *ops;
fs->dev_id = dev_id;
+ /* For UFS, record the real filesystem name */
+ fs->data = (void *) filesystemtype;
+
/* release filesystem_table lock */
dfs_unlock();
@@ -447,7 +451,8 @@ int dfs_mkfs(const char *fs_name, const char *device_name)
for (index = 0; index < DFS_FILESYSTEM_TYPES_MAX; index ++)
{
if (filesystem_operation_table[index] != NULL &&
- strcmp(filesystem_operation_table[index]->name, fs_name) == 0)
+ strncmp(filesystem_operation_table[index]->name, fs_name,
+ strlen(filesystem_operation_table[index]->name)) == 0)
break;
}
dfs_unlock();
@@ -463,7 +468,7 @@ int dfs_mkfs(const char *fs_name, const char *device_name)
return -1;
}
- return ops->mkfs(dev_id);
+ return ops->mkfs(dev_id, fs_name);
}
LOG_E("File system (%s) was not found.", fs_name);
@@ -490,6 +495,7 @@ int dfs_statfs(const char *path, struct statfs *buffer)
return fs->ops->statfs(fs, buffer);
}
+ rt_set_errno(-ENOSYS);
return -1;
}
@@ -625,7 +631,10 @@ int df(const char *path)
result = dfs_statfs(path ? path : NULL, &buffer);
if (result != 0)
{
- rt_kprintf("dfs_statfs failed.\n");
+ if (rt_get_errno() == -ENOSYS)
+ rt_kprintf("The function is not implemented.\n");
+ else
+ rt_kprintf("statfs failed: errno=%d.\n", rt_get_errno());
return -1;
}
diff --git a/components/dfs/src/dfs_posix.c b/components/dfs/src/dfs_posix.c
index ed0647121d..e3efa5bed6 100644
--- a/components/dfs/src/dfs_posix.c
+++ b/components/dfs/src/dfs_posix.c
@@ -14,6 +14,16 @@
#include <dfs_private.h>
#include <sys/errno.h>
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#endif
+
+/**
+ * @addtogroup FsPosixApi
+ */
+
+/*@{*/
+
/**
* this function is a POSIX compliant version, which will open a file and
* return a file descriptor according specified flags.
@@ -42,17 +52,13 @@ int open(const char *file, int flags, ...)
if (result < 0)
{
/* release the ref-count of fd */
- fd_put(d);
- fd_put(d);
+ fd_release(fd);
rt_set_errno(result);
return -1;
}
- /* release the ref-count of fd */
- fd_put(d);
-
return fd;
}
RTM_EXPORT(open);
@@ -94,7 +100,6 @@ int close(int fd)
}
result = dfs_file_close(d);
- fd_put(d);
if (result < 0)
{
@@ -103,7 +108,7 @@ int close(int fd)
return -1;
}
- fd_put(d);
+ fd_release(fd);
return 0;
}
@@ -141,15 +146,11 @@ ssize_t read(int fd, void *buf, size_t len)
result = dfs_file_read(d, buf, len);
if (result < 0)
{
- fd_put(d);
rt_set_errno(result);
return -1;
}
- /* release the ref-count of fd */
- fd_put(d);
-
return result;
}
RTM_EXPORT(read);
@@ -185,15 +186,11 @@ ssize_t write(int fd, const void *buf, size_t len)
result = dfs_file_write(d, buf, len);
if (result < 0)
{
- fd_put(d);
rt_set_errno(result);
return -1;
}
- /* release the ref-count of fd */
- fd_put(d);
-
return result;
}
RTM_EXPORT(write);
@@ -231,11 +228,10 @@ off_t lseek(int fd, off_t offset, int whence)
break;
case SEEK_END:
- offset += d->size;
+ offset += d->vnode->size;
break;
default:
- fd_put(d);
rt_set_errno(-EINVAL);
return -1;
@@ -243,24 +239,17 @@ off_t lseek(int fd, off_t offset, int whence)
if (offset < 0)
{
- fd_put(d);
rt_set_errno(-EINVAL);
return -1;
}
- if(offset != d->pos)
+ result = dfs_file_lseek(d, offset);
+ if (result < 0)
{
- result = dfs_file_lseek(d, offset);
- if (result < 0)
- {
- fd_put(d);
- rt_set_errno(result);
+ rt_set_errno(result);
- return -1;
- }
+ return -1;
}
- /* release the ref-count of fd */
- fd_put(d);
return offset;
}
@@ -369,17 +358,15 @@ int fstat(int fildes, struct stat *buf)
buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
- if (d->type == FT_DIRECTORY)
+ if (d->vnode->type == FT_DIRECTORY)
{
buf->st_mode &= ~S_IFREG;
buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
}
- buf->st_size = d->size;
+ buf->st_size = d->vnode->size;
buf->st_mtime = 0;
- fd_put(d);
-
return RT_EOK;
}
RTM_EXPORT(fstat);
@@ -409,7 +396,6 @@ int fsync(int fildes)
ret = dfs_file_flush(d);
- fd_put(d);
return ret;
}
RTM_EXPORT(fsync);
@@ -443,7 +429,6 @@ int fcntl(int fildes, int cmd, ...)
va_end(ap);
ret = dfs_file_ioctl(d, cmd, arg);
- fd_put(d);
}
else ret = -EBADF;
@@ -508,7 +493,6 @@ int ftruncate(int fd, off_t length)
if (length < 0)
{
- fd_put(d);
rt_set_errno(-EINVAL);
return -1;
@@ -516,15 +500,11 @@ int ftruncate(int fd, off_t length)
result = dfs_file_ftruncate(d, length);
if (result < 0)
{
- fd_put(d);
rt_set_errno(result);
return -1;
}
- /* release the ref-count of fd */
- fd_put(d);
-
return 0;
}
RTM_EXPORT(ftruncate);
@@ -582,16 +562,14 @@ int mkdir(const char *path, mode_t mode)
if (result < 0)
{
- fd_put(d);
- fd_put(d);
+ fd_release(fd);
rt_set_errno(result);
return -1;
}
dfs_file_close(d);
- fd_put(d);
- fd_put(d);
+ fd_release(fd);
return 0;
}
@@ -653,7 +631,7 @@ DIR *opendir(const char *name)
if (t == NULL)
{
dfs_file_close(d);
- fd_put(d);
+ fd_release(fd);
}
else
{
@@ -661,14 +639,12 @@ DIR *opendir(const char *name)
t->fd = fd;
}
- fd_put(d);
return t;
}
/* open failed */
- fd_put(d);
- fd_put(d);
+ fd_release(fd);
rt_set_errno(result);
return NULL;
@@ -711,7 +687,6 @@ struct dirent *readdir(DIR *d)
sizeof(d->buf) - 1);
if (result <= 0)
{
- fd_put(fd);
rt_set_errno(result);
return NULL;
@@ -721,8 +696,6 @@ struct dirent *readdir(DIR *d)
d->cur = 0; /* current entry index */
}
- fd_put(fd);
-
return (struct dirent *)(d->buf + d->cur);
}
RTM_EXPORT(readdir);
@@ -749,7 +722,6 @@ long telldir(DIR *d)
}
result = fd->pos - d->num + d->cur;
- fd_put(fd);
return result;
}
@@ -777,7 +749,6 @@ void seekdir(DIR *d, long offset)
/* seek to the offset position of directory */
if (dfs_file_lseek(fd, offset) >= 0)
d->num = d->cur = 0;
- fd_put(fd);
}
RTM_EXPORT(seekdir);
@@ -802,7 +773,6 @@ void rewinddir(DIR *d)
/* seek to the beginning of directory */
if (dfs_file_lseek(fd, 0) >= 0)
d->num = d->cur = 0;
- fd_put(fd);
}
RTM_EXPORT(rewinddir);
@@ -828,9 +798,8 @@ int closedir(DIR *d)
}
result = dfs_file_close(fd);
- fd_put(fd);
+ fd_release(d->fd);
- fd_put(fd);
rt_free(d);
if (result < 0)
@@ -861,7 +830,9 @@ int chdir(const char *path)
if (path == NULL)
{
dfs_lock();
+#ifdef DFS_USING_WORKDIR
rt_kprintf("%s\n", working_directory);
+#endif
dfs_unlock();
return 0;
@@ -895,9 +866,12 @@ int chdir(const char *path)
/* close directory stream */
closedir(d);
-
+#ifdef RT_USING_LWP
/* copy full path to working directory */
- strncpy(working_directory, fullpath, DFS_PATH_MAX);
+ lwp_setcwd(fullpath);
+#else
+ rt_strncpy(working_directory, fullpath, DFS_PATH_MAX);
+#endif
/* release normalize directory path name */
rt_free(fullpath);
@@ -930,6 +904,31 @@ int access(const char *path, int amode)
/* ignore R_OK,W_OK,X_OK condition */
return 0;
}
+/**
+ * this function is a POSIX compliant version, which will set current
+ * working directory.
+ *
+ * @param buf the current directory.
+ *
+ * @return null.
+ */
+void setcwd(char *buf)
+{
+#ifdef DFS_USING_WORKDIR
+ dfs_lock();
+#ifdef RT_USING_LWP
+ lwp_setcwd(buf);
+#else
+ rt_strncpy(working_directory, buf, DFS_PATH_MAX);
+#endif
+ dfs_unlock();
+#else
+ rt_kprintf(NO_WORKING_DIR);
+#endif
+
+ return ;
+}
+RTM_EXPORT(setcwd);
/**
* this function is a POSIX compliant version, which will return current
@@ -943,8 +942,22 @@ int access(const char *path, int amode)
char *getcwd(char *buf, size_t size)
{
#ifdef DFS_USING_WORKDIR
+ char *dir_buf = RT_NULL;
+
dfs_lock();
- strncpy(buf, working_directory, size);
+
+#ifdef RT_USING_LWP
+ dir_buf = lwp_getcwd();
+#else
+ dir_buf = &working_directory[0];
+#endif
+
+ /* copy to buf parameter */
+ if (buf)
+ {
+ rt_strncpy(buf, dir_buf, size);
+ }
+
dfs_unlock();
#else
rt_kprintf(NO_WORKING_DIR);
@@ -953,3 +966,5 @@ char *getcwd(char *buf, size_t size)
return buf;
}
RTM_EXPORT(getcwd);
+
+/* @} */
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index af4132f4e2..da0211683f 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -4,6 +4,10 @@ config RT_USING_DEVICE_IPC
bool "Using device drivers IPC"
default y
+config RT_UNAMED_PIPE_NUMBER
+ int "The number of unamed pipe"
+ default 64
+
if RT_USING_DEVICE_IPC
config RT_USING_SYSTEM_WORKQUEUE
bool "Using system default workqueue"
@@ -45,6 +49,17 @@ menuconfig RT_USING_SERIAL
default 64
endif
+config RT_USING_TTY
+ bool "Using TTY SYSTEM"
+ depends on RT_USING_LWP
+ default y
+
+if RT_USING_TTY
+ config RT_TTY_DEBUG
+ bool "Using TTY DEBUG"
+ default n
+endif
+
config RT_USING_CAN
bool "Using CAN device drivers"
default n
@@ -86,6 +101,12 @@ if RT_USING_CPUTIME
default y
depends on ARCH_ARM_CORTEX_M0 || ARCH_ARM_CORTEX_M3 || ARCH_ARM_CORTEX_M4 || ARCH_ARM_CORTEX_M7
select PKG_USING_PERF_COUNTER
+ config RT_USING_CPUTIME_RISCV
+ bool "Use rdtime instructions for CPU time"
+ default y
+ depends on ARCH_RISCV64
+ help
+ Some RISCV64 MCU Use rdtime instructions read CPU time.
endif
config RT_USING_I2C
@@ -123,7 +144,19 @@ config RT_USING_ADC
config RT_USING_DAC
bool "Using DAC device drivers"
default n
-
+
+config RT_USING_NULL
+ bool "Using NULL device drivers"
+ default n
+
+config RT_USING_ZERO
+ bool "Using ZERO device drivers"
+ default n
+
+config RT_USING_RANDOM
+ bool "Using RANDOM device drivers"
+ default n
+
config RT_USING_PWM
bool "Using PWM device drivers"
default n
@@ -182,6 +215,19 @@ config RT_USING_PM
endif
endif
+config RT_USING_FDT
+ bool "Using fdt interface for device drivers"
+ default n
+ if RT_USING_FDT
+ config RT_USING_FDTLIB
+ bool "Using fdt lib for device drivers"
+ default y
+ config FDT_USING_DEBUG
+ bool "Using fdt debug function "
+ default n
+
+ endif
+
config RT_USING_RTC
bool "Using RTC device drivers"
default n
@@ -322,13 +368,8 @@ config RT_USING_SENSOR
if RT_USING_SENSOR
config RT_USING_SENSOR_CMD
- bool "Enable sensor commands"
- select PKG_USING_RT_VSNPRINTF_FULL
+ bool "Using Sensor cmd"
default y
-
- config RT_USING_SENSOR_DOUBLE_FLOAT
- bool "Using double floating as sensor data type"
- default n
endif
config RT_USING_TOUCH
@@ -340,6 +381,10 @@ config RT_USING_TOUCH
default n
endif
+config RT_USING_LCD
+ bool "Using LCD graphic drivers"
+ default n
+
menuconfig RT_USING_HWCRYPTO
bool "Using Hardware Crypto drivers"
default n
@@ -520,6 +565,11 @@ if RT_USING_INPUT_CAPTURE
default 100
endif
+config RT_USING_DEV_BUS
+ bool "Using Device Bus device drivers"
+ default y if RT_USING_LWP
+ default n if !RT_USING_LWP
+
menuconfig RT_USING_WIFI
bool "Using Wi-Fi framework"
default n
@@ -671,6 +721,50 @@ menuconfig RT_USING_WIFI
endif
endif
+menuconfig RT_USING_VIRTIO
+ bool "Using VirtIO device drivers"
+ default n
+
+ if RT_USING_VIRTIO
+ choice
+ prompt "VirtIO Version"
+ default RT_USING_VIRTIO10
+
+ config RT_USING_VIRTIO10
+ bool "VirtIO v1.0"
+ endchoice
+
+ config RT_USING_VIRTIO_MMIO_ALIGN
+ bool "Using VirtIO MMIO alignment"
+ default y
+
+ config RT_USING_VIRTIO_BLK
+ bool "Using VirtIO BLK"
+ default y
+
+ config RT_USING_VIRTIO_NET
+ bool "Using VirtIO NET"
+ default y
+
+ menuconfig RT_USING_VIRTIO_CONSOLE
+ bool "Using VirtIO Console"
+ default y
+
+ if RT_USING_VIRTIO_CONSOLE
+ config RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR
+ int "Max number of port in VirtIO Console"
+ default 4
+ endif
+
+ config RT_USING_VIRTIO_GPU
+ bool "Using VirtIO GPU"
+ default y
+
+ config RT_USING_VIRTIO_INPUT
+ bool "Using VirtIO Input"
+ default y
+ endif
+
menu "Using USB"
config RT_USING_USB
bool
diff --git a/components/drivers/cputime/SConscript b/components/drivers/cputime/SConscript
index 57c0b44fa8..e1b447e16b 100644
--- a/components/drivers/cputime/SConscript
+++ b/components/drivers/cputime/SConscript
@@ -9,6 +9,9 @@ cputime.c
if GetDepend('RT_USING_CPUTIME_CORTEXM'):
src += ['cputime_cortexm.c']
+if GetDepend('RT_USING_CPUTIME_RISCV'):
+ src += ['cputime_riscv.c']
+
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CPUTIME'], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/cputime/cputime.c b/components/drivers/cputime/cputime.c
index 490f5725c1..5fe0b07cb1 100644
--- a/components/drivers/cputime/cputime.c
+++ b/components/drivers/cputime/cputime.c
@@ -51,11 +51,11 @@ uint64_t clock_cpu_gettime(void)
*
* @return the microsecond
*/
-uint32_t clock_cpu_microsecond(uint32_t cpu_tick)
+uint64_t clock_cpu_microsecond(uint64_t cpu_tick)
{
float unit = clock_cpu_getres();
- return (uint32_t)((cpu_tick * unit) / 1000);
+ return (uint64_t)((cpu_tick * unit) / 1000);
}
/**
@@ -66,11 +66,11 @@ uint32_t clock_cpu_microsecond(uint32_t cpu_tick)
*
* @return the millisecond
*/
-uint32_t clock_cpu_millisecond(uint32_t cpu_tick)
+uint64_t clock_cpu_millisecond(uint64_t cpu_tick)
{
float unit = clock_cpu_getres();
- return (uint32_t)((cpu_tick * unit) / (1000 * 1000));
+ return (uint64_t)((cpu_tick * unit) / (1000 * 1000));
}
/**
diff --git a/components/drivers/cputime/cputime_riscv.c b/components/drivers/cputime/cputime_riscv.c
new file mode 100644
index 0000000000..7e327fc2d4
--- /dev/null
+++ b/components/drivers/cputime/cputime_riscv.c
@@ -0,0 +1,39 @@
+#include <rthw.h>
+#include <rtdevice.h>
+#include <rtthread.h>
+
+#include <board.h>
+
+
+#define TIMER_FREQ (24000000)
+
+/* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */
+
+static float riscv_cputime_getres(void)
+{
+ float ret = 1000 * 1000 * 1000;
+
+ ret = ret / TIMER_FREQ;
+ return ret;
+}
+
+static uint64_t riscv_cputime_gettime(void)
+{
+ uint64_t time_elapsed;
+ __asm__ __volatile__(
+ "rdtime %0"
+ : "=r"(time_elapsed));
+ return time_elapsed;
+}
+
+const static struct rt_clock_cputime_ops _riscv_ops =
+ {
+ riscv_cputime_getres,
+ riscv_cputime_gettime};
+
+int riscv_cputime_init(void)
+{
+ clock_cpu_setops(&_riscv_ops);
+ return 0;
+}
+INIT_BOARD_EXPORT(riscv_cputime_init);
diff --git a/components/drivers/fdt/README.md b/components/drivers/fdt/README.md
new file mode 100644
index 0000000000..d8a049c8fc
--- /dev/null
+++ b/components/drivers/fdt/README.md
@@ -0,0 +1,41 @@
+# fdt
+
+## 1、介绍
+fdt基于libfdt进行封装,可实现在内存或文件系统中加载dtb设备树,对内存中的设备树修改、解析,并转换为设备节点树,通过该节点树开发者可通过设备树信息开发驱动。
+
+### 1.1 目录结构
+| 名称 | 说明 |
+| ---- | ---- |
+| docs | 文档目录 |
+| examples | 例子目录,并有相应的一些说明 |
+| inc | 头文件目录 |
+| src | 源代码目录 |
+
+### 1.2 许可证
+fdt package 遵循 GPL-3.0 许可,详见 LICENSE 文件。
+
+### 1.3 依赖
+- RT-Thread 3.0+
+
+## 2、如何打开 fdt
+使用 fdt package 需要在 RT-Thread 的包管理器中选择它,具体路径如下:
+
+```
+RT-Thread online packages
+ tools packages --->
+ [*] Device Tree package in RT-Thread
+```
+
+## 3、使用 fdt
+在打开 fdt package 后,当进行 bsp 编译时,它会被加入到 bsp 工程中进行编译。
+
+* 完整的 API 手册可以访问这个[链接](docs/api.md)
+* 更多文档位于 [`/docs`](/docs) 下,使用前 **务必查看**
+
+## 4、注意事项
+如果发生`libfdt`库冲突,在package管理菜单中取消选择`Enable libfdt`
+
+## 5、联系方式
+
+* 维护:GuEe-GUI
+* 主页:https://github.com/GuEe-GUI/fdt \ No newline at end of file
diff --git a/components/drivers/fdt/SConscript b/components/drivers/fdt/SConscript
new file mode 100644
index 0000000000..d916b2dfbc
--- /dev/null
+++ b/components/drivers/fdt/SConscript
@@ -0,0 +1,16 @@
+# RT-Thread building script for bridge
+
+import os
+from building import *
+
+cwd = GetCurrentDir()
+objs = []
+list = os.listdir(cwd)
+
+if GetDepend('RT_USING_FDT'):
+ for d in list:
+ path = os.path.join(cwd, d)
+ if os.path.isfile(os.path.join(path, 'SConscript')):
+ objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')
diff --git a/components/drivers/fdt/docs/README.md b/components/drivers/fdt/docs/README.md
new file mode 100644
index 0000000000..f57e0a8e75
--- /dev/null
+++ b/components/drivers/fdt/docs/README.md
@@ -0,0 +1,13 @@
+# 文档
+
+## 软件包地址
+
+- https://gitee.com/GuEe_GUI/fdt
+
+## 文档列表
+
+|文件名 |描述|
+|:----- |:----|
+|[examples.md](examples.md) |示例程序|
+|[version.md](version.md) |版本信息|
+|[api.md](api.md) |API 说明|
diff --git a/components/drivers/fdt/docs/api.md b/components/drivers/fdt/docs/api.md
new file mode 100644
index 0000000000..13471de06f
--- /dev/null
+++ b/components/drivers/fdt/docs/api.md
@@ -0,0 +1,434 @@
+# fdt load API
+
+## 从文件系统上读取设备树
+```c
+void *fdt_load_from_fs(char *dtb_filename)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_filename | 设备树文件名 |
+| **返回** | **描述** |
+|void* | 设备树在内存上的地址 |
+
+## 从内存上读取设备树
+```c
+void *fdt_load_from_memory(void *dtb_ptr, rt_bool_t is_clone)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_ptr | 设备树在内存上的内存地址 |
+|is_clone | 是否克隆到新的内存区域 |
+| **返回** | **描述** |
+|void* | 设备树在内存上的地址 |
+
+# fdt set API
+
+## 设置Linux启动参数
+```c
+rt_size_t fdt_set_linux_cmdline(void *fdt, char *cmdline)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|cmdline | 启动参数 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 设置Linux init ramdisk
+```c
+rt_size_t fdt_set_linux_initrd(void *fdt, rt_uint64_t initrd_addr, rt_size_t initrd_size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|initrd_addr | init ramdisk 内存地址 |
+|initrd_size | init 大小 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 设置节点属性值
+```c
+rt_size_t fdt_set_dtb_property(void *fdt, char *pathname, char *property_name, rt_uint32_t *cells, rt_size_t cells_size);
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|pathname | 节点路径 |
+|property_name | 属性名称 |
+|cells | 属性值地址 |
+|cells_size | 属性值长度 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 添加保留内存
+```c
+rt_size_t fdt_add_dtb_memreserve(void *fdt, rt_uint64_t address, rt_uint64_t size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|address | 保留内存起始地址 |
+|size | 保留内存大小 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+## 删除保留内存
+```c
+rt_size_t fdt_del_dtb_memreserve(void *fdt, rt_uint64_t address)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树指针 |
+|address | 保留内存起始地址 |
+| **返回** | **描述** |
+|rt_size_t | 修改设备树后设备树的大小 |
+
+# fdt get API
+
+## 获取设备树软件包执行状态
+```c
+rt_err_t fdt_get_exec_status()
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|无 | 无参数 |
+| **返回** | **描述** |
+|FDT_RET_NO_MEMORY | 内存不足 |
+|FDT_RET_NO_LOADED | 设备树还未加载进内存 |
+|FDT_RET_GET_OK | 执行成功 |
+|FDT_RET_GET_EMPTY | 读取数据为空 |
+
+## 将原始设备树转换为设备节点树
+```c
+struct dtb_node *fdt_get_dtb_list(void *fdt)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|fdt | 设备树在内存上的地址 |
+| **返回** | **描述** |
+|struct dtb_node * | 设备节点树头指针 |
+## 释放设备节点树内存
+```c
+void fdt_free_dtb_list(struct dtb_node *dtb_node_head)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node_head | 设备节点树头节点 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+示例:加载设备树
+
+```c
+#include <rtthread.h>
+#include <fdt.h>
+
+int main()
+{
+ void *fdt = fdt_load_from_fs("sample.dtb");
+ if (fdt != RT_NULL)
+ {
+ struct dtb_node *dtb_node_list = fdt_get_dtb_list(fdt);
+
+ if (dtb_node_list != RT_NULL)
+ {
+ /* load dtb node list OK */
+
+ /* free dtb_node_list here */
+ fdt_free_dtb_list(dtb_node_list);
+ }
+
+ rt_free(fdt);
+ }
+
+ return 0;
+}
+```
+
+## 打印设备树信息
+```c
+void fdt_get_dts_dump(struct dtb_node *dtb_node_head)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node_head | 设备节点树头节点 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+## 遍历设备节点树并使用程序定义的回调函数
+```c
+void fdt_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (*callback(struct dtb_node *dtb_node)))
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node_head | 设备节点树头节点 |
+|callback | 程序定义的回调函数 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+示例:遍历设备树节点,并打印每个节点名称
+
+```c
+#include <rtthread.h>
+#include <fdt.h>
+
+void callback(struct dtb_node *node)
+{
+ rt_kprintf("this node's name is %s\n", node->name);
+}
+
+int main()
+{
+ /* loaded dtb_node */
+ extern struct dtb_node *dtb_node_list;
+
+ if (dtb_node_list != RT_NULL)
+ {
+ fdt_get_enum_dtb_node(dtb_node_list, callback);
+ }
+
+ return 0;
+}
+```
+
+## 通过节点名称查找节点
+```c
+struct dtb_node *fdt_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
+```
+```c
+struct dtb_node *fdt_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|nodename | 查找节点的名称 |
+| **返回** | **描述** |
+|struct dtb_node * | 返回查找的节点 |
+|RT_NULL | 未找到为RT_NULL |
+
+## 通过节点路径查找节点
+```c
+struct dtb_node *fdt_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|pathname | 查找节点的路径 |
+| **返回** | **描述** |
+|struct dtb_node * | 返回查找的节点 |
+|RT_NULL | 未找到为RT_NULL |
+
+## 通过节点phandle值查找节点
+```c
+struct dtb_node *fdt_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
+```
+```c
+struct dtb_node *fdt_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|handle | 查找节点的phandle值 |
+| **返回** | **描述** |
+|struct dtb_node * | 返回查找的节点 |
+|RT_NULL | 未找到为RT_NULL |
+
+DFS和BFS是用于区分不同深度节点的搜索方法,时间复杂度和空间复杂度都较高,建议使用路径查找。
+
+## 读取节点属性值的单位
+```c
+void fdt_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|addr_cells | 返回的地址块的单位(u32)大小 |
+|size_cells | 返回的尺寸块的单位(u32)大小 |
+| **返回** | **描述** |
+|无返回值 | 无描述 |
+
+
+## 读取节点属性值
+```c
+void *fdt_get_dtb_node_property(struct dtb_node *dtb_node, const char *property_name, rt_size_t *property_size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|property_name | 属性名称 |
+|property_size | 属性大小 |
+| **返回** | **描述** |
+|void * | 无描述 |
+|RT_NULL | 该设备树没有该属性 |
+
+读取的值为在设备树中存储的值,CPU小端模式下可能需要使用其他API进行转换才是正确的值
+
+## 读取预留内存信息
+```c
+struct dtb_memreserve *fdt_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|memreserve_size | 返回的内存信息数组长度 |
+| **返回** | **描述** |
+|struct dtb_memreserve *| 内存预留信息数组的内存地址 |
+|RT_NULL | 该设备树没有预留内存信息 |
+
+## 读取节点的状态
+```c
+rt_bool_t fdt_get_dtb_node_status(struct dtb_node *dtb_node)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+| **返回** | **描述** |
+|RT_FALSE | 状态为禁用 |
+|RT_TRUE | 状态为使用 |
+
+## 用于参数为字符串列表的函数
+```c
+fdt_string_list(string, ...)
+```
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|string | 字符串集合 |
+
+## 读取节点compatible标志匹配
+```c
+rt_bool_t fdt_get_dtb_node_compatible_match(struct dtb_node *dtb_node, char **compatibles)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|dtb_node | 设备节点树节点 |
+|compatibles | 所有要匹配的字符串列表 |
+| **返回** | **描述** |
+|RT_FALSE | 匹配失败 |
+|RT_TRUE | 匹配成功 |
+
+## 读取属性值中的字符串
+```c
+char *fdt_get_dtb_string_list_value(void *value, int size, int index)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+|size | 节点属性的尺寸 |
+|index | 要读取字符串的索引 |
+| **返回** | **描述** |
+|char * | 字符串的内存地址 |
+|RT_NULL | 该索引没有字符串 |
+
+## 读取值为字符串属性下一个字符串
+```c
+char *fdt_get_dtb_string_list_value_next(void *value, void *end)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+|end | 节点属性的结束地址 |
+| **返回** | **描述** |
+|char * | 字符串的内存地址 |
+|RT_NULL | 没有下一个字符串 |
+
+## 读取值为u32属性的值
+```c
+rt_uint32_t fdt_get_dtb_cell_value(void *value)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+| **返回** | **描述** |
+|rt_uint32_t | 该值小端的值 |
+
+## 读取值为u8属性的值
+```c
+rt_uint8_t fdt_get_dtb_byte_value(void *value)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|value | 节点属性的内存地址 |
+| **返回** | **描述** |
+|rt_uint8_t | 该值小端的值 |
+
+# fdt foreach API
+
+## 遍历属性中字符串宏
+```c
+for_each_property_string(node_ptr, property_name, str, size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+|property_name | 节点属性名称 |
+|str | 每次遍历到的字符串 |
+|size | 用于保存节点属性的尺寸 |
+
+## 遍历属性中u32宏
+```c
+for_each_property_cell(node_ptr, property_name, value, list, size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+|property_name | 节点属性名称 |
+|value | 每次遍历到的值 |
+|list | 用于保存节点属性的值内存地址 |
+|size | 用于保存节点属性的尺寸 |
+
+## 遍历属性中u8宏
+```c
+for_each_property_byte(node_ptr, property_name, value, list, size)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+|property_name | 节点属性名称 |
+|value | 每次遍历到的值 |
+|list | 用于保存节点属性的值内存地址 |
+|size | 用于保存节点属性的尺寸 |
+
+## 遍历子节点宏
+```c
+for_each_node_child(node_ptr)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
+
+## 遍历兄弟节点宏
+```c
+for_each_node_sibling(node_ptr)
+```
+
+| 参数 | 描述 |
+|:------------------|:------------------------------------|
+|node_ptr | 设备节点树节点 |
diff --git a/components/drivers/fdt/docs/examples.md b/components/drivers/fdt/docs/examples.md
new file mode 100644
index 0000000000..aa3e655987
--- /dev/null
+++ b/components/drivers/fdt/docs/examples.md
@@ -0,0 +1,81 @@
+# fdt示例 #
+
+在`examples`文件夹中存放`bcm2711-rpi-4-b.dtb`和`vexpress-v2p-ca9.dtb`可供测试,如果系统可以从bootloader或其他方式获取到bsp本身的dtb,也可以通过修改示例程序进行测试
+
+## fdt_dump
+```bash
+fdt_dump vexpress-v2p-ca9.dtb
+```
+
+#### 示例结果 ####
+```bash
+/dts-v1/;
+
+/ {
+ model = "V2P-CA9";
+ arm,hbi = <0x191>;
+ arm,vexpress,site = <0xf>;
+ compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+ interrupt-parent = <0x1>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+
+ chosen {
+ };
+
+ aliases {
+ serial0 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@9000";
+ serial1 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@a000";
+ serial2 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@b000";
+ serial3 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@c000";
+ i2c0 = "/smb@4000000/motherboard/iofpga@7,00000000/i2c@16000";
+ i2c1 = "/smb@4000000/motherboard/iofpga@7,00000000/i2c@2000";
+ };
+
+...... 省略
+
+ hsb@e0000000 {
+ compatible = "simple-bus";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ ranges = <0x0 0xe0000000 0x20000000>;
+ #interrupt-cells = <0x1>;
+ interrupt-map-mask = <0x0 0x3>;
+ interrupt-map = <0x0 0x0 0x1 0x0 0x24 0x4 0x0 0x1 0x1 0x0 0x25 0x4 0x0 0x2 0x1 0x0 0x26 0x4 0x0 0x3 0x1 0x0 0x27 0x4>;
+ };
+};
+```
+
+## fdt_test
+```bash
+fdt_test
+```
+
+#### 示例结果 ####
+```bash
+name = uart@9000
+reg = <0x9000,0x1000>;
+compatible = "arm,pl011","arm,primecell";
+
+name = cpus
+path = /cpus/cpu@0/
+path = /cpus/cpu@1/
+path = /cpus/cpu@2/
+path = /cpus/cpu@3/
+
+name = user1, lable = v2m:green:user1
+name = user2, lable = v2m:green:user2
+name = user3, lable = v2m:green:user3
+name = user4, lable = v2m:green:user4
+name = user5, lable = v2m:green:user5
+name = user6, lable = v2m:green:user6
+name = user7, lable = v2m:green:user7
+name = user8, lable = v2m:green:user8
+
+/memreserve/ 0x0000000000000000 0x0000000000001000;
+
+phandle = <0x9>
+name = bt_pins
+path = /soc/gpio@7e200000/bt_pins/
+brcm,pins = [2d 00]
+``` \ No newline at end of file
diff --git a/components/drivers/fdt/docs/version.md b/components/drivers/fdt/docs/version.md
new file mode 100644
index 0000000000..3c3499d91a
--- /dev/null
+++ b/components/drivers/fdt/docs/version.md
@@ -0,0 +1,7 @@
+# 版本和修订 #
+
+| Date | Version | Author | Note |
+| -------- | :-----: | :---- | :---- |
+| 2021-9-1 | v0.0.1 | GuEe-GUI | 初始版本 |
+| 2021-11-11 | v1.0.0 | GuEe-GUI | API确定版本 |
+| | | | | \ No newline at end of file
diff --git a/components/drivers/fdt/examples/SConscript b/components/drivers/fdt/examples/SConscript
new file mode 100644
index 0000000000..30867a1de3
--- /dev/null
+++ b/components/drivers/fdt/examples/SConscript
@@ -0,0 +1,10 @@
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('FDT', src, depend = ['FDT_USING_DEBUG'], CPPPATH = CPPPATH)
+
+Return('group') \ No newline at end of file
diff --git a/components/drivers/fdt/examples/fdt_test.c b/components/drivers/fdt/examples/fdt_test.c
new file mode 100644
index 0000000000..4bf2879256
--- /dev/null
+++ b/components/drivers/fdt/examples/fdt_test.c
@@ -0,0 +1,143 @@
+#include <rtthread.h>
+#include "dtb_node.h"
+
+int dtb_test()
+{
+ void *fdt;
+
+ if ((fdt = dtb_node_load_from_fs("vexpress-v2p-ca9.dtb")) != RT_NULL)
+ {
+ struct dtb_node *dtb_node_list = dtb_node_get_dtb_list(fdt);
+ if (dtb_node_list != RT_NULL)
+ {
+ struct dtb_node *serial0 = dtb_node_get_dtb_node_by_path(dtb_node_list, "/smb@4000000/motherboard/iofpga@7,00000000/uart@9000");
+ struct dtb_node *cpu = dtb_node_get_dtb_node_by_path(dtb_node_list, "/cpus");
+ struct dtb_node *user1 = dtb_node_get_dtb_node_by_path(dtb_node_list, "/smb@4000000/motherboard/leds/user1");
+
+ if (serial0 != RT_NULL)
+ {
+ int property_size;
+ rt_uint32_t u32_value;
+ rt_uint32_t *u32_ptr;
+ char *str_ptr;
+
+ rt_kprintf("name = %s\n", serial0->name);
+
+ rt_kputs("reg = <");
+ for_each_property_cell(serial0, "reg", u32_value, u32_ptr, property_size)
+ {
+ rt_kprintf("0x%x,", u32_value);
+ }
+ rt_kputs("\b>;\n");
+
+ rt_kputs("compatible = ");
+ for_each_property_string(serial0, "compatible", str_ptr, property_size)
+ {
+ rt_kprintf("\"%s\",", str_ptr);
+ }
+ rt_kputs("\b;\n");
+ }
+
+ if (cpu != RT_NULL)
+ {
+ struct dtb_node *cpu_child = cpu;
+
+ rt_kprintf("\nname = %s\n", cpu->name);
+
+ for_each_node_child(cpu_child)
+ {
+ rt_kprintf("path = %s\n", cpu_child->path);
+ }
+ }
+
+ if (user1 != RT_NULL)
+ {
+ struct dtb_node *user = user1;
+
+ rt_kprintf("\nname = %s, lable = %s\n", user1->name, dtb_node_get_dtb_node_property(user1, "label", RT_NULL));
+
+ for_each_node_sibling(user)
+ {
+ rt_kprintf("name = %s, lable = %s\n", user->name, dtb_node_get_dtb_node_property(user, "label", RT_NULL));
+ }
+ }
+ }
+ dtb_node_free_dtb_list(dtb_node_list);
+ }
+
+ if ((fdt = dtb_node_load_from_fs("bcm2711-rpi-4-b.dtb")) != RT_NULL)
+ {
+ struct dtb_node *dtb_node_list = dtb_node_get_dtb_list(fdt);
+ if (dtb_node_list != RT_NULL)
+ {
+ struct dtb_node *bt_pins;
+ int memreserve_size;
+ struct dtb_memreserve *memreserve;
+
+ bt_pins = dtb_node_get_dtb_node_by_name_DFS(dtb_node_list, "bt_pins");
+ bt_pins = dtb_node_get_dtb_node_by_name_BFS(dtb_node_list, bt_pins->name);
+ bt_pins = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node_list, bt_pins->handle);
+ bt_pins = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node_list, bt_pins->handle);
+
+ memreserve = dtb_node_get_dtb_memreserve(bt_pins, &memreserve_size);
+ if (memreserve_size > 0)
+ {
+ int i;
+ for (i = 0; i < memreserve_size; ++i)
+ {
+ rt_kputs("\n/memreserve/\t");
+ if (IN_64BITS_MODE)
+ {
+ rt_kprintf("0x%016x 0x%016x;", memreserve[i].address, memreserve[i].size);
+ }
+ else
+ {
+ rt_kprintf("0x%08x%08x 0x%08x%08x;", memreserve[i].address, memreserve[i].size);
+ }
+ }
+ }
+
+ if (bt_pins != RT_NULL)
+ {
+ int property_size;
+ rt_uint8_t u8_value;
+ rt_uint8_t *u8_ptr;
+
+ rt_kprintf("\n\nphandle = <0x%x>\n", bt_pins->handle);
+ rt_kprintf("name = %s\n", bt_pins->name);
+ rt_kprintf("path = %s\n", bt_pins->path);
+
+ rt_kputs("brcm,pins = [");
+ for_each_property_byte(bt_pins, "brcm,pins", u8_value, u8_ptr, property_size)
+ {
+ rt_kprintf("%02x ", u8_value);
+ }
+ rt_kputs("\b]\n");
+ }
+ }
+ dtb_node_free_dtb_list(dtb_node_list);
+ }
+ return 0;
+}
+MSH_CMD_EXPORT(dtb_test, dtb API test);
+
+int dtb_dump(int argc, char** argv)
+{
+ struct dtb_node *dtb_root_node = get_dtb_node_head();
+ if(argc == 1)
+ {
+ if (dtb_root_node != RT_NULL)
+ {
+ dtb_node_get_dts_dump(dtb_root_node);
+ }
+ }
+ else
+ {
+ rt_kprintf("invailed parameter\n");
+ }
+
+ return 0;
+}
+MSH_CMD_EXPORT(dtb_dump, dtb dump from mem);
+
+
diff --git a/components/drivers/fdt/inc/dtb_node.h b/components/drivers/fdt/inc/dtb_node.h
new file mode 100644
index 0000000000..be304a48c8
--- /dev/null
+++ b/components/drivers/fdt/inc/dtb_node.h
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef _DTB_NODE_H__
+#define _DTB_NODE_H__
+
+#include "libfdt_env.h"
+#include <rtthread.h>
+
+//#define RT_DTB_DEBUG
+#ifdef RT_DTB_DEBUG
+#define debug(fmt, args...) rt_kprintf(fmt, ##args)
+#else
+#define debug(fmt, args...)
+#endif
+
+#define ERR_PTR(err) ((void *)((long)(err)))
+#define PTR_ERR(ptr) ((long)(ptr))
+#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
+
+#define DEV_ROOT_NODE_ADDR_CELLS_DEFAULT 2
+#define DEV_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+/* will be optimized to only u64 or u32 by gcc */
+#define IN_64BITS_MODE (sizeof(void *) == 8)
+
+#define FDT_ROOT_ADDR_CELLS_DEFAULT 1
+#define FDT_ROOT_SIZE_CELLS_DEFAULT 1
+
+#define FDT_DTB_ALL_NODES_PATH_SIZE (32 * 1024)
+#define FDT_DTB_PAD_SIZE 1024
+
+#define FDT_RET_NO_MEMORY 2
+#define FDT_RET_NO_LOADED 1
+#define FDT_RET_GET_OK 0
+#define FDT_RET_GET_EMPTY (-1)
+
+typedef uint32_t phandle;
+
+struct dtb_memreserve
+{
+ uintptr_t address;
+ size_t size;
+};
+
+struct dtb_header
+{
+ char root, zero; /* "/" */
+ struct dtb_memreserve *memreserve;
+ size_t memreserve_sz;
+};
+
+struct dtb_property
+{
+ const char *name;
+ int size;
+ void *value;
+
+ struct dtb_property *next;
+};
+
+struct dtb_node
+{
+ union
+ {
+ const char *name;
+ const struct dtb_header *header;
+ };
+ const char *path;
+ phandle handle;
+
+ struct dtb_property *properties;
+ struct dtb_node *parent;
+ struct dtb_node *child;
+ struct dtb_node *sibling;
+};
+
+#define FDT_MAX_PHANDLE_ARGS 16
+
+/**
+ * struct dtb_node_phandle_args - structure to hold phandle and arguments
+ *
+ * This is used when decoding a phandle in a device tree property. Typically
+ * these look like this:
+ *
+ * wibble {
+ * phandle = <5>;
+ * };
+ *
+ * ...
+ * some-prop = <&wibble 1 2 3>
+ *
+ * Here &node is the phandle of the node 'wibble', i.e. 5. There are three
+ * arguments: 1, 2, 3.
+ *
+ * So when decoding the phandle in some-prop, np will point to wibble,
+ * args_count will be 3 and the three arguments will be in args.
+ *
+ * @np: Node that the phandle refers to
+ * @args_count: Number of arguments
+ * @args: Argument values
+ */
+struct fdt_phandle_args
+{
+ struct dtb_node *np;
+ int args_count;
+ uint32_t args[FDT_MAX_PHANDLE_ARGS];
+};
+
+/*
+ * A single signal can be specified via a range of minimal and maximal values
+ * with a typical value, that lies somewhere inbetween.
+ */
+struct timing_entry
+{
+ uint32_t min;
+ uint32_t typ;
+ uint32_t max;
+};
+
+void *get_fdt_blob(void);
+struct dtb_node *get_dtb_node_head(void);
+rt_bool_t dtb_node_active(void);
+int device_tree_setup(void *mem_addr);
+
+void *dtb_node_load_from_fs(char *dtb_filename);
+void *dtb_node_load_from_memory(void *dtb_ptr, rt_bool_t is_clone);
+
+size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline);
+size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size);
+
+size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size);
+size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size);
+size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address);
+
+int dtb_node_get_exec_status();
+struct dtb_node *dtb_node_get_dtb_list(void *fdt);
+void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head);
+void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head);
+void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void(callback(struct dtb_node *dtb_node)));
+
+struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename);
+struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename);
+struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname);
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle);
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle);
+void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells);
+struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size);
+uint8_t dtb_node_get_dtb_byte_value(void *value);
+
+char *dtb_node_get_dtb_string_list_value(void *value, int size, int index);
+char *dtb_node_get_dtb_string_list_value_next(void *value, void *end);
+uint32_t dtb_node_get_dtb_cell_value(void *value);
+
+rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node);
+rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles);
+
+/*dtb_node_access.c */
+int dtb_node_read_u32(const struct dtb_node *dn, const char *propname, uint32_t *outp);
+uint32_t dtb_node_read_u32_default(const struct dtb_node *node, const char *propname, uint32_t def);
+int dtb_node_read_u32_index(const struct dtb_node *node, const char *propname, int index,
+ uint32_t *outp);
+uint32_t dtb_node_read_u32_index_default(const struct dtb_node *node, const char *propname, int index,
+ uint32_t def);
+int dtb_node_read_u32_array(const struct dtb_node *dn, const char *propname,
+ uint32_t *out_values, size_t sz);
+int dtb_node_read_u32_index(const struct dtb_node *dn, const char *propname,
+ int index, uint32_t *outp);
+int dtb_node_read_s32_default(const struct dtb_node *node, const char *propname, int32_t def);
+int dtb_node_read_u64(const struct dtb_node *dn, const char *propname, uint64_t *outp);
+uint64_t dtb_node_read_u64_default(const struct dtb_node *node, const char *propname, uint64_t def);
+
+int dtb_node_n_addr_cells(const struct dtb_node *dn);
+int dtb_node_n_size_cells(const struct dtb_node *dn);
+int dtb_node_simple_addr_cells(const struct dtb_node *np);
+int dtb_node_simple_size_cells(const struct dtb_node *np);
+
+struct dtb_node *dtb_node_find_all_nodes(const struct dtb_node *prev);
+struct dtb_node *dtb_node_find_node_by_phandle(phandle handle);
+struct dtb_node *dtb_node_find_compatible_node(struct dtb_node *from, const char *compatible);
+void *dtb_node_get_dtb_node_property_value(const struct dtb_node *dtb_node, const char *property_name, int *property_size);
+struct dtb_property *dtb_node_get_dtb_node_property(const struct dtb_node *dtb_node, const char *property_name, int *property_size);
+const struct dtb_node *dtb_node_find_node_by_prop_value(struct dtb_node *from, const char *propname, const void *propval, int proplen);
+struct dtb_node *dtb_node_find_node_opts_by_path(const char *path,
+ const char **opts);
+
+static inline struct dtb_node *dtb_node_find_node_by_path(const char *path)
+{
+ return dtb_node_find_node_opts_by_path(path, NULL);
+}
+
+rt_bool_t dtb_node_device_is_available(const struct dtb_node *device);
+struct dtb_node *dtb_node_get_parent(const struct dtb_node *node);
+int dtb_node_property_match_string(const struct dtb_node *dn, const char *propname,
+ const char *string);
+int dtb_node_property_read_string_helper(const struct dtb_node *dn,
+ const char *propname, const char **out_strs,
+ size_t sz, int skip);
+/**
+ * of_property_read_string_index() - Find and read a string from a multiple
+ * strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the string in the list of strings
+ * @out_string: pointer to null terminated return string, modified only if
+ * return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy) in the list of strings
+ * contained in that property.
+ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EILSEQ if the string is not
+ * null-terminated within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+static inline int dtb_node_property_read_string_index(const struct dtb_node *dn,
+ const char *propname,
+ int index, const char **output)
+{
+ int rc = dtb_node_property_read_string_helper(dn, propname, output, 1, index);
+ return rc < 0 ? rc : 0;
+}
+
+/**
+ * of_property_count_strings() - Find and return the number of strings from a
+ * multiple strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+static inline int dtb_node_property_count_strings(const struct dtb_node *dn,
+ const char *propname)
+{
+ return dtb_node_property_read_string_helper(dn, propname, NULL, 0, 0);
+}
+
+struct dtb_node *dtb_node_parse_phandle(const struct dtb_node *dn,
+ const char *phandle_name, int index);
+int dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
+ const char *list_name, const char *cells_name,
+ int index, struct fdt_phandle_args *out_args);
+int dtb_node_count_phandle_with_args(const struct dtb_node *dn,
+ const char *list_name, const char *cells_name);
+
+/* dtb_node_addr.c */
+const uint32_t *dtb_node_get_address(const struct dtb_node *dev, int index,
+ uint64_t *size, unsigned int *flags);
+
+#define dtb_node_string_list(string, ...) ((char *[]){string, ##__VA_ARGS__, NULL})
+
+#define for_each_property_string(node_ptr, property_name, str, size) \
+ for (str = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
+ size += (typeof(size))(size_t)str; \
+ str && *str; \
+ str = dtb_node_get_dtb_string_list_value_next((void *)str, (void *)(size_t)size))
+
+#define for_each_property_cell(node_ptr, property_name, value, list, size) \
+ for (list = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
+ value = dtb_node_get_dtb_cell_value(list), \
+ size /= sizeof(uint32_t); \
+ size > 0; \
+ value = dtb_node_get_dtb_cell_value(++list), --size)
+
+#define for_each_property_byte(node_ptr, property_name, value, list, size) \
+ for (list = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
+ value = dtb_node_get_dtb_byte_value(list); \
+ size > 0; \
+ value = dtb_node_get_dtb_byte_value(++list), --size)
+
+#define for_each_node_child(node_ptr) \
+ for (node_ptr = (node_ptr ? node_ptr->child : NULL); \
+ node_ptr != NULL; \
+ node_ptr = node_ptr->sibling)
+
+#define for_each_node_sibling(node_ptr) \
+ for (node_ptr = (node_ptr ? node_ptr->sibling : NULL); \
+ node_ptr != NULL; \
+ node_ptr = node_ptr->sibling)
+
+#define for_each_of_allnodes_from(from, dn) \
+ for (dn = dtb_node_find_all_nodes(from); dn; dn = dtb_node_find_all_nodes(dn))
+
+#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn)
+
+#define dtb_node_get(x) (x)
+static inline void dtb_node_put(const struct dtb_node *np)
+{
+}
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline uint64_t dtb_node_read_number(const uint32_t *cell, int size)
+{
+ uint64_t r = 0;
+ while (size--)
+ r = (r << 32) | fdt32_to_cpu(*(cell++));
+ return r;
+}
+
+/**
+ * ofnode_valid() - check if an ofnode is valid
+ *
+ * @return true if the reference contains a valid ofnode, RT_FALSE if it is NULL
+ */
+static inline rt_bool_t dtb_node_valid(const struct dtb_node *node)
+{
+ if (dtb_node_active())
+ return node != NULL;
+ return RT_FALSE;
+}
+
+/*dtb_base.c */
+rt_bool_t dtb_node_read_bool(const struct dtb_node *node, const char *propname);
+const void *dtb_node_read_prop(const struct dtb_node *node, const char *propname, int *sizep);
+const char *dtb_node_read_string(const struct dtb_node *node, const char *propname);
+const struct dtb_node *dtb_node_find_subnode(const struct dtb_node *node, const char *subnode_name);
+int dtb_node_read_u32_array(const struct dtb_node *node, const char *propname,
+ uint32_t *out_values, size_t sz);
+struct dtb_node *dtb_node_first_subnode(const struct dtb_node *node);
+struct dtb_node *dtb_node_next_subnode(const struct dtb_node *node);
+struct dtb_node *dtb_node_get_parent(const struct dtb_node *node);
+const char *dtb_node_get_name(const struct dtb_node *node);
+struct dtb_node *dtb_node_get_by_phandle(uint phandle);
+int dtb_node_read_size(const struct dtb_node *node, const char *propname);
+size_t dtb_node_get_addr_index(const struct dtb_node *node, int index);
+size_t dtb_node_get_addr(const struct dtb_node *node);
+int dtb_node_stringlist_search(const struct dtb_node *node, const char *property,
+ const char *string);
+int dtb_node_read_string_index(const struct dtb_node *node, const char *property, int index,
+ const char **outp);
+int dtb_node_read_string_count(const struct dtb_node *node, const char *property);
+struct dtb_node *dtb_node_path(const char *path);
+const char *dtb_node_get_chosen_prop(const char *name);
+struct dtb_node *dtb_node_get_chosen_node(const char *name);
+const void *dtb_node_get_property(const struct dtb_node *node, const char *propname, int *lenp);
+rt_bool_t dtb_node_is_available(const struct dtb_node *node);
+size_t dtb_node_get_addr_size(const struct dtb_node *node, const char *property,
+ size_t *sizep);
+const uint8_t *dtb_node_read_u8_array_ptr(const struct dtb_node *node, const char *propname, size_t sz);
+int dtb_node_find_all_compatible_node(const struct dtb_node *from, const char *compatible, struct dtb_node **node_table, int max_num, int *node_num);
+int dtb_node_write_prop(const struct dtb_node *node, const char *propname, int len,
+ const void *value);
+int dtb_node_write_string(const struct dtb_node *node, const char *propname, const char *value);
+int dtb_node_set_enabled(const struct dtb_node *node, rt_bool_t value);
+int dtb_node_irq_get(struct dtb_node *dev, int index);
+int dtb_node_irq_get_byname(struct dtb_node *dev, const char *name);
+int dtb_node_irq_count(struct dtb_node *dev);
+
+/**
+ * dtb_node_for_each_subnode() - iterate over all subnodes of a parent
+ *
+ * @node: child node (ofnode, lvalue)
+ * @parent: parent node (ofnode)
+ *
+ * This is a wrapper around a for loop and is used like so:
+ *
+ * ofnode node;
+ *
+ * dtb_node_for_each_subnode(node, parent) {
+ * Use node
+ * ...
+ * }
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable can be a constant or even a
+ * literal.
+ */
+#define dtb_node_for_each_subnode(node, parent) \
+ for (node = dtb_node_first_subnode(parent); \
+ dtb_node_valid(node); \
+ node = dtb_node_next_subnode(node))
+
+#endif /* RT_FDT_H__ */
diff --git a/components/drivers/fdt/libfdt/SConscript b/components/drivers/fdt/libfdt/SConscript
new file mode 100644
index 0000000000..638a457bfe
--- /dev/null
+++ b/components/drivers/fdt/libfdt/SConscript
@@ -0,0 +1,10 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('FDT', src, depend = ['RT_USING_FDTLIB'], CPPPATH = CPPPATH)
+
+Return('group') \ No newline at end of file
diff --git a/components/drivers/fdt/libfdt/fdt.c b/components/drivers/fdt/libfdt/fdt.c
new file mode 100644
index 0000000000..1d4c606985
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt.c
@@ -0,0 +1,249 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ /* Complete tree */
+ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ /* Unfinished sequential-write blob */
+ if (fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+ unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+
+ if ((absoffset < offset)
+ || ((absoffset + len) < absoffset)
+ || (absoffset + len) > fdt_totalsize(fdt))
+ return NULL;
+
+ if (fdt_version(fdt) >= 0x11)
+ if (((offset + len) < offset)
+ || ((offset + len) > fdt_size_dt_struct(fdt)))
+ return NULL;
+
+ return _fdt_offset_ptr(fdt, offset);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+ const fdt32_t *tagp, *lenp;
+ uint32_t tag;
+ int offset = startoffset;
+ const char *p;
+
+ *nextoffset = -FDT_ERR_TRUNCATED;
+ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+ if (!tagp)
+ return FDT_END; /* premature end */
+ tag = fdt32_to_cpu(*tagp);
+ offset += FDT_TAGSIZE;
+
+ *nextoffset = -FDT_ERR_BADSTRUCTURE;
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /* skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!p)
+ return FDT_END; /* premature end */
+ break;
+
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+ if (!lenp)
+ return FDT_END; /* premature end */
+ /* skip-name offset, length and value */
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ + fdt32_to_cpu(*lenp);
+ break;
+
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return FDT_END;
+ }
+
+ if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+ return FDT_END; /* premature end */
+
+ *nextoffset = FDT_TAGALIGN(offset);
+ return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int _fdt_check_prop_offset(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset >= 0)
+ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+ return nextoffset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ case FDT_BEGIN_NODE:
+ if (depth)
+ (*depth)++;
+ break;
+
+ case FDT_END_NODE:
+ if (depth && ((--(*depth)) < 0))
+ return nextoffset;
+ break;
+
+ case FDT_END:
+ if ((nextoffset >= 0)
+ || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+ return -FDT_ERR_NOTFOUND;
+ else
+ return nextoffset;
+ }
+ } while (tag != FDT_BEGIN_NODE);
+
+ return offset;
+}
+
+int fdt_first_subnode(const void *fdt, int offset)
+{
+ int depth = 0;
+
+ offset = fdt_next_node(fdt, offset, &depth);
+ if (offset < 0 || depth != 1)
+ return -FDT_ERR_NOTFOUND;
+
+ return offset;
+}
+
+int fdt_next_subnode(const void *fdt, int offset)
+{
+ int depth = 1;
+
+ /*
+ * With respect to the parent, the depth of the next subnode will be
+ * the same as the last.
+ */
+ do {
+ offset = fdt_next_node(fdt, offset, &depth);
+ if (offset < 0 || depth < 1)
+ return -FDT_ERR_NOTFOUND;
+ } while (depth > 1);
+
+ return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+ int len = strlen(s) + 1;
+ const char *last = strtab + tabsize - len;
+ const char *p;
+
+ for (p = strtab; p <= last; p++)
+ if (memcmp(p, s, len) == 0)
+ return p;
+ return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_totalsize(fdt) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/components/drivers/fdt/libfdt/fdt.h b/components/drivers/fdt/libfdt/fdt.h
new file mode 100644
index 0000000000..526aedb515
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt.h
@@ -0,0 +1,111 @@
+#ifndef _FDT_H
+#define _FDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+ fdt32_t magic; /* magic word FDT_MAGIC */
+ fdt32_t totalsize; /* total size of DT block */
+ fdt32_t off_dt_struct; /* offset to structure */
+ fdt32_t off_dt_strings; /* offset to strings */
+ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
+ fdt32_t version; /* format version */
+ fdt32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ fdt32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ fdt32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ fdt64_t address;
+ fdt64_t size;
+};
+
+struct fdt_node_header {
+ fdt32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ fdt32_t tag;
+ fdt32_t len;
+ fdt32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(fdt32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(fdt32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
+
+#endif /* _FDT_H */
diff --git a/components/drivers/fdt/libfdt/fdt_addresses.c b/components/drivers/fdt/libfdt/fdt_addresses.c
new file mode 100644
index 0000000000..a8f2ad5ebc
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_addresses.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2014 David Gibson <[email protected]>
+ * Copyright (C) 2018 embedded brains GmbH
+ */
+#include "libfdt_env.h"
+#include <fdt.h>
+#include <libfdt.h>
+#include "libfdt_internal.h"
+
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
+{
+ const fdt32_t *c;
+ uint32_t val;
+ int len;
+
+ c = fdt_getprop(fdt, nodeoffset, name, &len);
+ if (!c)
+ return len;
+
+ if (len != sizeof(*c))
+ return -FDT_ERR_BADNCELLS;
+
+ val = fdt32_to_cpu(*c);
+ if (val > FDT_MAX_NCELLS)
+ return -FDT_ERR_BADNCELLS;
+
+ return (int)val;
+}
+
+int fdt_address_cells(const void *fdt, int nodeoffset)
+{
+ int val;
+
+ val = fdt_cells(fdt, nodeoffset, "#address-cells");
+ if (val == 0)
+ return -FDT_ERR_BADNCELLS;
+ if (val == -FDT_ERR_NOTFOUND)
+ return 2;
+ return val;
+}
+
+int fdt_size_cells(const void *fdt, int nodeoffset)
+{
+ int val;
+
+ val = fdt_cells(fdt, nodeoffset, "#size-cells");
+ if (val == -FDT_ERR_NOTFOUND)
+ return 1;
+ return val;
+}
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+ const char *name, uint64_t addr, uint64_t size)
+{
+ int addr_cells, size_cells, ret;
+ uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+ ret = fdt_address_cells(fdt, parent);
+ if (ret < 0)
+ return ret;
+ addr_cells = ret;
+
+ ret = fdt_size_cells(fdt, parent);
+ if (ret < 0)
+ return ret;
+ size_cells = ret;
+
+ /* check validity of address */
+ prop = data;
+ if (addr_cells == 1) {
+ if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+ return -FDT_ERR_BADVALUE;
+
+ fdt32_st(prop, (uint32_t)addr);
+ } else if (addr_cells == 2) {
+ fdt64_st(prop, addr);
+ } else {
+ return -FDT_ERR_BADNCELLS;
+ }
+
+ /* check validity of size */
+ prop += addr_cells * sizeof(fdt32_t);
+ if (size_cells == 1) {
+ if (size > UINT32_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ fdt32_st(prop, (uint32_t)size);
+ } else if (size_cells == 2) {
+ fdt64_st(prop, size);
+ } else {
+ return -FDT_ERR_BADNCELLS;
+ }
+
+ return fdt_appendprop(fdt, nodeoffset, name, data,
+ (addr_cells + size_cells) * sizeof(fdt32_t));
+}
diff --git a/components/drivers/fdt/libfdt/fdt_empty_tree.c b/components/drivers/fdt/libfdt/fdt_empty_tree.c
new file mode 100644
index 0000000000..26ab2d3641
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_empty_tree.c
@@ -0,0 +1,84 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include "fdt.h"
+#include "libfdt.h"
+
+#include "libfdt_internal.h"
+
+int fdt_create_empty_tree(void *buf, int bufsize)
+{
+ int err;
+
+ err = fdt_create(buf, bufsize);
+ if (err)
+ return err;
+
+ err = fdt_finish_reservemap(buf);
+ if (err)
+ return err;
+
+ err = fdt_begin_node(buf, "");
+ if (err)
+ return err;
+
+ err = fdt_end_node(buf);
+ if (err)
+ return err;
+
+ err = fdt_finish(buf);
+ if (err)
+ return err;
+
+ return fdt_open_into(buf, buf, bufsize);
+}
+
diff --git a/components/drivers/fdt/libfdt/fdt_ro.c b/components/drivers/fdt/libfdt/fdt_ro.c
new file mode 100644
index 0000000000..984e8fe227
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_ro.c
@@ -0,0 +1,701 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+ const char *s, int len)
+{
+ const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+ if (! p)
+ /* short match */
+ return 0;
+
+ if (memcmp(p, s, len) != 0)
+ return 0;
+
+ if (p[len] == '\0')
+ return 1;
+ else if (!memchr(s, '@', len) && (p[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+ const char *s, int len)
+{
+ const char *p = fdt_string(fdt, stroffset);
+
+ return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+uint32_t fdt_get_max_phandle(const void *fdt)
+{
+ uint32_t max_phandle = 0;
+ int offset;
+
+ for (offset = fdt_next_node(fdt, -1, NULL);;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ uint32_t phandle;
+
+ if (offset == -FDT_ERR_NOTFOUND)
+ return max_phandle;
+
+ if (offset < 0)
+ return (uint32_t)-1;
+
+ phandle = fdt_get_phandle(fdt, offset);
+ if (phandle == (uint32_t)-1)
+ continue;
+
+ if (phandle > max_phandle)
+ max_phandle = phandle;
+ }
+
+ return 0;
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+ FDT_CHECK_HEADER(fdt);
+ *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+ *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i = 0;
+
+ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+ i++;
+ return i;
+}
+
+static int _nextprop(const void *fdt, int offset)
+{
+ uint32_t tag;
+ int nextoffset;
+
+ do {
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_END:
+ if (nextoffset >= 0)
+ return -FDT_ERR_BADSTRUCTURE;
+ else
+ return nextoffset;
+
+ case FDT_PROP:
+ return offset;
+ }
+ offset = nextoffset;
+ } while (tag == FDT_NOP);
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+ const char *name, int namelen)
+{
+ int depth;
+
+ FDT_CHECK_HEADER(fdt);
+
+ for (depth = 0;
+ (offset >= 0) && (depth >= 0);
+ offset = fdt_next_node(fdt, offset, &depth))
+ if ((depth == 1)
+ && _fdt_nodename_eq(fdt, offset, name, namelen))
+ return offset;
+
+ if (depth < 0)
+ return -FDT_ERR_NOTFOUND;
+ return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+ const char *name)
+{
+ return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
+{
+ const char *end = path + namelen;
+ const char *p = path;
+ int offset = 0;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* see if we have an alias */
+ if (*path != '/') {
+ const char *q = memchr(path, '/', end - p);
+
+ if (!q)
+ q = end;
+
+ p = fdt_get_alias_namelen(fdt, p, q - p);
+ if (!p)
+ return -FDT_ERR_BADPATH;
+ offset = fdt_path_offset(fdt, p);
+
+ p = q;
+ }
+
+ while (p < end) {
+ const char *q;
+
+ while (*p == '/') {
+ p++;
+ if (p == end)
+ return offset;
+ }
+ q = memchr(p, '/', end - p);
+ if (! q)
+ q = end;
+
+ offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+ if (offset < 0)
+ return offset;
+
+ p = q;
+ }
+
+ return offset;
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ return fdt_path_offset_namelen(fdt, path, strlen(path));
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+ const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+ int err;
+
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ if (len)
+ *len = strlen(nh->name);
+
+ return nh->name;
+
+ fail:
+ if (len)
+ *len = err;
+ return NULL;
+}
+
+int fdt_first_property_offset(const void *fdt, int nodeoffset)
+{
+ int offset;
+
+ if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return offset;
+
+ return _nextprop(fdt, offset);
+}
+
+int fdt_next_property_offset(const void *fdt, int offset)
+{
+ if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+ return offset;
+
+ return _nextprop(fdt, offset);
+}
+
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp)
+{
+ int err;
+ const struct fdt_property *prop;
+
+ if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
+ if (lenp)
+ *lenp = err;
+ return NULL;
+ }
+
+ prop = _fdt_offset_ptr(fdt, offset);
+
+ if (lenp)
+ *lenp = fdt32_to_cpu(prop->len);
+
+ return prop;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int offset,
+ const char *name,
+ int namelen, int *lenp)
+{
+ for (offset = fdt_first_property_offset(fdt, offset);
+ (offset >= 0);
+ (offset = fdt_next_property_offset(fdt, offset))) {
+ const struct fdt_property *prop;
+
+ if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
+ offset = -FDT_ERR_INTERNAL;
+ break;
+ }
+ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+ name, namelen))
+ return prop;
+ }
+
+ if (lenp)
+ *lenp = offset;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+ int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_get_property_namelen(fdt, nodeoffset, name,
+ strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+ if (! prop)
+ return NULL;
+
+ return prop->data;
+}
+
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+ const char **namep, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_by_offset(fdt, offset, lenp);
+ if (!prop)
+ return NULL;
+ if (namep)
+ *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+ const fdt32_t *php;
+ int len;
+
+ /* FIXME: This is a bit sub-optimal, since we potentially scan
+ * over all the properties twice. */
+ php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+ if (!php || (len != sizeof(*php))) {
+ php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+ if (!php || (len != sizeof(*php)))
+ return 0;
+ }
+
+ return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen)
+{
+ int aliasoffset;
+
+ aliasoffset = fdt_path_offset(fdt, "/aliases");
+ if (aliasoffset < 0)
+ return NULL;
+
+ return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+ return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+ int pdepth = 0, p = 0;
+ int offset, depth, namelen;
+ const char *name;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (buflen < 2)
+ return -FDT_ERR_NOSPACE;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ while (pdepth > depth) {
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ pdepth--;
+ }
+
+ if (pdepth >= depth) {
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if ((p + namelen + 1) <= buflen) {
+ memcpy(buf + p, name, namelen);
+ p += namelen;
+ buf[p++] = '/';
+ pdepth++;
+ }
+ }
+
+ if (offset == nodeoffset) {
+ if (pdepth < (depth + 1))
+ return -FDT_ERR_NOSPACE;
+
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return 0;
+ }
+ }
+
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth)
+{
+ int offset, depth;
+ int supernodeoffset = -FDT_ERR_INTERNAL;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (supernodedepth < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth == supernodedepth)
+ supernodeoffset = offset;
+
+ if (offset == nodeoffset) {
+ if (nodedepth)
+ *nodedepth = depth;
+
+ if (supernodedepth > depth)
+ return -FDT_ERR_NOTFOUND;
+ else
+ return supernodeoffset;
+ }
+ }
+
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+ int nodedepth;
+ int err;
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+ if (err)
+ return (err < 0) ? err : -FDT_ERR_INTERNAL;
+ return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+ int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+ if (nodedepth < 0)
+ return nodedepth;
+ return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ int offset;
+ const void *val;
+ int len;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_getprop(), then if that didn't
+ * find what we want, we scan over them again making our way
+ * to the next node. Still it's the easiest to implement
+ * approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+ int offset;
+
+ if ((phandle == 0) || (phandle == -1))
+ return -FDT_ERR_BADPHANDLE;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we
+ * potentially scan each property of a node in
+ * fdt_get_phandle(), then if that didn't find what
+ * we want, we scan over them again making our way to the next
+ * node. Still it's the easiest to implement approach;
+ * performance can come later. */
+ for (offset = fdt_next_node(fdt, -1, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ if (fdt_get_phandle(fdt, offset) == phandle)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
+{
+ int len = strlen(str);
+ const char *p;
+
+ while (listlen >= len) {
+ if (memcmp(str, strlist, len+1) == 0)
+ return 1;
+ p = memchr(strlist, '\0', listlen);
+ if (!p)
+ return 0; /* malformed strlist.. */
+ listlen -= (p-strlist) + 1;
+ strlist = p + 1;
+ }
+ return 0;
+}
+
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
+{
+ const char *list, *end;
+ int length, count = 0;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list)
+ return length;
+
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end)
+ return -FDT_ERR_BADVALUE;
+
+ list += length;
+ count++;
+ }
+
+ return count;
+}
+
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+ const char *string)
+{
+ int length, len, idx = 0;
+ const char *list, *end;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list)
+ return length;
+
+ len = strlen(string) + 1;
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end)
+ return -FDT_ERR_BADVALUE;
+
+ if (length == len && memcmp(list, string, length) == 0)
+ return idx;
+
+ list += length;
+ idx++;
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+ const char *property, int idx,
+ int *lenp)
+{
+ const char *list, *end;
+ int length;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list) {
+ if (lenp)
+ *lenp = length;
+
+ return NULL;
+ }
+
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVALUE;
+
+ return NULL;
+ }
+
+ if (idx == 0) {
+ if (lenp)
+ *lenp = length - 1;
+
+ return list;
+ }
+
+ list += length;
+ idx--;
+ }
+
+ if (lenp)
+ *lenp = -FDT_ERR_NOTFOUND;
+
+ return NULL;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+ if (!prop)
+ return len;
+
+ return !fdt_stringlist_contains(prop, len, compatible);
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible)
+{
+ int offset, err;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_node_check_compatible(), then if
+ * that didn't find what we want, we scan over them again
+ * making our way to the next node. Still it's the easiest to
+ * implement approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ err = fdt_node_check_compatible(fdt, offset, compatible);
+ if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
diff --git a/components/drivers/fdt/libfdt/fdt_rw.c b/components/drivers/fdt/libfdt/fdt_rw.c
new file mode 100644
index 0000000000..4406471b74
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_rw.c
@@ -0,0 +1,489 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+ int mem_rsv_size, int struct_size)
+{
+ return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+ || (fdt_off_dt_struct(fdt) <
+ (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+ || (fdt_off_dt_strings(fdt) <
+ (fdt_off_dt_struct(fdt) + struct_size))
+ || (fdt_totalsize(fdt) <
+ (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_version(fdt) < 17)
+ return -FDT_ERR_BADVERSION;
+ if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_BADLAYOUT;
+ if (fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+ { \
+ int __err; \
+ if ((__err = _fdt_rw_check_header(fdt)) != 0) \
+ return __err; \
+ }
+
+static inline int _fdt_data_size(void *fdt)
+{
+ return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+ char *p = splicepoint;
+ char *end = (char *)fdt + _fdt_data_size(fdt);
+
+ if (((p + oldlen) < p) || ((p + oldlen) > end))
+ return -FDT_ERR_BADOFFSET;
+ if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+ return -FDT_ERR_BADOFFSET;
+ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, end - p - oldlen);
+ return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+ int oldn, int newn)
+{
+ int delta = (newn - oldn) * sizeof(*p);
+ int err;
+ err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+ if (err)
+ return err;
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+ int oldlen, int newlen)
+{
+ int delta = newlen - oldlen;
+ int err;
+
+ if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+ return err;
+
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+ void *p = (char *)fdt
+ + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+ int err;
+
+ if ((err = _fdt_splice(fdt, p, 0, newlen)))
+ return err;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+ return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+ if (p)
+ /* found it */
+ return (p - strtab);
+
+ new = strtab + fdt_size_dt_strings(fdt);
+ err = _fdt_splice_string(fdt, len);
+ if (err)
+ return err;
+
+ memcpy(new, s, len);
+ return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+ err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+ if (err)
+ return err;
+
+ re->address = cpu_to_fdt64(address);
+ re->size = cpu_to_fdt64(size);
+ return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+ struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+ return _fdt_splice_mem_rsv(fdt, re, 1, 0);
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int oldlen;
+ int err;
+
+ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (! (*prop))
+ return oldlen;
+
+ if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(len))))
+ return err;
+
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int proplen;
+ int nextoffset;
+ int namestroff;
+ int err;
+
+ if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return nextoffset;
+
+ namestroff = _fdt_find_add_string(fdt, name);
+ if (namestroff < 0)
+ return namestroff;
+
+ *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+ proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+ err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+ if (err)
+ return err;
+
+ (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+ (*prop)->nameoff = cpu_to_fdt32(namestroff);
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+ char *namep;
+ int oldlen, newlen;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+ if (!namep)
+ return oldlen;
+
+ newlen = strlen(name);
+
+ err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ FDT_TAGALIGN(newlen+1));
+ if (err)
+ return err;
+
+ memcpy(namep, name, newlen+1);
+ return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+ if (err == -FDT_ERR_NOTFOUND)
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+
+ if (len)
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err, oldlen, newlen;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (prop) {
+ newlen = len + oldlen;
+ err = _fdt_splice_struct(fdt, prop->data,
+ FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(newlen));
+ if (err)
+ return err;
+ prop->len = cpu_to_fdt32(newlen);
+ memcpy(prop->data + oldlen, val, len);
+ } else {
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+ memcpy(prop->data, val, len);
+ }
+ return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len, proplen;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+ return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ struct fdt_node_header *nh;
+ int offset, nextoffset;
+ int nodelen;
+ int err;
+ uint32_t tag;
+ fdt32_t *endtag;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+ if (offset >= 0)
+ return -FDT_ERR_EXISTS;
+ else if (offset != -FDT_ERR_NOTFOUND)
+ return offset;
+
+ /* Try to place the new node after the parent's properties */
+ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+ nh = _fdt_offset_ptr_w(fdt, offset);
+ nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+ err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+ if (err)
+ return err;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+ memcpy(nh->name, name, namelen);
+ endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+ *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+ return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+ int mem_rsv_size, int struct_size)
+{
+ int mem_rsv_off, struct_off, strings_off;
+
+ mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+ struct_off = mem_rsv_off + mem_rsv_size;
+ strings_off = struct_off + struct_size;
+
+ memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+ memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+ fdt_set_off_dt_struct(new, struct_off);
+ fdt_set_size_dt_struct(new, struct_size);
+
+ memmove(new + strings_off, old + fdt_off_dt_strings(old),
+ fdt_size_dt_strings(old));
+ fdt_set_off_dt_strings(new, strings_off);
+ fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+ int err;
+ int mem_rsv_size, struct_size;
+ int newsize;
+ const char *fdtstart = fdt;
+ const char *fdtend = fdtstart + fdt_totalsize(fdt);
+ char *tmp;
+
+ FDT_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ if (struct_size < 0)
+ return struct_size;
+ }
+
+ if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ /* no further work necessary */
+ err = fdt_move(fdt, buf, bufsize);
+ if (err)
+ return err;
+ fdt_set_version(buf, 17);
+ fdt_set_size_dt_struct(buf, struct_size);
+ fdt_set_totalsize(buf, bufsize);
+ return 0;
+ }
+
+ /* Need to reorder */
+ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ + struct_size + fdt_size_dt_strings(fdt);
+
+ if (bufsize < newsize)
+ return -FDT_ERR_NOSPACE;
+
+ /* First attempt to build converted tree at beginning of buffer */
+ tmp = buf;
+ /* But if that overlaps with the old tree... */
+ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+ /* Try right after the old tree instead */
+ tmp = (char *)(uintptr_t)fdtend;
+ if ((tmp + newsize) > ((char *)buf + bufsize))
+ return -FDT_ERR_NOSPACE;
+ }
+
+ _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ memmove(buf, tmp, newsize);
+
+ fdt_set_magic(buf, FDT_MAGIC);
+ fdt_set_totalsize(buf, bufsize);
+ fdt_set_version(buf, 17);
+ fdt_set_last_comp_version(buf, 16);
+ fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+ return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+ int mem_rsv_size;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+ _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+ return 0;
+}
diff --git a/components/drivers/fdt/libfdt/fdt_strerror.c b/components/drivers/fdt/libfdt/fdt_strerror.c
new file mode 100644
index 0000000000..eda657ff07
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_strerror.c
@@ -0,0 +1,100 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+ const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+ [(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+ FDT_ERRTABENT(FDT_ERR_EXISTS),
+ FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
+ FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+ FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+ FDT_ERRTABENT(FDT_ERR_INTERNAL),
+ FDT_ERRTABENT(FDT_ERR_BADNCELLS),
+ FDT_ERRTABENT(FDT_ERR_BADVALUE),
+ FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
+ FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
+};
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (errval > -FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/components/drivers/fdt/libfdt/fdt_sw.c b/components/drivers/fdt/libfdt/fdt_sw.c
new file mode 100644
index 0000000000..5d6de1b1b2
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_sw.c
@@ -0,0 +1,286 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+ if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ /* FIXME: should check more details about the header state */
+ return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_sw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+ int offset = fdt_size_dt_struct(fdt);
+ int spaceleft;
+
+ spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+ - fdt_size_dt_strings(fdt);
+
+ if ((offset + len < offset) || (offset + len > spaceleft))
+ return NULL;
+
+ fdt_set_size_dt_struct(fdt, offset + len);
+ return _fdt_offset_ptr_w(fdt, offset);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+ void *fdt = buf;
+
+ if (bufsize < sizeof(struct fdt_header))
+ return -FDT_ERR_NOSPACE;
+
+ memset(buf, 0, bufsize);
+
+ fdt_set_magic(fdt, FDT_SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry)));
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, bufsize);
+
+ return 0;
+}
+
+int fdt_resize(void *fdt, void *buf, int bufsize)
+{
+ size_t headsize, tailsize;
+ char *oldtail, *newtail;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ headsize = fdt_off_dt_struct(fdt);
+ tailsize = fdt_size_dt_strings(fdt);
+
+ if ((headsize + tailsize) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
+ newtail = (char *)buf + bufsize - tailsize;
+
+ /* Two cases to avoid clobbering data if the old and new
+ * buffers partially overlap */
+ if (buf <= fdt) {
+ memmove(buf, fdt, headsize);
+ memmove(newtail, oldtail, tailsize);
+ } else {
+ memmove(newtail, oldtail, tailsize);
+ memmove(buf, fdt, headsize);
+ }
+
+ fdt_set_off_dt_strings(buf, bufsize);
+ fdt_set_totalsize(buf, bufsize);
+
+ return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int offset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ if (fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADSTATE;
+
+ offset = fdt_off_dt_struct(fdt);
+ if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+
+ re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+ re->address = cpu_to_fdt64(addr);
+ re->size = cpu_to_fdt64(size);
+
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+ return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+ return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int namelen = strlen(name) + 1;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+ if (! nh)
+ return -FDT_ERR_NOSPACE;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memcpy(nh->name, name, namelen);
+ return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+ fdt32_t *en;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+ if (! en)
+ return -FDT_ERR_NOSPACE;
+
+ *en = cpu_to_fdt32(FDT_END_NODE);
+ return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ const char *p;
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+ int struct_top, offset;
+
+ p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+ if (p)
+ return p - strtab;
+
+ /* Add it */
+ offset = -strtabsize - len;
+ struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ if (fdt_totalsize(fdt) + offset < struct_top)
+ return 0; /* no more room :( */
+
+ memcpy(strtab + offset, s, len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
+ return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ struct fdt_property *prop;
+ int nameoff;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nameoff = _fdt_find_add_string(fdt, name);
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ if (! prop)
+ return -FDT_ERR_NOSPACE;
+
+ prop->tag = cpu_to_fdt32(FDT_PROP);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ prop->len = cpu_to_fdt32(len);
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+ char *p = (char *)fdt;
+ fdt32_t *end;
+ int oldstroffset, newstroffset;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ /* Add terminator */
+ end = _fdt_grab_space(fdt, sizeof(*end));
+ if (! end)
+ return -FDT_ERR_NOSPACE;
+ *end = cpu_to_fdt32(FDT_END);
+
+ /* Relocate the string table */
+ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+ newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(fdt, newstroffset);
+
+ /* Walk the structure, correcting string offsets */
+ offset = 0;
+ while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+ if (tag == FDT_PROP) {
+ struct fdt_property *prop =
+ _fdt_offset_ptr_w(fdt, offset);
+ int nameoff;
+
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ nameoff += fdt_size_dt_strings(fdt);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ }
+ offset = nextoffset;
+ }
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /* Finally, adjust the header */
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+ fdt_set_magic(fdt, FDT_MAGIC);
+ return 0;
+}
diff --git a/components/drivers/fdt/libfdt/fdt_wip.c b/components/drivers/fdt/libfdt/fdt_wip.c
new file mode 100644
index 0000000000..a9f2d66679
--- /dev/null
+++ b/components/drivers/fdt/libfdt/fdt_wip.c
@@ -0,0 +1,137 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+#include "fdt.h"
+#include "libfdt.h"
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+ const char *name, int namelen,
+ uint32_t idx, const void *val,
+ int len)
+{
+ void *propval;
+ int proplen;
+
+ propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
+ &proplen);
+ if (!propval)
+ return proplen;
+
+ if (proplen < (len + idx))
+ return -FDT_ERR_NOSPACE;
+
+ memcpy((char *)propval + idx, val, len);
+ return 0;
+}
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ const void *propval;
+ int proplen;
+
+ propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+ return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
+ strlen(name), 0,
+ val, len);
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+ fdt32_t *p;
+
+ for (p = start; (char *)p < ((char *)start + len); p++)
+ *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len;
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ _fdt_nop_region(prop, len + sizeof(*prop));
+
+ return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+ int depth = 0;
+
+ while ((offset >= 0) && (depth >= 0))
+ offset = fdt_next_node(fdt, offset, &depth);
+
+ return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ endoffset - nodeoffset);
+ return 0;
+}
diff --git a/components/drivers/fdt/libfdt/libfdt.h b/components/drivers/fdt/libfdt/libfdt.h
new file mode 100644
index 0000000000..05de18d721
--- /dev/null
+++ b/components/drivers/fdt/libfdt/libfdt.h
@@ -0,0 +1,1876 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libfdt_env.h"
+#include "fdt.h"
+
+#define FDT_FIRST_SUPPORTED_VERSION 0x10
+#define FDT_LAST_SUPPORTED_VERSION 0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS 2
+ /* FDT_ERR_EXISTS: Attempted to create a node or property which
+ * already exists */
+#define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+ * tree, but its buffer did not have sufficient space to
+ * contain the expanded tree. Use fdt_open_into() to move the
+ * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET 4
+ /* FDT_ERR_BADOFFSET: Function was passed a structure block
+ * offset which is out-of-bounds, or which points to an
+ * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH 5
+ /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+#define FDT_ERR_BADPHANDLE 6
+ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
+ * This can be caused either by an invalid phandle property
+ * length, or the phandle value was either 0 or -1, which are
+ * not permitted. */
+#define FDT_ERR_BADSTATE 7
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+ * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED 8
+ /* FDT_ERR_TRUNCATED: Structure block of the given device tree
+ * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC 9
+ /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+ * device tree at all - it is missing the flattened device
+ * tree magic number. */
+#define FDT_ERR_BADVERSION 10
+ /* FDT_ERR_BADVERSION: Given device tree has a version which
+ * can't be handled by the requested operation. For
+ * read-write functions, this may mean that fdt_open_into() is
+ * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE 11
+ /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+ * structure block or other serious error (e.g. misnested
+ * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT 12
+ /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+ * device tree has it's sub-blocks in an order that the
+ * function can't handle (memory reserve map, then structure,
+ * then strings). Use fdt_open_into() to reorganize the tree
+ * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL 13
+ /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+ * Should never be returned, if it is, it indicates a bug in
+ * libfdt itself. */
+
+/* Errors in device tree content */
+#define FDT_ERR_BADNCELLS 14
+ /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
+ * or similar property with a bad format or value */
+
+#define FDT_ERR_BADVALUE 15
+ /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
+ * value. For example: a property expected to contain a string list
+ * is not NUL-terminated within the length of its value. */
+
+#define FDT_ERR_BADOVERLAY 16
+ /* FDT_ERR_BADOVERLAY: The device tree overlay, while
+ * correctly structured, cannot be applied due to some
+ * unexpected or missing value, property or node. */
+
+#define FDT_ERR_NOPHANDLES 17
+ /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
+ * phandle available anymore without causing an overflow */
+
+#define FDT_ERR_MAX 17
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these) */
+/**********************************************************************/
+
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+#endif
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+ return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+ uint8_t *bp = (uint8_t *)property;
+
+ bp[0] = value >> 24;
+ bp[1] = (value >> 16) & 0xff;
+ bp[2] = (value >> 8) & 0xff;
+ bp[3] = value & 0xff;
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+ uint8_t *bp = (uint8_t *)property;
+
+ bp[0] = value >> 56;
+ bp[1] = (value >> 48) & 0xff;
+ bp[2] = (value >> 40) & 0xff;
+ bp[3] = (value >> 32) & 0xff;
+ bp[4] = (value >> 24) & 0xff;
+ bp[5] = (value >> 16) & 0xff;
+ bp[6] = (value >> 8) & 0xff;
+ bp[7] = value & 0xff;
+}
+
+/**********************************************************************/
+/* Traversal functions */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt: FDT blob
+ * @offset: Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt: FDT blob
+ * @offset: Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_subnode - iterate over all subnodes of a parent
+ *
+ * @node: child node (int, lvalue)
+ * @fdt: FDT blob (const void *)
+ * @parent: parent node (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ * fdt_for_each_subnode(node, fdt, parent) {
+ * Use node
+ * ...
+ * }
+ *
+ * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ * Error handling
+ * }
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable be constant or even a
+ * literal.
+ *
+ */
+#define fdt_for_each_subnode(node, fdt, parent) \
+ for (node = fdt_first_subnode(fdt, parent); \
+ node >= 0; \
+ node = fdt_next_subnode(fdt, node))
+
+/**********************************************************************/
+/* General functions */
+/**********************************************************************/
+#define fdt_get_header(fdt, field) \
+ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt) (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+ static inline void fdt_set_##name(void *fdt, uint32_t val) \
+ { \
+ struct fdt_header *fdth = (struct fdt_header *)fdt; \
+ fdth->name = cpu_to_fdt32(val); \
+ }
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ * 0, if the buffer appears to contain a valid device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize. The buffer may overlap
+ * with the existing device tree blob at fdt. Therefore,
+ * fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_get_max_phandle - retrieves the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ *
+ * fdt_get_max_phandle retrieves the highest phandle in the given
+ * device tree. This will ignore badly formatted phandles, or phandles
+ * with a value of 0 or -1.
+ *
+ * returns:
+ * the highest phandle on success
+ * 0, if no phandle was found in the device tree
+ * -1, if an error occurred
+ */
+uint32_t fdt_get_max_phandle(const void *fdt);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map. This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ * the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen);
+#endif
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset_namelen - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ * @namelen: number of characters of path to consider
+ *
+ * Identical to fdt_path_offset(), but only consider the first namelen
+ * characters of path as the path name.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+#endif
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on
+ * success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * If lenp is non-NULL, *lenp contains the length of that name
+ * (>=0)
+ * NULL, on error
+ * if lenp is non-NULL *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ * structure block offset of the property (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested node has no properties
+ * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset. This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ * structure block offset of the next property (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the given property is the last in its node
+ * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_property_offset - iterate over all properties of a node
+ *
+ * @property_offset: property offset (int, lvalue)
+ * @fdt: FDT blob (const void *)
+ * @node: node offset (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ * fdt_for_each_property_offset(property, fdt, node) {
+ * Use property
+ * ...
+ * }
+ *
+ * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ * Error handling
+ * }
+ *
+ * Note that this is implemented as a macro and property is used as
+ * iterator in the loop. The node variable can be constant or even a
+ * literal.
+ */
+#define fdt_for_each_property_offset(property, fdt, node) \
+ for (property = fdt_first_property_offset(fdt, node); \
+ property >= 0; \
+ property = fdt_next_property_offset(fdt, property))
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset. If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp);
+#endif
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset. If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+ const char *name,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @ffset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value). If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp. If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * if namep is non-NULL *namep contiains a pointer to the property
+ * name.
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+ const char **namep, int *lenp);
+#endif
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp);
+static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
+ const char *name, int namelen,
+ int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
+ namelen, lenp);
+}
+#endif
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ * the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ * 0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+#ifndef SWIG /* Not available in Python */
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen);
+#endif
+
+/**
+ * fdt_get_alias - retrieve the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias. That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ * a pointer to the expansion of the alias named 'name', if it exists
+ * NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * 0, on success
+ * buf contains the absolute path of the node at
+ * nodeoffset, as a NUL-terminated string.
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ * characters and will not fit in the given buffer.
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth). So
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node. If the node at
+ * nodeoffset has depth D, then:
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
+ * nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node. The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * depth of the node at nodeoffset (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ * structure block offset of the parent of the node at nodeoffset
+ * (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ * propval, proplen);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ * propval, proplen);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value. If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0), on success
+ * -FDT_ERR_NOTFOUND, no node with that phandle exists
+ * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ * 0, if the node has a 'compatible' property listing the given string
+ * 1, if the node has a 'compatible' property, but it does not list
+ * the given string
+ * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible);
+
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**
+ * fdt_stringlist_count - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @return:
+ * the number of strings in the given property
+ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ * -FDT_ERR_NOTFOUND if the property does not exist
+ */
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
+
+/**
+ * fdt_stringlist_search - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ *
+ * Note that it is possible for this function to succeed on property values
+ * that are not NUL-terminated. That's because the function will stop after
+ * finding the first occurrence of @string. This can for example happen with
+ * small-valued cell properties, such as #address-cells, when searching for
+ * the empty string.
+ *
+ * @return:
+ * the index of the string in the list of strings
+ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ * -FDT_ERR_NOTFOUND if the property does not exist or does not contain
+ * the given string
+ */
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+ const char *string);
+
+/**
+ * fdt_stringlist_get() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @lenp: return location for the string length or an error code on failure
+ *
+ * Note that this will successfully extract strings from properties with
+ * non-NUL-terminated values. For example on small-valued cell properties
+ * this function will return the empty string.
+ *
+ * If non-NULL, the length of the string (on success) or a negative error-code
+ * (on failure) will be stored in the integer pointer to by lenp.
+ *
+ * @return:
+ * A pointer to the string at the given index in the string list or NULL on
+ * failure. On success the length of the string will be stored in the memory
+ * location pointed to by the lenp parameter, if non-NULL. On failure one of
+ * the following negative error codes will be returned in the lenp parameter
+ * (if non-NULL):
+ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ * -FDT_ERR_NOTFOUND if the property does not exist
+ */
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+ const char *property, int index,
+ int *lenp);
+
+/**********************************************************************/
+/* Read-only functions (addressing related) */
+/**********************************************************************/
+
+/**
+ * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
+ *
+ * This is the maximum value for #address-cells, #size-cells and
+ * similar properties that will be processed by libfdt. IEE1275
+ * requires that OF implementations handle values up to 4.
+ * Implementations may support larger values, but in practice higher
+ * values aren't used.
+ */
+#define FDT_MAX_NCELLS 4
+
+/**
+ * fdt_address_cells - retrieve address size for a bus represented in the tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address size for
+ *
+ * When the node has a valid #address-cells property, returns its value.
+ *
+ * returns:
+ * 0 <= n < FDT_MAX_NCELLS, on success
+ * 2, if the node has no #address-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #address-cells property
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_address_cells(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_size_cells - retrieve address range size for a bus represented in the
+ * tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address range size for
+ *
+ * When the node has a valid #size-cells property, returns its value.
+ *
+ * returns:
+ * 0 <= n < FDT_MAX_NCELLS, on success
+ * 2, if the node has no #address-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #size-cells property
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_size_cells(const void *fdt, int nodeoffset);
+
+
+/**********************************************************************/
+/* Write-in-place functions */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace_namelen_partial - change a property's value,
+ * but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: number of characters of name to consider
+ * @idx: index of the property to change in the array
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * Identical to fdt_setprop_inplace(), but modifies the given property
+ * starting from the given index, and using only the first characters
+ * of the name. It is useful when you want to manipulate only one value of
+ * an array and you have a string that doesn't end with \0.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+ const char *name, int namelen,
+ uint32_t idx, const void *val,
+ int len);
+#endif
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len. This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+#endif
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary. This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary. This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+ const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_resize(void *fdt, void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ return fdt_property_u32(fdt, name, val);
+}
+#define fdt_property_string(fdt, name, str) \
+ fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new reservation entry
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ * are less than n+1 reserve map entries)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string. NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ * to contain the new name
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_u32 - set a property to a 32-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+ uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+
+/**
+ * fdt_setprop_empty - set a property to an empty value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ *
+ * fdt_setprop_empty() sets the value of the named property in the
+ * given node to an empty (zero length) value, or creates a new empty
+ * property if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_empty(fdt, nodeoffset, name) \
+ fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ fdt32_t tmp = cpu_to_fdt32(val);
+ return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+ const char *name, uint64_t val)
+{
+ fdt64_t tmp = cpu_to_fdt64(val);
+ return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string to the value of
+ * the named property in the given node, or creates a new property
+ * with that value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+ fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node. This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen);
+#endif
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on
+ * success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ * tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE
+ * -FDT_ERR_BADLAYOUT
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**
+ * fdt_overlay_apply - Applies a DT overlay on a base DT
+ * @fdt: pointer to the base device tree blob
+ * @fdto: pointer to the device tree overlay blob
+ *
+ * fdt_overlay_apply() will apply the given device tree overlay on the
+ * given base device tree.
+ *
+ * Expect the base device tree to be modified, even if the function
+ * returns an error.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there's not enough space in the base device tree
+ * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
+ * properties in the base DT
+ * -FDT_ERR_BADPHANDLE,
+ * -FDT_ERR_BADOVERLAY,
+ * -FDT_ERR_NOPHANDLES,
+ * -FDT_ERR_INTERNAL,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADOFFSET,
+ * -FDT_ERR_BADPATH,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_overlay_apply(void *fdt, void *fdto);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/components/drivers/fdt/libfdt/libfdt_env.h b/components/drivers/fdt/libfdt/libfdt_env.h
new file mode 100644
index 0000000000..f4a6b6063b
--- /dev/null
+++ b/components/drivers/fdt/libfdt/libfdt_env.h
@@ -0,0 +1,113 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __CHECKER__
+#define FDT_FORCE __attribute__((force))
+#define FDT_BITWISE __attribute__((bitwise))
+#else
+#define FDT_FORCE
+#define FDT_BITWISE
+#endif
+
+typedef uint16_t FDT_BITWISE fdt16_t;
+typedef uint32_t FDT_BITWISE fdt32_t;
+typedef uint64_t FDT_BITWISE fdt64_t;
+typedef uint64_t unaligned_fdt64_t __attribute__((aligned(4)));
+
+#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
+ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
+ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
+ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
+ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+static inline uint16_t fdt16_to_cpu(fdt16_t x)
+{
+ return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
+}
+static inline fdt16_t cpu_to_fdt16(uint16_t x)
+{
+ return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
+}
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+ return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
+}
+static inline fdt32_t cpu_to_fdt32(uint32_t x)
+{
+ return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+ return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
+}
+static inline fdt64_t cpu_to_fdt64(uint64_t x)
+{
+ return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
+}
+#undef CPU_TO_FDT64
+#undef CPU_TO_FDT32
+#undef CPU_TO_FDT16
+#undef EXTRACT_BYTE
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/components/drivers/fdt/libfdt/libfdt_internal.h b/components/drivers/fdt/libfdt/libfdt_internal.h
new file mode 100644
index 0000000000..5cb817b365
--- /dev/null
+++ b/components/drivers/fdt/libfdt/libfdt_internal.h
@@ -0,0 +1,95 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "fdt.h"
+
+#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+ { \
+ int __err; \
+ if ((__err = fdt_check_header(fdt)) != 0) \
+ return __err; \
+ }
+
+int _fdt_check_node_offset(const void *fdt, int offset);
+int _fdt_check_prop_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+ return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+ const struct fdt_reserve_entry *rsv_table =
+ (const struct fdt_reserve_entry *)
+ ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+ return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+ return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC (~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/components/drivers/fdt/src/SConscript b/components/drivers/fdt/src/SConscript
new file mode 100644
index 0000000000..74ae118929
--- /dev/null
+++ b/components/drivers/fdt/src/SConscript
@@ -0,0 +1,17 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+list = os.listdir(cwd)
+CPPPATH = [cwd + '/../inc' , cwd + '/libfdt']
+objs = []
+
+group = DefineGroup('FDT', src, depend = ['RT_USING_FDT'], CPPPATH = CPPPATH)
+
+for d in list:
+ path = os.path.join(cwd, d)
+ if os.path.isfile(os.path.join(path, 'SConscript')):
+ objs = objs + SConscript(os.path.join(d, 'SConscript'))
+objs = objs + group
+
+Return('objs') \ No newline at end of file
diff --git a/components/drivers/fdt/src/dtb_access.c b/components/drivers/fdt/src/dtb_access.c
new file mode 100644
index 0000000000..71de2989db
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_access.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#define _GNU_SOURCE
+
+#include "libfdt.h"
+#include "dtb_node.h"
+
+/* "/aliaes" node */
+static struct dtb_node *fdt_aliases;
+
+/**
+ * of_find_property_value_of_size() - find property of given size
+ *
+ * Search for a property in a device node and validate the requested size.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @len: requested length of property value
+ *
+ * @return the property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ */
+static void *dtb_node_find_property_value_of_size(const struct dtb_node *dn,
+ const char *propname, uint32_t len)
+{
+ struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
+
+ if (!prop)
+ return ERR_PTR(-EINVAL);
+ if (!prop->value)
+ return ERR_PTR(-ENODATA);
+ if (len > prop->size)
+ return ERR_PTR(-EOVERFLOW);
+ return prop->value;
+}
+
+int dtb_node_read_u32(const struct dtb_node *dn, const char *propname, uint32_t *outp)
+{
+ const uint32_t *val;
+
+ debug("%s: %s: \n", __func__, propname);
+ if (!dn)
+ return -EINVAL;
+ val = dtb_node_find_property_value_of_size(dn, propname, sizeof(*outp));
+ if (IS_ERR(val))
+ {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = fdt32_to_cpu(*val);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+uint32_t dtb_node_read_u32_default(const struct dtb_node *node, const char *propname, uint32_t def)
+{
+ dtb_node_read_u32(node, propname, &def);
+
+ return def;
+}
+
+int dtb_node_read_u32_array(const struct dtb_node *dn, const char *propname,
+ uint32_t *out_values, size_t sz)
+{
+ const uint32_t *val;
+
+ debug("%s: %s: ", __func__, propname);
+ val = dtb_node_find_property_value_of_size(dn, propname,
+ sz * sizeof(*out_values));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ debug("size %zd, val:%d\n", sz, *val);
+ while (sz--)
+ *out_values++ = fdt32_to_cpu(*val++);
+
+ return 0;
+}
+
+uint32_t dtb_node_read_u32_index_default(const struct dtb_node *node, const char *propname, int index,
+ uint32_t def)
+{
+ RT_ASSERT(dtb_node_valid(node));
+ dtb_node_read_u32_index(node, propname, index, &def);
+
+ return def;
+}
+
+int dtb_node_read_s32_default(const struct dtb_node *node, const char *propname, int32_t def)
+{
+ RT_ASSERT(dtb_node_valid(node));
+ dtb_node_read_u32(node, propname, (uint32_t *)&def);
+
+ return def;
+}
+
+int dtb_node_read_u32_index(const struct dtb_node *dn, const char *propname,
+ int index, uint32_t *outp)
+{
+ const uint32_t *val;
+
+ debug("%s: %s: ", __func__, propname);
+ if (!dn)
+ return -EINVAL;
+
+ val = dtb_node_find_property_value_of_size(dn, propname,
+ sizeof(*outp) * (index + 1));
+ if (IS_ERR(val))
+ {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = fdt32_to_cpu(val[index]);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+int dtb_node_read_u64(const struct dtb_node *dn, const char *propname, uint64_t *outp)
+{
+ const uint64_t *val;
+
+ debug("%s: %s: ", __func__, propname);
+ if (!dn)
+ return -EINVAL;
+ val = dtb_node_find_property_value_of_size(dn, propname, sizeof(*outp));
+ if (IS_ERR(val))
+ {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = fdt64_to_cpu(*val);
+ debug("%#llx (%lld)\n", (unsigned long long)*outp,
+ (unsigned long long)*outp);
+
+ return 0;
+}
+
+uint64_t dtb_node_read_u64_default(const struct dtb_node *node, const char *propname, uint64_t def)
+{
+ RT_ASSERT(dtb_node_valid(node));
+ dtb_node_read_u64(node, propname, &def);
+
+ return def;
+}
+
+int dtb_node_n_addr_cells(const struct dtb_node *dn)
+{
+ const uint32_t *ip;
+
+ do
+ {
+ if (dn->parent)
+ dn = dn->parent;
+ ip = dtb_node_get_dtb_node_property_value(dn, "#address-cells", NULL);
+ if (ip)
+ return fdt32_to_cpu(*ip);
+ } while (dn->parent);
+
+ /* No #address-cells property for the root node */
+ return DEV_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+
+int dtb_node_n_size_cells(const struct dtb_node *dn)
+{
+ const uint32_t *ip;
+
+ do
+ {
+ if (dn->parent)
+ dn = dn->parent;
+ ip = dtb_node_get_dtb_node_property_value(dn, "#size-cells", NULL);
+ if (ip)
+ return fdt32_to_cpu(*ip);
+ } while (dn->parent);
+
+ /* No #size-cells property for the root node */
+ return DEV_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+
+int dtb_node_simple_addr_cells(const struct dtb_node *dn)
+{
+ const uint32_t *ip;
+
+ ip = dtb_node_get_dtb_node_property_value(dn, "#address-cells", NULL);
+ if (ip)
+ return fdt32_to_cpu(*ip);
+
+ /* Return a default of 2 to match fdt_address_cells()*/
+ return 2;
+}
+
+int dtb_node_simple_size_cells(const struct dtb_node *dn)
+{
+ const uint32_t *ip;
+
+ ip = dtb_node_get_dtb_node_property_value(dn, "#size-cells", NULL);
+ if (ip)
+ return fdt32_to_cpu(*ip);
+
+ /* Return a default of 2 to match fdt_size_cells()*/
+ return 2;
+}
+
+struct dtb_property *dtb_node_get_dtb_node_property(const struct dtb_node *dtb_node, const char *property_name, int *property_size)
+{
+ struct dtb_property *dtb_property = NULL;
+
+ if (dtb_node != NULL && property_name != NULL)
+ {
+ dtb_property = dtb_node->properties;
+
+ while (dtb_property != NULL)
+ {
+ if (!strcmp(dtb_property->name, property_name))
+ {
+ if (property_size != NULL)
+ {
+ *property_size = dtb_property->size;
+ }
+ return dtb_property;
+ }
+ dtb_property = dtb_property->next;
+ }
+ }
+
+ return dtb_property;
+}
+
+#define for_each_property_of_node(dn, pp) \
+ for (pp = dn->properties; pp != NULL; pp = pp->next)
+
+struct dtb_node *dtb_node_find_node_opts_by_path(const char *path,
+ const char **opts)
+{
+ struct dtb_node *np = NULL;
+ struct dtb_property *pp;
+ const char *separator = strchr(path, ':');
+
+ if (opts)
+ *opts = separator ? separator + 1 : NULL;
+
+ if (strcmp(path, "/") == 0)
+ return dtb_node_get(get_dtb_node_head());
+
+ /* The path could begin with an alias */
+ if (*path != '/')
+ {
+ int len;
+ const char *p = separator;
+
+ if (!p)
+ p = strchrnul(path, '/');
+ len = p - path;
+
+ /* of_aliases must not be NULL */
+ if (!fdt_aliases)
+ return NULL;
+
+ for_each_property_of_node(fdt_aliases, pp)
+ {
+ if (strlen(pp->name) == len && !strncmp(pp->name, path,
+ len))
+ {
+ np = dtb_node_find_node_by_path(pp->value);
+ break;
+ }
+ }
+ if (!np)
+ return NULL;
+ path = p;
+ }
+
+ /* Step down the tree matching path components */
+ if (!np)
+ np = dtb_node_get(get_dtb_node_head());
+ while (np && *path == '/')
+ {
+ struct dtb_node *tmp = np;
+
+ path++; /* Increment past '/' delimiter */
+ np = dtb_node_get_dtb_node_by_path(np, path);
+ dtb_node_put(tmp);
+ path = strchrnul(path, '/');
+ if (separator && separator < path)
+ break;
+ }
+
+ return np;
+}
+
+struct dtb_node *dtb_node_find_compatible_node(struct dtb_node *from, const char *compatible)
+{
+ struct dtb_node *dn;
+
+ for_each_of_allnodes_from(from, dn)
+ {
+ if (dtb_node_get_dtb_node_compatible_match(dn, compatible) &&
+ dtb_node_get(dn))
+ break;
+ }
+ dtb_node_put(from);
+
+ return dn;
+}
+
+void *dtb_node_get_dtb_node_property_value(const struct dtb_node *dtb_node, const char *property_name, int *property_size)
+{
+ struct dtb_property *dtb_property = dtb_node_get_dtb_node_property(dtb_node, property_name, NULL);
+
+ if (!dtb_property || !dtb_property->value || !dtb_property->size)
+ {
+ return NULL;
+ }
+
+ if (property_size != NULL)
+ {
+ *property_size = dtb_property->size;
+ }
+
+ return dtb_property->value;
+}
+
+const struct dtb_node *dtb_node_find_node_by_prop_value(struct dtb_node *from,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ struct dtb_node *np;
+ void *value;
+ for_each_of_allnodes_from(from, np)
+ {
+ value = dtb_node_get_dtb_node_property_value(np, propname, &proplen);
+ if (!memcmp(value, propval, proplen) && dtb_node_get(np))
+ break;
+ }
+ dtb_node_put(from);
+
+ return np;
+}
+
+struct dtb_node *dtb_node_find_all_nodes(const struct dtb_node *prev)
+{
+ const struct dtb_node *dn;
+
+ if (!prev)
+ {
+ dn = get_dtb_node_head();
+ }
+ else if (prev->child)
+ {
+ dn = prev->child;
+ }
+ else
+ {
+ /*
+ * Walk back up looking for a sibling, or the end of the
+ * structure
+ */
+ dn = prev;
+ while (dn->parent && !dn->sibling)
+ dn = dn->parent;
+ dn = dn->sibling; /* Might be null at the end of the tree */
+ }
+
+ return (struct dtb_node *)dn;
+}
+
+rt_bool_t dtb_node_device_is_available(const struct dtb_node *device)
+{
+ const char *status;
+ int statlen;
+
+ if (!device)
+ return RT_FALSE;
+
+ status = dtb_node_get_dtb_node_property_value(device, "status", &statlen);
+ if (status == NULL)
+ return RT_TRUE;
+
+ if (statlen > 0)
+ {
+ if (!strcmp(status, "okay"))
+ return RT_TRUE;
+ }
+
+ return RT_FALSE;
+}
+
+struct dtb_node *dtb_node_get_parent(const struct dtb_node *node)
+{
+ const struct dtb_node *dn;
+
+ if (!node)
+ return NULL;
+
+ dn = dtb_node_get(node->parent);
+
+ return (struct dtb_node *)dn;
+}
+
+struct dtb_node *dtb_node_find_node_by_phandle(phandle handle)
+{
+ struct dtb_node *dn;
+
+ if (!handle)
+ return NULL;
+
+ for_each_of_allnodes(dn) if (dn->handle == handle) break;
+ (void)dtb_node_get(dn);
+
+ return dn;
+}
+
+int dtb_node_property_match_string(const struct dtb_node *dn, const char *propname,
+ const char *string)
+{
+ const struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
+ size_t l;
+ int i;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ p = prop->value;
+ end = p + prop->size;
+
+ for (i = 0; p < end; i++, p += l)
+ {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ debug("comparing %s with %s\n", string, p);
+ if (strcmp(string, p) == 0)
+ return i; /* Found it; return index */
+ }
+ return -ENODATA;
+}
+
+/**
+ * of_property_read_string_helper() - Utility helper for parsing string properties
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ * @skip: Number of strings to skip over at beginning of list.
+ *
+ * Don't call this function directly. It is a utility helper for the
+ * of_property_read_string*() family of functions.
+ */
+int dtb_node_property_read_string_helper(const struct dtb_node *dn,
+ const char *propname, const char **out_strs,
+ size_t sz, int skip)
+{
+ const struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
+ int l = 0, i = 0;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ p = prop->value;
+ end = p + prop->size;
+
+ for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l)
+ {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ if (out_strs && i >= skip)
+ *out_strs++ = p;
+ }
+ i -= skip;
+ return i <= 0 ? -ENODATA : i;
+}
+
+static int __dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count, int index,
+ struct fdt_phandle_args *out_args)
+{
+ const uint32_t *list, *list_end;
+ int rc = 0, cur_index = 0;
+ uint32_t count = 0;
+ struct dtb_node *node = NULL;
+ phandle phandle;
+ int size;
+
+ /* Retrieve the phandle list property */
+ list = dtb_node_get_dtb_node_property_value(dn, list_name, &size);
+ if (!list)
+ return -ENOENT;
+ list_end = list + size / sizeof(*list);
+
+ /* Loop over the phandles until all the requested entry is found */
+ while (list < list_end)
+ {
+ rc = -EINVAL;
+ count = 0;
+
+ /*
+ * If phandle is 0, then it is an empty entry with no
+ * arguments. Skip forward to the next entry.
+ */
+ phandle = fdt32_to_cpu(*(list++));
+ if (phandle)
+ {
+ /*
+ * Find the provider node and parse the #*-cells
+ * property to determine the argument length.
+ *
+ * This is not needed if the cell count is hard-coded
+ * (i.e. cells_name not set, but cell_count is set),
+ * except when we're going to return the found node
+ * below.
+ */
+ if (cells_name || cur_index == index)
+ {
+ node = dtb_node_find_node_by_phandle(phandle);
+ if (!node)
+ {
+ debug("%s: could not find phandle\n",
+ dn->path);
+ goto err;
+ }
+ }
+
+ if (cells_name)
+ {
+ if (dtb_node_read_u32(node, cells_name, &count))
+ {
+ debug("%s: could not get %s for %s\n",
+ dn->path, cells_name,
+ node->path);
+ goto err;
+ }
+ }
+ else
+ {
+ count = cell_count;
+ }
+
+ /*
+ * Make sure that the arguments actually fit in the
+ * remaining property data length
+ */
+ if (list + count > list_end)
+ {
+ debug("%s: arguments longer than property\n",
+ dn->path);
+ goto err;
+ }
+ }
+
+ /*
+ * All of the error cases above bail out of the loop, so at
+ * this point, the parsing is successful. If the requested
+ * index matches, then fill the out_args structure and return,
+ * or return -ENOENT for an empty entry.
+ */
+ rc = -ENOENT;
+ if (cur_index == index)
+ {
+ if (!phandle)
+ goto err;
+
+ if (out_args)
+ {
+ int i;
+ if (count > FDT_MAX_PHANDLE_ARGS)
+ count = FDT_MAX_PHANDLE_ARGS;
+ out_args->np = node;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++)
+ out_args->args[i] =
+ fdt32_to_cpu(*(list++));
+ }
+ else
+ {
+ dtb_node_put(node);
+ }
+
+ /* Found it! return success */
+ return 0;
+ }
+
+ dtb_node_put(node);
+ node = NULL;
+ list += count;
+ cur_index++;
+ }
+
+ /*
+ * Unlock node before returning result; will be one of:
+ * -ENOENT : index is for empty phandle
+ * -EINVAL : parsing error on data
+ * [1..n] : Number of phandle (count mode; when index = -1)
+ */
+ rc = index < 0 ? cur_index : -ENOENT;
+err:
+ if (node)
+ dtb_node_put(node);
+ return rc;
+}
+
+struct dtb_node *dtb_node_parse_phandle(const struct dtb_node *dn,
+ const char *phandle_name, int index)
+{
+ struct fdt_phandle_args args;
+
+ if (index < 0)
+ return NULL;
+
+ if (__dtb_node_parse_phandle_with_args(dn, phandle_name, NULL, 0, index,
+ &args))
+ return NULL;
+
+ return args.np;
+}
+
+int dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
+ const char *list_name, const char *cells_name,
+ int index, struct fdt_phandle_args *out_args)
+{
+ if (index < 0)
+ return -EINVAL;
+
+ return __dtb_node_parse_phandle_with_args(dn, list_name, cells_name, 0,
+ index, out_args);
+}
+
+int dtb_node_count_phandle_with_args(const struct dtb_node *dn,
+ const char *list_name, const char *cells_name)
+{
+ return __dtb_node_parse_phandle_with_args(dn, list_name, cells_name, 0,
+ -1, NULL);
+}
diff --git a/components/drivers/fdt/src/dtb_addr.c b/components/drivers/fdt/src/dtb_addr.c
new file mode 100644
index 0000000000..e4a296ea7f
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_addr.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include "dtb_node.h"
+
+/* Max address size we deal with */
+#define FDT_MAX_ADDR_CELLS 4
+#define FDT_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= FDT_MAX_ADDR_CELLS)
+#define FDT_CHECK_COUNTS(na, ns) (FDT_CHECK_ADDR_COUNT(na) && (ns) > 0)
+
+static void dtb_node_default_count_cells(const struct dtb_node *dn,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = dtb_node_n_addr_cells(dn);
+ if (sizec)
+ *sizec = dtb_node_n_size_cells(dn);
+}
+
+const uint32_t *dtb_node_get_address(const struct dtb_node *dev, int index,
+ uint64_t *size, unsigned int *flags)
+{
+ const uint32_t *prop;
+ int psize;
+ struct dtb_node *parent;
+ int onesize, i, na, ns;
+
+ /* Get parent */
+ parent = dtb_node_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+
+ dtb_node_default_count_cells(dev, &na, &ns);
+ if (!FDT_CHECK_ADDR_COUNT(na))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = dtb_node_get_dtb_node_property_value(dev, "reg", &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if (i == index)
+ {
+ if (size)
+ *size = dtb_node_read_number(prop + na, ns);
+ if (flags)
+ *flags = 0x200;
+ return prop;
+ }
+ return NULL;
+} \ No newline at end of file
diff --git a/components/drivers/fdt/src/dtb_base.c b/components/drivers/fdt/src/dtb_base.c
new file mode 100644
index 0000000000..d89e5dad9e
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_base.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "dtb_node.h"
+#include "libfdt.h"
+#include "libfdt_env.h"
+#include <ctype.h>
+
+static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
+{
+ if (*base == 0)
+ {
+ if (s[0] == '0')
+ {
+ if (tolower(s[1]) == 'x' && isxdigit(s[2]))
+ *base = 16;
+ else
+ *base = 8;
+ }
+ else
+ *base = 10;
+ }
+ if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
+ s += 2;
+ return s;
+}
+
+unsigned long simple_strtoul(const char *cp, char **endp,
+ unsigned int base)
+{
+ unsigned long result = 0;
+ unsigned long value;
+
+ cp = _parse_integer_fixup_radix(cp, &base);
+
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base)
+ {
+ result = result*base + value;
+ cp++;
+ }
+
+ if (endp)
+ *endp = (char *)cp;
+
+ return result;
+}
+
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
+{
+ char *tail;
+ unsigned long val;
+ size_t len;
+
+ *res = 0;
+ len = strlen(cp);
+ if (len == 0)
+ return -EINVAL;
+
+ val = simple_strtoul(cp, &tail, base);
+ if (tail == cp)
+ return -EINVAL;
+
+ if ((*tail == '\0') ||
+ ((len == (size_t)(tail - cp) + 1) && (*tail == '\n')))
+ {
+ *res = val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+ if (*cp == '-')
+ return -simple_strtoul(cp + 1, endp, base);
+
+ return simple_strtoul(cp, endp, base);
+}
+
+rt_bool_t dtb_node_read_bool(const struct dtb_node *node, const char *propname)
+{
+ const void *prop;
+
+ RT_ASSERT(dtb_node_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ prop = dtb_node_get_property(node, propname, NULL);
+
+ debug("%s\n", prop ? "true" : "false");
+
+ return prop ? RT_TRUE : RT_FALSE;
+}
+
+const void *dtb_node_read_prop(const struct dtb_node *node, const char *propname, int *sizep)
+{
+ const char *val = NULL;
+ int len;
+
+ RT_ASSERT(dtb_node_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ struct dtb_property *prop = dtb_node_get_dtb_node_property(node, propname, &len);
+
+ if (prop)
+ {
+ val = prop->value;
+ len = prop->size;
+ }
+
+ if (!val)
+ {
+ debug("<not found>\n");
+ if (sizep)
+ *sizep = -FDT_ERR_NOTFOUND;
+ return NULL;
+ }
+ if (sizep)
+ *sizep = len;
+
+ return val;
+}
+
+const char *dtb_node_read_string(const struct dtb_node *node, const char *propname)
+{
+ const char *str;
+ int len;
+
+ str = dtb_node_read_prop(node, propname, &len);
+ if (!str)
+ return NULL;
+
+ if (strnlen(str, len) >= len)
+ {
+ debug("<invalid>\n");
+ return NULL;
+ }
+ debug("%s\n", str);
+
+ return str;
+}
+
+const struct dtb_node *dtb_node_find_subnode(const struct dtb_node *node, const char *subnode_name)
+{
+ const struct dtb_node *subnode;
+
+ RT_ASSERT(dtb_node_valid(node));
+ debug("%s: %s: ", __func__, subnode_name);
+
+ for (node = node->child; node; node = node->sibling)
+ {
+ if (!strcmp(subnode_name, node->name))
+ break;
+ }
+ subnode = node;
+
+ debug("%s\n", dtb_node_valid(subnode) ?\
+ dtb_node_get_name(subnode) : "<none>");
+
+ return subnode;
+}
+
+struct dtb_node *dtb_node_first_subnode(const struct dtb_node *node)
+{
+ RT_ASSERT(dtb_node_valid(node));
+
+ return node->child;
+}
+
+struct dtb_node *dtb_node_next_subnode(const struct dtb_node *node)
+{
+ RT_ASSERT(dtb_node_valid(node));
+
+ return node->sibling;
+}
+
+const char *dtb_node_get_name(const struct dtb_node *node)
+{
+ if (!dtb_node_valid(node))
+ {
+ debug("%s node not valid\n", __func__);
+ return NULL;
+ }
+
+ return strrchr(node->path, '/') + 1;
+
+}
+
+struct dtb_node *dtb_node_get_by_phandle(uint phandle)
+{
+ if (dtb_node_active())
+ return dtb_node_find_node_by_phandle(phandle);
+ return NULL;
+}
+
+int dtb_node_read_size(const struct dtb_node *node, const char *propname)
+{
+ struct dtb_property *prop = dtb_node_get_dtb_node_property( node, propname, NULL);
+
+ if (prop)
+ return prop->size;
+
+ return -EINVAL;
+}
+
+size_t dtb_node_get_addr_index(const struct dtb_node *node, int index)
+{
+ int na;
+ size_t size;
+
+ const uint32_t *prop_val;
+ uint flags;
+
+ prop_val = dtb_node_get_address(node, index,
+ (uint64_t *)&size, &flags);
+ if (!prop_val)
+ return -1;
+
+ na = dtb_node_n_addr_cells(node);
+
+ return dtb_node_read_number(prop_val, na);
+}
+
+size_t dtb_node_get_addr(const struct dtb_node *node)
+{
+ return dtb_node_get_addr_index(node, 0);
+}
+
+int dtb_node_stringlist_search(const struct dtb_node *node, const char *property,
+ const char *string)
+{
+ return dtb_node_property_match_string(node, property, string);
+}
+
+int dtb_node_read_string_index(const struct dtb_node *node, const char *property, int index,
+ const char **outp)
+{
+ return dtb_node_property_read_string_index(node, property, index, outp);
+}
+
+int dtb_node_read_string_count(const struct dtb_node *node, const char *property)
+{
+ return dtb_node_property_count_strings(node, property);
+}
+
+struct dtb_node *dtb_node_path(const char *path)
+{
+ if (dtb_node_active())
+ return dtb_node_find_node_by_path(path);
+ return NULL;
+}
+
+const char *dtb_node_get_chosen_prop(const char *name)
+{
+ const struct dtb_node *chosen_node;
+
+ chosen_node = (const struct dtb_node *)dtb_node_path("/chosen");
+
+ return dtb_node_read_string(chosen_node, name);
+}
+
+struct dtb_node *dtb_node_get_chosen_node(const char *name)
+{
+ const char *prop;
+
+ prop = dtb_node_get_chosen_prop(name);
+ if (!prop)
+ return NULL;
+
+ return dtb_node_path(prop);
+}
+
+const void *dtb_node_get_property(const struct dtb_node *node, const char *propname, int *lenp)
+{
+ return dtb_node_get_dtb_node_property_value(node, propname, lenp);
+}
+
+rt_bool_t dtb_node_is_available(const struct dtb_node *node)
+{
+ return dtb_node_device_is_available(node);
+}
+
+size_t dtb_node_get_addr_size(const struct dtb_node *node, const char *property,
+ size_t *sizep)
+{
+ int na, ns;
+ int psize;
+ const uint32_t *prop = dtb_node_get_dtb_node_property_value(node, property, &psize);
+
+ if (!prop)
+ return -1;
+ na = dtb_node_n_addr_cells(node);
+ ns = dtb_node_n_size_cells(node);
+ *sizep = dtb_node_read_number(prop + na, ns);
+
+ return dtb_node_read_number(prop, na);
+}
+
+const uint8_t *dtb_node_read_u8_array_ptr(const struct dtb_node *node, const char *propname,
+ size_t sz)
+{
+ int psize;
+ const uint32_t *prop = dtb_node_get_dtb_node_property_value(node, propname, &psize);
+
+ if (!prop || sz != psize)
+ return NULL;
+ return (uint8_t *)prop;
+}
+
+int dtb_node_find_all_compatible_node(const struct dtb_node *from, const char *compatible, struct dtb_node **node_table, int max_num, int *node_num)
+{
+ const struct dtb_node *dn;
+ int num = 0;
+ for_each_of_allnodes_from(from, dn)
+ {
+ if (dtb_node_get_dtb_node_compatible_match(dn, compatible) &&
+ dtb_node_get(dn))
+ {
+
+ num++;
+ *node_table = (struct dtb_node *)dn;
+ node_table++;
+ if (num >= max_num)
+ {
+ break;
+ }
+ }
+ }
+ *node_num = num;
+ dtb_node_put(from);
+
+ return 0;
+}
+
+int dtb_node_write_prop(const struct dtb_node *node, const char *propname, int len,
+ const void *value)
+{
+ struct dtb_property *pp;
+ struct dtb_property *pp_last = NULL;
+ struct dtb_property *new;
+
+ if (!dtb_node_active())
+ return -ENOSYS;
+
+ if (!node)
+ return -EINVAL;
+
+ for (pp = node->properties; pp; pp = pp->next)
+ {
+ if (strcmp(pp->name, propname) == 0)
+ {
+ /* Property exists -> change value */
+ pp->value = (void *)value;
+ pp->size = len;
+ return 0;
+ }
+ pp_last = pp;
+ }
+
+ if (!pp_last)
+ return -ENOENT;
+
+ /* Property does not exist -> append new property */
+ new = malloc(sizeof(struct dtb_property));
+ if (!new)
+ return -ENOMEM;
+
+ new->name = strdup(propname);
+ if (!new->name)
+ {
+ free(new);
+ return -ENOMEM;
+ }
+
+ new->value = (void *)value;
+ new->size = len;
+ new->next = NULL;
+
+ pp_last->next = new;
+
+ return 0;
+}
+
+int dtb_node_write_string(const struct dtb_node *node, const char *propname, const char *value)
+{
+ if (!dtb_node_active())
+ return -ENOSYS;
+
+ RT_ASSERT(dtb_node_valid(node));
+
+ debug("%s: %s = %s", __func__, propname, value);
+
+ return dtb_node_write_prop(node, propname, strlen(value) + 1, value);
+}
+
+int dtb_node_set_enabled(const struct dtb_node *node, rt_bool_t value)
+{
+ if (!dtb_node_active())
+ return -ENOSYS;
+
+ RT_ASSERT(dtb_node_valid(node));
+
+ if (value)
+ return dtb_node_write_string(node, "status", "okay");
+ else
+ return dtb_node_write_string(node, "status", "disable");
+}
+
+/**
+ * dtb_node_irq_find_parent - Given a device node, find its interrupt parent node
+ * @child: pointer to device node
+ *
+ * Returns a pointer to the interrupt parent node, or NULL if the interrupt
+ * parent could not be determined.
+ */
+static struct dtb_node *dtb_node_irq_find_parent(struct dtb_node *child)
+{
+ struct dtb_node *p;
+ phandle parent;
+
+ if (!dtb_node_get(child))
+ return NULL;
+ do
+ {
+ if (dtb_node_read_u32_array(child, "interrupt-parent", &parent, 1))
+ {
+ p = dtb_node_get_parent(child);
+ }
+ else
+ {
+ p = dtb_node_get_by_phandle(parent);
+ }
+ dtb_node_put(child);
+ child = p;
+ } while (p && dtb_node_get_property(p, "#interrupt-cells", NULL) == NULL);
+
+ return p;
+}
+
+int dtb_node_irq_get(struct dtb_node *dev, int index)
+{
+ int rc = 0;
+ struct fdt_phandle_args out_irq;
+ struct dtb_node *p;
+ uint32_t intsize;
+ int res, i;
+
+ p = dtb_node_irq_find_parent(dev);
+ if (p == NULL)
+ return -EINVAL;
+ /* Get size of interrupt specifier */
+ if (dtb_node_read_u32_array(p, "#interrupt-cells", &intsize, 1))
+ {
+ res = -EINVAL;
+ goto out;
+ }
+
+ debug(" path:%s, parent=%pOF, intsize=%d\n", p->path,p, intsize);
+
+ /* Copy intspec into irq structure */
+ out_irq.np = p;
+ out_irq.args_count = intsize;
+ for (i = 0; i < intsize; i++)
+ {
+ res = dtb_node_read_u32_index(dev, "interrupts",
+ (index * 3 + i),
+ out_irq.args + i);
+ if (res)
+ goto out;
+ }
+ rc = out_irq.args[1];
+ out:
+ dtb_node_put(p);
+ return rc;
+
+}
+
+/**
+ * dtb_node_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
+ * @dev: pointer to device tree node
+ * @name: IRQ name
+ *
+ * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
+ * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
+ * of any other failure.
+ */
+int dtb_node_irq_get_byname(struct dtb_node *dev, const char *name)
+{
+ int index;
+
+ if (!name)
+ return -EINVAL;
+
+ index = dtb_node_stringlist_search(dev, "interrupt-names", name);
+ if (index < 0)
+ return index;
+
+ return dtb_node_irq_get(dev, index);
+}
+
+/**
+ * dtb_node_irq_count - Count the number of IRQs a node uses
+ * @dev: pointer to device tree node
+ */
+int dtb_node_irq_count(struct dtb_node *device)
+{
+ struct dtb_node *p;
+ uint32_t intsize;
+ int nr = 0, res = 0;
+
+ p = dtb_node_irq_find_parent(device);
+ if (p == NULL)
+ return -EINVAL;
+
+ /* Get size of interrupt specifier */
+ if (dtb_node_read_u32_array(p, "#interrupt-cells", &intsize, 1))
+ {
+ res = -EINVAL;
+ goto out;
+ }
+
+ debug(" path:%s, parent=%pOF, intsize=%d\n", p->path,p, intsize);
+
+ res = dtb_node_read_size(device, "interrupts");
+ if (res < 0)
+ {
+ goto out;
+ }
+ nr = res / (intsize * 4);
+ out:
+ dtb_node_put(p);
+
+ return nr;
+} \ No newline at end of file
diff --git a/components/drivers/fdt/src/dtb_get.c b/components/drivers/fdt/src/dtb_get.c
new file mode 100644
index 0000000000..df1b5f9341
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_get.c
@@ -0,0 +1,817 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include "dtb_node.h"
+
+static struct
+{
+ const char *ptr;
+ const char *end;
+ char *cur;
+} paths_buf = {NULL, NULL};
+static void *current_fdt;
+
+int fdt_exec_status = FDT_RET_GET_OK;
+
+int dtb_node_get_exec_status()
+{
+ return fdt_exec_status;
+}
+
+static int _dtb_node_get_dtb_properties_list(struct dtb_property *dtb_property, off_t node_off)
+{
+ /* caller alrealy checked current_fdt */
+ off_t property_off = fdt_first_property_offset(current_fdt, node_off);
+ struct fdt_property *fdt_property;
+
+ if (property_off < 0)
+ {
+ return FDT_RET_GET_EMPTY;
+ }
+
+ for (;;)
+ {
+ fdt_property = (struct fdt_property *)fdt_get_property_by_offset(current_fdt, property_off, &dtb_property->size);
+ if (fdt_property != NULL)
+ {
+ dtb_property->name = fdt_string(current_fdt, fdt32_to_cpu(fdt_property->nameoff));
+ dtb_property->value = fdt_property->data;
+ dtb_property->size = fdt32_to_cpu(fdt_property->len);
+ }
+
+ property_off = fdt_next_property_offset(current_fdt, property_off);
+ if (property_off >= 0)
+ {
+ dtb_property->next = (struct dtb_property *)malloc(sizeof(struct dtb_property));
+ if (dtb_property->next == NULL)
+ {
+ return FDT_RET_NO_MEMORY;
+ }
+ dtb_property = dtb_property->next;
+ }
+ else
+ {
+ dtb_property->next = NULL;
+ break;
+ }
+ }
+
+ return FDT_RET_GET_OK;
+}
+
+static int _dtb_node_get_dtb_nodes_list(struct dtb_node *dtb_node_head, struct dtb_node *dtb_node, const char *pathname)
+{
+ off_t root_off;
+ off_t node_off;
+ int pathname_sz;
+ int node_name_sz;
+
+ /* caller alrealy checked current_fdt */
+ if ((root_off = fdt_path_offset(current_fdt, pathname)) >= 0)
+ {
+ pathname_sz = strlen(pathname);
+ node_off = fdt_first_subnode(current_fdt, root_off);
+
+ if (node_off < 0)
+ {
+ return FDT_RET_GET_EMPTY;
+ }
+
+ for (;;)
+ {
+ dtb_node->parent = dtb_node_head;
+ dtb_node->sibling = NULL;
+ dtb_node->name = fdt_get_name(current_fdt, node_off, &node_name_sz);
+
+ /* parent_path + name + '/' + '\0' */
+ if (paths_buf.cur + pathname_sz + node_name_sz + 2 < paths_buf.end)
+ {
+ dtb_node->path = (const char *)paths_buf.cur;
+ strncpy(paths_buf.cur, pathname, pathname_sz);
+ paths_buf.cur += pathname_sz;
+ strncpy(paths_buf.cur, (char *)dtb_node->name, node_name_sz);
+ paths_buf.cur += node_name_sz;
+ *paths_buf.cur++ = '/';
+ *paths_buf.cur++ = '\0';
+ }
+ else
+ {
+ dtb_node->path = NULL;
+ rt_kprintf("\033[31m\rERROR: `FDT_DTB_ALL_NODES_PATH_SIZE' = %d bytes is configured too low.\033[0m\n", FDT_DTB_ALL_NODES_PATH_SIZE);
+ return FDT_RET_NO_MEMORY;
+ }
+
+ dtb_node->handle = fdt_get_phandle(current_fdt, node_off);
+ dtb_node->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
+ dtb_node->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
+
+ if (dtb_node->properties == NULL || dtb_node->child == NULL)
+ {
+ return FDT_RET_NO_MEMORY;
+ }
+
+ fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node->properties, node_off);
+ if (fdt_exec_status == FDT_RET_GET_EMPTY)
+ {
+ free(dtb_node->properties);
+ dtb_node->properties = NULL;
+ }
+ else if (fdt_exec_status != FDT_RET_GET_OK)
+ {
+ return fdt_exec_status;
+ }
+
+ fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node, dtb_node->child, dtb_node->path);
+ if (fdt_exec_status == FDT_RET_GET_EMPTY)
+ {
+ free(dtb_node->child);
+ dtb_node->child = NULL;
+ }
+ else if (fdt_exec_status != FDT_RET_GET_OK)
+ {
+ return fdt_exec_status;
+ }
+
+ node_off = fdt_next_subnode(current_fdt, node_off);
+ if (node_off >= 0)
+ {
+ dtb_node->sibling = (struct dtb_node *)malloc(sizeof(struct dtb_node));
+ if (dtb_node->sibling == NULL)
+ {
+ return FDT_RET_NO_MEMORY;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return FDT_RET_GET_OK;
+}
+
+struct dtb_node *dtb_node_get_dtb_list(void *fdt)
+{
+ int root_off;
+ struct dtb_node *dtb_node_head = NULL;
+
+ if (fdt == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_LOADED;
+ goto fail;
+ }
+
+ current_fdt = fdt;
+
+ if ((dtb_node_head = (struct dtb_node *)malloc(sizeof(struct dtb_node))) == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ goto fail;
+ }
+
+ if (paths_buf.ptr == NULL)
+ {
+ paths_buf.ptr = malloc(FDT_DTB_ALL_NODES_PATH_SIZE);
+ if (paths_buf.ptr == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ goto fail;
+ }
+ paths_buf.cur = (char *)paths_buf.ptr;
+ paths_buf.end = (char *)(paths_buf.ptr + FDT_DTB_ALL_NODES_PATH_SIZE);
+ }
+
+ root_off = fdt_path_offset(fdt, "/");
+
+ if ((dtb_node_head->header = malloc(sizeof(struct dtb_header))) == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ goto fail;
+ }
+ else
+ {
+ ((struct dtb_header *)dtb_node_head->header)->root = '/';
+ ((struct dtb_header *)dtb_node_head->header)->zero = '\0';
+ ((struct dtb_header *)dtb_node_head->header)->memreserve_sz = fdt_num_mem_rsv(fdt);
+
+ if (dtb_node_head->header->memreserve_sz > 0)
+ {
+ int i;
+ int memreserve_sz = dtb_node_head->header->memreserve_sz;
+ uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
+ struct fdt_reserve_entry *rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
+
+ ((struct dtb_header *)dtb_node_head->header)->memreserve = malloc(sizeof(struct dtb_memreserve) * memreserve_sz);
+ if (dtb_node_head->header->memreserve == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ goto fail;
+ }
+ for (i = 0; i < memreserve_sz; ++i)
+ {
+ ((struct dtb_header *)dtb_node_head->header)->memreserve[i].address = fdt64_to_cpu(rsvmap[i].address);
+ ((struct dtb_header *)dtb_node_head->header)->memreserve[i].size = fdt64_to_cpu(rsvmap[i].size);
+ }
+ }
+ else
+ {
+ ((struct dtb_header *)dtb_node_head->header)->memreserve = NULL;
+ }
+ }
+
+ dtb_node_head->path = paths_buf.ptr;
+ *paths_buf.cur++ = '/';
+ *paths_buf.cur++ = '\0';
+ dtb_node_head->parent = NULL;
+ dtb_node_head->sibling = NULL;
+
+ dtb_node_head->handle = fdt_get_phandle(fdt, root_off);
+ dtb_node_head->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
+ dtb_node_head->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
+
+ if (dtb_node_head->properties == NULL || dtb_node_head->child == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ goto fail;
+ }
+
+ if ((fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node_head->properties, root_off)) != FDT_RET_GET_OK)
+ {
+ goto fail;
+ }
+
+ if ((fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node_head, dtb_node_head->child, dtb_node_head->path)) != FDT_RET_GET_OK)
+ {
+ goto fail;
+ }
+
+ /* paths_buf.ptr addr save in the dtb_node_head's path */
+ paths_buf.ptr = NULL;
+ paths_buf.cur = NULL;
+
+ return dtb_node_head;
+
+fail:
+ if (dtb_node_head != NULL)
+ {
+ dtb_node_free_dtb_list(dtb_node_head);
+ }
+
+ return NULL;
+}
+
+static void _dtb_node_free_dtb_node(struct dtb_node *dtb_node)
+{
+ struct dtb_node *dtb_node_last;
+ struct dtb_property *dtb_property;
+ struct dtb_property *dtb_property_last;
+
+ while (dtb_node != NULL)
+ {
+ dtb_property = dtb_node->properties;
+ while (dtb_property != NULL)
+ {
+ dtb_property_last = dtb_property;
+ dtb_property = dtb_property->next;
+ free(dtb_property_last);
+ }
+
+ _dtb_node_free_dtb_node(dtb_node->child);
+
+ dtb_node_last = dtb_node;
+ dtb_node = dtb_node->sibling;
+ free(dtb_node_last);
+ }
+}
+
+void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head)
+{
+ if (dtb_node_head == NULL)
+ {
+ return;
+ }
+
+ /* only root node can free all path buffer */
+ if (dtb_node_head->parent == NULL || (dtb_node_head->path != NULL && !strcmp(dtb_node_head->path, "/")))
+ {
+ if (dtb_node_head->path != NULL)
+ {
+ free((void *)dtb_node_head->path);
+ }
+ if (dtb_node_head->header != NULL)
+ {
+ if (dtb_node_head->header->memreserve != NULL)
+ {
+ free((void *)dtb_node_head->header->memreserve);
+ }
+ free((void *)dtb_node_head->header);
+ }
+ }
+
+ _dtb_node_free_dtb_node(dtb_node_head);
+}
+
+static void _dtb_node_printf_depth(int depth)
+{
+ int i = depth;
+ while (i --> 0)
+ {
+ rt_kputs("\t");
+ }
+}
+
+rt_bool_t _dtb_node_test_string_list(const void *value, int size)
+{
+ const char *str = value;
+ const char *str_start, *str_end;
+
+ if (size == 0)
+ {
+ return RT_FALSE;
+ }
+
+ /* string end with '\0' */
+ if (str[size - 1] != '\0')
+ {
+ return RT_FALSE;
+ }
+
+ /* get string list end */
+ str_end = str + size;
+
+ while (str < str_end)
+ {
+ str_start = str;
+ /* before string list end, not '\0' and a printable characters */
+ while (str < str_end && *str && ((unsigned char)*str >= ' ' && (unsigned char)*str <= '~'))
+ {
+ ++str;
+ }
+
+ /* not zero, or not increased */
+ if (*str != '\0' || str == str_start)
+ {
+ return RT_FALSE;
+ }
+
+ /* next string */
+ ++str;
+ }
+
+ return RT_TRUE;
+}
+
+static void _dtb_node_printf_dtb_node_info(struct dtb_node *dtb_node)
+{
+ static int depth = 0;
+ struct dtb_property *dtb_property;
+
+ while (dtb_node != NULL)
+ {
+ rt_kputs("\n");
+ _dtb_node_printf_depth(depth);
+ rt_kputs(dtb_node->name);
+ rt_kputs(" {\n");
+ ++depth;
+
+ dtb_property = dtb_node->properties;
+ while (dtb_property != NULL)
+ {
+ _dtb_node_printf_depth(depth);
+
+ rt_kputs(dtb_property->name);
+
+ if (dtb_property->size > 0)
+ {
+ int size = dtb_property->size;
+ char *value = dtb_property->value;
+
+ rt_kputs(" = ");
+ if (_dtb_node_test_string_list(value, size) == RT_TRUE)
+ {
+ /* print string list */
+ char *str = value;
+ do
+ {
+ rt_kprintf("\"%s\"", str);
+ str += strlen(str) + 1;
+ rt_kputs(", ");
+ } while (str < value + size);
+ rt_kputs("\b\b");
+ }
+ else if ((size % 4) == 0)
+ {
+ /* print addr and size cell */
+ int i;
+ fdt32_t *cell = (fdt32_t *)value;
+
+ rt_kputs("<");
+ for (i = 0, size /= 4; i < size; ++i)
+ {
+ rt_kprintf("0x%x ", fdt32_to_cpu(cell[i]));
+ }
+ rt_kputs("\b>");
+ }
+ else
+ {
+ /* print bytes array */
+ int i;
+ uint8_t *byte = (uint8_t *)value;
+
+ rt_kputs("[");
+ for (i = 0; i < size; ++i)
+ {
+ rt_kprintf("%02x ", *byte++);
+ }
+ rt_kputs("\b]");
+ }
+ }
+ rt_kputs(";\n");
+ dtb_property = dtb_property->next;
+ }
+
+ _dtb_node_printf_dtb_node_info(dtb_node->child);
+ dtb_node = dtb_node->sibling;
+
+ --depth;
+ _dtb_node_printf_depth(depth);
+ rt_kputs("};\n");
+ }
+}
+
+void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head)
+{
+ if (dtb_node_head != NULL)
+ {
+ int i = dtb_node_head->header->memreserve_sz;
+
+ rt_kputs("/dts-v1/;\n");
+ while (i --> 0)
+ {
+ rt_kprintf("\n/memreserve/\t0x%lx 0x%zx;", dtb_node_head->header->memreserve[i].address, dtb_node_head->header->memreserve[i].size);
+ }
+
+ _dtb_node_printf_dtb_node_info(dtb_node_head);
+ }
+}
+
+static void _dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node, void (callback(struct dtb_node *dtb_node)))
+{
+ while (dtb_node != NULL)
+ {
+ callback(dtb_node);
+ _dtb_node_get_enum_dtb_node(dtb_node->child, callback);
+ dtb_node = dtb_node->sibling;
+ }
+}
+
+void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (callback(struct dtb_node *dtb_node)))
+{
+ if (dtb_node_head == NULL || callback == NULL)
+ {
+ return;
+ }
+
+ _dtb_node_get_enum_dtb_node(dtb_node_head, callback);
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
+{
+ struct dtb_node *dtb_node_child;
+
+ while (dtb_node != NULL)
+ {
+ if (!strcmp(nodename, dtb_node->name))
+ {
+ return dtb_node;
+ }
+
+ dtb_node_child = dtb_node_get_dtb_node_by_name_DFS(dtb_node->child, nodename);
+
+ if (dtb_node_child != NULL)
+ {
+ return dtb_node_child;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+
+ return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
+{
+ if (dtb_node != NULL)
+ {
+ struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
+
+ while (dtb_node != NULL)
+ {
+ if (!strcmp(nodename, dtb_node->name))
+ {
+ return dtb_node;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+
+ dtb_node = dtb_node_head;
+
+ while (dtb_node != NULL)
+ {
+ dtb_node_child = dtb_node_get_dtb_node_by_name_BFS(dtb_node->child, nodename);
+
+ if (dtb_node_child != NULL)
+ {
+ return dtb_node_child;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+ }
+
+ return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
+{
+ int i = 0;
+ char *node_name;
+ char *pathname_clone;
+ int pathname_sz;
+
+ if (pathname == NULL || dtb_node == NULL)
+ {
+ return NULL;
+ }
+
+ /* skip '/' */
+ if (*pathname == '/')
+ {
+ ++pathname;
+ }
+
+ /* root not have sibling, so skip */
+ if (dtb_node->parent == NULL || !strcmp(dtb_node->path, "/"))
+ {
+ dtb_node = dtb_node->child;
+ }
+
+ pathname_sz = strlen(pathname) + 1;
+ pathname_clone = malloc(pathname_sz);
+ if (pathname_clone == NULL)
+ {
+ return NULL;
+ }
+ strncpy(pathname_clone, pathname, pathname_sz);
+ node_name = pathname_clone;
+
+ while (pathname_clone[i])
+ {
+ if (pathname_clone[i] == '/')
+ {
+ /* set an end of name that can used to strcmp */
+ pathname_clone[i] = '\0';
+
+ while (dtb_node != NULL)
+ {
+ if (!strcmp(dtb_node->name, node_name))
+ {
+ break;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+ if (dtb_node == NULL)
+ {
+ free(pathname_clone);
+ return NULL;
+ }
+ dtb_node = dtb_node->child;
+ node_name = &pathname_clone[i + 1];
+ }
+ ++i;
+ }
+
+ /*
+ * found the end node and it's name:
+ * (pathname[pathname_sz - 1]) is '\0'
+ * (&pathname_clone[i] - node_name) is the node_name's length
+ */
+ node_name = &((char *)pathname)[(pathname_sz - 1) - (&pathname_clone[i] - node_name)];
+ free(pathname_clone);
+
+ while (dtb_node != NULL)
+ {
+ if (!strcmp(dtb_node->name, node_name))
+ {
+ return dtb_node;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+
+ return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
+{
+ struct dtb_node *dtb_node_child;
+
+ while (dtb_node != NULL)
+ {
+ if (dtb_node->handle == handle)
+ {
+ return dtb_node;
+ }
+
+ dtb_node_child = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node->child, handle);
+
+ if (dtb_node_child != NULL)
+ {
+ return dtb_node_child;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+
+ return NULL;
+}
+
+struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
+{
+ if (dtb_node != NULL)
+ {
+ struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
+
+ while (dtb_node != NULL)
+ {
+ if (dtb_node->handle == handle)
+ {
+ return dtb_node;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+
+ dtb_node = dtb_node_head;
+
+ while (dtb_node != NULL)
+ {
+ dtb_node_child = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node->child, handle);
+
+ if (dtb_node_child != NULL)
+ {
+ return dtb_node_child;
+ }
+ dtb_node = dtb_node->sibling;
+ }
+ }
+
+ return NULL;
+}
+
+void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
+{
+ if (dtb_node != NULL && addr_cells != NULL && size_cells != NULL)
+ {
+ struct dtb_property *dtb_property;
+ *addr_cells = -1;
+ *size_cells = -1;
+
+ /* if couldn't found, check parent */
+ while ((dtb_node = dtb_node->parent) != NULL)
+ {
+ dtb_property = dtb_node->properties;
+ while (dtb_property != NULL)
+ {
+ if (!strcmp(dtb_property->name, "#address-cells"))
+ {
+ *addr_cells = fdt32_to_cpu(*(int *)dtb_property->value);
+ }
+ else if (!strcmp(dtb_property->name, "#size-cells"))
+ {
+ *size_cells = fdt32_to_cpu(*(int *)dtb_property->value);
+ }
+ if (*addr_cells != -1 && *size_cells != -1)
+ {
+ return;
+ }
+ dtb_property = dtb_property->next;
+ }
+ }
+
+ if (*addr_cells == -1)
+ {
+ *addr_cells = FDT_ROOT_ADDR_CELLS_DEFAULT;
+ }
+ if (*size_cells == -1)
+ {
+ *size_cells = FDT_ROOT_SIZE_CELLS_DEFAULT;
+ }
+ }
+}
+
+struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
+{
+ if (dtb_node != NULL && memreserve_size != NULL)
+ {
+ struct dtb_node *dtb_node_root = dtb_node;
+
+ while (dtb_node_root != NULL)
+ {
+ if (!strcmp(dtb_node_root->path, "/"))
+ {
+ break;
+ }
+ dtb_node_root = dtb_node_root->parent;
+ }
+
+ *memreserve_size = dtb_node_root->header->memreserve_sz;
+
+ return dtb_node_root->header->memreserve;
+ }
+ return NULL;
+}
+
+rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node)
+{
+ if (dtb_node != NULL)
+ {
+ char *status = dtb_node_get_dtb_node_property_value(dtb_node, "status", NULL);
+ if (status != NULL)
+ {
+ return (!strcmp(status, "okay") || !strcmp(status, "ok")) ? RT_TRUE : RT_FALSE;
+ }
+
+ return RT_TRUE;
+ }
+
+ return RT_FALSE;
+}
+
+rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles)
+{
+ if (dtb_node != NULL)
+ {
+ if (compatibles != NULL)
+ {
+ char *str_ptr;
+ int prop_sz;
+
+ for_each_property_string(dtb_node, "compatible", str_ptr, prop_sz)
+ {
+ if (!strcmp(compatibles, str_ptr))
+ {
+ return RT_TRUE;
+ }
+ }
+ }
+ }
+
+ return RT_FALSE;
+}
+
+char *dtb_node_get_dtb_string_list_value(void *value, int size, int index)
+{
+ int i = 0;
+ char *str = value;
+
+ if (str != NULL)
+ {
+ do
+ {
+ if (i++ == index)
+ {
+ return str;
+ }
+ str += strlen(str) + 1;
+ } while (str < (char *)value + size);
+ }
+
+ return NULL;
+}
+
+char *dtb_node_get_dtb_string_list_value_next(void *value, void *end)
+{
+ char *str = value;
+
+ if (str != NULL)
+ {
+ str += strlen(str) + 1;
+ if (str < (char *)end)
+ {
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+uint32_t dtb_node_get_dtb_cell_value(void *value)
+{
+ return fdt32_to_cpu(*(fdt32_t *)value);
+}
+
+uint8_t dtb_node_get_dtb_byte_value(void *value)
+{
+ return *(uint8_t *)value;
+}
diff --git a/components/drivers/fdt/src/dtb_head.c b/components/drivers/fdt/src/dtb_head.c
new file mode 100644
index 0000000000..7fe661943d
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_head.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "dtb_node.h"
+
+static void *dtb_root = NULL;
+static struct dtb_node *dtb_node_list = NULL;
+void *get_fdt_blob(void)
+{
+ return dtb_root;
+}
+
+struct dtb_node *get_dtb_node_head(void)
+{
+ return dtb_node_list;
+}
+
+rt_bool_t dtb_node_active(void)
+{
+ return dtb_node_list != NULL;
+}
+
+int device_tree_setup(void *mem_addr)
+{
+ if(mem_addr)
+ {
+ if ((dtb_root = dtb_node_load_from_memory(mem_addr,1)) != NULL)
+ {
+ dtb_node_list = dtb_node_get_dtb_list(dtb_root);
+ if (dtb_node_list != NULL)
+ {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ return -1;
+} \ No newline at end of file
diff --git a/components/drivers/fdt/src/dtb_load.c b/components/drivers/fdt/src/dtb_load.c
new file mode 100644
index 0000000000..a6c6dca6f9
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_load.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include <unistd.h>
+#include "dtb_node.h"
+
+extern int fdt_exec_status;
+
+rt_bool_t dtb_node_check(void *fdt)
+{
+ return fdt_check_header(fdt) == 0 ? RT_TRUE : RT_FALSE;
+}
+
+void *dtb_node_load_from_fs(char *dtb_filename)
+{
+ void *fdt = NULL;
+ size_t dtb_sz;
+ int fd = -1;
+
+ if (dtb_filename == NULL)
+ {
+ fdt_exec_status = FDT_RET_GET_EMPTY;
+ goto end;
+ }
+
+ fd = open(dtb_filename, O_RDONLY, 0);
+
+ if (fd == -1)
+ {
+ rt_kprintf("File `%s' not found.\n", dtb_filename);
+ fdt_exec_status = FDT_RET_GET_EMPTY;
+ goto end;
+ }
+
+ dtb_sz = lseek(fd, 0, SEEK_END);
+
+ if (dtb_sz > 0)
+ {
+ if ((fdt = (struct fdt_header *)malloc(sizeof(uint8_t) * dtb_sz)) == NULL)
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ goto end;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ read(fd, fdt, sizeof(uint8_t) * dtb_sz);
+
+ if (dtb_node_check(fdt) == RT_FALSE)
+ {
+ free(fdt);
+ }
+ }
+
+end:
+ if (fd != -1)
+ {
+ close(fd);
+ }
+
+ return fdt;
+}
+
+void *dtb_node_load_from_memory(void *dtb_ptr, rt_bool_t is_clone)
+{
+ void *fdt = NULL;
+
+ if (dtb_ptr == NULL)
+ {
+ fdt_exec_status = FDT_RET_GET_EMPTY;
+ goto end;
+ }
+
+ if (dtb_node_check(dtb_ptr) == RT_FALSE)
+ {
+ fdt_exec_status = FDT_RET_GET_EMPTY;
+ fdt = NULL;
+ goto end;
+ }
+
+ if (is_clone)
+ {
+ size_t dtb_sz = fdt_totalsize(dtb_ptr);
+ if (dtb_sz > 0)
+ {
+ if ((fdt = malloc(dtb_sz)) != NULL)
+ {
+ memcpy(fdt, dtb_ptr, dtb_sz);
+ }
+ else
+ {
+ fdt_exec_status = FDT_RET_NO_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ fdt = dtb_ptr;
+ }
+
+end:
+ return fdt;
+}
diff --git a/components/drivers/fdt/src/dtb_set.c b/components/drivers/fdt/src/dtb_set.c
new file mode 100644
index 0000000000..28fe2b5fde
--- /dev/null
+++ b/components/drivers/fdt/src/dtb_set.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "libfdt.h"
+#include "dtb_node.h"
+
+static off_t dtb_node_find_and_add_subnode(void *fdt, char* name)
+{
+ off_t chosen_offset = 0;
+
+ chosen_offset = fdt_subnode_offset(fdt, 0, name);
+
+ if (chosen_offset == -FDT_ERR_NOTFOUND)
+ {
+ chosen_offset = fdt_add_subnode(fdt, 0, name);
+ }
+
+ return chosen_offset;
+}
+
+size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline)
+{
+ off_t chosen_offset;
+ size_t cmdline_size;
+
+ if (cmdline == NULL || fdt == NULL)
+ {
+ goto end;
+ }
+
+ chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
+ cmdline_size = strlen(cmdline);
+
+ /* install bootargs */
+ if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
+ {
+ if (fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size) < 0)
+ {
+ fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
+ fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size);
+ }
+ }
+
+end:
+ return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size)
+{
+ uint64_t addr, size_ptr;
+ off_t chosen_offset;
+ int i;
+
+ if (fdt == NULL)
+ {
+ goto end;
+ }
+
+ chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
+
+ /* update the entry */
+ for (i = fdt_num_mem_rsv(fdt) - 1; i >= 0; --i)
+ {
+ fdt_get_mem_rsv(fdt, i, &addr, &size_ptr);
+ if (addr == initrd_addr)
+ {
+ fdt_del_mem_rsv(fdt, i);
+ break;
+ }
+ }
+
+ /* add the memory */
+ if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
+ {
+ /* move the memory */
+ fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
+ if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
+ {
+ goto end;
+ }
+ }
+
+ /* install initrd */
+ if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
+ {
+ chosen_offset = fdt_path_offset(fdt, "/chosen");
+
+ if (IN_64BITS_MODE)
+ {
+ fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
+ fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
+ }
+ else
+ {
+ fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
+ fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
+ }
+ }
+
+end:
+ return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size)
+{
+ int node_off;
+
+ if (fdt == NULL)
+ {
+ goto end;
+ }
+
+ node_off = fdt_path_offset(fdt, pathname);
+
+ if (node_off >= 0 && cells_size != 0)
+ {
+ fdt_setprop(fdt, node_off, property_name, cells, cells_size);
+ }
+
+end:
+ return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size)
+{
+ if (fdt == NULL)
+ {
+ goto end;
+ }
+
+ fdt_add_mem_rsv(fdt, address, size);
+
+end:
+ return fdt_totalsize(fdt);
+}
+
+size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address)
+{
+ int i;
+ int num_mem_rsvmap;
+ uint32_t off_mem_rsvmap;
+ struct fdt_reserve_entry *rsvmap;
+
+ if (fdt == NULL)
+ {
+ goto end;
+ }
+
+ num_mem_rsvmap = fdt_num_mem_rsv(fdt);
+ off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
+ rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
+
+ for (i = 0; i < num_mem_rsvmap; ++i)
+ {
+ if (address == fdt64_to_cpu(rsvmap[i].address))
+ {
+ fdt_del_mem_rsv(fdt, i);
+ break;
+ }
+ }
+
+end:
+ return fdt_totalsize(fdt);
+}
diff --git a/components/drivers/include/drivers/cputime.h b/components/drivers/include/drivers/cputime.h
index ec98f3152e..bcc339ca35 100644
--- a/components/drivers/include/drivers/cputime.h
+++ b/components/drivers/include/drivers/cputime.h
@@ -22,8 +22,8 @@ struct rt_clock_cputime_ops
float clock_cpu_getres(void);
uint64_t clock_cpu_gettime(void);
-uint32_t clock_cpu_microsecond(uint32_t cpu_tick);
-uint32_t clock_cpu_millisecond(uint32_t cpu_tick);
+uint64_t clock_cpu_microsecond(uint64_t cpu_tick);
+uint64_t clock_cpu_millisecond(uint64_t cpu_tick);
int clock_cpu_setops(const struct rt_clock_cputime_ops *ops);
diff --git a/components/drivers/include/drivers/gpt.h b/components/drivers/include/drivers/gpt.h
new file mode 100644
index 0000000000..c1bdcb732a
--- /dev/null
+++ b/components/drivers/include/drivers/gpt.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-05-05 linzhenxing first version
+ */
+#ifndef __GPT_H
+#define __GPT_H
+
+#include <rtthread.h>
+#include <stdint.h>
+
+typedef struct
+{
+ uint8_t b[16]; /* GUID 16 bytes*/
+} guid_t;
+
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_MBR_PROTECTIVE 1
+#define GPT_MBR_HYBRID 2
+
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+typedef guid_t gpt_guid_t __attribute__ ((aligned (4)));
+#define EFI_GUID(a, b, c, d...) (gpt_guid_t){ { \
+ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+ (c) & 0xff, ((c) >> 8) & 0xff, d } }
+
+#define NULL_GUID \
+ EFI_GUID(0x00000000, 0x0000, 0x0000,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
+#define PARTITION_SYSTEM_GUID \
+ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
+ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define LEGACY_MBR_PARTITION_GUID \
+ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
+#pragma pack(push, 1)
+typedef struct _gpt_header
+{
+ uint64_t signature;
+ uint32_t revision;
+ uint32_t header_size;
+ uint32_t header_crc32;
+ uint32_t reserved1;
+ uint64_t start_lba; /*GPT head start sector*/
+ uint64_t alternate_lba; /*GPT head alternate sector*/
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ gpt_guid_t disk_guid;
+ uint64_t partition_entry_lba;
+ uint32_t num_partition_entries;
+ uint32_t sizeof_partition_entry;
+ uint32_t partition_entry_array_crc32;
+
+ /* The rest of the logical block is reserved by UEFI and must be zero.
+ * EFI standard handles this by:
+ *
+ * uint8_t reserved2[ BlockSize - 92 ];
+ */
+} gpt_header;
+
+typedef struct _gpt_entry_attributes
+{
+ uint64_t required_to_function:1;
+ uint64_t reserved:47;
+ uint64_t type_guid_specific:16;
+} gpt_entry_attributes;
+
+typedef struct _gpt_entry
+{
+ gpt_guid_t partition_type_guid;
+ gpt_guid_t unique_partition_guid;
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ gpt_entry_attributes attributes;
+ uint16_t partition_name[72/sizeof(uint16_t)];
+} gpt_entry;
+
+typedef struct _gpt_mbr_record
+{
+ uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */
+ uint8_t start_head; /* unused by EFI, pt start in CHS */
+ uint8_t start_sector; /* unused by EFI, pt start in CHS */
+ uint8_t start_track;
+ uint8_t os_type; /* EFI and legacy non-EFI OS types */
+ uint8_t end_head; /* unused by EFI, pt end in CHS */
+ uint8_t end_sector; /* unused by EFI, pt end in CHS */
+ uint8_t end_track; /* unused by EFI, pt end in CHS */
+ uint32_t starting_lba; /* used by EFI - start addr of the on disk pt */
+ uint32_t size_in_lba; /* used by EFI - size of pt in LBA */
+} gpt_mbr_record;
+
+
+typedef struct _legacy_mbr
+{
+ uint8_t boot_code[440];
+ uint32_t unique_mbr_signature;
+ uint16_t unknown;
+ gpt_mbr_record partition_record[4];
+ uint16_t signature;
+} legacy_mbr;
+#pragma pack(pop)
+
+int check_gpt(struct rt_mmcsd_card *card);
+int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex);
+void gpt_free(void);
+#endif /*__GPT_H*/
diff --git a/components/drivers/include/drivers/lcd.h b/components/drivers/include/drivers/lcd.h
new file mode 100644
index 0000000000..74d291feac
--- /dev/null
+++ b/components/drivers/include/drivers/lcd.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-03-05 bernard first version.
+ */
+
+#ifndef RT_LCD_H__
+#define RT_LCD_H__
+
+/* ioctls
+ 0x46 is 'F' */
+
+#define FBIOGET_VSCREENINFO 0x4600
+#define FBIOPUT_VSCREENINFO 0x4601
+#define FBIOGET_FSCREENINFO 0x4602
+#define FBIOGETCMAP 0x4604
+#define FBIOPUTCMAP 0x4605
+#define FBIOPAN_DISPLAY 0x4606
+#define FBIO_CURSOR 0x4608
+/* #define FBIOGET_MONITORSPEC 0x460C */
+/* #define FBIOPUT_MONITORSPEC 0x460D */
+/* #define FBIOSWITCH_MONIBIT 0x460E */
+
+#define FBIOGET_CON2FBMAP 0x460F
+#define FBIOPUT_CON2FBMAP 0x4610
+#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */
+#define FBIOGET_VBLANK 0x4612
+#define FBIO_ALLOC 0x4613
+#define FBIO_FREE 0x4614
+#define FBIOGET_GLYPH 0x4615
+#define FBIOGET_HWCINFO 0x4616
+#define FBIOPUT_MODEINFO 0x4617
+#define FBIOGET_DISPINFO 0x4618
+#define FBIO_WAITFORVSYNC 0x4620
+
+struct fb_bitfield
+{
+ uint32_t offset; /* beginning of bitfield */
+ uint32_t length; /* length of bitfield */
+ uint32_t msb_right; /* != 0 : Most significant bit is */
+ /* right */
+};
+
+struct fb_var_screeninfo
+{
+ uint32_t xres; /* visible resolution */
+ uint32_t yres;
+ uint32_t xres_virtual; /* virtual resolution */
+ uint32_t yres_virtual;
+ uint32_t xoffset; /* offset from virtual to visible */
+ uint32_t yoffset; /* resolution */
+
+ uint32_t bits_per_pixel; /* guess what */
+ uint32_t grayscale; /* 0 = color, 1 = grayscale, */
+ /* >1 = FOURCC */
+ struct fb_bitfield red; /* bitfield in fb mem if true color, */
+ struct fb_bitfield green; /* else only length is significant */
+ struct fb_bitfield blue;
+ struct fb_bitfield transp; /* transparency */
+
+ uint32_t nonstd; /* != 0 Non standard pixel format */
+
+ uint32_t activate; /* see FB_ACTIVATE_* */
+
+ uint32_t height; /* height of picture in mm */
+ uint32_t width; /* width of picture in mm */
+
+ uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */
+
+ /* Timing: All values in pixclocks, except pixclock (of course) */
+ uint32_t pixclock; /* pixel clock in ps (pico seconds) */
+ uint32_t left_margin; /* time from sync to picture */
+ uint32_t right_margin; /* time from picture to sync */
+ uint32_t upper_margin; /* time from sync to picture */
+ uint32_t lower_margin;
+ uint32_t hsync_len; /* length of horizontal sync */
+ uint32_t vsync_len; /* length of vertical sync */
+ uint32_t sync; /* see FB_SYNC_* */
+ uint32_t vmode; /* see FB_VMODE_* */
+ uint32_t rotate; /* angle we rotate counter clockwise */
+ uint32_t colorspace; /* colorspace for FOURCC-based modes */
+ uint32_t reserved[4]; /* Reserved for future compatibility */
+};
+
+struct fb_fix_screeninfo
+{
+ char id[16]; /* identification string eg "TT Builtin" */
+ unsigned long smem_start; /* Start of frame buffer mem */
+ /* (physical address) */
+ uint32_t smem_len; /* Length of frame buffer mem */
+ uint32_t type; /* see FB_TYPE_* */
+ uint32_t type_aux; /* Interleave for interleaved Planes */
+ uint32_t visual; /* see FB_VISUAL_* */
+ uint16_t xpanstep; /* zero if no hardware panning */
+ uint16_t ypanstep; /* zero if no hardware panning */
+ uint16_t ywrapstep; /* zero if no hardware ywrap */
+ uint32_t line_length; /* length of a line in bytes */
+ unsigned long mmio_start; /* Start of Memory Mapped I/O */
+ /* (physical address) */
+ uint32_t mmio_len; /* Length of Memory Mapped I/O */
+ uint32_t accel; /* Indicate to driver which */
+ /* specific chip/card we have */
+ uint16_t capabilities; /* see FB_CAP_* */
+ uint16_t reserved[2]; /* Reserved for future compatibility */
+};
+
+#endif
diff --git a/components/drivers/include/drivers/mmcsd_card.h b/components/drivers/include/drivers/mmcsd_card.h
index 8a49978a17..f877e60069 100644
--- a/components/drivers/include/drivers/mmcsd_card.h
+++ b/components/drivers/include/drivers/mmcsd_card.h
@@ -141,6 +141,7 @@ struct rt_mmcsd_card {
rt_uint32_t max_data_rate; /* max data transfer rate */
rt_uint32_t card_capacity; /* card capacity, unit:KB */
rt_uint32_t card_blksize; /* card block size */
+ rt_uint32_t card_sec_cnt; /* card sector count*/
rt_uint32_t erase_size; /* erase size in sectors */
rt_uint16_t card_type;
#define CARD_TYPE_MMC 0 /* MMC card */
@@ -152,7 +153,8 @@ struct rt_mmcsd_card {
#define CARD_FLAG_HIGHSPEED (1 << 0) /* SDIO bus speed 50MHz */
#define CARD_FLAG_SDHC (1 << 1) /* SDHC card */
#define CARD_FLAG_SDXC (1 << 2) /* SDXC card */
-
+#define CARD_FLAG_HIGHSPEED_DDR (1 << 3) /*HIGH SPEED DDR*/
+#define CARD_FLAG_HS200 (1 << 4) /* BUS SPEED 200mHz*/
struct rt_sd_scr scr;
struct rt_mmcsd_csd csd;
rt_uint32_t hs_max_data_rate; /* max data transfer rate in high speed mode */
diff --git a/components/drivers/include/drivers/mmcsd_cmd.h b/components/drivers/include/drivers/mmcsd_cmd.h
index 2993fe5406..2bd7b93ee1 100644
--- a/components/drivers/include/drivers/mmcsd_cmd.h
+++ b/components/drivers/include/drivers/mmcsd_cmd.h
@@ -37,7 +37,8 @@ extern "C" {
#define SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
-
+#define SEND_TUNING_BLOCK 19 /* adtc R1 */
+#define SEND_TUNING_BLOCK_HS200 21 /* adtc R1*/
/* class 3 */
#define WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
diff --git a/components/drivers/include/drivers/mmcsd_core.h b/components/drivers/include/drivers/mmcsd_core.h
index 51263d35f2..04a6ffde2b 100644
--- a/components/drivers/include/drivers/mmcsd_core.h
+++ b/components/drivers/include/drivers/mmcsd_core.h
@@ -26,7 +26,8 @@ extern "C" {
#define mmcsd_dbg(fmt, ...)
#endif
-struct rt_mmcsd_data {
+struct rt_mmcsd_data
+{
rt_uint32_t blksize;
rt_uint32_t blks;
rt_uint32_t *buf;
@@ -43,9 +44,15 @@ struct rt_mmcsd_data {
rt_uint32_t timeout_ns;
rt_uint32_t timeout_clks;
+
+ void *sg; /* scatter list */
+ rt_uint16_t sg_len; /* size of scatter list */
+ rt_int16_t sg_count; /* mapped sg entries */
+ rt_ubase_t host_cookie; /* host driver private data */
};
-struct rt_mmcsd_cmd {
+struct rt_mmcsd_cmd
+{
rt_uint32_t cmd_code;
rt_uint32_t arg;
rt_uint32_t resp[4];
@@ -94,15 +101,20 @@ struct rt_mmcsd_cmd {
rt_int32_t retries; /* max number of retries */
rt_int32_t err;
+ unsigned int busy_timeout; /* busy detect timeout in ms */
struct rt_mmcsd_data *data;
struct rt_mmcsd_req *mrq; /* associated request */
};
-struct rt_mmcsd_req {
+struct rt_mmcsd_req
+{
struct rt_mmcsd_data *data;
struct rt_mmcsd_cmd *cmd;
struct rt_mmcsd_cmd *stop;
+ struct rt_mmcsd_cmd *sbc; /* SET_BLOCK_COUNT for multiblock */
+ /* Allow other commands during this ongoing data transfer or busy wait */
+ int cap_cmd_during_tfr;
};
/*the following is response bit*/
@@ -208,6 +220,7 @@ rt_inline rt_uint32_t __rt_fls(rt_uint32_t val)
#define MMCSD_HOST_PLUGED 0
#define MMCSD_HOST_UNPLUGED 1
+rt_int32_t mmcsd_excute_tuning(struct rt_mmcsd_card *card);
int mmcsd_wait_cd_changed(rt_int32_t timeout);
void mmcsd_host_lock(struct rt_mmcsd_host *host);
void mmcsd_host_unlock(struct rt_mmcsd_host *host);
@@ -226,14 +239,18 @@ void mmcsd_set_chip_select(struct rt_mmcsd_host *host, rt_int32_t mode);
void mmcsd_set_clock(struct rt_mmcsd_host *host, rt_uint32_t clk);
void mmcsd_set_bus_mode(struct rt_mmcsd_host *host, rt_uint32_t mode);
void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width);
+void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing);
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card);
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
void mmcsd_change(struct rt_mmcsd_host *host);
void mmcsd_detect(void *param);
+void mmcsd_host_init(struct rt_mmcsd_host *host);
struct rt_mmcsd_host *mmcsd_alloc_host(void);
void mmcsd_free_host(struct rt_mmcsd_host *host);
int rt_mmcsd_core_init(void);
+int rt_mmcsd_blk_init(void);
+rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count);
rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card);
void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card);
diff --git a/components/drivers/include/drivers/mmcsd_host.h b/components/drivers/include/drivers/mmcsd_host.h
index 44f7b1c916..774f515c8a 100644
--- a/components/drivers/include/drivers/mmcsd_host.h
+++ b/components/drivers/include/drivers/mmcsd_host.h
@@ -17,7 +17,8 @@
extern "C" {
#endif
-struct rt_mmcsd_io_cfg {
+struct rt_mmcsd_io_cfg
+{
rt_uint32_t clock; /* clock rate */
rt_uint16_t vdd;
@@ -45,21 +46,50 @@ struct rt_mmcsd_io_cfg {
#define MMCSD_BUS_WIDTH_1 0
#define MMCSD_BUS_WIDTH_4 2
#define MMCSD_BUS_WIDTH_8 3
-#define MMCSD_DDR_BUS_WIDTH_4 4
-#define MMCSD_DDR_BUS_WIDTH_8 5
+
+ unsigned char timing; /* timing specification used */
+
+#define MMCSD_TIMING_LEGACY 0
+#define MMCSD_TIMING_MMC_HS 1
+#define MMCSD_TIMING_SD_HS 2
+#define MMCSD_TIMING_UHS_SDR12 3
+#define MMCSD_TIMING_UHS_SDR25 4
+#define MMCSD_TIMING_UHS_SDR50 5
+#define MMCSD_TIMING_UHS_SDR104 6
+#define MMCSD_TIMING_UHS_DDR50 7
+#define MMCSD_TIMING_MMC_DDR52 8
+#define MMCSD_TIMING_MMC_HS200 9
+#define MMCSD_TIMING_MMC_HS400 10
+
+ unsigned char drv_type; /* driver type (A, B, C, D) */
+
+#define MMCSD_SET_DRIVER_TYPE_B 0
+#define MMCSD_SET_DRIVER_TYPE_A 1
+#define MMCSD_SET_DRIVER_TYPE_C 2
+#define MMCSD_SET_DRIVER_TYPE_D 3
+
+ unsigned char signal_voltage;
+
+#define MMCSD_SIGNAL_VOLTAGE_330 0
+#define MMCSD_SIGNAL_VOLTAGE_180 1
+#define MMCSD_SIGNAL_VOLTAGE_120 2
};
struct rt_mmcsd_host;
struct rt_mmcsd_req;
-struct rt_mmcsd_host_ops {
+struct rt_mmcsd_host_ops
+{
void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
+ rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode);
};
-struct rt_mmcsd_host {
+struct rt_mmcsd_host
+{
+ char name[RT_NAME_MAX];
struct rt_mmcsd_card *card;
const struct rt_mmcsd_host_ops *ops;
rt_uint32_t freq_min;
@@ -90,10 +120,15 @@ struct rt_mmcsd_host {
#define MMCSD_HOST_IS_SPI (1 << 3)
#define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI)
#define MMCSD_SUP_SDIO_IRQ (1 << 4) /* support signal pending SDIO IRQs */
-#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed */
-#define MMCSD_SUP_HIGHSPEED_DDR (1 << 6) /* support high speed(DDR) */
-#define MMCSD_SUP_HIGHSPEED_HS200 (1 << 7) /* support high speed HS200 */
-#define MMCSD_SUP_HIGHSPEED_HS400 (1 << 8) /* support high speed HS400 */
+#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed SDR*/
+#define MMCSD_SUP_DDR_3V3 (1 << 6)
+#define MMCSD_SUP_DDR_1V8 (1 << 7)
+#define MMCSD_SUP_DDR_1V2 (1 << 8)
+#define MMCSD_SUP_HIGHSPEED_DDR (MMCSD_SUP_DDR_3V3 | MMCSD_SUP_DDR_1V8 | MMCSD_SUP_DDR_1V2)/* HIGH SPEED DDR*/
+#define MMCSD_SUP_HS200_1V8 (1 << 9)
+#define MMCSD_SUP_HS200_1V2 (1 << 10)
+#define MMCSD_SUP_HS200 (MMCSD_SUP_HS200_1V2 | MMCSD_SUP_HS200_1V8) /* hs200 sdr */
+#define MMCSD_SUP_NONREMOVABLE (1 << 11)
rt_uint32_t max_seg_size; /* maximum size of one dma segment */
rt_uint32_t max_dma_segs; /* maximum number of dma segments in one request */
diff --git a/components/drivers/include/drivers/rt_dev_bus.h b/components/drivers/include/drivers/rt_dev_bus.h
new file mode 100644
index 0000000000..9fe8af893c
--- /dev/null
+++ b/components/drivers/include/drivers/rt_dev_bus.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-13 flybreak the first version
+ */
+
+#ifndef __RT_DEV_BUS_H__
+#define __RT_DEV_BUS_H__
+#include <rtthread.h>
+
+rt_device_t rt_device_bus_create(char *name, int attach_size);
+rt_err_t rt_device_bus_destroy(rt_device_t dev);
+
+#endif /* __RT_BUS_H__ */
diff --git a/components/drivers/include/drivers/serial.h b/components/drivers/include/drivers/serial.h
index 3b0d4c80da..1d0b9afe5c 100644
--- a/components/drivers/include/drivers/serial.h
+++ b/components/drivers/include/drivers/serial.h
@@ -150,6 +150,8 @@ struct rt_serial_device
void *serial_rx;
void *serial_tx;
+
+ struct rt_device_notify rx_notify;
};
typedef struct rt_serial_device rt_serial_t;
diff --git a/components/drivers/include/drivers/serial_v2.h b/components/drivers/include/drivers/serial_v2.h
index a449372e8a..b1020aaf99 100644
--- a/components/drivers/include/drivers/serial_v2.h
+++ b/components/drivers/include/drivers/serial_v2.h
@@ -158,6 +158,8 @@ struct rt_serial_device
void *serial_rx;
void *serial_tx;
+
+ struct rt_device_notify rx_notify;
};
/**
diff --git a/components/drivers/include/ipc/pipe.h b/components/drivers/include/ipc/pipe.h
index 08b9f266c8..5f64506011 100644
--- a/components/drivers/include/ipc/pipe.h
+++ b/components/drivers/include/ipc/pipe.h
@@ -20,16 +20,18 @@ struct rt_pipe_device
{
struct rt_device parent;
rt_bool_t is_named;
+#ifdef RT_USING_POSIX_DEVIO
+ int pipeno; /* for unamed pipe */
+#endif
/* ring buffer in pipe device */
struct rt_ringbuffer *fifo;
rt_uint16_t bufsz;
- rt_uint8_t readers;
- rt_uint8_t writers;
-
rt_wqueue_t reader_queue;
rt_wqueue_t writer_queue;
+ int writer;
+ int reader;
struct rt_mutex lock;
};
diff --git a/components/drivers/include/ipc/waitqueue.h b/components/drivers/include/ipc/waitqueue.h
index fbf5f93142..0727810696 100644
--- a/components/drivers/include/ipc/waitqueue.h
+++ b/components/drivers/include/ipc/waitqueue.h
@@ -43,6 +43,8 @@ rt_inline void rt_wqueue_init(rt_wqueue_t *queue)
void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node);
void rt_wqueue_remove(struct rt_wqueue_node *node);
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int timeout);
+int rt_wqueue_wait_killable(rt_wqueue_t *queue, int condition, int timeout);
+int rt_wqueue_wait_interruptible(rt_wqueue_t *queue, int condition, int timeout);
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key);
#define DEFINE_WAIT_FUNC(name, function) \
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index 18c3ef9cd4..c7a61c1994 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -157,6 +157,10 @@ extern "C" {
#include "drivers/touch.h"
#endif
+#ifdef RT_USING_DEV_BUS
+#include "drivers/rt_dev_bus.h"
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/components/drivers/ipc/completion.c b/components/drivers/ipc/completion.c
index 84dfb740b1..3f7644216b 100644
--- a/components/drivers/ipc/completion.c
+++ b/components/drivers/ipc/completion.c
@@ -80,11 +80,14 @@ rt_err_t rt_completion_wait(struct rt_completion *completion,
thread->error = RT_EOK;
/* suspend thread */
- rt_thread_suspend(thread);
+ rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
/* add to suspended list */
rt_list_insert_before(&(completion->suspended_list),
&(thread->tlist));
+ /* current context checking */
+ RT_DEBUG_NOT_IN_INTERRUPT;
+
/* start timer */
if (timeout > 0)
{
diff --git a/components/drivers/ipc/dataqueue.c b/components/drivers/ipc/dataqueue.c
index 4b1a14add9..6b53962384 100644
--- a/components/drivers/ipc/dataqueue.c
+++ b/components/drivers/ipc/dataqueue.c
@@ -119,7 +119,7 @@ rt_err_t rt_data_queue_push(struct rt_data_queue *queue,
thread->error = RT_EOK;
/* suspend thread on the push list */
- rt_thread_suspend(thread);
+ rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
rt_list_insert_before(&(queue->suspended_push_list), &(thread->tlist));
/* start timer */
if (timeout > 0)
@@ -237,7 +237,7 @@ rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
thread->error = RT_EOK;
/* suspend thread on the pop list */
- rt_thread_suspend(thread);
+ rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
rt_list_insert_before(&(queue->suspended_pop_list), &(thread->tlist));
/* start timer */
if (timeout > 0)
diff --git a/components/drivers/ipc/pipe.c b/components/drivers/ipc/pipe.c
index 5483ffa549..7567a73482 100644
--- a/components/drivers/ipc/pipe.c
+++ b/components/drivers/ipc/pipe.c
@@ -19,6 +19,28 @@
#include <poll.h>
#include <sys/ioctl.h>
#include <dfs_file.h>
+#include <resource_id.h>
+
+/* check RT_UNAMED_PIPE_NUMBER */
+
+#ifndef RT_UNAMED_PIPE_NUMBER
+#define RT_UNAMED_PIPE_NUMBER 64
+#endif
+
+#define BITS(x) _BITS(x)
+#define _BITS(x) (sizeof(#x) - 1)
+
+struct check_rt_unamed_pipe_number
+{
+ /* -4 for "pipe" prefix */
+ /* -1 for '\0' postfix */
+ char _check[RT_NAME_MAX - 4 - 1 - BITS(RT_UNAMED_PIPE_NUMBER)];
+};
+
+/* check end */
+
+static void *resoure_id[RT_UNAMED_PIPE_NUMBER];
+static resource_id_t id_mgr = RESOURCE_ID_INIT(RT_UNAMED_PIPE_NUMBER, resoure_id);
/**
* @brief This function will open a pipe.
@@ -33,16 +55,26 @@
static int pipe_fops_open(struct dfs_fd *fd)
{
int rc = 0;
- rt_device_t device;
rt_pipe_t *pipe;
- pipe = (rt_pipe_t *)fd->data;
- if (!pipe) return -1;
+ pipe = (rt_pipe_t *)fd->vnode->data;
+ if (!pipe)
+ {
+ return -1;
+ }
+
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
- device = &(pipe->parent);
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
+ if ((fd->flags & O_RDONLY) == O_RDONLY)
+ {
+ pipe->reader = 1;
+ }
- if (device->ref_count == 0)
+ if ((fd->flags & O_WRONLY) == O_WRONLY)
+ {
+ pipe->writer = 1;
+ }
+ if (fd->vnode->ref_count == 1)
{
pipe->fifo = rt_ringbuffer_create(pipe->bufsz);
if (pipe->fifo == RT_NULL)
@@ -52,23 +84,8 @@ static int pipe_fops_open(struct dfs_fd *fd)
}
}
- switch (fd->flags & O_ACCMODE)
- {
- case O_RDONLY:
- pipe->readers ++;
- break;
- case O_WRONLY:
- pipe->writers ++;
- break;
- case O_RDWR:
- pipe->readers ++;
- pipe->writers ++;
- break;
- }
- device->ref_count ++;
-
__exit:
- rt_mutex_release(&(pipe->lock));
+ rt_mutex_release(&pipe->lock);
return rc;
}
@@ -87,47 +104,41 @@ static int pipe_fops_close(struct dfs_fd *fd)
rt_device_t device;
rt_pipe_t *pipe;
- pipe = (rt_pipe_t *)fd->data;
- if (!pipe) return -1;
-
- device = &(pipe->parent);
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
-
- switch (fd->flags & O_ACCMODE)
+ pipe = (rt_pipe_t *)fd->vnode->data;
+ if (!pipe)
{
- case O_RDONLY:
- pipe->readers --;
- break;
- case O_WRONLY:
- pipe->writers --;
- break;
- case O_RDWR:
- pipe->readers --;
- pipe->writers --;
- break;
+ return -1;
}
- if (pipe->writers == 0)
+ device = &pipe->parent;
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
+
+ if ((fd->flags & O_RDONLY) == O_RDONLY)
{
- rt_wqueue_wakeup(&(pipe->reader_queue), (void *)(POLLIN | POLLERR | POLLHUP));
+ pipe->reader = 0;
}
- if (pipe->readers == 0)
+ if ((fd->flags & O_WRONLY) == O_WRONLY)
{
- rt_wqueue_wakeup(&(pipe->writer_queue), (void *)(POLLOUT | POLLERR | POLLHUP));
+ pipe->writer = 0;
+ while (!rt_list_isempty(&pipe->reader_queue.waiting_list))
+ {
+ rt_wqueue_wakeup(&pipe->reader_queue, (void*)POLLIN);
+ }
}
- if (device->ref_count == 1)
+ if (fd->vnode->ref_count == 1)
{
if (pipe->fifo != RT_NULL)
+ {
rt_ringbuffer_destroy(pipe->fifo);
+ }
pipe->fifo = RT_NULL;
}
- device->ref_count --;
- rt_mutex_release(&(pipe->lock));
+ rt_mutex_release(&pipe->lock);
- if (device->ref_count == 0 && pipe->is_named == RT_FALSE)
+ if (fd->vnode->ref_count == 1 && pipe->is_named == RT_FALSE)
{
/* delete the unamed pipe */
rt_pipe_delete(device->parent.name);
@@ -158,15 +169,15 @@ static int pipe_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
rt_pipe_t *pipe;
int ret = 0;
- pipe = (rt_pipe_t *)fd->data;
+ pipe = (rt_pipe_t *)fd->vnode->data;
switch (cmd)
{
case FIONREAD:
- *((int *)args) = rt_ringbuffer_data_len(pipe->fifo);
+ *((int*)args) = rt_ringbuffer_data_len(pipe->fifo);
break;
case FIONWRITE:
- *((int *)args) = rt_ringbuffer_space_len(pipe->fifo);
+ *((int*)args) = rt_ringbuffer_space_len(pipe->fifo);
break;
default:
ret = -EINVAL;
@@ -194,24 +205,16 @@ static int pipe_fops_read(struct dfs_fd *fd, void *buf, size_t count)
int len = 0;
rt_pipe_t *pipe;
- pipe = (rt_pipe_t *)fd->data;
+ pipe = (rt_pipe_t *)fd->vnode->data;
/* no process has the pipe open for writing, return end-of-file */
- if (pipe->writers == 0)
- return 0;
-
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
while (1)
{
- if (pipe->writers == 0)
- {
- goto out;
- }
-
len = rt_ringbuffer_get(pipe->fifo, buf, count);
- if (len > 0)
+ if (len > 0 || pipe->writer == 0)
{
break;
}
@@ -224,14 +227,14 @@ static int pipe_fops_read(struct dfs_fd *fd, void *buf, size_t count)
}
rt_mutex_release(&pipe->lock);
- rt_wqueue_wakeup(&(pipe->writer_queue), (void *)POLLOUT);
- rt_wqueue_wait(&(pipe->reader_queue), 0, -1);
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
+ rt_wqueue_wakeup(&pipe->writer_queue, (void*)POLLOUT);
+ rt_wqueue_wait(&pipe->reader_queue, 0, -1);
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
}
}
/* wakeup writer */
- rt_wqueue_wakeup(&(pipe->writer_queue), (void *)POLLOUT);
+ rt_wqueue_wakeup(&pipe->writer_queue, (void*)POLLOUT);
out:
rt_mutex_release(&pipe->lock);
@@ -259,29 +262,18 @@ static int pipe_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
int ret = 0;
uint8_t *pbuf;
- pipe = (rt_pipe_t *)fd->data;
-
- if (pipe->readers == 0)
- {
- ret = -EPIPE;
- goto out;
- }
+ pipe = (rt_pipe_t *)fd->vnode->data;
if (count == 0)
+ {
return 0;
+ }
- pbuf = (uint8_t *)buf;
+ pbuf = (uint8_t*)buf;
rt_mutex_take(&pipe->lock, -1);
while (1)
{
- if (pipe->readers == 0)
- {
- if (ret == 0)
- ret = -EPIPE;
- break;
- }
-
len = rt_ringbuffer_put(pipe->fifo, pbuf, count - ret);
ret += len;
pbuf += len;
@@ -305,19 +297,18 @@ static int pipe_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
}
rt_mutex_release(&pipe->lock);
- rt_wqueue_wakeup(&(pipe->reader_queue), (void *)POLLIN);
+ rt_wqueue_wakeup(&pipe->reader_queue, (void*)POLLIN);
/* pipe full, waiting on suspended write list */
- rt_wqueue_wait(&(pipe->writer_queue), 0, -1);
+ rt_wqueue_wait(&pipe->writer_queue, 0, -1);
rt_mutex_take(&pipe->lock, -1);
}
rt_mutex_release(&pipe->lock);
if (wakeup)
{
- rt_wqueue_wakeup(&(pipe->reader_queue), (void *)POLLIN);
+ rt_wqueue_wakeup(&pipe->reader_queue, (void*)POLLIN);
}
-out:
return ret;
}
@@ -339,10 +330,10 @@ static int pipe_fops_poll(struct dfs_fd *fd, rt_pollreq_t *req)
int mask = 0;
rt_pipe_t *pipe;
int mode = 0;
- pipe = (rt_pipe_t *)fd->data;
+ pipe = (rt_pipe_t *)fd->vnode->data;
- rt_poll_add(&(pipe->reader_queue), req);
- rt_poll_add(&(pipe->writer_queue), req);
+ rt_poll_add(&pipe->reader_queue, req);
+ rt_poll_add(&pipe->writer_queue, req);
switch (fd->flags & O_ACCMODE)
{
@@ -363,10 +354,6 @@ static int pipe_fops_poll(struct dfs_fd *fd, rt_pollreq_t *req)
{
mask |= POLLIN;
}
- if (pipe->writers == 0)
- {
- mask |= POLLHUP;
- }
}
if (mode & 2)
@@ -375,10 +362,6 @@ static int pipe_fops_poll(struct dfs_fd *fd, rt_pollreq_t *req)
{
mask |= POLLOUT;
}
- if (pipe->readers == 0)
- {
- mask |= POLLERR;
- }
}
return mask;
@@ -410,7 +393,7 @@ static const struct dfs_file_ops pipe_fops =
* When the return value is -RT_EINVAL, it means the device handle is empty.
* When the return value is -RT_ENOMEM, it means insufficient memory allocation failed.
*/
-static rt_err_t rt_pipe_open(rt_device_t device, rt_uint16_t oflag)
+rt_err_t rt_pipe_open(rt_device_t device, rt_uint16_t oflag)
{
rt_pipe_t *pipe = (rt_pipe_t *)device;
rt_err_t ret = RT_EOK;
@@ -421,7 +404,7 @@ static rt_err_t rt_pipe_open(rt_device_t device, rt_uint16_t oflag)
goto __exit;
}
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
if (pipe->fifo == RT_NULL)
{
@@ -432,7 +415,7 @@ static rt_err_t rt_pipe_open(rt_device_t device, rt_uint16_t oflag)
}
}
- rt_mutex_release(&(pipe->lock));
+ rt_mutex_release(&pipe->lock);
__exit:
return ret;
@@ -447,20 +430,20 @@ __exit:
* When the return value is RT_EOK, the operation is successful.
* When the return value is -RT_EINVAL, it means the device handle is empty.
*/
-static rt_err_t rt_pipe_close(rt_device_t device)
+rt_err_t rt_pipe_close(rt_device_t device)
{
rt_pipe_t *pipe = (rt_pipe_t *)device;
- if (device == RT_NULL) return -RT_EINVAL;
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
-
- if (device->ref_count == 1)
+ if (device == RT_NULL)
{
- rt_ringbuffer_destroy(pipe->fifo);
- pipe->fifo = RT_NULL;
+ return -RT_EINVAL;
}
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
+
+ rt_ringbuffer_destroy(pipe->fifo);
+ pipe->fifo = RT_NULL;
- rt_mutex_release(&(pipe->lock));
+ rt_mutex_release(&pipe->lock);
return RT_EOK;
}
@@ -479,7 +462,7 @@ static rt_err_t rt_pipe_close(rt_device_t device)
* @return Return the length of data read.
* When the return value is 0, it means the pipe device handle is empty or the count is 0.
*/
-static rt_size_t rt_pipe_read(rt_device_t device, rt_off_t pos, void *buffer, rt_size_t count)
+rt_size_t rt_pipe_read(rt_device_t device, rt_off_t pos, void *buffer, rt_size_t count)
{
uint8_t *pbuf;
rt_size_t read_bytes = 0;
@@ -487,18 +470,24 @@ static rt_size_t rt_pipe_read(rt_device_t device, rt_off_t pos, void *buffer, rt
if (device == RT_NULL)
{
- rt_set_errno(EINVAL);
+ rt_set_errno(-EINVAL);
+ return 0;
+ }
+ if (count == 0)
+ {
return 0;
}
- if (count == 0) return 0;
- pbuf = (uint8_t *)buffer;
- rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
+ pbuf = (uint8_t*)buffer;
+ rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
while (read_bytes < count)
{
- int len = rt_ringbuffer_get(pipe->fifo, &pbuf[read_bytes], (rt_uint16_t)(count - read_bytes));
- if (len <= 0) break;
+ int len = rt_ringbuffer_get(pipe->fifo, &pbuf[read_bytes], count - read_bytes);
+ if (len <= 0)
+ {
+ break;
+ }
read_bytes += len;
}
@@ -521,7 +510,7 @@ static rt_size_t rt_pipe_read(rt_device_t device, rt_off_t pos, void *buffer, rt
* @return Return the length of data written.
* When the return value is 0, it means the pipe device handle is empty or the count is 0.
*/
-static rt_size_t rt_pipe_write(rt_device_t device, rt_off_t pos, const void *buffer, rt_size_t count)
+rt_size_t rt_pipe_write(rt_device_t device, rt_off_t pos, const void *buffer, rt_size_t count)
{
uint8_t *pbuf;
rt_size_t write_bytes = 0;
@@ -529,18 +518,24 @@ static rt_size_t rt_pipe_write(rt_device_t device, rt_off_t pos, const void *buf
if (device == RT_NULL)
{
- rt_set_errno(EINVAL);
+ rt_set_errno(-EINVAL);
+ return 0;
+ }
+ if (count == 0)
+ {
return 0;
}
- if (count == 0) return 0;
- pbuf = (uint8_t *)buffer;
+ pbuf = (uint8_t*)buffer;
rt_mutex_take(&pipe->lock, -1);
while (write_bytes < count)
{
- int len = rt_ringbuffer_put(pipe->fifo, &pbuf[write_bytes], (rt_uint16_t)(count - write_bytes));
- if (len <= 0) break;
+ int len = rt_ringbuffer_put(pipe->fifo, &pbuf[write_bytes], count - write_bytes);
+ if (len <= 0)
+ {
+ break;
+ }
write_bytes += len;
}
@@ -560,7 +555,7 @@ static rt_size_t rt_pipe_write(rt_device_t device, rt_off_t pos, const void *buf
*
* @return Always return RT_EOK.
*/
-static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
+rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
{
return RT_EOK;
}
@@ -599,14 +594,19 @@ rt_pipe_t *rt_pipe_create(const char *name, int bufsz)
rt_memset(pipe, 0, sizeof(rt_pipe_t));
pipe->is_named = RT_TRUE; /* initialize as a named pipe */
- rt_mutex_init(&(pipe->lock), name, RT_IPC_FLAG_PRIO);
- rt_wqueue_init(&(pipe->reader_queue));
- rt_wqueue_init(&(pipe->writer_queue));
+#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
+ pipe->pipeno = -1;
+#endif
+ rt_mutex_init(&pipe->lock, name, RT_IPC_FLAG_FIFO);
+ rt_wqueue_init(&pipe->reader_queue);
+ rt_wqueue_init(&pipe->writer_queue);
+ pipe->writer = 0;
+ pipe->reader = 0;
RT_ASSERT(bufsz < 0xFFFF);
pipe->bufsz = bufsz;
- dev = &(pipe->parent);
+ dev = &pipe->parent;
dev->type = RT_Device_Class_Pipe;
#ifdef RT_USING_DEVICE_OPS
dev->ops = &pipe_ops;
@@ -622,8 +622,12 @@ rt_pipe_t *rt_pipe_create(const char *name, int bufsz)
dev->rx_indicate = RT_NULL;
dev->tx_complete = RT_NULL;
- if (rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE) != 0)
+ if (rt_device_register(&pipe->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE) != 0)
{
+ rt_mutex_detach(&pipe->lock);
+#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
+ resource_id_put(&id_mgr, pipe->pipeno);
+#endif
rt_free(pipe);
return RT_NULL;
}
@@ -657,14 +661,12 @@ int rt_pipe_delete(const char *name)
{
rt_pipe_t *pipe;
- if (device->ref_count != 0)
- {
- return -RT_EBUSY;
- }
-
pipe = (rt_pipe_t *)device;
- rt_mutex_detach(&(pipe->lock));
+ rt_mutex_detach(&pipe->lock);
+#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
+ resource_id_put(&id_mgr, pipe->pipeno);
+#endif
rt_device_unregister(device);
/* close fifo ringbuffer */
@@ -677,12 +679,12 @@ int rt_pipe_delete(const char *name)
}
else
{
- result = -RT_EINVAL;
+ result = -ENODEV;
}
}
else
{
- result = -RT_EINVAL;
+ result = -ENODEV;
}
return result;
@@ -702,19 +704,26 @@ int rt_pipe_delete(const char *name)
int pipe(int fildes[2])
{
rt_pipe_t *pipe;
- char dname[RT_NAME_MAX];
- char dev_name[RT_NAME_MAX * 4];
- static int pipeno = 0;
+ char dname[8];
+ char dev_name[32];
+ int pipeno = 0;
- rt_snprintf(dname, sizeof(dname), "pipe%d", pipeno++);
+ pipeno = resource_id_get(&id_mgr);
+ if (pipeno == -1)
+ {
+ return -1;
+ }
+ rt_snprintf(dname, sizeof(dname), "pipe%d", pipeno);
pipe = rt_pipe_create(dname, RT_USING_POSIX_PIPE_SIZE);
if (pipe == RT_NULL)
{
+ resource_id_put(&id_mgr, pipeno);
return -1;
}
pipe->is_named = RT_FALSE; /* unamed pipe */
+ pipe->pipeno = pipeno;
rt_snprintf(dev_name, sizeof(dev_name), "/dev/%s", dname);
fildes[0] = open(dev_name, O_RDONLY, 0);
if (fildes[0] < 0)
diff --git a/components/drivers/ipc/waitqueue.c b/components/drivers/ipc/waitqueue.c
index 97b5075638..25ebc71f68 100644
--- a/components/drivers/ipc/waitqueue.c
+++ b/components/drivers/ipc/waitqueue.c
@@ -118,13 +118,14 @@ void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)
*
* @return Return 0 if the thread is woken up.
*/
-int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)
+static int _rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec, int suspend_flag)
{
int tick;
rt_thread_t tid = rt_thread_self();
rt_timer_t tmr = &(tid->thread_timer);
struct rt_wqueue_node __wait;
rt_base_t level;
+ rt_err_t ret;
/* current context checking */
RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
@@ -150,8 +151,14 @@ int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)
goto __exit_wakeup;
}
+ ret = rt_thread_suspend_with_flag(tid, suspend_flag);
+ if (ret != RT_EOK)
+ {
+ rt_hw_interrupt_enable(level);
+ /* suspend failed */
+ return -RT_EINTR;
+ }
rt_wqueue_add(queue, &__wait);
- rt_thread_suspend(tid);
/* start timer */
if (tick != RT_WAITING_FOREVER)
@@ -176,3 +183,18 @@ __exit_wakeup:
return tid->error;
}
+
+int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)
+{
+ return _rt_wqueue_wait(queue, condition, msec, RT_UNINTERRUPTIBLE);
+}
+
+int rt_wqueue_wait_killable(rt_wqueue_t *queue, int condition, int msec)
+{
+ return _rt_wqueue_wait(queue, condition, msec, RT_KILLABLE);
+}
+
+int rt_wqueue_wait_interruptible(rt_wqueue_t *queue, int condition, int msec)
+{
+ return _rt_wqueue_wait(queue, condition, msec, RT_INTERRUPTIBLE);
+}
diff --git a/components/drivers/ipc/workqueue.c b/components/drivers/ipc/workqueue.c
index 3dae192d0d..d9b98929c8 100644
--- a/components/drivers/ipc/workqueue.c
+++ b/components/drivers/ipc/workqueue.c
@@ -65,7 +65,7 @@ static void _workqueue_thread_entry(void *parameter)
if (rt_list_isempty(&(queue->work_list)))
{
/* no software timer exist, suspend self. */
- rt_thread_suspend(rt_thread_self());
+ rt_thread_suspend_with_flag(rt_thread_self(), RT_UNINTERRUPTIBLE);
rt_hw_interrupt_enable(level);
rt_schedule();
continue;
@@ -116,7 +116,7 @@ static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
/* whether the workqueue is doing work */
if (queue->work_current == RT_NULL &&
- ((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
+ ((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_STAT_MASK))
{
/* resume work thread */
rt_thread_resume(queue->work_thread);
@@ -198,7 +198,7 @@ static void _delayed_work_timeout_handler(void *parameter)
}
/* whether the workqueue is doing work */
if (queue->work_current == RT_NULL &&
- ((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
+ ((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_STAT_MASK))
{
/* resume work thread */
rt_thread_resume(queue->work_thread);
@@ -356,7 +356,7 @@ rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *wo
rt_list_insert_after(&queue->work_list, &(work->list));
/* whether the workqueue is doing work */
if (queue->work_current == RT_NULL &&
- ((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
+ ((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_STAT_MASK))
{
/* resume work thread */
rt_thread_resume(queue->work_thread);
diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript
index 72058eeeca..b0d0354cf4 100644
--- a/components/drivers/misc/SConscript
+++ b/components/drivers/misc/SConscript
@@ -23,6 +23,18 @@ if GetDepend(['RT_USING_PULSE_ENCODER']):
if GetDepend(['RT_USING_INPUT_CAPTURE']):
src = src + ['rt_inputcapture.c']
+if GetDepend(['RT_USING_DEV_BUS']):
+ src = src + ['rt_dev_bus.c']
+
+if GetDepend(['RT_USING_NULL']):
+ src = src + ['rt_null.c']
+
+if GetDepend(['RT_USING_ZERO']):
+ src = src + ['rt_zero.c']
+
+if GetDepend(['RT_USING_RANDOM']):
+ src = src + ['rt_random.c']
+
if len(src):
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
diff --git a/components/drivers/misc/rt_dev_bus.c b/components/drivers/misc/rt_dev_bus.c
new file mode 100644
index 0000000000..5e858d1781
--- /dev/null
+++ b/components/drivers/misc/rt_dev_bus.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-13 flybreak the first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#define DBG_TAG "dev_bus"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#if defined(RT_USING_POSIX_DEVIO)
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <dfs_file.h>
+
+static int bus_fops_open(struct dfs_fd *fd)
+{
+ LOG_D("bus fops open");
+ return 0;
+}
+
+static int bus_fops_close(struct dfs_fd *fd)
+{
+ LOG_D("bus fops close");
+ return 0;
+}
+
+static const struct dfs_file_ops bus_fops =
+{
+ bus_fops_open,
+ bus_fops_close,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+};
+#endif
+
+rt_device_t rt_device_bus_create(char *name, int attach_size)
+{
+ rt_err_t result = RT_EOK;
+ rt_device_t dev = rt_device_create(RT_Device_Class_Bus, 0);
+
+ result = rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
+ if (result < 0)
+ {
+ rt_kprintf("dev bus [%s] register failed!, ret=%d\n", name, result);
+ return RT_NULL;
+ }
+#if defined(RT_USING_POSIX_DEVIO)
+ dev->fops = &bus_fops;
+#endif
+
+ LOG_D("bus create");
+ return dev;
+}
+
+rt_err_t rt_device_bus_destroy(rt_device_t dev)
+{
+ rt_device_unregister(dev);
+ dev->parent.type = RT_Object_Class_Device;
+ rt_device_destroy(dev);
+ LOG_D("bus destroy");
+ return RT_EOK;
+}
diff --git a/components/drivers/misc/rt_null.c b/components/drivers/misc/rt_null.c
new file mode 100644
index 0000000000..3e4cf6f3da
--- /dev/null
+++ b/components/drivers/misc/rt_null.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011-2020, Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-12-03 quanzhao the first version
+ */
+
+#include <time.h>
+#include <string.h>
+#include <rtthread.h>
+
+static struct rt_device null_dev;
+
+static rt_size_t null_read (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ return 0;
+}
+
+static rt_size_t null_write (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ return size;
+}
+
+static rt_err_t null_control (rt_device_t dev, int cmd, void *args)
+{
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops null_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ null_read,
+ null_write,
+ null_control
+};
+#endif
+
+int null_device_init(void)
+{
+ static rt_bool_t init_ok = RT_FALSE;
+
+ if (init_ok)
+ {
+ return 0;
+ }
+ RT_ASSERT(!rt_device_find("null"));
+ null_dev.type = RT_Device_Class_Miscellaneous;
+
+#ifdef RT_USING_DEVICE_OPS
+ null_dev.ops = &null_ops;
+#else
+ null_dev.init = RT_NULL;
+ null_dev.open = RT_NULL;
+ null_dev.close = RT_NULL;
+ null_dev.read = null_read;
+ null_dev.write = null_write;
+ null_dev.control = null_control;
+#endif
+
+ /* no private */
+ null_dev.user_data = RT_NULL;
+
+ rt_device_register(&null_dev, "null", RT_DEVICE_FLAG_RDWR);
+
+ init_ok = RT_TRUE;
+
+ return 0;
+}
+INIT_DEVICE_EXPORT(null_device_init);
+
diff --git a/components/drivers/misc/rt_random.c b/components/drivers/misc/rt_random.c
new file mode 100644
index 0000000000..1ea0480b7c
--- /dev/null
+++ b/components/drivers/misc/rt_random.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2011-2020, Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-12-18 quanzhao the first version
+ */
+
+#include <time.h>
+#include <string.h>
+#include <rtthread.h>
+
+static struct rt_device random_dev;
+static unsigned long seed;
+
+static rt_uint16_t calc_random(void)
+{
+ seed = 214013L * seed + 2531011L;
+ return (seed >> 16) & 0x7FFF; /* return bits 16~30 */
+}
+
+static rt_size_t random_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_uint16_t rand = calc_random();
+ ssize_t ret = sizeof(rand);
+ rt_memcpy(buffer, &rand, ret);
+ return ret;
+}
+
+static rt_size_t random_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ ssize_t ret = sizeof(seed);
+ rt_memcpy(&seed, buffer, ret);
+ return ret;
+}
+
+static rt_err_t random_control(rt_device_t dev, int cmd, void *args)
+{
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops random_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ random_read,
+ random_write,
+ random_control
+};
+#endif
+
+int random_device_init(void)
+{
+ static rt_bool_t init_ok = RT_FALSE;
+
+ if (init_ok)
+ {
+ return 0;
+ }
+ RT_ASSERT(!rt_device_find("random"));
+ random_dev.type = RT_Device_Class_Miscellaneous;
+
+#ifdef RT_USING_DEVICE_OPS
+ random_dev.ops = &random_ops;
+#else
+ random_dev.init = RT_NULL;
+ random_dev.open = RT_NULL;
+ random_dev.close = RT_NULL;
+ random_dev.read = random_read;
+ random_dev.write = random_write;
+ random_dev.control = random_control;
+#endif
+
+ /* no private */
+ random_dev.user_data = RT_NULL;
+
+ rt_device_register(&random_dev, "random", RT_DEVICE_FLAG_RDWR);
+
+ init_ok = RT_TRUE;
+
+ return 0;
+}
+INIT_DEVICE_EXPORT(random_device_init);
+
+static struct rt_device urandom_dev;
+static unsigned long useed;
+
+static rt_uint16_t calc_urandom(void)
+{
+ useed = 214013L * useed + 2531011L;
+ return (useed >> 16) & 0x7FFF; /* return bits 16~30 */
+}
+
+static rt_size_t random_uread(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_uint16_t rand = calc_urandom();
+ ssize_t ret = sizeof(rand);
+ rt_memcpy(buffer, &rand, ret);
+ return ret;
+}
+
+static rt_size_t random_uwrite(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ ssize_t ret = sizeof(useed);
+ rt_memcpy(&useed, buffer, ret);
+ return ret;
+}
+
+static rt_err_t random_ucontrol(rt_device_t dev, int cmd, void *args)
+{
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops urandom_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ random_uread,
+ random_uwrite,
+ random_ucontrol
+};
+#endif
+
+int urandom_device_init(void)
+{
+ static rt_bool_t init_ok = RT_FALSE;
+
+ if (init_ok)
+ {
+ return 0;
+ }
+ RT_ASSERT(!rt_device_find("urandom"));
+ urandom_dev.type = RT_Device_Class_Miscellaneous;
+
+#ifdef RT_USING_DEVICE_OPS
+ urandom_dev.ops = &urandom_ops;
+#else
+ urandom_dev.init = RT_NULL;
+ urandom_dev.open = RT_NULL;
+ urandom_dev.close = RT_NULL;
+ urandom_dev.read = random_uread;
+ urandom_dev.write = random_uwrite;
+ urandom_dev.control = random_ucontrol;
+#endif
+
+ /* no private */
+ urandom_dev.user_data = RT_NULL;
+
+ rt_device_register(&urandom_dev, "urandom", RT_DEVICE_FLAG_RDWR);
+
+ init_ok = RT_TRUE;
+
+ return 0;
+}
+INIT_DEVICE_EXPORT(urandom_device_init);
diff --git a/components/drivers/misc/rt_zero.c b/components/drivers/misc/rt_zero.c
new file mode 100644
index 0000000000..f2657a2360
--- /dev/null
+++ b/components/drivers/misc/rt_zero.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011-2020, Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-12-03 quanzhao the first version
+ */
+
+#include <time.h>
+#include <string.h>
+#include <rtthread.h>
+
+static struct rt_device zero_dev;
+
+static rt_size_t zero_read (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_memset(buffer, 0, size);
+ return size;
+}
+
+static rt_size_t zero_write (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ return size;
+}
+
+static rt_err_t zero_control (rt_device_t dev, int cmd, void *args)
+{
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops zero_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ zero_read,
+ zero_write,
+ zero_control
+};
+#endif
+
+int zero_device_init(void)
+{
+ static rt_bool_t init_ok = RT_FALSE;
+
+ if (init_ok)
+ {
+ return 0;
+ }
+ RT_ASSERT(!rt_device_find("zero"));
+ zero_dev.type = RT_Device_Class_Miscellaneous;
+
+#ifdef RT_USING_DEVICE_OPS
+ zero_dev.ops = &zero_ops;
+#else
+ zero_dev.init = RT_NULL;
+ zero_dev.open = RT_NULL;
+ zero_dev.close = RT_NULL;
+ zero_dev.read = zero_read;
+ zero_dev.write = zero_write;
+ zero_dev.control = zero_control;
+#endif
+
+ /* no private */
+ zero_dev.user_data = RT_NULL;
+
+ rt_device_register(&zero_dev, "zero", RT_DEVICE_FLAG_RDWR);
+
+ init_ok = RT_TRUE;
+
+ return 0;
+}
+INIT_DEVICE_EXPORT(zero_device_init);
+
diff --git a/components/drivers/sdio/SConscript b/components/drivers/sdio/SConscript
index 95dcfa2578..d5b6eb1cb9 100644
--- a/components/drivers/sdio/SConscript
+++ b/components/drivers/sdio/SConscript
@@ -7,6 +7,7 @@ block_dev.c
mmcsd_core.c
sd.c
sdio.c
+gpt.c
mmc.c
""")
diff --git a/components/drivers/sdio/block_dev.c b/components/drivers/sdio/block_dev.c
index 522fa753db..70159af30c 100644
--- a/components/drivers/sdio/block_dev.c
+++ b/components/drivers/sdio/block_dev.c
@@ -12,6 +12,7 @@
#include <dfs_fs.h>
#include <drivers/mmcsd_core.h>
+#include <drivers/gpt.h>
#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
@@ -21,6 +22,7 @@
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
+static rt_list_t blk_devices = RT_LIST_OBJECT_INIT(blk_devices);
#define BLK_MIN(a, b) ((a) < (b) ? (a) : (b))
@@ -37,6 +39,67 @@ struct mmcsd_blk_device
#ifndef RT_MMCSD_MAX_PARTITION
#define RT_MMCSD_MAX_PARTITION 16
#endif
+#define RT_GPT_PARTITION_MAX 128
+
+static int __send_status(struct rt_mmcsd_card *card, rt_uint32_t *status, unsigned retries)
+{
+ int err;
+ struct rt_mmcsd_cmd cmd;
+
+ cmd.busy_timeout = 0;
+ cmd.cmd_code = SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = RESP_R1 | CMD_AC;
+ err = mmcsd_send_cmd(card->host, &cmd, retries);
+ if (err)
+ return err;
+
+ if (status)
+ *status = cmd.resp[0];
+
+ return 0;
+}
+
+static int card_busy_detect(struct rt_mmcsd_card *card, unsigned int timeout_ms,
+ rt_uint32_t *resp_errs)
+{
+ int timeout = rt_tick_from_millisecond(timeout_ms);
+ int err = 0;
+ rt_uint32_t status;
+ rt_tick_t start;
+
+ start = rt_tick_get();
+ do
+ {
+ rt_bool_t out = (int)(rt_tick_get() - start) > timeout;
+
+ err = __send_status(card, &status, 5);
+ if (err)
+ {
+ LOG_E("error %d requesting status", err);
+ return err;
+ }
+
+ /* Accumulate any response error bits seen */
+ if (resp_errs)
+ *resp_errs |= status;
+
+ if (out)
+ {
+ LOG_E("wait card busy timeout");
+ return -RT_ETIMEOUT;
+ }
+ /*
+ * Some cards mishandle the status bits,
+ * so make sure to check both the busy
+ * indication and the card state.
+ */
+ }
+ while (!(status & R1_READY_FOR_DATA) ||
+ (R1_CURRENT_STATE(status) == 7));
+
+ return err;
+}
rt_int32_t mmcsd_num_wr_blocks(struct rt_mmcsd_card *card)
{
@@ -73,7 +136,7 @@ rt_int32_t mmcsd_num_wr_blocks(struct rt_mmcsd_card *card)
timeout_us = data.timeout_ns / 1000;
timeout_us += data.timeout_clks * 1000 /
- (card->host->io_cfg.clock / 1000);
+ (card->host->io_cfg.clock / 1000);
if (timeout_us > 100000)
{
@@ -148,44 +211,29 @@ static rt_err_t rt_mmcsd_req_blk(struct rt_mmcsd_card *card,
w_cmd = WRITE_BLOCK;
}
+ if (!controller_is_spi(card->host) && (card->flags & 0x8000))
+ {
+ /* last request is WRITE,need check busy */
+ card_busy_detect(card, 10000, RT_NULL);
+ }
+
if (!dir)
{
cmd.cmd_code = r_cmd;
data.flags |= DATA_DIR_READ;
+ card->flags &= 0x7fff;
}
else
{
cmd.cmd_code = w_cmd;
data.flags |= DATA_DIR_WRITE;
+ card->flags |= 0x8000;
}
mmcsd_set_data_timeout(&data, card);
data.buf = buf;
- mmcsd_send_request(host, &req);
- if (!controller_is_spi(card->host) && dir != 0)
- {
- do
- {
- rt_int32_t err;
-
- cmd.cmd_code = SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = RESP_R1 | CMD_AC;
- err = mmcsd_send_cmd(card->host, &cmd, 5);
- if (err)
- {
- LOG_E("error %d requesting status", err);
- break;
- }
- /*
- * Some cards mishandle the status bits,
- * so make sure to check both the busy
- * indication and the card state.
- */
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd.resp[0]) == 7));
- }
+ mmcsd_send_request(host, &req);
mmcsd_host_unlock(host);
@@ -193,7 +241,7 @@ static rt_err_t rt_mmcsd_req_blk(struct rt_mmcsd_card *card,
{
LOG_E("mmcsd request blocks error");
LOG_E("%d,%d,%d, 0x%08x,0x%08x",
- cmd.err, data.err, stop.err, data.flags, sector);
+ cmd.err, data.err, stop.err, data.flags, sector);
return -RT_ERROR;
}
@@ -224,6 +272,8 @@ static rt_err_t rt_mmcsd_control(rt_device_t dev, int cmd, void *args)
case RT_DEVICE_CTRL_BLK_GETGEOME:
rt_memcpy(args, &blk_dev->geometry, sizeof(struct rt_device_blk_geometry));
break;
+ case RT_DEVICE_CTRL_BLK_PARTITION:
+ rt_memcpy(args, &blk_dev->part, sizeof(struct dfs_partition));
default:
break;
}
@@ -253,7 +303,7 @@ static rt_size_t rt_mmcsd_read(rt_device_t dev,
while (remain_size)
{
req_size = (remain_size > blk_dev->max_req_size) ? blk_dev->max_req_size : remain_size;
- err = rt_mmcsd_req_blk(blk_dev->card, part->offset + pos + offset, rd_ptr, req_size, 0);
+ err = rt_mmcsd_req_blk(blk_dev->card, pos + offset, rd_ptr, req_size, 0);
if (err)
break;
offset += req_size;
@@ -294,7 +344,7 @@ static rt_size_t rt_mmcsd_write(rt_device_t dev,
while (remain_size)
{
req_size = (remain_size > blk_dev->max_req_size) ? blk_dev->max_req_size : remain_size;
- err = rt_mmcsd_req_blk(blk_dev->card, part->offset + pos + offset, wr_ptr, req_size, 1);
+ err = rt_mmcsd_req_blk(blk_dev->card, pos + offset, wr_ptr, req_size, 1);
if (err)
break;
offset += req_size;
@@ -338,6 +388,19 @@ static rt_int32_t mmcsd_set_blksize(struct rt_mmcsd_card *card)
return 0;
}
+rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count)
+{
+ rt_uint8_t status = 0;
+
+ status = mmcsd_set_blksize(card);
+ if (status)
+ {
+ return status;
+ }
+ rt_thread_mdelay(1);
+ status = rt_mmcsd_req_blk(card, lba, buffer, count, 0);
+ return status;
+}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops mmcsd_blk_ops =
@@ -351,44 +414,31 @@ const static struct rt_device_ops mmcsd_blk_ops =
};
#endif
-
-static struct mmcsd_blk_device * rt_mmcsd_create_blkdev(struct rt_mmcsd_card *card, const char* dname, struct dfs_partition* psPart)
+rt_int32_t gpt_device_probe(struct rt_mmcsd_card *card)
{
- struct mmcsd_blk_device *blk_dev;
- char sname[12];
+ rt_int32_t err = RT_EOK;
+ rt_uint8_t i, status;
+ char dname[10];
+ char sname[16];
+ struct mmcsd_blk_device *blk_dev = RT_NULL;
blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
if (!blk_dev)
{
LOG_E("mmcsd:malloc memory failed!");
- return RT_NULL;
+ return -1;
}
- if (psPart != RT_NULL)
- {
- rt_memcpy(&blk_dev->part, psPart, sizeof(struct dfs_partition));
- blk_dev->geometry.sector_count = psPart->size;
- }
- else
- {
- blk_dev->part.offset = 0;
- blk_dev->part.size = 0;
- blk_dev->geometry.sector_count = card->card_capacity * (1024 / 512);
- }
-
- blk_dev->geometry.bytes_per_sector = 1<<9;
- blk_dev->geometry.block_size = card->card_blksize;
-
- rt_snprintf(sname, sizeof(sname), "sem_%s", dname);
- blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
-
blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
card->host->max_seg_size) >> 9,
(card->host->max_blk_count *
card->host->max_blk_size) >> 9);
-
+ blk_dev->part.offset = 0;
+ blk_dev->part.size = 0;
+ rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, 0);
+ blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
/* register mmcsd device */
- blk_dev->dev.type = RT_Device_Class_Block;
+ blk_dev->dev.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
blk_dev->dev.ops = &mmcsd_blk_ops;
#else
@@ -399,42 +449,100 @@ static struct mmcsd_blk_device * rt_mmcsd_create_blkdev(struct rt_mmcsd_card *ca
blk_dev->dev.write = rt_mmcsd_write;
blk_dev->dev.control = rt_mmcsd_control;
#endif
+ blk_dev->card = card;
+
+ blk_dev->geometry.bytes_per_sector = 1 << 9;
+ blk_dev->geometry.block_size = card->card_blksize;
+ blk_dev->geometry.sector_count =
+ card->card_capacity * (1024 / 512);
+
blk_dev->dev.user_data = blk_dev;
- blk_dev->card = card;
+ rt_device_register(&(blk_dev->dev), card->host->name,
+ RT_DEVICE_FLAG_RDWR);
+ rt_list_insert_after(&blk_devices, &blk_dev->list);
+
+ for (i = 0; i < RT_GPT_PARTITION_MAX; i++)
+ {
+ blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
+ if (!blk_dev)
+ {
+ LOG_E("mmcsd:malloc memory failed!");
+ break;
+ }
+ blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
+ card->host->max_seg_size) >> 9,
+ (card->host->max_blk_count *
+ card->host->max_blk_size) >> 9);
- rt_device_register(&blk_dev->dev, dname,
- RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
+ /* get the first partition */
+ status = gpt_get_partition_param(card, &blk_dev->part, i);
+ if (status == RT_EOK)
+ {
+ rt_snprintf(dname, sizeof(dname) - 1, "%s%d", card->host->name, i);
+ rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, i + 1);
+ blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
+
+ /* register mmcsd device */
+ blk_dev->dev.type = RT_Device_Class_Block;
+#ifdef RT_USING_DEVICE_OPS
+ blk_dev->dev.ops = &mmcsd_blk_ops;
+#else
+ blk_dev->dev.init = rt_mmcsd_init;
+ blk_dev->dev.open = rt_mmcsd_open;
+ blk_dev->dev.close = rt_mmcsd_close;
+ blk_dev->dev.read = rt_mmcsd_read;
+ blk_dev->dev.write = rt_mmcsd_write;
+ blk_dev->dev.control = rt_mmcsd_control;
+#endif
+ blk_dev->card = card;
- /* Insert to list. */
- rt_list_insert_after(&card->blk_devices, &blk_dev->list);
+ blk_dev->geometry.bytes_per_sector = 1 << 9;
+ blk_dev->geometry.block_size = card->card_blksize;
+ blk_dev->geometry.sector_count = blk_dev->part.size;
+
+ blk_dev->dev.user_data = blk_dev;
+
+ rt_device_register(&(blk_dev->dev), dname,
+ RT_DEVICE_FLAG_RDWR);
+ rt_list_insert_after(&blk_devices, &blk_dev->list);
+ }
+ else
+ {
+ rt_free(blk_dev);
+ blk_dev = RT_NULL;
+ break;
+ }
#ifdef RT_USING_DFS_MNTTABLE
- if ( blk_dev )
- {
- LOG_I("try to mount file system!");
- /* try to mount file system on this block device */
- dfs_mount_device(&(blk_dev->dev));
- }
+ if (blk_dev)
+ {
+ LOG_I("try to mount file system!");
+ /* try to mount file system on this block device */
+ dfs_mount_device(&(blk_dev->dev));
+ }
#endif
+ }
+ gpt_free();
- return blk_dev;
+ return err;
}
-rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
+rt_int32_t mbr_device_probe(struct rt_mmcsd_card *card)
{
rt_int32_t err = 0;
- rt_err_t status;
+ rt_uint8_t i, status;
rt_uint8_t *sector;
+ char dname[10];
+ char sname[16];
+ struct mmcsd_blk_device *blk_dev = RT_NULL;
err = mmcsd_set_blksize(card);
- if(err)
+ if (err)
{
return err;
}
-
- LOG_D("probe mmcsd block device!");
-
+ rt_thread_mdelay(1);
/* get the first sector to read partition table */
sector = (rt_uint8_t *)rt_malloc(SECTOR_SIZE);
if (sector == RT_NULL)
@@ -447,43 +555,104 @@ rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
status = rt_mmcsd_req_blk(card, 0, sector, 1, 0);
if (status == RT_EOK)
{
- rt_uint8_t i;
- char dname[8];
- struct dfs_partition part;
- struct mmcsd_blk_device *blk_dev = RT_NULL;
- rt_int32_t host_id = card->host->id;
+ blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
+ if (!blk_dev)
+ {
+ LOG_E("mmcsd:malloc memory failed!");
+ return -1;
+ }
+ blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
+ card->host->max_seg_size) >> 9,
+ (card->host->max_blk_count *
+ card->host->max_blk_size) >> 9);
+ blk_dev->part.offset = 0;
+ blk_dev->part.size = 0;
+ rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, 0);
+ blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
+ /* register mmcsd device */
+ blk_dev->dev.type = RT_Device_Class_Block;
+#ifdef RT_USING_DEVICE_OPS
+ blk_dev->dev.ops = &mmcsd_blk_ops;
+#else
+ blk_dev->dev.init = rt_mmcsd_init;
+ blk_dev->dev.open = rt_mmcsd_open;
+ blk_dev->dev.close = rt_mmcsd_close;
+ blk_dev->dev.read = rt_mmcsd_read;
+ blk_dev->dev.write = rt_mmcsd_write;
+ blk_dev->dev.control = rt_mmcsd_control;
+#endif
+ blk_dev->card = card;
- /* Initial blk_device link-list. */
- rt_list_init(&card->blk_devices);
+ blk_dev->geometry.bytes_per_sector = 1 << 9;
+ blk_dev->geometry.block_size = card->card_blksize;
+ blk_dev->geometry.sector_count =
+ card->card_capacity * (1024 / 512);
+ blk_dev->dev.user_data = blk_dev;
+
+ rt_device_register(&(blk_dev->dev), card->host->name,
+ RT_DEVICE_FLAG_RDWR);
+ rt_list_insert_after(&blk_devices, &blk_dev->list);
for (i = 0; i < RT_MMCSD_MAX_PARTITION; i++)
{
- /* Get the first partition */
- status = dfs_filesystem_get_partition(&part, sector, i);
+ blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
+ if (!blk_dev)
+ {
+ LOG_E("mmcsd:malloc memory failed!");
+ break;
+ }
+ blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
+ card->host->max_seg_size) >> 9,
+ (card->host->max_blk_count *
+ card->host->max_blk_size) >> 9);
+
+ /* get the first partition */
+ status = dfs_filesystem_get_partition(&blk_dev->part, sector, i);
if (status == RT_EOK)
{
- /* Given name is with allocated host id and its partition index. */
- rt_snprintf(dname, sizeof(dname), "sd%dp%d", host_id, i);
- blk_dev = rt_mmcsd_create_blkdev(card, (const char*)dname, &part);
- if ( blk_dev == RT_NULL )
- {
- err = -RT_ENOMEM;
- goto exit_rt_mmcsd_blk_probe;
- }
+ rt_snprintf(dname, sizeof(dname) - 1, "%s%d", card->host->name, i);
+ rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, i + 1);
+ blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
+
+ /* register mmcsd device */
+ blk_dev->dev.type = RT_Device_Class_Block;
+#ifdef RT_USING_DEVICE_OPS
+ blk_dev->dev.ops = &mmcsd_blk_ops;
+#else
+ blk_dev->dev.init = rt_mmcsd_init;
+ blk_dev->dev.open = rt_mmcsd_open;
+ blk_dev->dev.close = rt_mmcsd_close;
+ blk_dev->dev.read = rt_mmcsd_read;
+ blk_dev->dev.write = rt_mmcsd_write;
+ blk_dev->dev.control = rt_mmcsd_control;
+#endif
+ blk_dev->card = card;
+
+ blk_dev->geometry.bytes_per_sector = 1 << 9;
+ blk_dev->geometry.block_size = card->card_blksize;
+ blk_dev->geometry.sector_count = blk_dev->part.size;
+
+ blk_dev->dev.user_data = blk_dev;
+
+ rt_device_register(&(blk_dev->dev), dname,
+ RT_DEVICE_FLAG_RDWR);
+ rt_list_insert_after(&blk_devices, &blk_dev->list);
}
else
{
+ rt_free(blk_dev);
+ blk_dev = RT_NULL;
break;
}
- }
- /* Always create the super node, given name is with allocated host id. */
- rt_snprintf(dname, sizeof(dname), "sd%d", host_id);
- blk_dev = rt_mmcsd_create_blkdev(card, (const char*)dname, RT_NULL);
- if ( blk_dev == RT_NULL )
- {
- err = -RT_ENOMEM;
- goto exit_rt_mmcsd_blk_probe;
+#ifdef RT_USING_DFS_MNTTABLE
+ if (blk_dev)
+ {
+ LOG_I("try to mount file system!");
+ /* try to mount file system on this block device */
+ dfs_mount_device(&(blk_dev->dev));
+ }
+#endif
}
}
else
@@ -492,42 +661,45 @@ rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
err = -RT_ERROR;
}
-exit_rt_mmcsd_blk_probe:
-
/* release sector buffer */
rt_free(sector);
return err;
+
}
-void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card)
+rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
{
- rt_list_t *l, *n;
- struct mmcsd_blk_device *blk_dev;
+ uint32_t err = 0;
- if(card == RT_NULL)
+ LOG_D("probe mmcsd block device!");
+ if (check_gpt(card) != 0)
{
- LOG_E("card is null!");
- return;
+ err = gpt_device_probe(card);
}
-
- if(rt_list_isempty(&card->blk_devices))
+ else
{
- LOG_E("card blk_devices is empty!");
- return;
+ err = mbr_device_probe(card);
}
+ return err;
+}
- for (l = (&card->blk_devices)->next, n = l->next; l != &card->blk_devices; l = n, n=n->next)
+void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card)
+{
+ rt_list_t *l, *n;
+ struct mmcsd_blk_device *blk_dev;
+
+ for (l = (&blk_devices)->next, n = l->next; l != &blk_devices; l = n, n = n->next)
{
blk_dev = (struct mmcsd_blk_device *)rt_list_entry(l, struct mmcsd_blk_device, list);
if (blk_dev->card == card)
{
/* unmount file system */
- const char * mounted_path = dfs_filesystem_get_mounted_path(&(blk_dev->dev));
+ const char *mounted_path = dfs_filesystem_get_mounted_path(&(blk_dev->dev));
if (mounted_path)
{
- dfs_unmount(mounted_path);
- LOG_D("unmount file system %s for device %s.\r\n", mounted_path, blk_dev->dev.parent.name);
+ dfs_unmount(mounted_path);
+ LOG_D("unmount file system %s for device %s.\r\n", mounted_path, blk_dev->dev.parent.name);
}
rt_sem_delete(blk_dev->part.lock);
rt_device_unregister(&blk_dev->dev);
@@ -536,3 +708,15 @@ void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card)
}
}
}
+
+/*
+ * This function will initialize block device on the mmc/sd.
+ *
+ * @deprecated since 2.1.0, this function does not need to be invoked
+ * in the system initialization.
+ */
+int rt_mmcsd_blk_init(void)
+{
+ /* nothing */
+ return 0;
+}
diff --git a/components/drivers/sdio/gpt.c b/components/drivers/sdio/gpt.c
new file mode 100644
index 0000000000..19bc1ad453
--- /dev/null
+++ b/components/drivers/sdio/gpt.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-05-05 linzhenxing first version
+ */
+#include <rtthread.h>
+#include <dfs_fs.h>
+#include <drivers/gpt.h>
+#include <drivers/mmcsd_core.h>
+
+#define DBG_TAG "GPT"
+#ifdef RT_SDIO_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_SDIO_DEBUG */
+#include <rtdbg.h>
+
+#define min(a, b) a < b ? a : b
+static int force_gpt = 0;
+static gpt_header *_gpt;
+static gpt_entry *_ptes;
+#define GPT_TYPE 1
+#define MBR_TYPE 0
+
+static inline int efi_guidcmp (gpt_guid_t left, gpt_guid_t right)
+{
+ return rt_memcmp(&left, &right, sizeof (gpt_guid_t));
+}
+
+static uint32_t last_lba(struct rt_mmcsd_card *card)
+{
+ RT_ASSERT(card != RT_NULL);
+ return (card->card_sec_cnt) - 1;
+}
+
+static inline int pmbr_part_valid(gpt_mbr_record *part)
+{
+ if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
+ {
+ goto invalid;
+ }
+
+ /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
+ if ((uint32_t)(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
+ {
+ goto invalid;
+ }
+
+ return GPT_MBR_PROTECTIVE;
+invalid:
+ return 0;
+}
+
+/*
+*
+* return ret
+* ret = 0, invalid mbr
+* ret = 1, protect mbr
+* ret = 2, hybrid mbr
+*/
+int is_pmbr_valid(legacy_mbr *mbr, uint64_t total_sectors)
+{
+ uint32_t sz = 0;
+ int i, part = 0, ret = 0; /* invalid by default */
+
+ if (!mbr || (uint16_t)(mbr->signature) != MSDOS_MBR_SIGNATURE)
+ {
+ goto done;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ ret = pmbr_part_valid(&mbr->partition_record[i]);
+ if (ret == GPT_MBR_PROTECTIVE)
+ {
+ part = i;
+ /*
+ * Ok, we at least know that there's a protective MBR,
+ * now check if there are other partition types for
+ * hybrid MBR.
+ */
+ goto check_hybrid;
+ }
+ }
+
+ if (ret != GPT_MBR_PROTECTIVE)
+ {
+ goto done;
+ }
+
+check_hybrid:
+ for (i = 0; i < 4; i++)
+ {
+ if ((mbr->partition_record[i].os_type !=
+ EFI_PMBR_OSTYPE_EFI_GPT) &&
+ (mbr->partition_record[i].os_type != 0x00))
+ {
+ ret = GPT_MBR_HYBRID;
+ }
+
+ }
+
+ /*
+ * Protective MBRs take up the lesser of the whole disk
+ * or 2 TiB (32bit LBA), ignoring the rest of the disk.
+ * Some partitioning programs, nonetheless, choose to set
+ * the size to the maximum 32-bit limitation, disregarding
+ * the disk size.
+ *
+ * Hybrid MBRs do not necessarily comply with this.
+ *
+ * Consider a bad value here to be a warning to support dd'ing
+ * an image from a smaller disk to a larger disk.
+ */
+ if (ret == GPT_MBR_PROTECTIVE)
+ {
+ sz = (uint32_t)(mbr->partition_record[part].size_in_lba);
+ if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
+ {
+ LOG_I("GPT: mbr size in lba (%u) different than whole disk (%u).",
+ sz, min(total_sectors - 1, 0xFFFFFFFF));
+ }
+ }
+
+done:
+ return ret;
+
+}
+
+static gpt_entry *alloc_read_gpt_entries(struct rt_mmcsd_card *card, gpt_header *gpt)
+{
+ size_t count;
+ gpt_entry *pte;
+
+ if (!gpt)
+ {
+ return RT_NULL;
+ }
+
+ count = (size_t)(gpt->num_partition_entries) * (gpt->sizeof_partition_entry);
+ if (!count)
+ {
+ return RT_NULL;
+ }
+
+ pte = rt_malloc(count);
+ if (!pte)
+ return RT_NULL;
+
+ if (read_lba(card, (size_t)(gpt->partition_entry_lba),(uint8_t *)pte, count/512) != RT_EOK)
+ {
+ rt_free(pte);
+ return RT_NULL;
+ }
+ return pte;
+
+}
+
+static gpt_header *alloc_read_gpt_header(struct rt_mmcsd_card *card, size_t lba)
+{
+ gpt_header *gpt;
+ void *buf;
+
+ buf = rt_malloc(512);
+ if (!buf)
+ {
+ return RT_NULL;
+ }
+
+ if (read_lba(card, lba, (uint8_t *)buf, 1) != RT_EOK)
+ {
+ rt_free(buf);
+ return RT_NULL;
+ }
+ gpt = (gpt_header *)buf;
+
+ return gpt;
+}
+
+static int is_gpt_valid(struct rt_mmcsd_card *card, size_t lba, gpt_header **gpt, gpt_entry **ptes)
+{
+ size_t lastlba;
+
+ if (!ptes)
+ {
+ return 0;
+ }
+
+ if (!(*gpt = alloc_read_gpt_header(card, lba)))
+ {
+ return 0;
+ }
+
+ /* Check the GUID Partition Table signature */
+ if ((uint64_t)((*gpt)->signature) != GPT_HEADER_SIGNATURE)
+ {
+ LOG_E("GUID Partition Table Header signature is wrong:"
+ "%ld != %ld",(uint64_t)((*gpt)->signature),(uint64_t)GPT_HEADER_SIGNATURE);
+ goto fail;
+ }
+
+ /* Check the GUID Partition Table header size is too small */
+ if ((uint32_t)((*gpt)->header_size) < sizeof(gpt_header))
+ {
+ LOG_E("GUID Partition Table Header size is too small: %u < %zu",
+ (uint32_t)((*gpt)->header_size),sizeof(gpt_header));
+ goto fail;
+ }
+
+ /* Check that the start_lba entry points to the LBA that contains
+ * the GUID Partition Table */
+ if ((uint64_t)((*gpt)->start_lba) != lba)
+ {
+ LOG_E("GPT start_lba incorrect: %ld != %ld",
+ (uint64_t)((*gpt)->start_lba),
+ (uint64_t)lba);
+ goto fail;
+ }
+
+ /* Check the first_usable_lba and last_usable_lba are
+ * within the disk.
+ */
+ lastlba = last_lba(card);
+ if ((uint64_t)((*gpt)->first_usable_lba) > lastlba)
+ {
+ LOG_E("GPT: first_usable_lba incorrect: %ld > %ld",
+ ((uint64_t)((*gpt)->first_usable_lba)),
+ (size_t)lastlba);
+ goto fail;
+ }
+
+ if ((uint64_t)((*gpt)->last_usable_lba) > lastlba)
+ {
+ LOG_E("GPT: last_usable_lba incorrect: %ld > %ld",
+ (uint64_t)((*gpt)->last_usable_lba),
+ (size_t)lastlba);
+ goto fail;
+ }
+
+ if ((uint64_t)((*gpt)->last_usable_lba) < (uint64_t)((*gpt)->first_usable_lba))
+ {
+ LOG_E("GPT: last_usable_lba incorrect: %ld > %ld",
+ (uint64_t)((*gpt)->last_usable_lba),
+ (uint64_t)((*gpt)->first_usable_lba));
+ goto fail;
+ }
+ /* Check that sizeof_partition_entry has the correct value */
+ if ((uint32_t)((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
+ LOG_E("GUID Partition Entry Size check failed.");
+ goto fail;
+ }
+
+ if (!(*ptes = alloc_read_gpt_entries(card, *gpt)))
+ {
+ goto fail;
+ }
+
+ /* We're done, all's well */
+ return 1;
+
+ fail:
+ rt_free(*gpt);
+ *gpt = RT_NULL;
+ return 0;
+}
+
+/**
+ * is_pte_valid() - tests one PTE for validity
+ * pte:pte to check
+ * lastlba: last lba of the disk
+ *
+ * Description: returns 1 if valid, 0 on error.
+ */
+static inline int is_pte_valid(const gpt_entry *pte, const size_t lastlba)
+{
+ if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
+ (uint64_t)(pte->starting_lba) > lastlba ||
+ (uint64_t)(pte->ending_lba) > lastlba)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * compare_gpts() - Search disk for valid GPT headers and PTEs
+ * pgpt: primary GPT header
+ * agpt: alternate GPT header
+ * lastlba: last LBA number
+ *
+ * Description: Returns nothing. Sanity checks pgpt and agpt fields
+ * and prints warnings on discrepancies.
+ *
+ */
+static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, size_t lastlba)
+{
+ int error_found = 0;
+ if (!pgpt || !agpt)
+ {
+ return;
+ }
+
+ if ((uint64_t)(pgpt->start_lba) != (uint64_t)(agpt->alternate_lba))
+ {
+ LOG_I("GPT:Primary header LBA != Alt. header alternate_lba");
+ LOG_I("GPT:%lld != %lld",
+ (uint64_t)(pgpt->start_lba),
+ (uint64_t)(agpt->alternate_lba));
+ error_found++;
+ }
+
+ if ((uint64_t)(pgpt->alternate_lba) != (uint64_t)(agpt->start_lba))
+ {
+ LOG_I("GPT:Primary header alternate_lba != Alt. header start_lba");
+ LOG_I("GPT:%lld != %lld",
+ (uint64_t)(pgpt->alternate_lba),
+ (uint64_t)(agpt->start_lba));
+ error_found++;
+ }
+
+ if ((uint64_t)(pgpt->first_usable_lba) != (uint64_t)(agpt->first_usable_lba))
+ {
+ LOG_I("GPT:first_usable_lbas don't match.");
+ LOG_I("GPT:%lld != %lld",
+ (uint64_t)(pgpt->first_usable_lba),
+ (uint64_t)(agpt->first_usable_lba));
+ error_found++;
+ }
+
+ if ((uint64_t)(pgpt->last_usable_lba) != (uint64_t)(agpt->last_usable_lba))
+ {
+ LOG_I("GPT:last_usable_lbas don't match.");
+ LOG_I("GPT:%lld != %lld",
+ (uint64_t)(pgpt->last_usable_lba),
+ (uint64_t)(agpt->last_usable_lba));
+ error_found++;
+ }
+
+ if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid))
+ {
+ LOG_I("GPT:disk_guids don't match.");
+ error_found++;
+ }
+
+ if ((pgpt->num_partition_entries) != (agpt->num_partition_entries))
+ {
+ LOG_I("GPT:num_partition_entries don't match: "
+ "0x%x != 0x%x",
+ (pgpt->num_partition_entries),
+ (agpt->num_partition_entries));
+ error_found++;
+ }
+
+ if ((pgpt->sizeof_partition_entry) != (agpt->sizeof_partition_entry))
+ {
+ LOG_I("GPT:sizeof_partition_entry values don't match: "
+ "0x%x != 0x%x",
+ (pgpt->sizeof_partition_entry),
+ (agpt->sizeof_partition_entry));
+ error_found++;
+ }
+
+ if ((pgpt->partition_entry_array_crc32) != (agpt->partition_entry_array_crc32))
+ {
+ LOG_I("GPT:partition_entry_array_crc32 values don't match: "
+ "0x%x != 0x%x",
+ (pgpt->partition_entry_array_crc32),
+ (agpt->partition_entry_array_crc32));
+ error_found++;
+ }
+
+ if ((pgpt->alternate_lba) != lastlba)
+ {
+ LOG_I("GPT:Primary header thinks Alt. header is not at the end of the disk.");
+ LOG_I("GPT:%lld != %lld",
+ (uint64_t)(pgpt->alternate_lba),
+ (size_t)lastlba);
+ error_found++;
+ }
+
+ if ((agpt->start_lba) != lastlba)
+ {
+ LOG_I("GPT:Alternate GPT header not at the end of the disk.");
+ LOG_I("GPT:%lld != %lld",
+ (uint64_t)(agpt->start_lba),
+ (size_t)lastlba);
+ error_found++;
+ }
+
+ if (error_found)
+ {
+ LOG_I("GPT: Use GNU Parted to correct GPT errors.");
+ }
+ return;
+}
+
+/**
+ * find_valid_gpt() - Search disk for valid GPT headers and PTEs
+ * state: disk parsed partitions
+ * gpt: GPT header ptr, filled on return.
+ * ptes: PTEs ptr, filled on return.
+ *
+ * Description: Returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ * Validity depends on PMBR being valid (or being overridden by the
+ * 'gpt' kernel command line option) and finding either the Primary
+ * GPT header and PTEs valid, or the Alternate GPT header and PTEs
+ * valid. If the Primary GPT header is not valid, the Alternate GPT header
+ * is not checked unless the 'gpt' kernel command line option is passed.
+ * This protects against devices which misreport their size, and forces
+ * the user to decide to use the Alternate GPT.
+ */
+static int find_valid_gpt(struct rt_mmcsd_card *card, gpt_header **gpt,
+ gpt_entry **ptes)
+{
+ int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
+ gpt_header *pgpt = RT_NULL, *agpt = RT_NULL;
+ gpt_entry *pptes = RT_NULL, *aptes = RT_NULL;
+ legacy_mbr *legacymbr;
+ size_t total_sectors = last_lba(card) + 1;
+ size_t lastlba;
+ int status = 0;
+
+ if (!ptes)
+ {
+ return 0;
+ }
+
+ lastlba = last_lba(card);
+ if (!force_gpt)
+ {
+ /* This will be added to the EFI Spec. per Intel after v1.02. */
+ legacymbr = rt_malloc(512);
+ if (!legacymbr)
+ {
+ goto fail;
+ }
+
+ status = read_lba(card, 0, (uint8_t *)legacymbr, 1);
+ if (status)
+ {
+ LOG_I("status:%d", status);
+ goto fail;
+ }
+
+ good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
+ rt_free(legacymbr);
+
+ if (!good_pmbr)
+ {
+ goto fail;
+ }
+
+ rt_kprintf("Device has a %s MBR\n",
+ good_pmbr == GPT_MBR_PROTECTIVE ?
+ "protective" : "hybrid");
+ }
+
+ good_pgpt = is_gpt_valid(card, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &pgpt, &pptes);
+ if (good_pgpt)
+ {
+ good_agpt = is_gpt_valid(card, (pgpt->alternate_lba), &agpt, &aptes);
+ if (!good_agpt && force_gpt)
+ {
+ good_agpt = is_gpt_valid(card, lastlba, &agpt, &aptes);
+ }
+
+ /* The obviously unsuccessful case */
+ if (!good_pgpt && !good_agpt)
+ {
+ goto fail;
+ }
+
+ compare_gpts(pgpt, agpt, lastlba);
+
+ /* The good cases */
+ if (good_pgpt)
+ {
+ *gpt = pgpt;
+ *ptes = pptes;
+ rt_free(agpt);
+ rt_free(aptes);
+ if (!good_agpt)
+ {
+ LOG_D("Alternate GPT is invalid, using primary GPT.");
+ }
+ return 1;
+ }
+ else if (good_agpt)
+ {
+ *gpt = agpt;
+ *ptes = aptes;
+ rt_free(pgpt);
+ rt_free(pptes);
+ LOG_D("Primary GPT is invalid, using alternate GPT.");
+ return 1;
+ }
+ }
+
+ fail:
+ rt_free(pgpt);
+ rt_free(agpt);
+ rt_free(pptes);
+ rt_free(aptes);
+ *gpt = RT_NULL;
+ *ptes = RT_NULL;
+ return 0;
+}
+
+int check_gpt(struct rt_mmcsd_card *card)
+{
+ if (!find_valid_gpt(card, &_gpt, &_ptes) || !_gpt || !_ptes)
+ {
+ rt_free(_gpt);
+ rt_free(_ptes);
+ return MBR_TYPE;
+ }
+ return GPT_TYPE;
+}
+
+int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex)
+{
+ if (!is_pte_valid(&_ptes[pindex], last_lba(card)))
+ {
+ return -1;
+ }
+
+ part->offset = (off_t)(_ptes[pindex].starting_lba);
+ part->size = (_ptes[pindex].ending_lba) - (_ptes[pindex].starting_lba) + 1ULL;
+
+ rt_kprintf("found part[%d], begin(sector): %d, end(sector):%d size: ",
+ pindex, _ptes[pindex].starting_lba, _ptes[pindex].ending_lba);
+
+ if ((part->size >> 11) == 0)
+ {
+ rt_kprintf("%d%s", part->size >> 1, "KB\n"); /* KB */
+ }
+ else
+ {
+ unsigned int part_size;
+ part_size = part->size >> 11; /* MB */
+ if ((part_size >> 10) == 0)
+ rt_kprintf("%d.%d%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
+ else
+ rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
+ }
+ return 0;
+}
+
+void gpt_free(void)
+{
+ rt_free(_ptes);
+ rt_free(_gpt);
+}
diff --git a/components/drivers/sdio/mmc.c b/components/drivers/sdio/mmc.c
index 0365de8ed7..32a9a204d8 100644
--- a/components/drivers/sdio/mmc.c
+++ b/components/drivers/sdio/mmc.c
@@ -46,17 +46,17 @@ rt_inline rt_uint32_t GET_BITS(rt_uint32_t *resp,
rt_uint32_t start,
rt_uint32_t size)
{
- const rt_int32_t __size = size;
- const rt_uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
- const rt_int32_t __off = 3 - ((start) / 32);
- const rt_int32_t __shft = (start) & 31;
- rt_uint32_t __res;
+ const rt_int32_t __size = size;
+ const rt_uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
+ const rt_int32_t __off = 3 - ((start) / 32);
+ const rt_int32_t __shft = (start) & 31;
+ rt_uint32_t __res;
- __res = resp[__off] >> __shft;
- if (__size + __shft > 32)
- __res |= resp[__off-1] << ((32 - __shft) % 32);
+ __res = resp[__off] >> __shft;
+ if (__size + __shft > 32)
+ __res |= resp[__off - 1] << ((32 - __shft) % 32);
- return __res & __mask;
+ return __res & __mask;
}
/*
@@ -64,50 +64,52 @@ rt_inline rt_uint32_t GET_BITS(rt_uint32_t *resp,
*/
static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card)
{
- rt_uint32_t a, b;
- struct rt_mmcsd_csd *csd = &card->csd;
- rt_uint32_t *resp = card->resp_csd;
+ rt_uint32_t a, b;
+ struct rt_mmcsd_csd *csd = &card->csd;
+ rt_uint32_t *resp = card->resp_csd;
- /*
- * We only understand CSD structure v1.1 and v1.2.
- * v1.2 has extra information in bits 15, 11 and 10.
- * We also support eMMC v4.4 & v4.41.
- */
- csd->csd_structure = GET_BITS(resp, 126, 2);
- if (csd->csd_structure == 0) {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
+ * We also support eMMC v4.4 & v4.41.
+ */
+ csd->csd_structure = GET_BITS(resp, 126, 2);
+ if (csd->csd_structure == 0)
+ {
LOG_E("unrecognised CSD structure version %d!", csd->csd_structure);
return -RT_ERROR;
- }
+ }
- csd->taac = GET_BITS(resp, 112, 8);
- csd->nsac = GET_BITS(resp, 104, 8);
- csd->tran_speed = GET_BITS(resp, 96, 8);
- csd->card_cmd_class = GET_BITS(resp, 84, 12);
- csd->rd_blk_len = GET_BITS(resp, 80, 4);
- csd->rd_blk_part = GET_BITS(resp, 79, 1);
- csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
- csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
- csd->dsr_imp = GET_BITS(resp, 76, 1);
- csd->c_size = GET_BITS(resp, 62, 12);
- csd->c_size_mult = GET_BITS(resp, 47, 3);
- csd->r2w_factor = GET_BITS(resp, 26, 3);
- csd->wr_blk_len = GET_BITS(resp, 22, 4);
- csd->wr_blk_partial = GET_BITS(resp, 21, 1);
- csd->csd_crc = GET_BITS(resp, 1, 7);
+ csd->taac = GET_BITS(resp, 112, 8);
+ csd->nsac = GET_BITS(resp, 104, 8);
+ csd->tran_speed = GET_BITS(resp, 96, 8);
+ csd->card_cmd_class = GET_BITS(resp, 84, 12);
+ csd->rd_blk_len = GET_BITS(resp, 80, 4);
+ csd->rd_blk_part = GET_BITS(resp, 79, 1);
+ csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
+ csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
+ csd->dsr_imp = GET_BITS(resp, 76, 1);
+ csd->c_size = GET_BITS(resp, 62, 12);
+ csd->c_size_mult = GET_BITS(resp, 47, 3);
+ csd->r2w_factor = GET_BITS(resp, 26, 3);
+ csd->wr_blk_len = GET_BITS(resp, 22, 4);
+ csd->wr_blk_partial = GET_BITS(resp, 21, 1);
+ csd->csd_crc = GET_BITS(resp, 1, 7);
- card->card_blksize = 1 << csd->rd_blk_len;
- card->tacc_clks = csd->nsac * 100;
- card->tacc_ns = (tacc_uint[csd->taac&0x07] * tacc_value[(csd->taac&0x78)>>3] + 9) / 10;
- card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
- if (csd->wr_blk_len >= 9) {
+ card->card_blksize = 1 << csd->rd_blk_len;
+ card->tacc_clks = csd->nsac * 100;
+ card->tacc_ns = (tacc_uint[csd->taac & 0x07] * tacc_value[(csd->taac & 0x78) >> 3] + 9) / 10;
+ card->max_data_rate = tran_unit[csd->tran_speed & 0x07] * tran_value[(csd->tran_speed & 0x78) >> 3];
+ if (csd->wr_blk_len >= 9)
+ {
a = GET_BITS(resp, 42, 5);
b = GET_BITS(resp, 37, 5);
card->erase_size = (a + 1) * (b + 1);
card->erase_size <<= csd->wr_blk_len - 9;
- }
+ }
- return 0;
+ return 0;
}
/*
@@ -115,66 +117,66 @@ static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card)
*/
static int mmc_get_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t **new_ext_csd)
{
- void *ext_csd;
- struct rt_mmcsd_req req;
- struct rt_mmcsd_cmd cmd;
- struct rt_mmcsd_data data;
-
- *new_ext_csd = RT_NULL;
+ void *ext_csd;
+ struct rt_mmcsd_req req;
+ struct rt_mmcsd_cmd cmd;
+ struct rt_mmcsd_data data;
- if (GET_BITS(card->resp_csd, 122, 4) < 4)
- return 0;
+ *new_ext_csd = RT_NULL;
+ if (GET_BITS(card->resp_csd, 122, 4) < 4)
+ return 0;
- /*
- * As the ext_csd is so large and mostly unused, we don't store the
- * raw block in mmc_card.
- */
- ext_csd = rt_malloc(512);
- if (!ext_csd) {
- LOG_E("alloc memory failed when get ext csd!");
- return -RT_ENOMEM;
- }
+ /*
+ * As the ext_csd is so large and mostly unused, we don't store the
+ * raw block in mmc_card.
+ */
+ ext_csd = rt_malloc(512);
+ if (!ext_csd)
+ {
+ LOG_E("alloc memory failed when get ext csd!");
+ return -RT_ENOMEM;
+ }
- rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
- rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
- rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
+ rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
+ rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
+ rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
- req.cmd = &cmd;
- req.data = &data;
+ req.cmd = &cmd;
+ req.data = &data;
- cmd.cmd_code = SEND_EXT_CSD;
- cmd.arg = 0;
+ cmd.cmd_code = SEND_EXT_CSD;
+ cmd.arg = 0;
- /* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
- * rely on callers to never use this with "native" calls for reading
- * CSD or CID. Native versions of those commands use the R2 type,
- * not R1 plus a data block.
- */
- cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
+ /* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
+ * rely on callers to never use this with "native" calls for reading
+ * CSD or CID. Native versions of those commands use the R2 type,
+ * not R1 plus a data block.
+ */
+ cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
- data.blksize = 512;
- data.blks = 1;
- data.flags = DATA_DIR_READ;
- data.buf = ext_csd;
+ data.blksize = 512;
+ data.blks = 1;
+ data.flags = DATA_DIR_READ;
+ data.buf = ext_csd;
- /*
- * Some cards require longer data read timeout than indicated in CSD.
- * Address this by setting the read timeout to a "reasonably high"
- * value. For the cards tested, 300ms has proven enough. If necessary,
- * this value can be increased if other problematic cards require this.
- */
- data.timeout_ns = 300000000;
- data.timeout_clks = 0;
+ /*
+ * Some cards require longer data read timeout than indicated in CSD.
+ * Address this by setting the read timeout to a "reasonably high"
+ * value. For the cards tested, 300ms has proven enough. If necessary,
+ * this value can be increased if other problematic cards require this.
+ */
+ data.timeout_ns = 300000000;
+ data.timeout_clks = 0;
- mmcsd_send_request(card->host, &req);
+ mmcsd_send_request(card->host, &req);
- if (cmd.err)
- return cmd.err;
- if (data.err)
- return data.err;
+ if (cmd.err)
+ return cmd.err;
+ if (data.err)
+ return data.err;
- *new_ext_csd = ext_csd;
- return 0;
+ *new_ext_csd = ext_csd;
+ return 0;
}
/*
@@ -182,24 +184,39 @@ static int mmc_get_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t **new_ext_csd)
*/
static int mmc_parse_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
{
- rt_uint64_t card_capacity = 0;
-
- if(card == RT_NULL || ext_csd == RT_NULL)
- {
- LOG_E("emmc parse ext csd fail, invaild args");
- return -1;
- }
+ rt_uint64_t card_capacity = 0;
+ struct rt_mmcsd_host *host;
+ if (card == RT_NULL || ext_csd == RT_NULL)
+ {
+ LOG_E("emmc parse ext csd fail, invaild args");
+ return -1;
+ }
- card->flags |= CARD_FLAG_HIGHSPEED;
- card->hs_max_data_rate = 52000000;
+ host = card->host;
+ if (host->flags & MMCSD_SUP_HS200)
+ {
+ card->flags |= CARD_FLAG_HS200;
+ card->hs_max_data_rate = 200000000;
+ }
+ else if (host->flags & MMCSD_SUP_HIGHSPEED_DDR)
+ {
+ card->flags |= CARD_FLAG_HIGHSPEED_DDR;
+ card->hs_max_data_rate = 52000000;
+ }
+ else
+ {
+ card->flags |= CARD_FLAG_HIGHSPEED;
+ card->hs_max_data_rate = 52000000;
+ }
- card_capacity = *((rt_uint32_t *)&ext_csd[EXT_CSD_SEC_CNT]);
- card_capacity *= card->card_blksize;
- card_capacity >>= 10; /* unit:KB */
- card->card_capacity = (rt_uint32_t)card_capacity;
- LOG_I("emmc card capacity %d KB.", card->card_capacity);
+ card_capacity = *((rt_uint32_t *)&ext_csd[EXT_CSD_SEC_CNT]);
+ card->card_sec_cnt = card_capacity;
+ card_capacity *= card->card_blksize;
+ card_capacity >>= 10; /* unit:KB */
+ card->card_capacity = card_capacity;
+ LOG_I("emmc card capacity %d KB, card sec count:%d.", card->card_capacity, card->card_sec_cnt);
- return 0;
+ return 0;
}
/**
@@ -214,72 +231,73 @@ static int mmc_parse_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
static int mmc_switch(struct rt_mmcsd_card *card, rt_uint8_t set,
rt_uint8_t index, rt_uint8_t value)
{
- int err;
- struct rt_mmcsd_host *host = card->host;
- struct rt_mmcsd_cmd cmd = {0};
+ int err;
+ struct rt_mmcsd_host *host = card->host;
+ struct rt_mmcsd_cmd cmd = {0};
- cmd.cmd_code = SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (index << 16) | (value << 8) | set;
- cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
+ cmd.cmd_code = SWITCH;
+ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (index << 16) | (value << 8) | set;
+ cmd.flags = RESP_R1B | CMD_AC;
- err = mmcsd_send_cmd(host, &cmd, 3);
- if (err)
- return err;
+ err = mmcsd_send_cmd(host, &cmd, 3);
+ if (err)
+ return err;
- return 0;
+ return 0;
}
static int mmc_compare_ext_csds(struct rt_mmcsd_card *card,
rt_uint8_t *ext_csd, rt_uint32_t bus_width)
{
- rt_uint8_t *bw_ext_csd;
- int err;
+ rt_uint8_t *bw_ext_csd;
+ int err;
- if (bus_width == MMCSD_BUS_WIDTH_1)
- return 0;
+ if (bus_width == MMCSD_BUS_WIDTH_1)
+ return 0;
- err = mmc_get_ext_csd(card, &bw_ext_csd);
+ err = mmc_get_ext_csd(card, &bw_ext_csd);
- if (err || bw_ext_csd == RT_NULL) {
- err = -RT_ERROR;
- goto out;
- }
+ if (err || bw_ext_csd == RT_NULL)
+ {
+ err = -RT_ERROR;
+ goto out;
+ }
- /* only compare read only fields */
- err = !((ext_csd[EXT_CSD_PARTITION_SUPPORT] == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
- (ext_csd[EXT_CSD_ERASED_MEM_CONT] == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
- (ext_csd[EXT_CSD_REV] == bw_ext_csd[EXT_CSD_REV]) &&
- (ext_csd[EXT_CSD_STRUCTURE] == bw_ext_csd[EXT_CSD_STRUCTURE]) &&
- (ext_csd[EXT_CSD_CARD_TYPE] == bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
- (ext_csd[EXT_CSD_S_A_TIMEOUT] == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
- (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
- (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
- (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
- (ext_csd[EXT_CSD_SEC_TRIM_MULT] == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
- (ext_csd[EXT_CSD_SEC_ERASE_MULT] == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
- (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
- (ext_csd[EXT_CSD_TRIM_MULT] == bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
- (ext_csd[EXT_CSD_SEC_CNT + 0] == bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
- (ext_csd[EXT_CSD_SEC_CNT + 1] == bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
- (ext_csd[EXT_CSD_SEC_CNT + 2] == bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
- (ext_csd[EXT_CSD_SEC_CNT + 3] == bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
- (ext_csd[EXT_CSD_PWR_CL_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
- (ext_csd[EXT_CSD_PWR_CL_26_195] == bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
- (ext_csd[EXT_CSD_PWR_CL_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
- (ext_csd[EXT_CSD_PWR_CL_26_360] == bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
- (ext_csd[EXT_CSD_PWR_CL_200_195] == bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
- (ext_csd[EXT_CSD_PWR_CL_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
- (ext_csd[EXT_CSD_PWR_CL_DDR_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
- (ext_csd[EXT_CSD_PWR_CL_DDR_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
- (ext_csd[EXT_CSD_PWR_CL_DDR_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+ /* only compare read only fields */
+ err = !((ext_csd[EXT_CSD_PARTITION_SUPPORT] == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+ (ext_csd[EXT_CSD_ERASED_MEM_CONT] == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+ (ext_csd[EXT_CSD_REV] == bw_ext_csd[EXT_CSD_REV]) &&
+ (ext_csd[EXT_CSD_STRUCTURE] == bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+ (ext_csd[EXT_CSD_CARD_TYPE] == bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+ (ext_csd[EXT_CSD_S_A_TIMEOUT] == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+ (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+ (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+ (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+ (ext_csd[EXT_CSD_SEC_TRIM_MULT] == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+ (ext_csd[EXT_CSD_SEC_ERASE_MULT] == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+ (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+ (ext_csd[EXT_CSD_TRIM_MULT] == bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+ (ext_csd[EXT_CSD_SEC_CNT + 0] == bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
+ (ext_csd[EXT_CSD_SEC_CNT + 1] == bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
+ (ext_csd[EXT_CSD_SEC_CNT + 2] == bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
+ (ext_csd[EXT_CSD_SEC_CNT + 3] == bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
+ (ext_csd[EXT_CSD_PWR_CL_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
+ (ext_csd[EXT_CSD_PWR_CL_26_195] == bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
+ (ext_csd[EXT_CSD_PWR_CL_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
+ (ext_csd[EXT_CSD_PWR_CL_26_360] == bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
+ (ext_csd[EXT_CSD_PWR_CL_200_195] == bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
+ (ext_csd[EXT_CSD_PWR_CL_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
+ (ext_csd[EXT_CSD_PWR_CL_DDR_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
+ (ext_csd[EXT_CSD_PWR_CL_DDR_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+ (ext_csd[EXT_CSD_PWR_CL_DDR_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
- if (err)
- err = -RT_ERROR;
+ if (err)
+ err = -RT_ERROR;
out:
- rt_free(bw_ext_csd);
- return err;
+ rt_free(bw_ext_csd);
+ return err;
}
/*
@@ -289,104 +307,103 @@ out:
*/
static int mmc_select_bus_width(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
{
- rt_uint32_t ext_csd_bits[] = {
- EXT_CSD_DDR_BUS_WIDTH_8,
- EXT_CSD_DDR_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_8,
- EXT_CSD_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_1
- };
- rt_uint32_t bus_widths[] = {
- MMCSD_DDR_BUS_WIDTH_8,
- MMCSD_DDR_BUS_WIDTH_4,
- MMCSD_BUS_WIDTH_8,
- MMCSD_BUS_WIDTH_4,
- MMCSD_BUS_WIDTH_1
- };
- struct rt_mmcsd_host *host = card->host;
- unsigned idx, trys, bus_width = 0;
- int err = 0;
+ rt_uint32_t ext_csd_bits[][2] =
+ {
+ {EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8},
+ {EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4},
+ {EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1},
+ };
+ rt_uint32_t bus_widths[] =
+ {
+ MMCSD_BUS_WIDTH_8,
+ MMCSD_BUS_WIDTH_4,
+ MMCSD_BUS_WIDTH_1
+ };
+ struct rt_mmcsd_host *host = card->host;
+ unsigned idx, bus_width = 0;
+ int err = 0, ddr = 0;
- if (GET_BITS(card->resp_csd, 122, 4) < 4)
- return 0;
+ if (GET_BITS(card->resp_csd, 122, 4) < 4)
+ return 0;
- /*
- * Unlike SD, MMC cards dont have a configuration register to notify
- * supported bus width. So bus test command should be run to identify
- * the supported bus width or compare the ext csd values of current
- * bus width and ext csd values of 1 bit mode read earlier.
- */
- for (idx = 0; idx < sizeof(ext_csd_bits)/sizeof(rt_uint32_t); idx++) {
+ if (card->flags & CARD_FLAG_HIGHSPEED_DDR)
+ {
+ ddr = 2;
+ }
/*
- * Host is capable of 8bit transfer, then switch
- * the device to work in 8bit transfer mode. If the
- * mmc switch command returns error then switch to
- * 4bit transfer mode. On success set the corresponding
- * bus width on the host. Meanwhile, mmc core would
- * bail out early if corresponding bus capable wasn't
- * set by drivers.
+ * Unlike SD, MMC cards dont have a configuration register to notify
+ * supported bus width. So bus test command should be run to identify
+ * the supported bus width or compare the ext csd values of current
+ * bus width and ext csd values of 1 bit mode read earlier.
*/
- if ((!((host->flags & MMCSD_BUSWIDTH_8) &&
- (host->flags & MMCSD_SUP_HIGHSPEED_DDR)) &&
- ext_csd_bits[idx] == EXT_CSD_DDR_BUS_WIDTH_8) ||
- (!((host->flags & MMCSD_BUSWIDTH_4) &&
- (host->flags & MMCSD_SUP_HIGHSPEED_DDR)) &&
- ext_csd_bits[idx] == EXT_CSD_DDR_BUS_WIDTH_4) ||
- (!(host->flags & MMCSD_BUSWIDTH_8) &&
- ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_8) ||
- (!(host->flags & MMCSD_BUSWIDTH_4) &&
- ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_4))
- continue;
-
- if (host->flags & MMCSD_SUP_HIGHSPEED_DDR)
+ for (idx = 0; idx < sizeof(bus_widths) / sizeof(rt_uint32_t); idx++)
{
- /* HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual-data-rate(DDR) operation */
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
- if (err)
- LOG_E("switch to speed mode width hight speed failed!");
- }
+ /*
+ * Host is capable of 8bit transfer, then switch
+ * the device to work in 8bit transfer mode. If the
+ * mmc switch command returns error then switch to
+ * 4bit transfer mode. On success set the corresponding
+ * bus width on the host. Meanwhile, mmc core would
+ * bail out early if corresponding bus capable wasn't
+ * set by drivers.
+ */
+ bus_width = bus_widths[idx];
+ if (bus_width == MMCSD_BUS_WIDTH_1)
+ {
+ ddr = 0;
+ }
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ext_csd_bits[idx]);
- if (err)
- continue;
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits[idx][0]);
+
+ if (err)
+ continue;
- bus_width = bus_widths[idx];
- for(trys = 0; trys < 5; trys++){
mmcsd_set_bus_width(host, bus_width);
- rt_thread_mdelay(10);
err = mmc_compare_ext_csds(card, ext_csd, bus_width);
- if(!err)
+ if (!err)
+ {
break;
+ }
+ else
+ {
+ switch (ext_csd_bits[idx][0])
+ {
+ case 0:
+ LOG_E("switch to bus width 1 bit failed!");
+ break;
+ case 1:
+ LOG_E("switch to bus width 4 bit failed!");
+ break;
+ case 2:
+ LOG_E("switch to bus width 8 bit failed!");
+ break;
+ default:
+ break;
+ }
+ }
}
- if (!err) {
- err = bus_width;
- break;
- } else {
- switch(ext_csd_bits[idx]){
- case EXT_CSD_DDR_BUS_WIDTH_8:
- LOG_E("switch to bus width DDR 8 bit failed!");
- break;
- case EXT_CSD_DDR_BUS_WIDTH_4:
- LOG_E("switch to bus width DDR 4 bit failed!");
- break;
- case EXT_CSD_BUS_WIDTH_8:
- LOG_E("switch to bus width 8 bit failed!");
- break;
- case EXT_CSD_BUS_WIDTH_4:
- LOG_E("switch to bus width 4 bit failed!");
- break;
- case EXT_CSD_BUS_WIDTH_1:
- LOG_E("switch to bus width 1 bit failed!");
- break;
- default:
- break;
- }
+
+ if (!err && ddr)
+ {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits[idx][1]);
}
- }
- return err;
+ if (!err)
+ {
+ if (card->flags & (CARD_FLAG_HIGHSPEED | CARD_FLAG_HIGHSPEED_DDR))
+ {
+
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING,
+ 1);
+ }
+ }
+
+ return err;
}
rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host,
rt_uint32_t ocr, rt_uint32_t *rocr)
@@ -401,55 +418,98 @@ rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host,
cmd.arg = controller_is_spi(host) ? 0 : ocr;
cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR;
- for (i = 100; i; i--) {
- err = mmcsd_send_cmd(host, &cmd, 3);
- if (err)
- break;
+ for (i = 100; i; i--)
+ {
+ err = mmcsd_send_cmd(host, &cmd, 3);
+ if (err)
+ break;
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
+ break;
- /* otherwise wait until reset completes */
- if (controller_is_spi(host)) {
- if (!(cmd.resp[0] & R1_SPI_IDLE))
- break;
- } else {
- if (cmd.resp[0] & CARD_BUSY)
- break;
- }
+ /* otherwise wait until reset completes */
+ if (controller_is_spi(host))
+ {
+ if (!(cmd.resp[0] & R1_SPI_IDLE))
+ break;
+ }
+ else
+ {
+ if (cmd.resp[0] & CARD_BUSY)
+ break;
+ }
- err = -RT_ETIMEOUT;
+ err = -RT_ETIMEOUT;
- rt_thread_mdelay(10); //delay 10ms
+ rt_thread_mdelay(10); //delay 10ms
}
- if (rocr && !controller_is_spi(host))
- *rocr = cmd.resp[0];
+ if (rocr && !controller_is_spi(host))
+ *rocr = cmd.resp[0];
- return err;
+ return err;
}
static rt_err_t mmc_set_card_addr(struct rt_mmcsd_host *host, rt_uint32_t rca)
{
- rt_err_t err;
- struct rt_mmcsd_cmd cmd;
+ rt_err_t err;
+ struct rt_mmcsd_cmd cmd;
- rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
+ rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
- cmd.cmd_code = SET_RELATIVE_ADDR;
- cmd.arg = rca << 16;
- cmd.flags = RESP_R1 | CMD_AC;
+ cmd.cmd_code = SET_RELATIVE_ADDR;
+ cmd.arg = rca << 16;
+ cmd.flags = RESP_R1 | CMD_AC;
- err = mmcsd_send_cmd(host, &cmd, 3);
- if (err)
- return err;
+ err = mmcsd_send_cmd(host, &cmd, 3);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int mmc_select_hs200(struct rt_mmcsd_card *card)
+{
+ int ret;
- return 0;
+ ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200);
+ if (ret)
+ return ret;
+
+ mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS200);
+ mmcsd_set_clock(card->host, 200000000);
+
+ ret = mmcsd_excute_tuning(card);
+
+ return ret;
+}
+
+static int mmc_select_timing(struct rt_mmcsd_card *card)
+{
+ int ret = 0;
+
+ if (card->flags & CARD_FLAG_HS200)
+ {
+ ret = mmc_select_hs200(card);
+ }
+ else if (card->flags & CARD_FLAG_HIGHSPEED_DDR)
+ {
+ mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_DDR52);
+ mmcsd_set_clock(card->host, card->hs_max_data_rate);
+ }
+ else
+ {
+ mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR50);
+ mmcsd_set_clock(card->host, card->hs_max_data_rate);
+ }
+
+ return ret;
}
static rt_int32_t mmcsd_mmc_init_card(struct rt_mmcsd_host *host,
- rt_uint32_t ocr)
+ rt_uint32_t ocr)
{
rt_int32_t err;
rt_uint32_t resp[4];
@@ -463,7 +523,7 @@ static rt_int32_t mmcsd_mmc_init_card(struct rt_mmcsd_host *host,
/* The extra bit indicates that we support high capacity */
err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
if (err)
- goto err;
+ goto err;
if (controller_is_spi(host))
{
@@ -526,35 +586,47 @@ static rt_int32_t mmcsd_mmc_init_card(struct rt_mmcsd_host *host,
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
- goto err1;
+ goto err1;
err = mmc_parse_ext_csd(card, ext_csd);
if (err)
- goto err1;
+ goto err1;
/* If doing byte addressing, check if required to do sector
* addressing. Handle the case of <2GB cards needing sector
* addressing. See section 8.1 JEDEC Standard JED84-A441;
* ocr register has bit 30 set for sector addressing.
*/
- if (!(card->flags & CARD_FLAG_SDHC) && (rocr & (1<<30)))
+ if (!(card->flags & CARD_FLAG_SDHC) && (rocr & (1 << 30)))
card->flags |= CARD_FLAG_SDHC;
/* set bus speed */
- if (card->flags & CARD_FLAG_HIGHSPEED)
+ if (card->flags & (CARD_FLAG_HIGHSPEED | CARD_FLAG_HIGHSPEED_DDR))
max_data_rate = card->hs_max_data_rate;
else
max_data_rate = card->max_data_rate;
- mmcsd_set_clock(host, max_data_rate);
+ /*switch bus width and bus mode*/
+ err = mmc_select_bus_width(card, ext_csd);
+ if (err)
+ {
+ LOG_E("mmc select buswidth fail");
+ goto err0;
+ }
- /*switch bus width*/
- mmc_select_bus_width(card, ext_csd);
+ err = mmc_select_timing(card);
+ if (err)
+ {
+ LOG_E("mmc select timing fail");
+ goto err0;
+ }
host->card = card;
rt_free(ext_csd);
return 0;
+err0:
+ rt_free(ext_csd);
err1:
rt_free(card);
err:
diff --git a/components/drivers/sdio/mmcsd_core.c b/components/drivers/sdio/mmcsd_core.c
index 179368026d..f896901804 100644
--- a/components/drivers/sdio/mmcsd_core.c
+++ b/components/drivers/sdio/mmcsd_core.c
@@ -13,6 +13,7 @@
#include <drivers/sd.h>
#include <drivers/mmc.h>
#include <drivers/sdio.h>
+#include <string.h>
#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
@@ -40,7 +41,6 @@ static struct rt_mailbox mmcsd_detect_mb;
static rt_uint32_t mmcsd_detect_mb_pool[4];
static struct rt_mailbox mmcsd_hotpluge_mb;
static rt_uint32_t mmcsd_hotpluge_mb_pool[4];
-static rt_uint32_t allocated_host_num = 0;
void mmcsd_host_lock(struct rt_mmcsd_host *host)
{
@@ -59,7 +59,8 @@ void mmcsd_req_complete(struct rt_mmcsd_host *host)
void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
{
- do {
+ do
+ {
req->cmd->retries--;
req->cmd->err = 0;
req->cmd->mrq = req;
@@ -79,7 +80,8 @@ void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
rt_sem_take(&host->sem_ack, RT_WAITING_FOREVER);
- } while(req->cmd->err && (req->cmd->retries > 0));
+ }
+ while (req->cmd->err && (req->cmd->retries > 0));
}
@@ -243,7 +245,7 @@ rt_int32_t mmcsd_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid)
return -RT_ERROR;
}
- for (i = 0;i < 4;i++)
+ for (i = 0; i < 4; i++)
cid[i] = buf[i];
rt_free(buf);
@@ -274,7 +276,7 @@ rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd)
return 0;
}
- buf = (rt_uint32_t*)rt_malloc(16);
+ buf = (rt_uint32_t *)rt_malloc(16);
if (!buf)
{
LOG_E("allocate memory failed!");
@@ -320,7 +322,7 @@ rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd)
return -RT_ERROR;
}
- for (i = 0;i < 4;i++)
+ for (i = 0; i < 4; i++)
csd[i] = buf[i];
rt_free(buf);
@@ -388,10 +390,10 @@ rt_inline void mmcsd_set_iocfg(struct rt_mmcsd_host *host)
struct rt_mmcsd_io_cfg *io_cfg = &host->io_cfg;
mmcsd_dbg("clock %uHz busmode %u powermode %u cs %u Vdd %u "
- "width %u \n",
- io_cfg->clock, io_cfg->bus_mode,
- io_cfg->power_mode, io_cfg->chip_select, io_cfg->vdd,
- io_cfg->bus_width);
+ "width %u \n",
+ io_cfg->clock, io_cfg->bus_mode,
+ io_cfg->power_mode, io_cfg->chip_select, io_cfg->vdd,
+ io_cfg->bus_width);
host->ops->set_iocfg(host, io_cfg);
}
@@ -438,6 +440,12 @@ void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width)
mmcsd_set_iocfg(host);
}
+void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing)
+{
+ host->io_cfg.timing = timing;
+ mmcsd_set_iocfg(host);
+}
+
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data,
const struct rt_mmcsd_card *card)
{
@@ -475,7 +483,7 @@ void mmcsd_set_data_timeout(struct rt_mmcsd_data *data,
timeout_us = data->timeout_ns / 1000;
timeout_us += data->timeout_clks * 1000 /
- (card->host->io_cfg.clock / 1000);
+ (card->host->io_cfg.clock / 1000);
if (data->flags & DATA_DIR_WRITE)
/*
@@ -596,7 +604,7 @@ int mmcsd_wait_cd_changed(rt_int32_t timeout)
struct rt_mmcsd_host *host;
if (rt_mb_recv(&mmcsd_hotpluge_mb, (rt_ubase_t *)&host, timeout) == RT_EOK)
{
- if(host->card == RT_NULL)
+ if (host->card == RT_NULL)
{
return MMCSD_HOST_UNPLUGED;
}
@@ -667,7 +675,6 @@ void mmcsd_detect(void *param)
continue;
}
mmcsd_host_unlock(host);
- rt_mb_send(&mmcsd_hotpluge_mb, (rt_ubase_t)host);
}
else
{
@@ -691,6 +698,19 @@ void mmcsd_detect(void *param)
}
}
+void mmcsd_host_init(struct rt_mmcsd_host *host)
+{
+ rt_memset(host, 0, sizeof(struct rt_mmcsd_host));
+ strncpy(host->name, "sd", sizeof(host->name) - 1);
+ host->max_seg_size = 65535;
+ host->max_dma_segs = 1;
+ host->max_blk_size = 512;
+ host->max_blk_count = 4096;
+
+ rt_mutex_init(&host->bus_lock, "sd_bus_lock", RT_IPC_FLAG_FIFO);
+ rt_sem_init(&host->sem_ack, "sd_ack", 0, RT_IPC_FLAG_FIFO);
+}
+
struct rt_mmcsd_host *mmcsd_alloc_host(void)
{
struct rt_mmcsd_host *host;
@@ -703,17 +723,7 @@ struct rt_mmcsd_host *mmcsd_alloc_host(void)
return RT_NULL;
}
- rt_memset(host, 0, sizeof(struct rt_mmcsd_host));
-
- host->max_seg_size = 65535;
- host->max_dma_segs = 1;
- host->max_blk_size = 512;
- host->max_blk_count = 4096;
- host->id = allocated_host_num;
- allocated_host_num++;
-
- rt_mutex_init(&host->bus_lock, "sd_bus_lock", RT_IPC_FLAG_PRIO);
- rt_sem_init(&host->sem_ack, "sd_ack", 0, RT_IPC_FLAG_FIFO);
+ mmcsd_host_init(host);
return host;
}
@@ -725,6 +735,22 @@ void mmcsd_free_host(struct rt_mmcsd_host *host)
rt_free(host);
}
+rt_int32_t mmcsd_excute_tuning(struct rt_mmcsd_card *card)
+{
+ struct rt_mmcsd_host *host = card->host;
+ rt_int32_t opcode;
+
+ if (!host->ops->execute_tuning)
+ return RT_EOK;
+
+ if (card->card_type == CARD_TYPE_MMC)
+ opcode = SEND_TUNING_BLOCK_HS200;
+ else
+ opcode = SEND_TUNING_BLOCK;
+
+ return host->ops->execute_tuning(host, opcode);;
+}
+
int rt_mmcsd_core_init(void)
{
rt_err_t ret;
@@ -732,16 +758,16 @@ int rt_mmcsd_core_init(void)
/* initialize detect SD cart thread */
/* initialize mailbox and create detect SD card thread */
ret = rt_mb_init(&mmcsd_detect_mb, "mmcsdmb",
- &mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool) / sizeof(mmcsd_detect_mb_pool[0]),
- RT_IPC_FLAG_FIFO);
+ &mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool) / sizeof(mmcsd_detect_mb_pool[0]),
+ RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
- ret = rt_mb_init(&mmcsd_hotpluge_mb, "mmcsdhotplugmb",
- &mmcsd_hotpluge_mb_pool[0], sizeof(mmcsd_hotpluge_mb_pool) / sizeof(mmcsd_hotpluge_mb_pool[0]),
- RT_IPC_FLAG_FIFO);
+ ret = rt_mb_init(&mmcsd_hotpluge_mb, "mmcsdhotplugmb",
+ &mmcsd_hotpluge_mb_pool[0], sizeof(mmcsd_hotpluge_mb_pool) / sizeof(mmcsd_hotpluge_mb_pool[0]),
+ RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
- ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
- &mmcsd_stack[0], RT_MMCSD_STACK_SIZE, RT_MMCSD_THREAD_PREORITY, 20);
+ ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
+ &mmcsd_stack[0], RT_MMCSD_STACK_SIZE, RT_MMCSD_THREAD_PREORITY, 20);
if (ret == RT_EOK)
{
rt_thread_startup(&mmcsd_detect_thread);
diff --git a/components/drivers/sdio/sd.c b/components/drivers/sdio/sd.c
index fe63cb86b5..0f2c823235 100644
--- a/components/drivers/sdio/sd.c
+++ b/components/drivers/sdio/sd.c
@@ -119,6 +119,7 @@ static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card)
card->card_blksize = 512;
card->card_capacity = (csd->c_size + 1) * 512; /* unit:KB */
+ card->card_sec_cnt = card->card_capacity * 2;
card->tacc_clks = 0;
card->tacc_ns = 0;
card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
diff --git a/components/drivers/sdio/sdio.c b/components/drivers/sdio/sdio.c
index 7d500c70a5..5c04277549 100644
--- a/components/drivers/sdio/sdio.c
+++ b/components/drivers/sdio/sdio.c
@@ -743,11 +743,7 @@ static rt_int32_t sdio_set_highspeed(struct rt_mmcsd_card *card)
rt_int32_t ret;
rt_uint8_t speed;
- if (!(card->host->flags &
- (MMCSD_SUP_HIGHSPEED |
- MMCSD_SUP_HIGHSPEED_DDR |
- MMCSD_SUP_HIGHSPEED_HS200 |
- MMCSD_SUP_HIGHSPEED_HS400)))
+ if (!(card->host->flags & MMCSD_SUP_HIGHSPEED))
return 0;
if (!card->cccr.high_speed)
diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c
index 25f06fa401..cce06217b5 100644
--- a/components/drivers/serial/serial.c
+++ b/components/drivers/serial/serial.c
@@ -70,7 +70,7 @@ static int serial_fops_open(struct dfs_fd *fd)
rt_uint16_t flags = 0;
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
RT_ASSERT(device != RT_NULL);
switch (fd->flags & O_ACCMODE)
@@ -104,7 +104,7 @@ static int serial_fops_close(struct dfs_fd *fd)
{
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
rt_device_set_rx_indicate(device, RT_NULL);
rt_device_close(device);
@@ -118,7 +118,7 @@ static int serial_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
int flags = (int)(rt_base_t)args;
int mask = O_NONBLOCK | O_APPEND;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
switch (cmd)
{
case FIONREAD:
@@ -139,12 +139,13 @@ static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count)
{
int size = 0;
rt_device_t device;
+ int wait_ret;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
do
{
- size = rt_device_read(device, -1, buf, count);
+ size = rt_device_read(device, -1, buf, count);
if (size <= 0)
{
if (fd->flags & O_NONBLOCK)
@@ -153,10 +154,18 @@ static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count)
break;
}
- rt_wqueue_wait(&(device->wait_queue), 0, RT_WAITING_FOREVER);
+ wait_ret = rt_wqueue_wait_interruptible(&(device->wait_queue), 0, RT_WAITING_FOREVER);
+ if (wait_ret != RT_EOK)
+ {
+ break;
+ }
}
}while (size <= 0);
+ if (size < 0)
+ {
+ size = 0;
+ }
return size;
}
@@ -164,7 +173,7 @@ static int serial_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
{
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
return rt_device_write(device, -1, buf, count);
}
@@ -175,7 +184,7 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
rt_device_t device;
struct rt_serial_device *serial;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
RT_ASSERT(device != RT_NULL);
serial = (struct rt_serial_device *)device;
@@ -590,6 +599,8 @@ static rt_err_t rt_serial_init(struct rt_device *dev)
serial->serial_rx = RT_NULL;
serial->serial_tx = RT_NULL;
+ rt_memset(&serial->rx_notify, 0, sizeof(struct rt_device_notify));
+
/* apply configuration */
if (serial->ops->configure)
result = serial->ops->configure(serial, &serial->config);
@@ -1026,7 +1037,19 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
serial->ops->configure(serial, (struct serial_configure *) args);
}
}
+ break;
+ case RT_DEVICE_CTRL_NOTIFY_SET:
+ if (args)
+ {
+ rt_memcpy(&serial->rx_notify, args, sizeof(struct rt_device_notify));
+ }
+ break;
+ case RT_DEVICE_CTRL_CONSOLE_OFLAG:
+ if (args)
+ {
+ *(rt_uint16_t*)args = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM;
+ }
break;
#ifdef RT_USING_POSIX_STDIO
#ifdef RT_USING_POSIX_TERMIOS
@@ -1345,6 +1368,10 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
serial->parent.rx_indicate(&serial->parent, rx_length);
}
}
+ if (serial->rx_notify.notify)
+ {
+ serial->rx_notify.notify(serial->rx_notify.dev);
+ }
break;
}
case RT_SERIAL_EVENT_TX_DONE:
diff --git a/components/drivers/serial/serial_v2.c b/components/drivers/serial/serial_v2.c
index f608999f19..fc03605c1d 100644
--- a/components/drivers/serial/serial_v2.c
+++ b/components/drivers/serial/serial_v2.c
@@ -49,7 +49,7 @@ static int serial_fops_open(struct dfs_fd *fd)
rt_uint16_t flags = 0;
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
RT_ASSERT(device != RT_NULL);
switch (fd->flags & O_ACCMODE)
@@ -83,7 +83,7 @@ static int serial_fops_close(struct dfs_fd *fd)
{
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
rt_device_set_rx_indicate(device, RT_NULL);
rt_device_close(device);
@@ -97,7 +97,7 @@ static int serial_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
int flags = (int)(rt_base_t)args;
int mask = O_NONBLOCK | O_APPEND;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
switch (cmd)
{
case FIONREAD:
@@ -119,7 +119,7 @@ static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count)
int size = 0;
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
do
{
@@ -143,7 +143,7 @@ static int serial_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
{
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
return rt_device_write(device, -1, buf, count);
}
@@ -154,7 +154,7 @@ static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
rt_device_t device;
struct rt_serial_device *serial;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
RT_ASSERT(device != RT_NULL);
serial = (struct rt_serial_device *)device;
@@ -889,6 +889,8 @@ static rt_err_t rt_serial_tx_disable(struct rt_device *dev,
rt_free(tx_fifo);
serial->serial_tx = RT_NULL;
+ rt_memset(&serial->rx_notify, 0, sizeof(struct rt_device_notify));
+
return RT_EOK;
}
@@ -1138,7 +1140,19 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
serial->config = *pconfig;
serial->ops->configure(serial, (struct serial_configure *) args);
}
+ break;
+ case RT_DEVICE_CTRL_NOTIFY_SET:
+ if (args)
+ {
+ rt_memcpy(&serial->rx_notify, args, sizeof(struct rt_device_notify));
+ }
+ break;
+ case RT_DEVICE_CTRL_CONSOLE_OFLAG:
+ if (args)
+ {
+ *(rt_uint16_t*)args = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM;
+ }
break;
#ifdef RT_USING_POSIX_STDIO
#ifdef RT_USING_POSIX_TERMIOS
@@ -1512,6 +1526,11 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
/* Trigger the receiving completion callback */
if (serial->parent.rx_indicate != RT_NULL)
serial->parent.rx_indicate(&(serial->parent), rx_length);
+
+ if (serial->rx_notify.notify)
+ {
+ serial->rx_notify.notify(serial->rx_notify.dev);
+ }
break;
}
diff --git a/components/drivers/tty/SConscript b/components/drivers/tty/SConscript
new file mode 100644
index 0000000000..3c561f4e46
--- /dev/null
+++ b/components/drivers/tty/SConscript
@@ -0,0 +1,10 @@
+from building import *
+
+# The set of source files associated with this SConscript file.
+src = Glob('*.c')
+cwd = GetCurrentDir()
+CPPPATH = [cwd + "/include"]
+
+group = DefineGroup('tty', src, depend = ['RT_USING_LWP', 'RT_USING_TTY'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/drivers/tty/console.c b/components/drivers/tty/console.c
new file mode 100644
index 0000000000..dfab484f2e
--- /dev/null
+++ b/components/drivers/tty/console.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#include <rtthread.h>
+#include <dfs_file.h>
+#include <dfs_fs.h>
+#include <tty.h>
+
+#define DBG_TAG "CONSOLE"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+static struct tty_struct console_driver;
+
+static void console_rx_notify(struct rt_device *dev)
+{
+ struct tty_struct *console = NULL;
+ int len = 0;
+ int lens = 0;
+ char ch = 0;
+ char buf[1024] = {0};
+
+ console = (struct tty_struct *)dev;
+ RT_ASSERT(console != RT_NULL);
+
+ while (1)
+ {
+ len = rt_device_read(console->driver, -1, &ch, 1);
+ if (len == 0)
+ {
+ break;
+ }
+ lens += len;
+ buf[lens-1] = ch;
+ if (lens > 1024)
+ {
+ break;
+ }
+ }
+
+ if (console->ldisc->ops->receive_buf)
+ {
+ console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens);
+ }
+}
+
+struct tty_struct *console_tty_get(void)
+{
+ return &console_driver;
+}
+
+static void iodev_close(struct tty_struct *console)
+{
+ struct rt_device_notify rx_notify;
+
+ rx_notify.notify = RT_NULL;
+ rx_notify.dev = RT_NULL;
+
+ /* clear notify */
+ rt_device_control(console->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
+ rt_device_close(console->driver);
+}
+
+static rt_err_t iodev_open(struct tty_struct *console)
+{
+ rt_err_t ret = RT_EOK;
+ struct rt_device_notify rx_notify;
+ rt_uint16_t oflags = 0;
+
+ rt_device_control(console->driver, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
+
+ ret = rt_device_open(console->driver, oflags);
+ if (ret != RT_EOK)
+ {
+ return RT_ERROR;
+ }
+
+ rx_notify.notify = console_rx_notify;
+ rx_notify.dev = (struct rt_device *)console;
+ rt_device_control(console->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
+ return RT_EOK;
+}
+
+struct rt_device *console_get_iodev(void)
+{
+ rt_base_t level = 0;
+ struct rt_device *iodev = RT_NULL;
+
+ level = rt_hw_interrupt_disable();
+ iodev = console_driver.driver;
+ rt_hw_interrupt_enable(level);
+ return iodev;
+}
+
+struct rt_device *console_set_iodev(struct rt_device *iodev)
+{
+ rt_base_t level = 0;
+ struct rt_device *io_before = RT_NULL;
+ struct tty_struct *console = RT_NULL;
+
+ RT_ASSERT(iodev != RT_NULL);
+
+ console = &console_driver;
+
+ level = rt_hw_interrupt_disable();
+
+ RT_ASSERT(console->init_flag >= TTY_INIT_FLAG_REGED);
+
+ io_before = console->driver;
+
+ if (iodev == io_before)
+ {
+ goto exit;
+ }
+
+ if (console->init_flag >= TTY_INIT_FLAG_INITED)
+ {
+ /* close old device */
+ iodev_close(console);
+ }
+
+ console->driver = iodev;
+
+ if (console->init_flag >= TTY_INIT_FLAG_INITED)
+ {
+ rt_err_t ret;
+ /* open new device */
+ ret = iodev_open(console);
+ RT_ASSERT(ret == RT_EOK);
+ }
+
+exit:
+ rt_hw_interrupt_enable(level);
+ return io_before;
+}
+
+/* RT-Thread Device Interface */
+/*
+ * This function initializes console device.
+ */
+static rt_err_t rt_console_init(struct rt_device *dev)
+{
+ rt_base_t level = 0;
+ rt_err_t result = RT_EOK;
+ struct tty_struct *console = RT_NULL;
+
+ RT_ASSERT(dev != RT_NULL);
+
+ console = (struct tty_struct *)dev;
+
+ level = rt_hw_interrupt_disable();
+
+ RT_ASSERT(console->init_flag == TTY_INIT_FLAG_REGED);
+
+ result = iodev_open(console);
+ if (result != RT_EOK)
+ {
+ goto exit;
+ }
+
+ console->init_flag = TTY_INIT_FLAG_INITED;
+exit:
+ rt_hw_interrupt_enable(level);
+ return result;
+}
+
+static rt_err_t rt_console_open(struct rt_device *dev, rt_uint16_t oflag)
+{
+ rt_err_t result = RT_EOK;
+ struct tty_struct *console = RT_NULL;
+
+ RT_ASSERT(dev != RT_NULL);
+ console = (struct tty_struct *)dev;
+ RT_ASSERT(console != RT_NULL);
+ RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+ return result;
+}
+
+static rt_err_t rt_console_close(struct rt_device *dev)
+{
+ rt_err_t result = RT_EOK;
+ struct tty_struct *console = RT_NULL;
+
+ console = (struct tty_struct *)dev;
+ RT_ASSERT(console != RT_NULL);
+ RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+ return result;
+}
+
+static rt_size_t rt_console_read(struct rt_device *dev,
+ rt_off_t pos,
+ void *buffer,
+ rt_size_t size)
+{
+ rt_size_t len = 0;
+ return len;
+}
+
+static rt_size_t rt_console_write(struct rt_device *dev,
+ rt_off_t pos,
+ const void *buffer,
+ rt_size_t size)
+{
+ rt_size_t len = 0;
+ struct tty_struct *console = RT_NULL;
+
+ console = (struct tty_struct *)dev;
+ RT_ASSERT(console != RT_NULL);
+ RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+
+ len = rt_device_write((struct rt_device *)console->driver, -1, buffer, size);
+
+ return len;
+}
+
+static rt_err_t rt_console_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_size_t len = 0;
+ struct tty_struct *console = RT_NULL;
+
+ console = (struct tty_struct *)dev;
+ RT_ASSERT(console != RT_NULL);
+ RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+
+ len = rt_device_control((struct rt_device *)console->driver, cmd, args);
+
+ return len;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops console_ops =
+{
+ rt_console_init,
+ rt_console_open,
+ rt_console_close,
+ rt_console_read,
+ rt_console_write,
+ rt_console_control,
+};
+#endif
+/*
+ * console register
+ */
+ static struct dfs_file_ops con_fops;
+rt_err_t console_register(const char *name, struct rt_device *iodev)
+{
+ rt_base_t level = 0;
+ rt_err_t ret = RT_EOK;
+ struct rt_device *device = RT_NULL;
+ struct tty_struct *console = &console_driver;
+
+ level = rt_hw_interrupt_disable();
+ RT_ASSERT(console->init_flag == TTY_INIT_FLAG_NONE);
+ RT_ASSERT(iodev != RT_NULL);
+
+ device = &(console->parent);
+
+ device->type = RT_Device_Class_Char;
+
+#ifdef RT_USING_DEVICE_OPS
+ device->ops = &console_ops;
+#else
+ device->init = rt_console_init;
+ device->open = rt_console_open;
+ device->close = rt_console_close;
+ device->read = rt_console_read;
+ device->write = rt_console_write;
+ device->control = rt_console_control;
+#endif
+
+
+ /* register a character device */
+ ret = rt_device_register(device, name, 0);
+ if (ret != RT_EOK)
+ {
+ LOG_E("console driver register fail\n");
+ goto exit;
+ }
+
+#ifdef RT_USING_POSIX_DEVIO
+ /* set fops */
+ console_set_fops(&con_fops);
+ device->fops = &con_fops;
+#endif
+ console->type = TTY_DRIVER_TYPE_CONSOLE;
+ console->subtype = SERIAL_TYPE_NORMAL;
+ console->driver = iodev;
+ console->head = rt_calloc(1, sizeof(struct tty_node));
+ if (!console->head)
+ {
+ return -RT_ENOMEM;
+ }
+ tty_initstack(console->head);
+
+ rt_mutex_init(&console->lock, "ttylock", RT_IPC_FLAG_PRIO);
+ console->pgrp = -1;
+ console->session = -1;
+ console->foreground = RT_NULL;
+ rt_wqueue_init(&console->wait_queue);
+
+ tty_ldisc_init(console);
+
+extern struct termios tty_std_termios;
+ console->init_termios = tty_std_termios;
+ console->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL; /* is normally B9600 default... */
+ console->init_termios.__c_ispeed = 9600;
+ console->init_termios.__c_ospeed = 9600;
+
+ console_ldata_init(console);
+ console->init_flag = TTY_INIT_FLAG_REGED;
+exit:
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
diff --git a/components/drivers/tty/include/console.h b/components/drivers/tty/include/console.h
new file mode 100644
index 0000000000..779d816d4b
--- /dev/null
+++ b/components/drivers/tty/include/console.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#ifndef __CONSOLE_
+#define __CONSOLE_
+#include <rtthread.h>
+#include "tty.h"
+
+struct tty_struct *console_tty_get(void);
+struct rt_device *console_get_iodev(void);
+struct rt_device *console_set_iodev(struct rt_device *iodev);
+rt_err_t console_register(const char *name, struct rt_device *iodev);
+#endif
diff --git a/components/drivers/tty/include/tty.h b/components/drivers/tty/include/tty.h
new file mode 100644
index 0000000000..2040cc45f3
--- /dev/null
+++ b/components/drivers/tty/include/tty.h
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#ifndef __TTY_H__
+#define __TTY_H__
+#include <rthw.h>
+#include <rtthread.h>
+#include <tty_ldisc.h>
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#endif
+#if defined(RT_USING_POSIX_TERMIOS)
+#include <poll.h>
+#include <termios.h>
+#endif
+
+#ifndef ENOIOCTLCMD
+#define ENOIOCTLCMD (515) /* No ioctl command */
+#endif
+
+#define current lwp_self()
+#define __DISABLED_CHAR '\0'
+
+struct tty_node
+{
+ struct rt_lwp *lwp;
+ struct tty_node *next;
+};
+
+void tty_initstack(struct tty_node *node);
+int tty_push(struct tty_node **head, struct rt_lwp *lwp);
+struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp);
+/*
+ * When a break, frame error, or parity error happens, these codes are
+ * stuffed into the flags buffer.
+ */
+#define TTY_NORMAL 0
+#define TTY_BREAK 1
+#define TTY_FRAME 2
+#define TTY_PARITY 3
+#define TTY_OVERRUN 4
+
+#define INTR_CHAR(tty) ((tty)->init_termios.c_cc[VINTR])
+#define QUIT_CHAR(tty) ((tty)->init_termios.c_cc[VQUIT])
+#define ERASE_CHAR(tty) ((tty)->init_termios.c_cc[VERASE])
+#define KILL_CHAR(tty) ((tty)->init_termios.c_cc[VKILL])
+#define EOF_CHAR(tty) ((tty)->init_termios.c_cc[VEOF])
+#define TIME_CHAR(tty) ((tty)->init_termios.c_cc[VTIME])
+#define MIN_CHAR(tty) ((tty)->init_termios.c_cc[VMIN])
+#define SWTC_CHAR(tty) ((tty)->init_termios.c_cc[VSWTC])
+#define START_CHAR(tty) ((tty)->init_termios.c_cc[VSTART])
+#define STOP_CHAR(tty) ((tty)->init_termios.c_cc[VSTOP])
+#define SUSP_CHAR(tty) ((tty)->init_termios.c_cc[VSUSP])
+#define EOL_CHAR(tty) ((tty)->init_termios.c_cc[VEOL])
+#define REPRINT_CHAR(tty) ((tty)->init_termios.c_cc[VREPRINT])
+#define DISCARD_CHAR(tty) ((tty)->init_termios.c_cc[VDISCARD])
+#define WERASE_CHAR(tty) ((tty)->init_termios.c_cc[VWERASE])
+#define LNEXT_CHAR(tty) ((tty)->init_termios.c_cc[VLNEXT])
+#define EOL2_CHAR(tty) ((tty)->init_termios.c_cc[VEOL2])
+
+#define _I_FLAG(tty,f) ((tty)->init_termios.c_iflag & (f))
+#define _O_FLAG(tty,f) ((tty)->init_termios.c_oflag & (f))
+#define _C_FLAG(tty,f) ((tty)->init_termios.c_cflag & (f))
+#define _L_FLAG(tty,f) ((tty)->init_termios.c_lflag & (f))
+
+#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
+#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
+#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
+#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
+#define I_INPCK(tty) _I_FLAG((tty),INPCK)
+#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
+#define I_INLCR(tty) _I_FLAG((tty),INLCR)
+#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
+#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
+#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
+#define I_IXON(tty) _I_FLAG((tty),IXON)
+#define I_IXANY(tty) _I_FLAG((tty),IXANY)
+#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
+#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
+#define I_IUTF8(tty) _I_FLAG((tty), IUTF8)
+
+#define O_OPOST(tty) _O_FLAG((tty),OPOST)
+#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
+#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
+#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
+#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
+#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
+#define O_OFILL(tty) _O_FLAG((tty),OFILL)
+#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
+#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
+#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
+#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
+#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
+#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
+#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
+
+#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
+#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
+#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
+#define C_CREAD(tty) _C_FLAG((tty),CREAD)
+#define C_PARENB(tty) _C_FLAG((tty),PARENB)
+#define C_PARODD(tty) _C_FLAG((tty),PARODD)
+#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
+#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
+#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
+#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
+
+#define L_ISIG(tty) _L_FLAG((tty),ISIG)
+#define L_ICANON(tty) _L_FLAG((tty),ICANON)
+#define L_XCASE(tty) _L_FLAG((tty),XCASE)
+#define L_ECHO(tty) _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
+#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
+#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
+#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
+#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
+#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
+#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
+#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
+#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
+#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
+
+/*
+ * Where all of the state associated with a tty is kept while the tty
+ * is open. Since the termios state should be kept even if the tty
+ * has been closed --- for things like the baud rate, etc --- it is
+ * not stored here, but rather a pointer to the real state is stored
+ * here. Possible the winsize structure should have the same
+ * treatment, but (1) the default 80x24 is usually right and (2) it's
+ * most often used by a windowing system, which will set the correct
+ * size each time the window is created or resized anyway.
+ * - TYT, 9/14/92
+ */
+struct tty_struct
+{
+ struct rt_device parent;
+ int type;
+ int subtype;
+ int init_flag;
+ int index; //for pty
+ int pts_lock; //for pty
+
+ struct tty_struct *other_struct; //for pty
+
+ struct termios init_termios;
+ struct winsize winsize;
+ struct rt_mutex lock;
+ pid_t pgrp;
+ pid_t session;
+ struct rt_lwp *foreground;
+ struct tty_node *head;
+
+ struct tty_ldisc *ldisc;
+ void *disc_data;
+ struct rt_device *driver;
+
+ struct rt_wqueue wait_queue;
+
+#define RT_TTY_BUF 1024
+ rt_list_t tty_drivers;
+};
+
+enum
+{
+ TTY_INIT_FLAG_NONE = 0,
+ TTY_INIT_FLAG_ALLOCED,
+ TTY_INIT_FLAG_REGED,
+ TTY_INIT_FLAG_INITED,
+};
+
+#define TTY_DRIVER_TYPE_SYSTEM 0x0001
+#define TTY_DRIVER_TYPE_CONSOLE 0x0002
+#define TTY_DRIVER_TYPE_SERIAL 0x0003
+#define TTY_DRIVER_TYPE_PTY 0x0004
+#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
+#define TTY_DRIVER_TYPE_SYSCONS 0x0006
+
+/* tty magic number */
+#define TTY_MAGIC 0x5401
+
+/*
+ * These bits are used in the flags field of the tty structure.
+ *
+ * So that interrupts won't be able to mess up the queues,
+ * copy_to_cooked must be atomic with respect to itself, as must
+ * tty->write. Thus, you must use the inline functions set_bit() and
+ * clear_bit() to make things atomic.
+ */
+#define TTY_THROTTLED 0
+#define TTY_IO_ERROR 1
+#define TTY_OTHER_CLOSED 2
+#define TTY_EXCLUSIVE 3
+#define TTY_DEBUG 4
+#define TTY_DO_WRITE_WAKEUP 5
+#define TTY_PUSH 6
+#define TTY_CLOSING 7
+#define TTY_DONT_FLIP 8
+#define TTY_HW_COOK_OUT 14
+#define TTY_HW_COOK_IN 15
+#define TTY_PTY_LOCK 16
+#define TTY_NO_WRITE_SPLIT 17
+
+/*
+ * These bits are used in the flags field of the tty structure.
+ *
+ * So that interrupts won't be able to mess up the queues,
+ * copy_to_cooked must be atomic with respect to itself, as must
+ * tty->write. Thus, you must use the inline functions set_bit() and
+ * clear_bit() to make things atomic.
+ */
+#define TTY_THROTTLED 0
+#define TTY_IO_ERROR 1
+#define TTY_OTHER_CLOSED 2
+#define TTY_EXCLUSIVE 3
+#define TTY_DEBUG 4
+#define TTY_DO_WRITE_WAKEUP 5
+#define TTY_PUSH 6
+#define TTY_CLOSING 7
+#define TTY_DONT_FLIP 8
+#define TTY_HW_COOK_OUT 14
+#define TTY_HW_COOK_IN 15
+#define TTY_PTY_LOCK 16
+#define TTY_NO_WRITE_SPLIT 17
+
+#define NR_LDISCS 30
+
+/* line disciplines */
+#define N_TTY 0
+#define N_SLIP 1
+#define N_MOUSE 2
+#define N_PPP 3
+#define N_STRIP 4
+#define N_AX25 5
+#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
+#define N_MASC 8 /* Reserved for Mobitex module <[email protected]> */
+#define N_R3964 9 /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */
+#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data */
+ /* cards about SMS messages */
+#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14 /* synchronous PPP */
+#define N_HCI 15 /* Bluetooth HCI UART */
+#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
+#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
+#define N_PPS 18 /* Pulse per Second */
+#define N_V253 19 /* Codec control over voice modem */
+#define N_CAIF 20 /* CAIF protocol for talking to modems */
+#define N_GSM0710 21 /* GSM 0710 Mux */
+#define N_TI_WL 22 /* for TI's WL BT, FM, GPS combo chips */
+#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
+#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
+#define N_NCI 25 /* NFC NCI UART */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA 0
+#define TIOCPKT_FLUSHREAD 1
+#define TIOCPKT_FLUSHWRITE 2
+#define TIOCPKT_STOP 4
+#define TIOCPKT_START 8
+#define TIOCPKT_NOSTOP 16
+#define TIOCPKT_DOSTOP 32
+
+/* tty driver types */
+#define TTY_DRIVER_TYPE_SYSTEM 0x0001
+#define TTY_DRIVER_TYPE_CONSOLE 0x0002
+#define TTY_DRIVER_TYPE_SERIAL 0x0003
+#define TTY_DRIVER_TYPE_PTY 0x0004
+#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
+#define TTY_DRIVER_TYPE_SYSCONS 0x0006
+
+/* pty subtypes */
+#define PTY_TYPE_MASTER 0x0001
+#define PTY_TYPE_SLAVE 0x0002
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+
+#define max(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a < _b ? _a : _b; })
+
+void tty_set_fops(struct dfs_file_ops *fops);
+void console_set_fops(struct dfs_file_ops *fops);
+void mutex_lock(rt_mutex_t mutex);
+void mutex_unlock(rt_mutex_t mutex);
+int __tty_check_change(struct tty_struct *tty, int sig);
+int tty_check_change(struct tty_struct *tty);
+
+rt_inline struct rt_wqueue *wait_queue_get(struct rt_lwp *lwp, struct tty_struct *tty)
+{
+ if (lwp == RT_NULL)
+ {
+ return &tty->wait_queue;
+ }
+ return &lwp->wait_queue;
+}
+
+rt_inline struct rt_wqueue *wait_queue_current_get(struct rt_lwp *lwp, struct tty_struct *tty)
+{
+ return wait_queue_get(lwp, tty);
+}
+
+rt_inline void tty_wakeup_check(struct tty_struct *tty)
+{
+ struct rt_wqueue *wq = NULL;
+
+ wq = wait_queue_current_get(tty->foreground, tty);
+ rt_wqueue_wakeup(wq, (void*)POLLIN);
+}
+
+rt_inline int set_bit(int nr,int *addr)
+{
+ int mask, retval, level;
+
+ addr += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ level = rt_hw_interrupt_disable();
+ retval = (mask & *addr) != 0;
+ *addr |= mask;
+ rt_hw_interrupt_enable(level);
+ return retval;
+}
+
+rt_inline int clear_bit(int nr, int *addr)
+{
+ int mask, retval, level;
+
+ addr += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ level = rt_hw_interrupt_disable();
+ retval = (mask & *addr) != 0;
+ *addr &= ~mask;
+ rt_hw_interrupt_enable(level);
+ return retval;
+}
+
+rt_inline int test_bit(int nr, int *addr)
+{
+ int mask;
+
+ addr += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ return ((mask & *addr) != 0);
+}
+
+rt_inline int test_and_clear_bit(int nr, volatile void *addr)
+{
+ int mask, retval, level;
+ volatile unsigned int *a = addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ level = rt_hw_interrupt_disable();
+ retval = (mask & *a) != 0;
+ *a &= ~mask;
+ rt_hw_interrupt_enable(level);
+
+ return retval;
+}
+
+rt_inline unsigned long __ffs(unsigned long word)
+{
+ int num = 0;
+
+#if BITS_PER_LONG == 64
+ if ((word & 0xffffffff) == 0)
+ {
+ num += 32;
+ word >>= 32;
+ }
+#endif
+ if ((word & 0xffff) == 0)
+ {
+ num += 16;
+ word >>= 16;
+ }
+ if ((word & 0xff) == 0)
+ {
+ num += 8;
+ word >>= 8;
+ }
+ if ((word & 0xf) == 0)
+ {
+ num += 4;
+ word >>= 4;
+ }
+ if ((word & 0x3) == 0)
+ {
+ num += 2;
+ word >>= 2;
+ }
+ if ((word & 0x1) == 0)
+ {
+ num += 1;
+ }
+
+ return num;
+}
+#define BITS_PER_LONG 32
+#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
+
+/*
+ * Find the next set bit in a memory region.
+ */
+rt_inline unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ const unsigned long *p = addr + BITOP_WORD(offset);
+ unsigned long result = offset & ~(BITS_PER_LONG-1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ {
+ return size;
+ }
+
+ size -= result;
+ offset %= BITS_PER_LONG;
+ if (offset)
+ {
+ tmp = *(p++);
+ tmp &= (~0UL << offset);
+ if (size < BITS_PER_LONG)
+ {
+ goto found_first;
+ }
+
+ if (tmp)
+ {
+ goto found_middle;
+ }
+
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+
+ while (size & ~(BITS_PER_LONG-1))
+ {
+ if ((tmp = *(p++)))
+ {
+ goto found_middle;
+ }
+
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+
+ if (!size)
+ {
+ return result;
+ }
+
+ tmp = *p;
+
+found_first:
+ tmp &= (~0UL >> (BITS_PER_LONG - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ {
+ return result + size; /* Nope. */
+ }
+
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/*create by tty_ioctl.c*/
+int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *arg);
+
+/*create by n_tty.c*/
+void console_ldata_init(struct tty_struct *tty);
+int n_tty_receive_buf(struct tty_struct *tty, char *cp, int count);
+void n_tty_init(void);
+
+#endif /*__TTY_H__*/
diff --git a/components/drivers/tty/include/tty_ldisc.h b/components/drivers/tty/include/tty_ldisc.h
new file mode 100644
index 0000000000..919805f645
--- /dev/null
+++ b/components/drivers/tty/include/tty_ldisc.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#ifndef __TTY_LDISC_
+#define __TTY_LDISC_
+#include <rtthread.h>
+#include <dfs.h>
+#include <dfs_fs.h>
+#include <tty.h>
+#if defined(RT_USING_POSIX_TERMIOS)
+#include <termios.h>
+#endif
+struct tty_struct;
+
+struct tty_ldisc_ops
+{
+ char *name;
+ int num;
+
+ int (*open) (struct dfs_fd *fd);
+ int (*close) (struct tty_struct *tty);
+ int (*ioctl) (struct dfs_fd *fd, int cmd, void *args);
+ int (*read) (struct dfs_fd *fd, void *buf, size_t count);
+ int (*write) (struct dfs_fd *fd, const void *buf, size_t count);
+ int (*flush) (struct dfs_fd *fd);
+ int (*lseek) (struct dfs_fd *fd, off_t offset);
+ int (*getdents) (struct dfs_fd *fd, struct dirent *dirp, uint32_t count);
+
+ int (*poll) (struct dfs_fd *fd, struct rt_pollreq *req);
+ void (*set_termios) (struct tty_struct *tty, struct termios *old);
+ int (*receive_buf) (struct tty_struct *tty,char *cp, int count);
+
+ int refcount;
+};
+
+struct tty_ldisc
+{
+ struct tty_ldisc_ops *ops;
+ struct tty_struct *tty;
+};
+
+#define TTY_LDISC_MAGIC 0x5403
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
+void tty_ldisc_kill(struct tty_struct *tty);
+void tty_ldisc_init(struct tty_struct *tty);
+void tty_ldisc_release(struct tty_struct *tty);
+void n_tty_init(void);
+
+#endif // __TTY_LDISC_
diff --git a/components/drivers/tty/n_tty.c b/components/drivers/tty/n_tty.c
new file mode 100644
index 0000000000..658c6c0d9e
--- /dev/null
+++ b/components/drivers/tty/n_tty.c
@@ -0,0 +1,2041 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#include <stddef.h>
+#include <ctype.h>
+#include <tty.h>
+#include <lwp.h>
+#if defined(RT_USING_POSIX_TERMIOS)
+#include <termios.h>
+#endif
+#include <sys/errno.h>
+
+#define DBG_TAG "N_TTY"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+/* number of characters left in xmit buffer before select has we have room */
+#define WAKEUP_CHARS 256
+
+/*
+ * This defines the low- and high-watermarks for throttling and
+ * unthrottling the TTY driver. These watermarks are used for
+ * controlling the space in the read buffer.
+ */
+#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
+#define TTY_THRESHOLD_UNTHROTTLE 128
+
+/*
+ * Special byte codes used in the echo buffer to represent operations
+ * or special handling of characters. Bytes in the echo buffer that
+ * are not part of such special blocks are treated as normal character
+ * codes.
+ */
+#define ECHO_OP_START 0xff
+#define ECHO_OP_MOVE_BACK_COL 0x80
+#define ECHO_OP_SET_CANON_COL 0x81
+#define ECHO_OP_ERASE_TAB 0x82
+
+#define ECHO_COMMIT_WATERMARK 256
+#define ECHO_BLOCK 256
+#define ECHO_DISCARD_WATERMARK RT_TTY_BUF - (ECHO_BLOCK + 32)
+
+rt_inline void tty_sigaddset(lwp_sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+
+ if (_LWP_NSIG_WORDS == 1)
+ {
+ set->sig[0] |= 1UL << sig;
+ }
+ else
+ {
+ set->sig[sig / _LWP_NSIG_BPW] |= 1UL << (sig % _LWP_NSIG_BPW);
+ }
+}
+
+struct n_tty_data
+{
+ /* producer-published */
+ size_t read_head;
+ size_t commit_head;
+ size_t canon_head;
+ size_t echo_head;
+ size_t echo_commit;
+ size_t echo_mark;
+ unsigned long char_map[256];
+
+ /* non-atomic */
+ rt_bool_t no_room;
+ /* must hold exclusive termios_rwsem to reset these */
+ unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+ unsigned char push:1;
+
+ /* shared by producer and consumer */
+ char read_buf[RT_TTY_BUF];
+ unsigned long read_flags[RT_TTY_BUF];
+ unsigned char echo_buf[RT_TTY_BUF];
+
+ /* consumer-published */
+ size_t read_tail;
+ size_t line_start;
+
+ /* protected by output lock */
+ unsigned int column;
+ unsigned int canon_column;
+ size_t echo_tail;
+
+ rt_mutex_t atomic_read_lock;
+ rt_mutex_t output_lock;
+};
+
+static inline size_t read_cnt(struct n_tty_data *ldata)
+{
+ return ldata->read_head - ldata->read_tail;
+}
+
+static inline char read_buf(struct n_tty_data *ldata, size_t i)
+{
+ return ldata->read_buf[i & (RT_TTY_BUF - 1)];
+}
+
+static inline char *read_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+ return &ldata->read_buf[i & (RT_TTY_BUF - 1)];
+}
+
+static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
+{
+ return ldata->echo_buf[i & (RT_TTY_BUF - 1)];
+}
+
+static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+ return &ldata->echo_buf[i & (RT_TTY_BUF - 1)];
+}
+
+/**
+ * put_tty_queue - add character to tty
+ * @c: character
+ * @ldata: n_tty data
+ *
+ * Add a character to the tty read_buf queue.
+ *
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ */
+
+static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
+{
+ *read_buf_addr(ldata, ldata->read_head) = c;
+ ldata->read_head++;
+}
+
+/**
+ * reset_buffer_flags - reset buffer state
+ * @tty: terminal to reset
+ *
+ * Reset the read buffer counters and clear the flags.
+ * Called from n_tty_open() and n_tty_flush_buffer().
+ *
+ * Locking: caller holds exclusive termios_rwsem
+ * (or locking is not required)
+ */
+
+static void reset_buffer_flags(struct n_tty_data *ldata)
+{
+ ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
+ ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
+ ldata->commit_head = 0;
+ ldata->echo_mark = 0;
+ ldata->line_start = 0;
+
+ ldata->erasing = 0;
+ rt_memset(ldata->read_flags, 0, RT_TTY_BUF);
+ ldata->push = 0;
+}
+
+/**
+ * add_echo_byte - add a byte to the echo buffer
+ * @c: unicode byte to echo
+ * @ldata: n_tty data
+ *
+ * Add a character or operation byte to the echo buffer.
+ */
+
+static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
+{
+ *echo_buf_addr(ldata, ldata->echo_head++) = c;
+}
+
+/**
+ * echo_move_back_col - add operation to move back a column
+ * @ldata: n_tty data
+ *
+ * Add an operation to the echo buffer to move back one column.
+ */
+
+static void echo_move_back_col(struct n_tty_data *ldata)
+{
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
+}
+
+/**
+ * echo_set_canon_col - add operation to set the canon column
+ * @ldata: n_tty data
+ *
+ * Add an operation to the echo buffer to set the canon column
+ * to the current column.
+ */
+
+static void echo_set_canon_col(struct n_tty_data *ldata)
+{
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
+}
+
+/**
+ * echo_erase_tab - add operation to erase a tab
+ * @num_chars: number of character columns already used
+ * @after_tab: true if num_chars starts after a previous tab
+ * @ldata: n_tty data
+ *
+ * Add an operation to the echo buffer to erase a tab.
+ *
+ * Called by the eraser function, which knows how many character
+ * columns have been used since either a previous tab or the start
+ * of input. This information will be used later, along with
+ * canon column (if applicable), to go back the correct number
+ * of columns.
+ */
+
+static void echo_erase_tab(unsigned int num_chars, int after_tab,
+ struct n_tty_data *ldata)
+{
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
+
+ /* We only need to know this modulo 8 (tab spacing) */
+ num_chars &= 7;
+
+ /* Set the high bit as a flag if num_chars is after a previous tab */
+ if (after_tab)
+ {
+ num_chars |= 0x80;
+ }
+
+ add_echo_byte(num_chars, ldata);
+}
+
+/**
+ * echo_char_raw - echo a character raw
+ * @c: unicode byte to echo
+ * @tty: terminal device
+ *
+ * Echo user input back onto the screen. This must be called only when
+ * L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ * This variant does not treat control characters specially.
+ */
+
+static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
+{
+ if (c == ECHO_OP_START)
+ {
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_START, ldata);
+ }
+ else
+ {
+ add_echo_byte(c, ldata);
+ }
+}
+
+/**
+ * echo_char - echo a character
+ * @c: unicode byte to echo
+ * @tty: terminal device
+ *
+ * Echo user input back onto the screen. This must be called only when
+ * L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ * This variant tags control characters to be echoed as "^X"
+ * (where X is the letter representing the control char).
+ */
+
+static void echo_char(unsigned char c, struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (c == ECHO_OP_START)
+ {
+ add_echo_byte(ECHO_OP_START, ldata);
+ add_echo_byte(ECHO_OP_START, ldata);
+ }
+ else
+ {
+ if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
+ {
+ add_echo_byte(ECHO_OP_START, ldata);
+ }
+ add_echo_byte(c, ldata);
+ }
+}
+
+/**
+ * finish_erasing - complete erase
+ * @ldata: n_tty data
+ */
+
+static inline void finish_erasing(struct n_tty_data *ldata)
+{
+ if (ldata->erasing)
+ {
+ echo_char_raw('/', ldata);
+ ldata->erasing = 0;
+ }
+}
+
+/**
+ * is_utf8_continuation - utf8 multibyte check
+ * @c: byte to check
+ *
+ * Returns true if the utf8 character 'c' is a multibyte continuation
+ * character. We use this to correctly compute the on screen size
+ * of the character when printing
+ */
+
+static inline int is_utf8_continuation(unsigned char c)
+{
+ return (c & 0xc0) == 0x80;
+}
+
+/**
+ * is_continuation - multibyte check
+ * @c: byte to check
+ *
+ * Returns true if the utf8 character 'c' is a multibyte continuation
+ * character and the terminal is in unicode mode.
+ */
+
+static inline int is_continuation(unsigned char c, struct tty_struct *tty)
+{
+ return I_IUTF8(tty) && is_utf8_continuation(c);
+}
+
+/**
+ * eraser - handle erase function
+ * @c: character input
+ * @tty: terminal device
+ *
+ * Perform erase and necessary output when an erase character is
+ * present in the stream from the driver layer. Handles the complexities
+ * of UTF-8 multibyte symbols.
+ *
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ */
+
+static void eraser(unsigned char c, struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ enum { KERASE, WERASE, KILL } kill_type;
+ size_t head = 0;
+ size_t cnt = 0;
+ int seen_alnums = 0;
+
+ if (ldata->read_head == ldata->canon_head)
+ {
+ /* process_output('\a', tty); */ /* what do you think? */
+ return;
+ }
+
+ if (c == ERASE_CHAR(tty))
+ {
+ kill_type = KERASE;
+ }
+ else if (c == WERASE_CHAR(tty))
+ {
+ kill_type = WERASE;
+ }
+ else
+ {
+ if (!L_ECHO(tty))
+ {
+ ldata->read_head = ldata->canon_head;
+ return;
+ }
+
+ if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty))
+ {
+ ldata->read_head = ldata->canon_head;
+ finish_erasing(ldata);
+ echo_char(KILL_CHAR(tty), tty);
+ /* Add a newline if ECHOK is on and ECHOKE is off. */
+ if (L_ECHOK(tty))
+ {
+ echo_char_raw('\n', ldata);
+ }
+ return;
+ }
+ kill_type = KILL;
+ }
+
+ seen_alnums = 0;
+ while (ldata->read_head != ldata->canon_head)
+ {
+ head = ldata->read_head;
+
+ /* erase a single possibly multibyte character */
+ do
+ {
+ head--;
+ c = read_buf(ldata, head);
+ } while (is_continuation(c, tty) && head != ldata->canon_head);
+
+ /* do not partially erase */
+ if (is_continuation(c, tty))
+ {
+ break;
+ }
+
+ if (kill_type == WERASE)
+ {
+ /* Equivalent to BSD's ALTWERASE. */
+ if (isalnum(c) || c == '_')
+ {
+ seen_alnums++;
+ }
+ else if (seen_alnums)
+ {
+ break;
+ }
+ }
+ cnt = ldata->read_head - head;
+ ldata->read_head = head;
+ if (L_ECHO(tty))
+ {
+ if (L_ECHOPRT(tty))
+ {
+ if (!ldata->erasing)
+ {
+ echo_char_raw('\\', ldata);
+ ldata->erasing = 1;
+ }
+ /* if cnt > 1, output a multi-byte character */
+ echo_char(c, tty);
+ while (--cnt > 0)
+ {
+ head++;
+ echo_char_raw(read_buf(ldata, head), ldata);
+ echo_move_back_col(ldata);
+ }
+ }
+ else if (kill_type == KERASE && !L_ECHOE(tty))
+ {
+ echo_char(ERASE_CHAR(tty), tty);
+ }
+ else if (c == '\t')
+ {
+ unsigned int num_chars = 0;
+ int after_tab = 0;
+ size_t tail = ldata->read_head;
+
+ /*
+ * Count the columns used for characters
+ * since the start of input or after a
+ * previous tab.
+ * This info is used to go back the correct
+ * number of columns.
+ */
+ while (tail != ldata->canon_head)
+ {
+ tail--;
+ c = read_buf(ldata, tail);
+ if (c == '\t')
+ {
+ after_tab = 1;
+ break;
+ }
+ else if (iscntrl(c))
+ {
+ if (L_ECHOCTL(tty))
+ {
+ num_chars += 2;
+ }
+ }
+ else if (!is_continuation(c, tty))
+ {
+ num_chars++;
+ }
+ }
+ echo_erase_tab(num_chars, after_tab, ldata);
+ }
+ else
+ {
+ if (iscntrl(c) && L_ECHOCTL(tty))
+ {
+ echo_char_raw('\b', ldata);
+ echo_char_raw(' ', ldata);
+ echo_char_raw('\b', ldata);
+ }
+ if (!iscntrl(c) || L_ECHOCTL(tty))
+ {
+ echo_char_raw('\b', ldata);
+ echo_char_raw(' ', ldata);
+ echo_char_raw('\b', ldata);
+ }
+ }
+ }
+ if (kill_type == KERASE)
+ {
+ break;
+ }
+ }
+ if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
+ {
+ finish_erasing(ldata);
+ }
+}
+
+/**
+ * isig - handle the ISIG optio
+ * @sig: signal
+ * @tty: terminal
+ *
+ * Called when a signal is being sent due to terminal input.
+ * Called from the driver receive_buf path so serialized.
+ *
+ * Performs input and output flush if !NOFLSH. In this context, the echo
+ * buffer is 'output'. The signal is processed first to alert any current
+ * readers or writers to discontinue and exit their i/o loops.
+ *
+ * Locking: ctrl_lock
+ */
+
+static void __isig(int sig, struct tty_struct *tty)
+{
+ struct rt_lwp *lwp = tty->foreground;
+ struct tty_ldisc *ld = RT_NULL;
+ struct termios old_termios;
+ struct termios *new_termios = get_old_termios();
+
+ if (lwp)
+ {
+ if (sig == SIGTSTP)
+ {
+ struct rt_lwp *old_lwp;
+
+ rt_memcpy(&old_termios, &(tty->init_termios), sizeof(struct termios));
+ tty->init_termios = *new_termios;
+ ld = tty->ldisc;
+ if (ld != RT_NULL)
+ {
+ if (ld->ops->set_termios)
+ {
+ ld->ops->set_termios(tty, &old_termios);
+ }
+ }
+ tty_sigaddset(&lwp->signal_mask, SIGTTOU);
+ old_lwp = tty_pop(&tty->head, RT_NULL);
+ tty->foreground = old_lwp;
+ }
+ else
+ {
+ lwp_kill(lwp_to_pid(lwp), sig);
+ }
+ }
+}
+
+static void isig(int sig, struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (L_NOFLSH(tty))
+ {
+ /* signal only */
+ __isig(sig, tty);
+
+ }
+ else
+ { /* signal and flush */
+ __isig(sig, tty);
+
+ /* clear echo buffer */
+ ldata->echo_head = ldata->echo_tail = 0;
+ ldata->echo_mark = ldata->echo_commit = 0;
+
+ /* clear input buffer */
+ reset_buffer_flags(tty->disc_data);
+ }
+}
+
+/**
+ * do_output_char - output one character
+ * @c: character (or partial unicode symbol)
+ * @tty: terminal device
+ * @space: space available in tty driver write buffer
+ *
+ * This is a helper function that handles one output character
+ * (including special characters like TAB, CR, LF, etc.),
+ * doing OPOST processing and putting the results in the
+ * tty driver's write buffer.
+ *
+ * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
+ * and NLDLY. They simply aren't relevant in the world today.
+ * If you ever need them, add them here.
+ *
+ * Returns the number of bytes of buffer space used or -1 if
+ * no space left.
+ *
+ * Locking: should be called under the output_lock to protect
+ * the column state and space left in the buffer
+ */
+
+static int do_output_char(unsigned char c, struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ int spaces = 0;
+ char *ch = RT_NULL;
+
+ switch (c)
+ {
+ case '\n':
+ if (O_ONLRET(tty))
+ {
+ ldata->column = 0;
+ }
+
+ if (O_ONLCR(tty))
+ {
+ ldata->canon_column = ldata->column = 0;
+ ch = "\r\n";
+ rt_device_write((rt_device_t)tty, -1, ch, 2);
+ return 2;
+ }
+ ldata->canon_column = ldata->column;
+ break;
+ case '\r':
+ if (O_ONOCR(tty) && ldata->column == 0)
+ {
+ return 0;
+ }
+
+ if (O_OCRNL(tty))
+ {
+ c = '\n';
+ if (O_ONLRET(tty))
+ {
+ ldata->canon_column = ldata->column = 0;
+ }
+ break;
+ }
+ ldata->canon_column = ldata->column = 0;
+ break;
+ case '\t':
+ spaces = 8 - (ldata->column & 7);
+ if (O_TABDLY(tty) == XTABS)
+ {
+ ldata->column += spaces;
+ ch = " ";
+ rt_device_write((rt_device_t)tty, -1, &ch, spaces);
+ return spaces;
+ }
+ ldata->column += spaces;
+ break;
+ case '\b':
+ if (ldata->column > 0)
+ {
+ ldata->column--;
+ }
+ ch = "\b \b";
+ rt_device_write((rt_device_t)tty, -1, ch, strlen(ch));
+ return 1;
+ default:
+ if (!iscntrl(c))
+ {
+ if (O_OLCUC(tty))
+ {
+ c = toupper(c);
+ }
+
+ if (!is_continuation(c, tty))
+ {
+ ldata->column++;
+ }
+ }
+ break;
+ }
+
+ rt_device_write((rt_device_t)tty, -1, &c, 1);
+ return 1;
+}
+
+/**
+ * process_output - output post processor
+ * @c: character (or partial unicode symbol)
+ * @tty: terminal device
+ *
+ * Output one character with OPOST processing.
+ * Returns -1 when the output device is full and the character
+ * must be retried.
+ *
+ * Locking: output_lock to protect column state and space left
+ * (also, this is called from n_tty_write under the
+ * tty layer write lock)
+ */
+
+static int process_output(unsigned char c, struct tty_struct *tty)
+{
+ int retval = 0;
+
+ retval = do_output_char(c, tty);
+ if (retval < 0)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * process_output_block - block post processor
+ * @tty: terminal device
+ * @buf: character buffer
+ * @nr: number of bytes to output
+ *
+ * Output a block of characters with OPOST processing.
+ * Returns the number of characters output.
+ *
+ * This path is used to speed up block console writes, among other
+ * things when processing blocks of output data. It handles only
+ * the simple cases normally found and helps to generate blocks of
+ * symbols for the console driver and thus improve performance.
+ *
+ * Locking: output_lock to protect column state and space left
+ * (also, this is called from n_tty_write under the
+ * tty layer write lock)
+ */
+
+static ssize_t process_output_block(struct tty_struct *tty,
+ const char *buf, unsigned int nr)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ int i = 0;
+ ssize_t size = 0;
+ const char *cp = RT_NULL;
+
+ for (i = 0, cp = buf; i < nr; i++, cp++)
+ {
+ char c = *cp;
+
+ switch (c)
+ {
+ case '\n':
+ if (O_ONLRET(tty))
+ {
+ ldata->column = 0;
+ }
+
+ if (O_ONLCR(tty))
+ {
+ goto break_out;
+ }
+ ldata->canon_column = ldata->column;
+ break;
+ case '\r':
+ if (O_ONOCR(tty) && ldata->column == 0)
+ {
+ goto break_out;
+ }
+
+ if (O_OCRNL(tty))
+ {
+ goto break_out;
+ }
+
+ ldata->canon_column = ldata->column = 0;
+ break;
+ case '\t':
+ goto break_out;
+ case '\b':
+ if (ldata->column > 0)
+ {
+ ldata->column--;
+ }
+ break;
+ default:
+ if (!iscntrl(c))
+ {
+ if (O_OLCUC(tty))
+ {
+ goto break_out;
+ }
+
+ if (!is_continuation(c, tty))
+ {
+ ldata->column++;
+ }
+ }
+ break;
+ }
+ }
+break_out:
+ size = rt_device_write((rt_device_t)tty, -1, buf, i);
+ return size;
+}
+
+static size_t __process_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t tail = 0;
+ unsigned char c = 0;
+ char ch = 0;
+ unsigned char num_chars = 0, num_bs = 0;
+
+ tail = ldata->echo_tail;
+ while (ldata->echo_commit != tail)
+ {
+ c = echo_buf(ldata, tail);
+ if (c == ECHO_OP_START)
+ {
+ unsigned char op = 0;
+
+ /*
+ * If the buffer byte is the start of a multi-byte
+ * operation, get the next byte, which is either the
+ * op code or a control character value.
+ */
+ op = echo_buf(ldata, tail + 1);
+
+ switch (op)
+ {
+ case ECHO_OP_ERASE_TAB:
+ num_chars = echo_buf(ldata, tail + 2);
+
+ /*
+ * Determine how many columns to go back
+ * in order to erase the tab.
+ * This depends on the number of columns
+ * used by other characters within the tab
+ * area. If this (modulo 8) count is from
+ * the start of input rather than from a
+ * previous tab, we offset by canon column.
+ * Otherwise, tab spacing is normal.
+ */
+ if (!(num_chars & 0x80))
+ {
+ num_chars += ldata->canon_column;
+ }
+ num_bs = 8 - (num_chars & 7);
+
+ while (num_bs--)
+ {
+ ch = '\b';
+ rt_device_write((rt_device_t)tty, -1, &ch, 1);
+ if (ldata->column > 0)
+ {
+ ldata->column--;
+ }
+ }
+ tail += 3;
+ break;
+
+ case ECHO_OP_SET_CANON_COL:
+ ldata->canon_column = ldata->column;
+ tail += 2;
+ break;
+
+ case ECHO_OP_MOVE_BACK_COL:
+ if (ldata->column > 0)
+ {
+ ldata->column--;
+ }
+ tail += 2;
+ break;
+
+ case ECHO_OP_START:
+ ch = ECHO_OP_START;
+ rt_device_write((rt_device_t)tty, -1, &ch, 1);
+ ldata->column++;
+ tail += 2;
+ break;
+
+ default:
+ /*
+ * If the op is not a special byte code,
+ * it is a ctrl char tagged to be echoed
+ * as "^X" (where X is the letter
+ * representing the control char).
+ * Note that we must ensure there is
+ * enough space for the whole ctrl pair.
+ *
+ */
+ ch = '^';
+ rt_device_write((rt_device_t)tty, -1, &ch, 1);
+ ch = op ^ 0100;
+ rt_device_write((rt_device_t)tty, -1, &ch, 1);
+ ldata->column += 2;
+ tail += 2;
+ }
+ }
+ else
+ {
+ if (O_OPOST(tty))
+ {
+ int retval = do_output_char(c, tty);
+ if (retval < 0)
+ {
+ break;
+ }
+ }
+ else
+ {
+ rt_device_write((rt_device_t)tty, -1, &c, 1);
+ }
+ tail += 1;
+ }
+ }
+
+ /* If the echo buffer is nearly full (so that the possibility exists
+ * of echo overrun before the next commit), then discard enough
+ * data at the tail to prevent a subsequent overrun */
+ while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK)
+ {
+ if (echo_buf(ldata, tail) == ECHO_OP_START)
+ {
+ if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
+ {
+ tail += 3;
+ }
+ else
+ {
+ tail += 2;
+ }
+ }
+ else
+ {
+ tail++;
+ }
+ }
+
+ ldata->echo_tail = tail;
+ return 0;
+}
+
+static void commit_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t nr = 0, old = 0;
+ size_t head = 0;
+
+ head = ldata->echo_head;
+ ldata->echo_mark = head;
+ old = ldata->echo_commit - ldata->echo_tail;
+
+ /* Process committed echoes if the accumulated # of bytes
+ * is over the threshold (and try again each time another
+ * block is accumulated) */
+ nr = head - ldata->echo_tail;
+ if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
+ {
+ return;
+ }
+
+ ldata->echo_commit = head;
+ __process_echoes(tty);
+}
+
+static void process_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (ldata->echo_mark == ldata->echo_tail)
+ {
+ return;
+ }
+
+ ldata->echo_commit = ldata->echo_mark;
+ __process_echoes(tty);
+}
+
+/* NB: echo_mark and echo_head should be equivalent here */
+static void flush_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
+ ldata->echo_commit == ldata->echo_head)
+ {
+ return;
+ }
+
+ ldata->echo_commit = ldata->echo_head;
+ __process_echoes(tty);
+}
+/**
+ * n_tty_set_termios - termios data changed
+ * @tty: terminal
+ * @old: previous data
+ *
+ * Called by the tty layer when the user changes termios flags so
+ * that the line discipline can plan ahead. This function cannot sleep
+ * and is protected from re-entry by the tty layer. The user is
+ * guaranteed that this function will not be re-entered or in progress
+ * when the ldisc is closed.
+ *
+ * Locking: Caller holds tty->termios_rwsem
+ */
+
+static void n_tty_set_termios(struct tty_struct *tty, struct termios *old)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (!old || (old->c_lflag ^ tty->init_termios.c_lflag) & (ICANON | EXTPROC))
+ {
+ rt_memset(ldata->read_flags, 0, RT_TTY_BUF);
+ ldata->line_start = ldata->read_tail;
+ if (!L_ICANON(tty) || !read_cnt(ldata))
+ {
+ ldata->canon_head = ldata->read_tail;
+ ldata->push = 0;
+ }
+ else
+ {
+ set_bit((ldata->read_head - 1) & (RT_TTY_BUF - 1),(int *)ldata->read_flags);
+ ldata->canon_head = ldata->read_head;
+ ldata->push = 1;
+ }
+ ldata->commit_head = ldata->read_head;
+ ldata->erasing = 0;
+ ldata->lnext = 0;
+ }
+
+ ldata->icanon = (L_ICANON(tty) != 0);
+
+ if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
+ I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
+ I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
+ I_PARMRK(tty))
+ {
+ rt_memset(ldata->char_map, 0, 256);
+ if (I_IGNCR(tty) || I_ICRNL(tty))
+ {
+ set_bit('\r', (int *)ldata->char_map);
+ }
+
+ if (I_INLCR(tty))
+ {
+ set_bit('\n', (int *)ldata->char_map);
+ }
+
+ if (L_ICANON(tty))
+ {
+ set_bit(ERASE_CHAR(tty), (int *)ldata->char_map);
+ set_bit(KILL_CHAR(tty),(int *) ldata->char_map);
+ set_bit(EOF_CHAR(tty), (int *)ldata->char_map);
+ set_bit('\n',(int *) ldata->char_map);
+ set_bit(EOL_CHAR(tty),(int *) ldata->char_map);
+ if (L_IEXTEN(tty))
+ {
+ set_bit(WERASE_CHAR(tty), (int *)ldata->char_map);
+ set_bit(LNEXT_CHAR(tty), (int *)ldata->char_map);
+ set_bit(EOL2_CHAR(tty), (int *)ldata->char_map);
+ if (L_ECHO(tty))
+ {
+ set_bit(REPRINT_CHAR(tty),
+ (int *)ldata->char_map);
+ }
+ }
+ }
+ if (I_IXON(tty))
+ {
+ set_bit(START_CHAR(tty), (int *)ldata->char_map);
+ set_bit(STOP_CHAR(tty), (int *)ldata->char_map);
+ }
+ if (L_ISIG(tty))
+ {
+ set_bit(INTR_CHAR(tty), (int *)ldata->char_map);
+ set_bit(QUIT_CHAR(tty), (int *)ldata->char_map);
+ set_bit(SUSP_CHAR(tty), (int *)ldata->char_map);
+ }
+ clear_bit(__DISABLED_CHAR, (int *)ldata->char_map);
+ ldata->raw = 0;
+ ldata->real_raw = 0;
+ }
+ else
+ {
+ ldata->raw = 1;
+ if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
+ (I_IGNPAR(tty) || !I_INPCK(tty))/* &&
+ (tty->driver->flags & TTY_DRIVER_REAL_RAW)*/)
+ {
+ ldata->real_raw = 1;
+ }
+ else
+ {
+ ldata->real_raw = 0;
+ }
+ }
+}
+
+void console_ldata_init(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = RT_NULL;
+
+ ldata = rt_malloc(sizeof(struct n_tty_data));
+ if (ldata == RT_NULL)
+ {
+ LOG_E("console_ldata_init ldata malloc fail");
+ return;
+ }
+ tty->disc_data = ldata;
+ reset_buffer_flags(ldata);
+ ldata->column = 0;
+ ldata->canon_column = 0;
+ ldata->no_room = 0;
+ ldata->lnext = 0;
+ n_tty_set_termios(tty, RT_NULL);
+ return;
+}
+
+static int n_tty_open(struct dfs_fd *fd)
+{
+ int ret = 0;
+ struct n_tty_data *ldata = RT_NULL;
+ struct tty_struct *tty = (struct tty_struct*)fd->vnode->data;
+
+ ldata = rt_malloc(sizeof(struct n_tty_data));
+ if (ldata == RT_NULL)
+ {
+ LOG_E("n_tty_open ldata malloc fail");
+ return -1;
+ }
+
+ ldata->atomic_read_lock = rt_mutex_create("atomic_read_lock",RT_IPC_FLAG_FIFO);
+ ldata->output_lock = rt_mutex_create("output_lock",RT_IPC_FLAG_FIFO);
+ tty->disc_data = ldata;
+ reset_buffer_flags(ldata);
+ ldata->column = 0;
+ ldata->canon_column = 0;
+ ldata->lnext = 0;
+ n_tty_set_termios(tty, RT_NULL);
+ return ret;
+}
+
+static inline int input_available_p(struct tty_struct *tty, int poll)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
+
+ if (ldata->icanon && !L_EXTPROC(tty))
+ {
+ return ldata->canon_head != ldata->read_tail;
+ }
+ else
+ {
+ return ldata->commit_head - ldata->read_tail >= amt;
+ }
+}
+
+/**
+ * copy_from_read_buf - copy read data directly
+ * @tty: terminal device
+ * @b: user data
+ * @nr: size of data
+ *
+ * Helper function to speed up n_tty_read. It is only called when
+ * ICANON is off; it copies characters straight from the tty queue to
+ * user space directly. It can be profitably called twice; once to
+ * drain the space from the tail pointer to the (physical) end of the
+ * buffer, and once to drain the space from the (physical) beginning of
+ * the buffer to head pointer.
+ *
+ * Called under the ldata->atomic_read_lock sem
+ *
+ * n_tty_read()/consumer path:
+ * caller holds non-exclusive termios_rwsem
+ * read_tail published
+ */
+
+static int copy_from_read_buf(struct tty_struct *tty,char *b,size_t nr)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t n = 0;
+ rt_bool_t is_eof = 0;
+ size_t head = ldata->commit_head;
+ size_t tail = ldata->read_tail & (RT_TTY_BUF - 1);
+
+ n = min(head - ldata->read_tail, RT_TTY_BUF - tail);
+ n = min(nr, n);
+ if (n)
+ {
+ const char *from = read_buf_addr(ldata, tail);
+ rt_memcpy(b, from, n);
+ is_eof = n == 1 && *from == EOF_CHAR(tty);
+ ldata->read_tail += n;
+ /* Turn single EOF into zero-length read */
+ if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
+ (head == ldata->read_tail))
+ {
+ n = 0;
+ }
+
+ }
+ return n;
+}
+
+/**
+ * canon_copy_from_read_buf - copy read data in canonical mode
+ * @tty: terminal device
+ * @b: user data
+ * @nr: size of data
+ *
+ * Helper function for n_tty_read. It is only called when ICANON is on;
+ * it copies one line of input up to and including the line-delimiting
+ * character into the user-space buffer.
+ *
+ * NB: When termios is changed from non-canonical to canonical mode and
+ * the read buffer contains data, n_tty_set_termios() simulates an EOF
+ * push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
+ * This causes data already processed as input to be immediately available
+ * as input although a newline has not been received.
+ *
+ * Called under the atomic_read_lock mutex
+ *
+ * n_tty_read()/consumer path:
+ * caller holds non-exclusive termios_rwsem
+ * read_tail published
+ */
+
+static int canon_copy_from_read_buf(struct tty_struct *tty, char *b, size_t nr)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t n = 0, size = 0, more = 0, c = 0;
+ size_t eol = 0;
+ size_t tail = 0;
+ int found = 0;
+
+ /* N.B. avoid overrun if nr == 0 */
+ if (nr == 0)
+ {
+ return 0;
+ }
+
+ n = min(nr + 1, ldata->canon_head - ldata->read_tail);
+
+ tail = ldata->read_tail & (RT_TTY_BUF - 1);
+ size = min(tail + n, RT_TTY_BUF);
+
+ eol = find_next_bit(ldata->read_flags, size, tail);
+ more = n - (size - tail);
+ if (eol == RT_TTY_BUF && more)
+ {
+ /* scan wrapped without finding set bit */
+ eol = find_next_bit(ldata->read_flags, more, 0);
+ found = eol != more;
+ }
+ else
+ {
+ found = eol != size;
+ }
+
+ n = eol - tail;
+ if (n > RT_TTY_BUF)
+ {
+ n += RT_TTY_BUF;
+ }
+ c = n + found;
+
+ if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
+ {
+ c = min(nr, c);
+ n = c;
+ }
+
+ size_t buf_size = RT_TTY_BUF - tail;
+ const void *from = read_buf_addr(ldata, tail);
+ if (n > buf_size)
+ {
+ rt_memcpy(b, from, buf_size);
+ b += buf_size;
+ n -= buf_size;
+ from = ldata->read_buf;
+ }
+ rt_memcpy(b, from, n);
+
+ if (found)
+ {
+ clear_bit(eol, (int *)ldata->read_flags);
+ }
+ ldata->read_tail = ldata->read_tail + c;
+
+ if (found)
+ {
+ if (!ldata->push)
+ {
+ ldata->line_start = ldata->read_tail;
+ }
+ else
+ {
+ ldata->push = 0;
+ }
+ }
+ return n;
+}
+
+
+static int n_tty_close(struct tty_struct *tty)
+{
+ int ret = 0;
+ struct n_tty_data *ldata = RT_NULL;
+ struct tty_struct *o_tty = RT_NULL;
+
+ RT_ASSERT(tty != RT_NULL);
+ if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+ {
+ o_tty = tty->other_struct;
+ }
+ else
+ {
+ o_tty = tty;
+ }
+
+ ldata = o_tty->disc_data;
+ rt_free(ldata);
+ o_tty->disc_data = RT_NULL;
+ return ret;
+}
+
+static int n_tty_ioctl(struct dfs_fd *fd, int cmd, void *args)
+{
+ int ret = 0;
+ struct tty_struct *real_tty = RT_NULL;
+ struct tty_struct *tty = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+ {
+ real_tty = tty->other_struct;
+ }
+ else
+ {
+ real_tty = tty;
+ }
+
+ switch(cmd)
+ {
+
+ default:
+ ret = n_tty_ioctl_extend(real_tty, cmd, args);
+ if (ret != -ENOIOCTLCMD)
+ {
+ return ret;
+ }
+ }
+
+ ret = rt_device_control((rt_device_t)real_tty, cmd, args);
+ if (ret != -ENOIOCTLCMD)
+ {
+ return ret;
+ }
+ return ret;
+}
+
+static void
+n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
+{
+ isig(signal, tty);
+ if (L_ECHO(tty))
+ {
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ else
+ {
+ process_echoes(tty);
+ }
+ return;
+}
+
+/**
+ * n_tty_receive_char - perform processing
+ * @tty: terminal device
+ * @c: character
+ *
+ * Process an individual character of input received from the driver.
+ * This is serialized with respect to itself by the rules for the
+ * driver above.
+ *
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ * publishes canon_head if canonical mode is active
+ *
+ * Returns 1 if LNEXT was received, else returns 0
+ */
+
+static int n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (I_IXON(tty))
+ {
+ if (c == START_CHAR(tty)) /*ctrl + p realize missing*/
+ {
+ process_echoes(tty);
+ return 0;
+ }
+ if (c == STOP_CHAR(tty)) /*ctrl + s realize missing*/
+ {
+ return 0;
+ }
+ }
+
+ if (L_ISIG(tty))
+ {
+ if (c == INTR_CHAR(tty)) /*ctrl + c realize missing*/
+ {
+ n_tty_receive_signal_char(tty, SIGINT, c);
+ return 0;
+ }
+ else if (c == QUIT_CHAR(tty)) /*ctrl + d realize missing*/
+ {
+ n_tty_receive_signal_char(tty, SIGQUIT, c);
+ return 0;
+ }
+ else if (c == SUSP_CHAR(tty)) /*ctrl + z realize missing*/
+ {
+ n_tty_receive_signal_char(tty, SIGTSTP, c);
+ return 0;
+ }
+ }
+
+ if (c == '\r')
+ {
+ if (I_IGNCR(tty))
+ {
+ return 0;
+ }
+
+ if (I_ICRNL(tty))
+ {
+ c = '\n';
+ }
+ }
+ else if (c == '\n' && I_INLCR(tty))
+ {
+ c = '\r';
+ }
+
+ if (ldata->icanon)
+ {
+ if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
+ (c == WERASE_CHAR(tty) && L_IEXTEN(tty)))
+ {
+ eraser(c, tty);
+ commit_echoes(tty);
+ return 0;
+ }
+ if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty))
+ {
+ ldata->lnext = 1;
+ if (L_ECHO(tty))
+ {
+ finish_erasing(ldata);
+ if (L_ECHOCTL(tty))
+ {
+ echo_char_raw('^', ldata);
+ echo_char_raw('\b', ldata);
+ commit_echoes(tty);
+ }
+ }
+ return 1;
+ }
+ if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty))
+ {
+ size_t tail = ldata->canon_head;
+
+ finish_erasing(ldata);
+ echo_char(c, tty);
+ echo_char_raw('\n', ldata);
+ while (tail != ldata->read_head)
+ {
+ echo_char(read_buf(ldata, tail), tty);
+ tail++;
+ }
+ commit_echoes(tty);
+ return 0;
+ }
+ if (c == '\n')
+ {
+ if (L_ECHO(tty) || L_ECHONL(tty))
+ {
+ echo_char_raw('\n', ldata);
+ commit_echoes(tty);
+ }
+ goto handle_newline;
+ }
+ if (c == EOF_CHAR(tty))
+ {
+ c = __DISABLED_CHAR;
+ goto handle_newline;
+ }
+ if ((c == EOL_CHAR(tty)) ||
+ (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))
+ {
+ /*
+ * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
+ */
+ if (L_ECHO(tty))
+ {
+ /* Record the column of first canon char. */
+ if (ldata->canon_head == ldata->read_head)
+ {
+ echo_set_canon_col(ldata);
+ }
+
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ /*
+ * XXX does PARMRK doubling happen for
+ * EOL_CHAR and EOL2_CHAR?
+ */
+ if (c == (unsigned char) '\377' && I_PARMRK(tty))
+ {
+ put_tty_queue(c, ldata);
+ }
+
+handle_newline:
+ set_bit(ldata->read_head & (RT_TTY_BUF - 1), (int *)ldata->read_flags);
+ put_tty_queue(c, ldata);
+ ldata->canon_head = ldata->read_head;
+ tty_wakeup_check(tty);
+ return 0;
+ }
+ }
+
+ if (L_ECHO(tty))
+ {
+ finish_erasing(ldata);
+ if (c == '\n')
+ {
+ echo_char_raw('\n', ldata);
+ }
+ else
+ {
+ /* Record the column of first canon char. */
+ if (ldata->canon_head == ldata->read_head)
+ {
+ echo_set_canon_col(ldata);
+ }
+ echo_char(c, tty);
+ }
+ commit_echoes(tty);
+ }
+
+ /* PARMRK doubling check */
+ if (c == (unsigned char) '\377' && I_PARMRK(tty))
+ {
+ put_tty_queue(c, ldata);
+ }
+
+ put_tty_queue(c, ldata);
+ return 0;
+}
+
+static inline void n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (L_ECHO(tty))
+ {
+ finish_erasing(ldata);
+ /* Record the column of first canon char. */
+ if (ldata->canon_head == ldata->read_head)
+ {
+ echo_set_canon_col(ldata);
+ }
+
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ /* PARMRK doubling check */
+ if (c == (unsigned char) '\377' && I_PARMRK(tty))
+ {
+ put_tty_queue(c, ldata);
+ }
+
+ put_tty_queue(c, ldata);
+}
+
+static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+{
+ n_tty_receive_char_inline(tty, c);
+}
+
+static void n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ ldata->lnext = 0;
+ if (flag == TTY_NORMAL)
+ {
+ if (I_ISTRIP(tty))
+ {
+ c &= 0x7f;
+ }
+
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ {
+ c = tolower(c);
+ }
+
+ n_tty_receive_char(tty, c);
+ }
+ else
+ {
+ //n_tty_receive_char_flagged(tty, c, flag);
+ }
+
+}
+
+static void n_tty_receive_buf_real_raw(struct tty_struct *tty, char *cp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t n = 0, head = 0;
+
+ head = ldata->read_head & (RT_TTY_BUF - 1);
+ n = min(count, RT_TTY_BUF - head);
+ rt_memcpy(read_buf_addr(ldata, head), cp, n);
+ ldata->read_head += n;
+ cp += n;
+ count -= n;
+
+ head = ldata->read_head & (RT_TTY_BUF - 1);
+ n = min(count, RT_TTY_BUF - head);
+ rt_memcpy(read_buf_addr(ldata, head), cp, n);
+ ldata->read_head += n;
+}
+
+static void n_tty_receive_buf_raw(struct tty_struct *tty, char *cp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char flag = TTY_NORMAL;
+
+ while (count--)
+ {
+ if (flag == TTY_NORMAL)
+ {
+ put_tty_queue(*cp++, ldata);
+ }
+ }
+}
+
+static void n_tty_receive_buf_standard(struct tty_struct *tty, char *cp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char flag = TTY_NORMAL;
+
+ while (count--)
+ {
+ char c = *cp++;
+
+ if (I_ISTRIP(tty))
+ {
+ c &= 0x7f;
+ }
+
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ {
+ c = tolower(c);
+ }
+
+ if (L_EXTPROC(tty))
+ {
+ put_tty_queue(c, ldata);
+ continue;
+ }
+
+ if (!test_bit(c, (int *)ldata->char_map))
+ {
+ n_tty_receive_char_inline(tty, c);
+ }
+ else if (n_tty_receive_char_special(tty, c) && count)
+ {
+ n_tty_receive_char_lnext(tty, *cp++, flag);
+ count--;
+ }
+ }
+}
+
+static inline void n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (L_ECHO(tty))
+ {
+ finish_erasing(ldata);
+ /* Record the column of first canon char. */
+ if (ldata->canon_head == ldata->read_head)
+ {
+ echo_set_canon_col(ldata);
+ }
+
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ put_tty_queue(c, ldata);
+}
+
+static void n_tty_receive_buf_fast(struct tty_struct *tty, char *cp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char flag = TTY_NORMAL;
+
+ while (count--)
+ {
+ unsigned char c = *cp++;
+
+ if (!test_bit(c, (int *)ldata->char_map))
+ {
+ n_tty_receive_char_fast(tty, c);
+ }
+ else if (n_tty_receive_char_special(tty, c) && count)
+ {
+ n_tty_receive_char_lnext(tty, *cp++, flag);
+ count--;
+ }
+ }
+}
+
+static void __receive_buf(struct tty_struct *tty, char *cp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ rt_bool_t preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
+
+ if (ldata->real_raw)
+ {
+ n_tty_receive_buf_real_raw(tty, cp, count);
+ }
+
+ else if (ldata->raw || (L_EXTPROC(tty) && !preops))
+ {
+ n_tty_receive_buf_raw(tty, cp, count);
+ }
+ else
+ {
+ if (!preops && !I_PARMRK(tty))
+ {
+ n_tty_receive_buf_fast(tty, cp, count);
+ }
+ else
+ {
+ n_tty_receive_buf_standard(tty, cp, count);
+ }
+ flush_echoes(tty);
+ }
+
+ if (ldata->icanon && !L_EXTPROC(tty))
+ return;
+
+ /* publish read_head to consumer */
+ ldata->commit_head = ldata->read_head;
+
+ if (read_cnt(ldata))
+ {
+ tty_wakeup_check(tty);
+ }
+}
+
+int n_tty_receive_buf(struct tty_struct *tty,char *cp, int count)
+{
+ int size = 0;
+ struct n_tty_data *ldata = tty->disc_data;
+ int room = 0, n = 0, rcvd = 0, overflow = 0;
+
+ size = count;
+ while(1)
+ {
+ size_t tail = ldata->read_tail;
+
+ room = RT_TTY_BUF - (ldata->read_head - tail);
+
+ if (I_PARMRK(tty))
+ {
+ room = (room +2)/3;
+ }
+ room--;
+ if (room <= 0)
+ {
+ overflow = ldata->icanon && ldata->canon_head == tail;
+ if (overflow && room < 0)
+ {
+ ldata->read_head--;
+ }
+
+ room = overflow;
+ }
+ else
+ {
+ overflow = 0;
+ }
+
+ n = min(size, room);
+
+ if (!n)
+ {
+ break;
+ }
+
+ if (!overflow)
+ {
+ __receive_buf(tty, cp, n);
+ }
+
+ cp += n;
+ size -= n;
+ rcvd += n;
+ }
+ return count - size;
+}
+
+/**
+ * job_control - check job control
+ * @tty: tty
+ * @file: file handle
+ *
+ * Perform job control management checks on this file/tty descriptor
+ * and if appropriate send any needed signals and return a negative
+ * error code if action should be taken.
+ *
+ * Locking: redirected write test is safe
+ * current->signal->tty check is safe
+ * ctrl_lock to safely reference tty->pgrp
+ */
+
+static int job_control(struct tty_struct *tty)
+{
+ return __tty_check_change(tty, SIGTTIN);
+}
+
+static int n_tty_read(struct dfs_fd *fd, void *buf, size_t count)
+{
+ int level = 0;
+ char *b = (char *)buf;
+ struct tty_struct *tty = RT_NULL;
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_wqueue *wq = RT_NULL;
+ int wait_ret = 0;
+ int retval = 0;
+ int c = 0;
+
+ level = rt_hw_interrupt_disable();
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ c = job_control(tty);
+ if (c < 0)
+ {
+ rt_hw_interrupt_enable(level);
+ return c;
+ }
+
+ struct n_tty_data *ldata = tty->disc_data;
+
+ lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
+ wq = wait_queue_get(lwp, tty);
+
+ while(count)
+ {
+ if ((!input_available_p(tty, 0)))
+ {
+ if (fd->flags & O_NONBLOCK)
+ {
+ retval = -EAGAIN;
+ break;
+ }
+
+ wait_ret = rt_wqueue_wait_interruptible(wq, 0, RT_WAITING_FOREVER);
+ if (wait_ret != 0)
+ {
+ break;
+ }
+ }
+
+ if (ldata->icanon && !L_EXTPROC(tty))
+ {
+ retval = canon_copy_from_read_buf(tty, b, count);
+ }
+ else
+ {
+ retval = copy_from_read_buf(tty, b, count);
+ }
+
+ if (retval >= 1)
+ {
+ break;
+ }
+ }
+ rt_hw_interrupt_enable(level);
+ return retval;
+}
+
+static int n_tty_write(struct dfs_fd *fd, const void *buf, size_t count)
+{
+ int retval = 0;
+ char *b = (char *)buf;
+ int c = 0;
+ struct tty_struct *tty = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ retval = tty_check_change(tty);
+ if (retval)
+ {
+ return retval;
+ }
+
+ process_echoes(tty);
+ retval = count;
+ while(1)
+ {
+ if (O_OPOST(tty))
+ {
+ while (count > 0)
+ {
+ ssize_t num = process_output_block(tty, b, count);
+ if (num < 0)
+ {
+ if (num == -EAGAIN)
+ {
+ break;
+ }
+
+ retval = num;
+ goto break_out;
+ }
+ b += num;
+ count -= num;
+ if (count == 0)
+ {
+ break;
+ }
+
+ c = *b;
+ if (process_output(c, tty) < 0)
+ {
+ break;
+ }
+
+ b++;
+ count--;
+ }
+ retval -= count;
+ }
+ else
+ {
+ while (count > 0)
+ {
+ c = rt_device_write((rt_device_t)tty, -1, b, count);
+ if (c < 0)
+ {
+ retval = c;
+ goto break_out;
+ }
+ b += c;
+ count -= c;
+ }
+ retval -= count;
+ }
+
+ if (!count)
+ {
+ break;
+ }
+ if (fd->flags & O_NONBLOCK)
+ {
+ break;
+ }
+ }
+break_out:
+ return retval;
+}
+
+static int n_tty_flush(struct dfs_fd *fd)
+{
+ return 0;
+}
+
+static int n_tty_lseek(struct dfs_fd *fd, off_t offset)
+{
+ return 0;
+}
+
+static int n_tty_getdents(struct dfs_fd *fd, struct dirent *dirp, uint32_t count)
+{
+ return 0;
+}
+
+static int n_tty_poll(struct dfs_fd *fd, struct rt_pollreq *req)
+{
+ rt_base_t level = 0;
+ int mask = POLLOUT;
+ struct tty_struct *tty = RT_NULL;
+ struct rt_wqueue *wq = RT_NULL;
+ struct rt_lwp *lwp = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+
+ RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
+
+ lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
+ wq = wait_queue_get(lwp, tty);
+ rt_poll_add(wq, req);
+ level = rt_hw_interrupt_disable();
+
+ if (input_available_p(tty, 1))
+ {
+ mask |= POLLIN;
+ }
+
+ rt_hw_interrupt_enable(level);
+
+ return mask;
+}
+
+static struct tty_ldisc_ops n_tty_ops = {
+ "n_tty",
+ 0,
+ n_tty_open,
+ n_tty_close,
+ n_tty_ioctl,
+ n_tty_read,
+ n_tty_write,
+ n_tty_flush,
+ n_tty_lseek,
+ n_tty_getdents,
+ n_tty_poll,
+ n_tty_set_termios,
+ n_tty_receive_buf,
+ 0,
+};
+
+void n_tty_init(void)
+{
+ tty_register_ldisc(N_TTY, &n_tty_ops);
+}
diff --git a/components/drivers/tty/pty.c b/components/drivers/tty/pty.c
new file mode 100644
index 0000000000..b3e6e7519a
--- /dev/null
+++ b/components/drivers/tty/pty.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#include <rtthread.h>
+#include <tty.h>
+#include <tty_ldisc.h>
+
+#define DBG_TAG "PTY"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+#define PTY_PTS_SIZE 10
+static struct tty_struct ptm_driver;
+static struct tty_struct pts_drivers[PTY_PTS_SIZE];
+static int pts_index = 0;
+
+static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index);
+
+/* check free pts device */
+static struct tty_struct *find_freepts(void)
+{
+ for(int i = 0; i < PTY_PTS_SIZE; i++)
+ {
+ if (pts_drivers[i].init_flag == TTY_INIT_FLAG_NONE)
+ {
+ pts_drivers[i].init_flag = TTY_INIT_FLAG_ALLOCED;
+ return &pts_drivers[i];
+ }
+ }
+ return RT_NULL;
+}
+
+/* Set the lock flag on a pty */
+static int pty_set_lock(struct tty_struct *tty, int *arg)
+{
+ int val = *arg;
+
+ if (val)
+ {
+ tty->pts_lock = val;
+ }
+ else
+ {
+ tty->pts_lock = val;
+ }
+ return 0;
+}
+
+static int pty_get_lock(struct tty_struct *tty, int *arg)
+{
+ *arg = tty->pts_lock;
+ return 0;
+}
+
+static int pty_get_index(struct tty_struct *tty, int *arg)
+{
+ *arg = tty->index;
+ return 0;
+}
+/* RT-Thread Device Interface */
+/*
+ * This function initializes console device.
+ */
+static rt_err_t pty_device_init(struct rt_device *dev)
+{
+ rt_err_t result = RT_EOK;
+ int level = 0;
+ struct tty_struct *tty = RT_NULL;
+ RT_ASSERT(dev != RT_NULL);
+
+ tty = (struct tty_struct *)dev;
+ level = rt_hw_interrupt_disable();
+ RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_REGED);
+ tty->init_flag = TTY_INIT_FLAG_INITED;
+ rt_hw_interrupt_enable(level);
+ return result;
+}
+
+static rt_err_t pty_device_open(struct rt_device *dev, rt_uint16_t oflag)
+{
+ rt_err_t result = RT_EOK;
+ return result;
+}
+
+static rt_err_t pty_device_close(struct rt_device *dev)
+{
+ rt_err_t result = RT_EOK;
+ struct tty_struct *tty = (struct tty_struct*)dev;
+ //struct tty_struct *to = RT_NULL;
+
+ if (tty->subtype == PTY_TYPE_MASTER)
+ {
+ // to = tty->other_struct;
+ // to->init_flag = TTY_INIT_FLAG_NONE;
+ // to->other_struct = RT_NULL;
+ // to->foreground = RT_NULL;
+ // to->index = -1;
+ // tty_ldisc_kill(to);
+ // tty->other_struct = RT_NULL;
+ }
+ else
+ {
+ // to = tty->other_struct;
+ // to->other_struct = RT_NULL;
+ // tty->init_flag = TTY_INIT_FLAG_NONE;
+ // tty->other_struct = RT_NULL;
+ // tty->foreground = RT_NULL;
+ // tty->index = -1;
+ // tty->other_struct = RT_NULL;
+ // tty_ldisc_kill(tty);
+ }
+
+ return result;
+}
+
+static rt_size_t pty_device_read(struct rt_device *dev,
+ rt_off_t pos,
+ void *buffer,
+ rt_size_t size)
+{
+ rt_size_t len = 0;
+
+ return len;
+}
+
+static rt_size_t pty_device_write(struct rt_device *dev,
+ rt_off_t pos,
+ const void *buffer,
+ rt_size_t size)
+{
+ rt_base_t level = 0;
+ rt_size_t len = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_struct *to = RT_NULL;
+
+ tty = (struct tty_struct *)dev;
+ RT_ASSERT(tty != RT_NULL);
+ RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
+ to = tty->other_struct;
+ level = rt_hw_interrupt_disable();
+
+ if (to->ldisc->ops->receive_buf)
+ {
+ len = to->ldisc->ops->receive_buf(to, (char *)buffer, size);
+ }
+ rt_hw_interrupt_enable(level);
+
+ return len;
+}
+
+static rt_err_t pty_device_control(rt_device_t dev, int cmd, void *args)
+{
+ struct tty_struct *tty = (struct tty_struct *)dev;
+
+ switch (cmd)
+ {
+ case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+ return pty_set_lock(tty, (int *)args);
+ case TIOCGPTLCK: /* Get PT Lock status */
+ return pty_get_lock(tty, (int *)args);
+ case TIOCGPTN: /* Get PT Number */
+ return pty_get_index(tty, (int *)args);
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int ptmx_open(struct dfs_fd *fd)
+{
+ int ret = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_struct *pts_drv = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_wqueue *wq = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+
+ pts_drv = find_freepts();
+ if (pts_drv == RT_NULL)
+ {
+ LOG_E("free pts driver find fail\n");
+ return -1;
+ }
+ ret = pts_register(tty, pts_drv, pts_index);
+ if (ret < 0)
+ {
+ LOG_E("pts register fail\n");
+ rt_free(pts_drv);
+ return -1;
+ }
+ pts_index++;
+ lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
+ wq = wait_queue_get(lwp, tty);
+ pts_drv->wait_queue = *wq;
+ tty->other_struct = pts_drv;
+ ld = tty->ldisc;
+ if (ld->ops->open)
+ {
+ ret = ld->ops->open(fd);
+ }
+
+ return ret;
+}
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops pty_device_ops =
+{
+ pty_device_init,
+ pty_device_open,
+ pty_device_close,
+ pty_device_read,
+ pty_device_write,
+ pty_device_control,
+};
+#endif /* RT_USING_DEVICE_OPS */
+static struct dfs_file_ops pts_fops;
+static struct dfs_file_ops ptmx_fops;
+static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index)
+{
+ rt_err_t ret = RT_EOK;
+ rt_base_t level = 0;
+ struct rt_device *device = RT_NULL;
+ char name[20];
+
+ RT_ASSERT(ptm_drv!=RT_NULL);
+ level = rt_hw_interrupt_disable();
+
+ if (pts_drv->init_flag != TTY_INIT_FLAG_ALLOCED)
+ {
+ LOG_E("pts%d has been registered\n", pts_index);
+ ret = (-RT_EBUSY);
+ goto _exit;
+ }
+
+ device = &pts_drv->parent;
+ device->type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ device->ops = &pty_device_ops;
+#else
+ device->init = pty_device_init;
+ device->open = pty_device_open;
+ device->close = pty_device_close;
+ device->read = pty_device_read;
+ device->write = pty_device_write;
+ device->control = pty_device_control;
+#endif /* RT_USING_DEVICE_OPS */
+
+ rt_snprintf(name, sizeof(name), "pts%d", pts_index);
+ ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
+ if (ret != RT_EOK)
+ {
+ LOG_E("pts%d register failed\n", pts_index);
+ ret = -RT_EIO;
+ goto _exit;
+ }
+
+#ifdef RT_USING_POSIX_DEVIO
+ /* set fops */
+ tty_set_fops(&pts_fops);
+ device->fops = &pts_fops;
+#endif
+
+ pts_drv->type = TTY_DRIVER_TYPE_PTY;
+ pts_drv->subtype = PTY_TYPE_SLAVE;
+
+ pts_drv->pgrp = -1;
+ pts_drv->session = -1;
+ pts_drv->foreground = RT_NULL;
+ pts_drv->index = pts_index;
+ pts_drv->pts_lock = 1;
+ rt_wqueue_init(&pts_drv->wait_queue);
+
+ tty_ldisc_init(pts_drv);
+
+extern struct termios tty_std_termios;
+ pts_drv->init_termios = tty_std_termios;
+ pts_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
+ pts_drv->init_termios.c_lflag |= ICANON;
+ pts_drv->init_termios.__c_ispeed = 38400;
+ pts_drv->init_termios.__c_ospeed = 38400;
+
+ pts_drv->other_struct = ptm_drv;
+
+ pts_drv->init_flag = TTY_INIT_FLAG_REGED;
+_exit:
+ rt_hw_interrupt_enable(level);
+
+ return ret;
+}
+
+static int ptmx_register(void)
+{
+ rt_base_t level = 0;
+ rt_err_t ret = RT_EOK;
+ struct rt_device *device = RT_NULL;
+ struct tty_struct *ptm_drv = &ptm_driver;
+
+ level = rt_hw_interrupt_disable();
+ RT_ASSERT(ptm_drv->init_flag == TTY_INIT_FLAG_NONE);
+
+ device = &(ptm_drv->parent);
+
+ device->type = RT_Device_Class_Char;
+
+#ifdef RT_USING_DEVICE_OPS
+ device->ops = &pty_device_ops;
+#else
+ device->init = pty_device_init;
+ device->open = pty_device_open;
+ device->close = pty_device_close;
+ device->read = pty_device_read;
+ device->write = pty_device_write;
+ device->control = pty_device_control;
+#endif /* RT_USING_DEVICE_OPS */
+
+ ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
+ if (ret != RT_EOK)
+ {
+ LOG_E("ptmx register fail\n");
+ ret = -RT_EIO;
+ goto _exit;
+ }
+
+#ifdef RT_USING_POSIX_DEVIO
+ /* set fops */
+ tty_set_fops(&ptmx_fops);
+ ptmx_fops.open = ptmx_open;
+ device->fops = &ptmx_fops;
+#endif
+
+ ptm_drv->type = TTY_DRIVER_TYPE_PTY;
+ ptm_drv->subtype = PTY_TYPE_MASTER;
+ ptm_drv->head = rt_calloc(1, sizeof(struct tty_node));
+ if (!ptm_drv->head)
+ {
+ return -RT_ENOMEM;
+ }
+ tty_initstack(ptm_drv->head);
+
+ rt_spin_lock_init(&ptm_drv->spinlock);
+ ptm_drv->pgrp = -1;
+ ptm_drv->session = -1;
+ ptm_drv->foreground = RT_NULL;
+ rt_wqueue_init(&ptm_drv->wait_queue);
+
+ tty_ldisc_init(ptm_drv);
+
+extern struct termios tty_std_termios;
+ ptm_drv->init_termios.c_iflag = 0;
+ ptm_drv->init_termios.c_oflag = 0;
+ ptm_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
+ ptm_drv->init_termios.c_lflag = 0;
+ ptm_drv->init_termios.__c_ispeed = 38400;
+ ptm_drv->init_termios.__c_ospeed = 38400;
+
+ ptm_drv->init_flag = TTY_INIT_FLAG_REGED;
+
+_exit:
+ rt_hw_interrupt_enable(level);
+
+ return ret;
+}
+INIT_DEVICE_EXPORT(ptmx_register);
diff --git a/components/drivers/tty/tty.c b/components/drivers/tty/tty.c
new file mode 100644
index 0000000000..2a9380f55a
--- /dev/null
+++ b/components/drivers/tty/tty.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021.12.07 linzhenxing first version
+ */
+#include <dfs_file.h>
+#include <dfs_fs.h>
+#include <lwp.h>
+#include <rtdevice.h>
+#include <rtthread.h>
+#include <tty.h>
+#include <tty_ldisc.h>
+
+#if defined(RT_USING_POSIX_DEVIO)
+#include <termios.h>
+#endif
+
+#define DBG_TAG "TTY"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+struct termios tty_std_termios = { /* for the benefit of tty drivers */
+ .c_iflag = IMAXBEL | IUCLC | INLCR | ICRNL | IGNPAR,
+ .c_oflag = OPOST,
+ .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+ .c_lflag = ISIG | ECHOE | TOSTOP | NOFLSH,
+ RT_NULL,/* .c_line = N_TTY, */
+ .c_cc = INIT_C_CC,
+ .__c_ispeed = 38400,
+ .__c_ospeed = 38400
+};
+
+void tty_initstack(struct tty_node *node)
+{
+ node->lwp = RT_NULL;
+ node->next = node;
+}
+
+static struct tty_node tty_node_cache = { RT_NULL, RT_NULL };
+
+static struct tty_node *_tty_node_alloc(void)
+{
+ struct tty_node *node = tty_node_cache.next;
+
+ if (node == RT_NULL)
+ {
+ node = rt_calloc(1, sizeof(struct tty_node));
+ }
+ else
+ {
+ tty_node_cache.next = node->next;
+ }
+
+ return node;
+}
+
+static void _tty_node_free(struct tty_node *node)
+{
+ node->next = tty_node_cache.next;
+ tty_node_cache.next = node;
+}
+
+int tty_push(struct tty_node **head, struct rt_lwp *lwp)
+{
+ struct tty_node *node = _tty_node_alloc();
+
+ if (!node)
+ {
+ return -1;
+ }
+
+ node->lwp = lwp;
+ node->next = *head;
+ *head = node;
+
+ return 0;
+}
+
+struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp)
+{
+ struct tty_node *node;
+ struct rt_lwp *lwp = RT_NULL;
+
+ if (!head || !*head)
+ {
+ return RT_NULL;
+ }
+
+ node = *head;
+
+ if (target_lwp != RT_NULL && node->lwp != target_lwp)
+ {
+ struct tty_node *prev = RT_NULL;
+
+ while (node != RT_NULL && node->lwp != target_lwp)
+ {
+ prev = node;
+ node = node->next;
+ }
+
+ if (node != RT_NULL)
+ {
+ /* prev is impossible equ RT_NULL */
+ prev->next = node->next;
+ lwp = target_lwp;
+ _tty_node_free(node);
+ }
+ }
+ else
+ {
+ lwp = (*head)->lwp;
+ *head = (*head)->next;
+ node->lwp = RT_NULL;
+ _tty_node_free(node);
+ }
+
+ return lwp;
+}
+
+rt_inline int tty_sigismember(lwp_sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+
+ if (_LWP_NSIG_WORDS == 1)
+ {
+ return 1 & (set->sig[0] >> sig);
+ }
+ else
+ {
+ return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
+ }
+}
+
+static int is_ignored(int sig)
+{
+ return (tty_sigismember(&current->signal_mask, sig) ||
+ current->signal_handler[sig-1] == SIG_IGN);
+}
+
+/**
+ * tty_check_change - check for POSIX terminal changes
+ * @tty: tty to check
+ *
+ * If we try to write to, or set the state of, a terminal and we're
+ * not in the foreground, send a SIGTTOU. If the signal is blocked or
+ * ignored, go ahead and perform the operation. (POSIX 7.2)
+ *
+ * Locking: ctrl_lock
+ */
+
+int __tty_check_change(struct tty_struct *tty, int sig)
+{
+ pid_t pgrp = 0, tty_pgrp = 0;
+ struct rt_lwp *lwp = tty->foreground;
+ int ret = 0;
+ int level = 0;
+
+ level = rt_hw_interrupt_disable();
+ if (current == RT_NULL)
+ {
+ rt_hw_interrupt_enable(level);
+ return 0;
+ }
+
+ if (current->tty != tty)
+ {
+ rt_hw_interrupt_enable(level);
+ return 0;
+ }
+
+ pgrp = current->__pgrp;
+ tty_pgrp = tty->pgrp;
+
+ if (tty_pgrp && (pgrp != tty->pgrp))
+ {
+ if (is_ignored(sig))
+ {
+ if (sig == SIGTTIN)
+ {
+ ret = -EIO;
+ }
+ }
+ else
+ {
+ if (lwp)
+ {
+ lwp_kill(lwp_to_pid(lwp), sig);
+ }
+ }
+ }
+ rt_hw_interrupt_enable(level);
+
+ if (!tty_pgrp)
+ {
+ LOG_D(tty, "sig=%d, tty->pgrp == -1!\n", sig);
+ }
+ return ret;
+}
+
+int tty_check_change(struct tty_struct *tty)
+{
+ return __tty_check_change(tty, SIGTTOU);
+}
+
+static int tty_open(struct dfs_fd *fd)
+{
+ int ret = 0;
+ int noctty = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ ld = tty->ldisc;
+ if (ld->ops->open)
+ {
+ ret = ld->ops->open(fd);
+ }
+ noctty = (fd->flags & O_NOCTTY);
+
+ rt_device_t device = (rt_device_t)fd->vnode->data;
+ if (fd->vnode->ref_count == 1)
+ {
+ ret = rt_device_open(device, fd->flags);
+ }
+ if (current == RT_NULL) //kernel mode not lwp
+ {
+ return ret;
+ }
+
+ if (!noctty &&
+ current->leader &&
+ !current->tty &&
+ tty->session == -1)
+ {
+ current->tty = tty;
+ current->tty_old_pgrp = 0;
+ tty->session = current->session;
+ tty->pgrp = current->__pgrp;
+ tty->foreground = current;
+ }
+
+ return ret;
+}
+
+static int tty_close(struct dfs_fd *fd)
+{
+ int ret = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ ld = tty->ldisc;
+ if (ld->ops->close)
+ {
+ //ld->ops->close(tty);
+ }
+ if (fd->vnode->ref_count == 1)
+ {
+ ret = rt_device_close((rt_device_t)tty);
+ }
+ return ret;
+}
+
+static int tiocsctty(struct tty_struct *tty, int arg)
+{
+ if (current->leader &&
+ (current->session == tty->session))
+ {
+ return 0;
+ }
+
+ /*
+ * The process must be a session leader and
+ * not have a controlling tty already.
+ */
+ if (!current->leader || current->tty)
+ {
+ return -EPERM;
+ }
+
+ if (tty->session > 0)
+ {
+ LOG_E("this tty have control process\n");
+
+ }
+ current->tty = tty;
+ current->tty_old_pgrp = 0;
+ tty->session = current->session;
+ tty->pgrp = current->__pgrp;
+ tty->foreground = current;
+ if (tty->type == TTY_DRIVER_TYPE_PTY)
+ {
+ tty->other_struct->foreground = current;
+ }
+ return 0;
+}
+
+static int tty_ioctl(struct dfs_fd *fd, int cmd, void *args)
+{
+ int ret = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_struct *real_tty = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+
+ if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+ {
+ real_tty = tty->other_struct;
+ }
+ else
+ {
+ real_tty = tty;
+ }
+ switch (cmd)
+ {
+ case TIOCSCTTY:
+ return tiocsctty(real_tty, 1);
+ }
+ ld = tty->ldisc;
+ if (ld->ops->ioctl)
+ {
+ ret = ld->ops->ioctl(fd, cmd, args);
+ }
+ return ret;
+}
+
+static int tty_read(struct dfs_fd *fd, void *buf, size_t count)
+{
+ int ret = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ ld = tty->ldisc;
+ if (ld->ops->read)
+ {
+ ret = ld->ops->read(fd, buf, count);
+ }
+ return ret;
+}
+
+static int tty_write(struct dfs_fd *fd, const void *buf, size_t count)
+{
+ int ret = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ ld = tty->ldisc;
+ if (ld->ops->write)
+ {
+ ret = ld->ops->write(fd, buf, count);
+ }
+ return ret;
+}
+
+static int tty_poll(struct dfs_fd *fd, struct rt_pollreq *req)
+{
+ int ret = 0;
+ struct tty_struct *tty = RT_NULL;
+ struct tty_ldisc *ld = RT_NULL;
+
+ tty = (struct tty_struct *)fd->vnode->data;
+ RT_ASSERT(tty != RT_NULL);
+ ld = tty->ldisc;
+ if (ld->ops->poll)
+ {
+ ret = ld->ops->poll(fd, req);
+ }
+ return ret;
+}
+
+static const struct dfs_file_ops tty_fops =
+{
+ tty_open,
+ tty_close,
+ tty_ioctl,
+ tty_read,
+ tty_write,
+ RT_NULL, /* flush */
+ RT_NULL, /* lseek */
+ RT_NULL, /* getdents */
+ tty_poll,
+};
+static const struct dfs_file_ops console_fops =
+{
+ tty_open,
+ tty_close,
+ tty_ioctl,
+ tty_read,
+ tty_write,
+ RT_NULL, /* flush */
+ RT_NULL, /* lseek */
+ RT_NULL, /* getdents */
+ tty_poll,
+};
+
+void console_init()
+{
+ n_tty_init();
+}
+
+void tty_set_fops(struct dfs_file_ops *fops)
+{
+ *fops = tty_fops;
+}
+
+void console_set_fops(struct dfs_file_ops *fops)
+{
+ *fops = console_fops;
+}
diff --git a/components/drivers/tty/tty_ioctl.c b/components/drivers/tty/tty_ioctl.c
new file mode 100644
index 0000000000..f7e0d495da
--- /dev/null
+++ b/components/drivers/tty/tty_ioctl.c
@@ -0,0 +1,109 @@
+#include <stddef.h>
+#include <rtthread.h>
+#include <tty.h>
+#if defined(RT_USING_POSIX_DEVIO)
+#include <termios.h>
+#endif
+
+#define DBG_TAG "TTY_IOCTL"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+/*
+ * Internal flag options for termios setting behavior
+ */
+#define TERMIOS_FLUSH 1
+#define TERMIOS_WAIT 2
+#define TERMIOS_TERMIO 4
+#define TERMIOS_OLD 8
+
+/**
+ * set_termios - set termios values for a tty
+ * @tty: terminal device
+ * @arg: user data
+ * @opt: option information
+ *
+ * Helper function to prepare termios data and run necessary other
+ * functions before using tty_set_termios to do the actual changes.
+ *
+ * Locking:
+ * Called functions take ldisc and termios_rwsem locks
+ */
+
+static int set_termios(struct tty_struct *tty, void *arg, int opt)
+{
+ struct termios old_termios;
+ struct tty_ldisc *ld = RT_NULL;
+ struct termios *new_termios = (struct termios *)arg;
+ int level = 0;
+ int retval = tty_check_change(tty);
+
+ if (retval)
+ {
+ return retval;
+ }
+
+ rt_memcpy(&old_termios, &(tty->init_termios), sizeof(struct termios));
+ level = rt_hw_interrupt_disable();
+ tty->init_termios = *new_termios;
+ rt_hw_interrupt_enable(level);
+ ld = tty->ldisc;
+ if (ld != NULL)
+ {
+ if (ld->ops->set_termios)
+ {
+ ld->ops->set_termios(tty, &old_termios);
+ }
+ }
+ return 0;
+}
+
+int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *args)
+{
+ int ret = 0;
+ void *p = (void *)args;
+ struct tty_struct *real_tty = RT_NULL;
+
+ if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+ {
+ real_tty = tty->other_struct;
+ }
+ else
+ {
+ real_tty = tty;
+ }
+
+ switch(cmd)
+ {
+ case TCGETS:
+ {
+ struct termios *tio = (struct termios *)p;
+ if (tio == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_memcpy(tio, &real_tty->init_termios, sizeof(real_tty->init_termios));
+ return ret;
+ }
+ case TCSETSF:
+ {
+ return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+ }
+ case TCSETSW:
+ {
+ return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+ }
+ case TCSETS:
+ {
+ return set_termios(real_tty, p, TERMIOS_OLD);
+ }
+ default:
+ break;
+ }
+ return -ENOIOCTLCMD;
+}
diff --git a/components/drivers/tty/tty_ldisc.c b/components/drivers/tty/tty_ldisc.c
new file mode 100644
index 0000000000..f736812414
--- /dev/null
+++ b/components/drivers/tty/tty_ldisc.c
@@ -0,0 +1,181 @@
+#include <tty.h>
+#include <tty_ldisc.h>
+
+#define DBG_TAG "TTY_LDISC"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+
+static struct tty_ldisc_ops *get_ldops(int disc)
+{
+ struct tty_ldisc_ops *ldops = RT_NULL;
+ int level = 0;
+ level = rt_hw_interrupt_disable();
+ ldops = tty_ldiscs[disc];
+ if (ldops)
+ {
+ ldops->refcount++;
+ }
+ rt_hw_interrupt_enable(level);
+ return ldops;
+}
+
+static void put_ldops(struct tty_ldisc_ops *ldops)
+{
+ int level = 0;
+
+ level = rt_hw_interrupt_disable();
+ ldops->refcount--;
+ rt_hw_interrupt_enable(level);
+}
+static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
+{
+ struct tty_ldisc *ld = RT_NULL;
+ struct tty_ldisc_ops *ldops = RT_NULL;
+
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ {
+ return RT_NULL;
+ }
+
+ ldops = get_ldops(disc);
+ if (ldops == RT_NULL)
+ {
+ LOG_E("tty ldisc get error\n");
+ return RT_NULL;
+ }
+
+ ld = rt_malloc(sizeof(struct tty_ldisc));
+ if (ld == RT_NULL)
+ {
+ ldops->refcount--;
+ return RT_NULL;
+ }
+
+ ld->ops = ldops;
+ ld->tty = tty;
+
+ return ld;
+}
+
+/**
+ * tty_ldisc_put - release the ldisc
+ *
+ * Complement of tty_ldisc_get().
+ */
+static void tty_ldisc_put(struct tty_ldisc *ld)
+{
+ if (ld == RT_NULL)
+ {
+ return;
+ }
+
+ put_ldops(ld->ops);
+ rt_free(ld);
+}
+
+/**
+ * tty_ldisc_close - close a line discipline
+ * @tty: tty we are opening the ldisc on
+ * @ld: discipline to close
+ *
+ * A helper close method. Also a convenient debugging and check
+ * point.
+ */
+
+static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+ if (ld->ops->close)
+ {
+ ld->ops->close(tty);
+ }
+}
+
+/**
+ * tty_ldisc_kill - teardown ldisc
+ * @tty: tty being released
+ *
+ * Perform final close of the ldisc and reset tty->ldisc
+ */
+void tty_ldisc_kill(struct tty_struct *tty)
+{
+ if (!tty->ldisc)
+ {
+ return;
+ }
+
+ /*
+ * Now kill off the ldisc
+ */
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
+}
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+{
+ int ret = 0;
+ int level = 0;
+
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ {
+ return -EINVAL;
+ }
+
+ level = rt_hw_interrupt_disable();
+ tty_ldiscs[disc] = new_ldisc;
+ new_ldisc->num = disc;
+ new_ldisc->refcount = 0;
+ rt_hw_interrupt_enable(level);
+
+ return ret;
+}
+
+/**
+ * tty_ldisc_release - release line discipline
+ * @tty: tty being shut down (or one end of pty pair)
+ *
+ * Called during the final close of a tty or a pty pair in order to shut
+ * down the line discpline layer. On exit, each tty's ldisc is NULL.
+ */
+
+void tty_ldisc_release(struct tty_struct *tty)
+{
+ int level = 0;
+ struct tty_struct *o_tty = tty->other_struct;
+
+ /*
+ * Shutdown this line discipline. As this is the final close,
+ * it does not race with the set_ldisc code path.
+ */
+
+ level = rt_hw_interrupt_disable();
+ tty_ldisc_kill(tty);
+ if (o_tty)
+ {
+ tty_ldisc_kill(o_tty);
+ }
+ rt_hw_interrupt_enable(level);
+
+}
+
+/**
+ * tty_ldisc_init - ldisc setup for new tty
+ * @tty: tty being allocated
+ *
+ * Set up the line discipline objects for a newly allocated tty. Note that
+ * the tty structure is not completely set up when this call is made.
+ */
+
+void tty_ldisc_init(struct tty_struct *tty)
+{
+ struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
+ RT_ASSERT(ld != RT_NULL);
+ tty->ldisc = ld;
+}
diff --git a/components/drivers/virtio/SConscript b/components/drivers/virtio/SConscript
new file mode 100644
index 0000000000..a7af6a017e
--- /dev/null
+++ b/components/drivers/virtio/SConscript
@@ -0,0 +1,11 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_VIRTIO'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/drivers/virtio/virtio.c b/components/drivers/virtio/virtio.c
new file mode 100644
index 0000000000..338b03ca94
--- /dev/null
+++ b/components/drivers/virtio/virtio.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#include <rtthread.h>
+#include <cpuport.h>
+
+#include <virtio.h>
+
+rt_inline void _virtio_dev_check(struct virtio_device *dev)
+{
+ RT_ASSERT(dev != RT_NULL);
+ RT_ASSERT(dev->mmio_config != RT_NULL);
+}
+
+void virtio_reset_device(struct virtio_device *dev)
+{
+ _virtio_dev_check(dev);
+
+ dev->mmio_config->status = 0;
+}
+
+void virtio_status_acknowledge_driver(struct virtio_device *dev)
+{
+ _virtio_dev_check(dev);
+
+ dev->mmio_config->status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER;
+}
+
+void virtio_status_driver_ok(struct virtio_device *dev)
+{
+ _virtio_dev_check(dev);
+
+ dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK;
+}
+
+void virtio_interrupt_ack(struct virtio_device *dev)
+{
+ rt_uint32_t status;
+
+ _virtio_dev_check(dev);
+
+ status = dev->mmio_config->interrupt_status;
+
+ if (status != 0)
+ {
+ dev->mmio_config->interrupt_ack = status;
+ }
+}
+
+rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit)
+{
+ _virtio_dev_check(dev);
+
+ return !!(dev->mmio_config->device_features & (1UL << feature_bit));
+}
+
+rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num)
+{
+ _virtio_dev_check(dev);
+
+ dev->queues = rt_malloc(sizeof(struct virtq) * queues_num);
+
+ if (dev->queues != RT_NULL)
+ {
+ dev->queues_num = queues_num;
+
+ return RT_EOK;
+ }
+
+ return -RT_ENOMEM;
+}
+
+void virtio_queues_free(struct virtio_device *dev)
+{
+ if (dev->queues != RT_NULL)
+ {
+ dev->queues_num = 0;
+ rt_free(dev->queues);
+ }
+}
+
+rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size)
+{
+ int i;
+ void *pages;
+ rt_size_t pages_total_size;
+ struct virtq *queue;
+
+ _virtio_dev_check(dev);
+
+ RT_ASSERT(dev->mmio_config->queue_num_max > 0);
+ RT_ASSERT(dev->mmio_config->queue_num_max > queue_index);
+ /* ring_size is power of 2 */
+ RT_ASSERT(ring_size > 0);
+ RT_ASSERT(((ring_size - 1) & ring_size) == 0);
+
+ queue = &dev->queues[queue_index];
+ pages_total_size = VIRTIO_PAGE_ALIGN(
+ VIRTQ_DESC_TOTAL_SIZE(ring_size) + VIRTQ_AVAIL_TOTAL_SIZE(ring_size)) + VIRTQ_USED_TOTAL_SIZE(ring_size);
+
+ pages = rt_malloc_align(pages_total_size, VIRTIO_PAGE_SIZE);
+
+ if (pages == RT_NULL)
+ {
+ return -RT_ENOMEM;
+ }
+
+ queue->free = rt_malloc(sizeof(rt_bool_t) * ring_size);
+
+ if (queue->free == RT_NULL)
+ {
+ rt_free_align(pages);
+ return -RT_ENOMEM;
+ }
+
+ rt_memset(pages, 0, pages_total_size);
+
+ dev->mmio_config->guest_page_size = VIRTIO_PAGE_SIZE;
+ dev->mmio_config->queue_sel = queue_index;
+ dev->mmio_config->queue_num = ring_size;
+ dev->mmio_config->queue_align = VIRTIO_PAGE_SIZE;
+ dev->mmio_config->queue_pfn = VIRTIO_VA2PA(pages) >> VIRTIO_PAGE_SHIFT;
+
+ queue->num = ring_size;
+ queue->desc = (struct virtq_desc *)((rt_ubase_t)pages);
+ queue->avail = (struct virtq_avail *)(((rt_ubase_t)pages) + VIRTQ_DESC_TOTAL_SIZE(ring_size));
+ queue->used = (struct virtq_used *)VIRTIO_PAGE_ALIGN(
+ (rt_ubase_t)&queue->avail->ring[ring_size] + VIRTQ_AVAIL_RES_SIZE);
+
+ queue->used_idx = 0;
+
+ /* All descriptors start out unused */
+ for (i = 0; i < ring_size; ++i)
+ {
+ queue->free[i] = RT_TRUE;
+ }
+
+ queue->free_count = ring_size;
+
+ return RT_EOK;
+}
+
+void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index)
+{
+ struct virtq *queue;
+
+ _virtio_dev_check(dev);
+
+ RT_ASSERT(dev->mmio_config->queue_num_max > 0);
+ RT_ASSERT(dev->mmio_config->queue_num_max > queue_index);
+
+ queue = &dev->queues[queue_index];
+
+ RT_ASSERT(queue->num > 0);
+
+ rt_free(queue->free);
+ rt_free_align((void *)queue->desc);
+
+ dev->mmio_config->queue_sel = queue_index;
+ dev->mmio_config->queue_pfn = RT_NULL;
+
+ queue->num = 0;
+ queue->desc = RT_NULL;
+ queue->avail = RT_NULL;
+ queue->used = RT_NULL;
+}
+
+void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index)
+{
+ _virtio_dev_check(dev);
+
+ dev->mmio_config->queue_notify = queue_index;
+}
+
+void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
+{
+ rt_size_t ring_size;
+ struct virtq *queue;
+
+ _virtio_dev_check(dev);
+
+ queue = &dev->queues[queue_index];
+ ring_size = queue->num;
+
+ /* Tell the device the first index in our chain of descriptors */
+ queue->avail->ring[queue->avail->idx % ring_size] = desc_index;
+ rt_hw_dsb();
+
+ /* Tell the device another avail ring entry is available */
+ queue->avail->idx++;
+ rt_hw_dsb();
+}
+
+rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index)
+{
+ int i;
+ struct virtq *queue;
+
+ _virtio_dev_check(dev);
+
+ RT_ASSERT(queue_index < dev->queues_num);
+
+ queue = &dev->queues[queue_index];
+
+ if (queue->free_count > 0)
+ {
+ rt_size_t ring_size = queue->num;
+
+ for (i = 0; i < ring_size; ++i)
+ {
+ if (queue->free[i])
+ {
+ queue->free[i] = RT_FALSE;
+ queue->free_count--;
+
+ return (rt_uint16_t)i;
+ }
+ }
+ }
+
+ return VIRTQ_INVALID_DESC_ID;
+}
+
+void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
+{
+ struct virtq *queue;
+
+ _virtio_dev_check(dev);
+
+ queue = &dev->queues[queue_index];
+
+ RT_ASSERT(queue_index < dev->queues_num);
+ RT_ASSERT(!queue->free[desc_index]);
+
+ queue->desc[desc_index].addr = 0;
+ queue->desc[desc_index].len = 0;
+ queue->desc[desc_index].flags = 0;
+ queue->desc[desc_index].next = 0;
+
+ queue->free[desc_index] = RT_TRUE;
+
+ queue->free_count++;
+}
+
+rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count,
+ rt_uint16_t *indexs)
+{
+ int i, j;
+
+ _virtio_dev_check(dev);
+
+ RT_ASSERT(indexs != RT_NULL);
+
+ if (dev->queues[queue_index].free_count < count)
+ {
+ return -RT_ERROR;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ indexs[i] = virtio_alloc_desc(dev, queue_index);
+
+ if (indexs[i] == VIRTQ_INVALID_DESC_ID)
+ {
+ for (j = 0; j < i; ++j)
+ {
+ virtio_free_desc(dev, queue_index, indexs[j]);
+ }
+
+ return -RT_ERROR;
+ }
+ }
+
+ return RT_EOK;
+}
+
+void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
+{
+ rt_uint16_t flags, next;
+ struct virtq_desc *desc;
+
+ _virtio_dev_check(dev);
+
+ desc = &dev->queues[queue_index].desc[0];
+
+ for (;;)
+ {
+ flags = desc[desc_index].flags;
+ next = desc[desc_index].next;
+
+ virtio_free_desc(dev, queue_index, desc_index);
+
+ if (flags & VIRTQ_DESC_F_NEXT)
+ {
+ desc_index = next;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index,
+ rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next)
+{
+ struct virtq_desc *desc;
+
+ _virtio_dev_check(dev);
+
+ desc = &dev->queues[queue_index].desc[desc_index];
+
+ desc->addr = addr;
+ desc->len = len;
+ desc->flags = flags;
+ desc->next = next;
+}
diff --git a/components/drivers/virtio/virtio.h b/components/drivers/virtio/virtio.h
new file mode 100644
index 0000000000..297975601b
--- /dev/null
+++ b/components/drivers/virtio/virtio.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI modify to virtio common interface
+ */
+
+#ifndef __VIRTIO_H__
+#define __VIRTIO_H__
+
+#include <rthw.h>
+#include <rtdef.h>
+
+#ifdef RT_USING_LWP
+#include <mmu.h>
+#include <ioremap.h>
+#endif
+
+#if RT_NAME_MAX < 16
+#error "Please set RT_NAME_MAX to at lest 16"
+#endif
+
+#ifdef RT_USING_VIRTIO10
+#define RT_USING_VIRTIO_VERSION 0x1
+#endif
+
+#include <virtio_mmio.h>
+#include <virtio_queue.h>
+
+#define VIRTIO_MAGIC_VALUE 0x74726976 /* "virt" */
+
+#define VIRTIO_STATUS_ACKNOWLEDGE (1 << 0)
+#define VIRTIO_STATUS_DRIVER (1 << 1)
+#define VIRTIO_STATUS_DRIVER_OK (1 << 2)
+#define VIRTIO_STATUS_FEATURES_OK (1 << 3)
+#define VIRTIO_STATUS_NEEDS_RESET (1 << 6)
+#define VIRTIO_STATUS_FAILED (1 << 7)
+
+#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+#define VIRTIO_F_ANY_LAYOUT 27
+#define VIRTIO_F_RING_INDIRECT_DESC 28
+#define VIRTIO_F_RING_EVENT_IDX 29
+#define VIRTIO_F_VERSION_1 32
+#define VIRTIO_F_RING_PACKED 34
+
+#ifdef RT_USING_LWP
+extern rt_mmu_info mmu_info;
+#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)rt_hw_mmu_v2p(&mmu_info, vaddr))
+#define VIRTIO_PA2VA(paddr) ((rt_ubase_t)rt_ioremap((void *)paddr, ARCH_PAGE_SIZE))
+#else
+#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)vaddr)
+#define VIRTIO_PA2VA(paddr) ((rt_ubase_t)paddr)
+#endif /* RT_USING_LWP */
+#define VIRTIO_PAGE_SHIFT 12
+#define VIRTIO_PAGE_SIZE (1 << VIRTIO_PAGE_SHIFT)
+#define VIRTIO_PAGE_ALIGN(addr) (RT_ALIGN(addr, VIRTIO_PAGE_SIZE))
+
+enum
+{
+ /* virtio 1.0 */
+ VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */
+ VIRTIO_DEVICE_ID_NET = 1, /* Net */
+ VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */
+ VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */
+ VIRTIO_DEVICE_ID_RNG = 4, /* Rng */
+ VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */
+ VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */
+ VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */
+ VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */
+ VIRTIO_DEVICE_ID_9P = 9, /* 9p console */
+ VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */
+ VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */
+ VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */
+ VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */
+ VIRTIO_DEVICE_ID_GPU = 16, /* GPU */
+ VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */
+ VIRTIO_DEVICE_ID_INPUT = 18, /* Input */
+ /* virtio 1.1 */
+ VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */
+ VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */
+ VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */
+ VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */
+ VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */
+ VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */
+ /* virtio 1.2 */
+ VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */
+ VIRTIO_DEVICE_ID_FS = 26, /* File system device */
+ VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */
+ VIRTIO_DEVICE_ID_RPMB = 28, /* RPMB device */
+ VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */
+ VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */
+ VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */
+ VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */
+ VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */
+ VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */
+ VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */
+ VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */
+ VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */
+ VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */
+ VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */
+ VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */
+ VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */
+ VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */
+
+ VIRTIO_DEVICE_TYPE_SIZE
+};
+
+struct virtio_device
+{
+ rt_uint32_t irq;
+
+ struct virtq *queues;
+ rt_size_t queues_num;
+
+ union
+ {
+ rt_ubase_t *mmio_base;
+ struct virtio_mmio_config *mmio_config;
+ };
+
+#ifdef RT_USING_SMP
+ struct rt_spinlock spinlock;
+#endif
+
+ void *priv;
+};
+
+typedef rt_err_t (*virtio_device_init_handler)(rt_ubase_t *mmio_base, rt_uint32_t irq);
+
+void virtio_reset_device(struct virtio_device *dev);
+void virtio_status_acknowledge_driver(struct virtio_device *dev);
+void virtio_status_driver_ok(struct virtio_device *dev);
+void virtio_interrupt_ack(struct virtio_device *dev);
+rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit);
+
+rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num);
+void virtio_queues_free(struct virtio_device *dev);
+rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size);
+void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index);
+void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index);
+
+void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
+
+rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index);
+void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
+rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count,
+ rt_uint16_t *indexs);
+void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
+void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index,
+ rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next);
+
+#endif /* __VIRTIO_H__ */
diff --git a/components/drivers/virtio/virtio_blk.c b/components/drivers/virtio/virtio_blk.c
new file mode 100644
index 0000000000..a568a7008a
--- /dev/null
+++ b/components/drivers/virtio/virtio_blk.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI using virtio common interface
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <cpuport.h>
+
+#ifdef RT_USING_VIRTIO_BLK
+
+#include <virtio_blk.h>
+
+static void virtio_blk_rw(struct virtio_blk_device *virtio_blk_dev, rt_off_t pos, void *buffer, rt_size_t count,
+ int flags)
+{
+ rt_uint16_t idx[3];
+ rt_size_t size = count * virtio_blk_dev->config->blk_size;
+ struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ /* Allocate 3 descriptors */
+ while (virtio_alloc_desc_chain(virtio_dev, 0, 3, idx))
+ {
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ rt_thread_yield();
+
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ }
+
+ virtio_blk_dev->info[idx[0]].status = 0xff;
+ virtio_blk_dev->info[idx[0]].valid = RT_TRUE;
+ virtio_blk_dev->info[idx[0]].req.type = flags;
+ virtio_blk_dev->info[idx[0]].req.ioprio = 0;
+ virtio_blk_dev->info[idx[0]].req.sector = pos * (virtio_blk_dev->config->blk_size / 512);
+
+ flags = flags == VIRTIO_BLK_T_OUT ? 0 : VIRTQ_DESC_F_WRITE;
+
+ virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[0],
+ VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].req), sizeof(struct virtio_blk_req), VIRTQ_DESC_F_NEXT, idx[1]);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[1],
+ VIRTIO_VA2PA(buffer), size, flags | VIRTQ_DESC_F_NEXT, idx[2]);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[2],
+ VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].status), sizeof(rt_uint8_t), VIRTQ_DESC_F_WRITE, 0);
+
+ virtio_submit_chain(virtio_dev, VIRTIO_BLK_QUEUE, idx[0]);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_BLK_QUEUE);
+
+ /* Wait for virtio_blk_isr() to done */
+ while (virtio_blk_dev->info[idx[0]].valid)
+ {
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ rt_thread_yield();
+
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ }
+
+ virtio_free_desc_chain(virtio_dev, VIRTIO_BLK_QUEUE, idx[0]);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+static rt_size_t virtio_blk_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t count)
+{
+ virtio_blk_rw((struct virtio_blk_device *)dev, pos, buffer, count, VIRTIO_BLK_T_IN);
+
+ return count;
+}
+
+static rt_size_t virtio_blk_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t count)
+{
+ virtio_blk_rw((struct virtio_blk_device *)dev, pos, (void *)buffer, count, VIRTIO_BLK_T_OUT);
+
+ return count;
+}
+
+static rt_err_t virtio_blk_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t status = RT_EOK;
+ struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)dev;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_BLK_GETGEOME:
+ {
+ struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args;
+
+ if (geometry == RT_NULL)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ geometry->bytes_per_sector = VIRTIO_BLK_BYTES_PER_SECTOR;
+ geometry->block_size = virtio_blk_dev->config->blk_size;
+ geometry->sector_count = virtio_blk_dev->config->capacity;
+ }
+ break;
+ default:
+ status = -RT_EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_blk_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ virtio_blk_read,
+ virtio_blk_write,
+ virtio_blk_control
+};
+#endif
+
+static void virtio_blk_isr(int irqno, void *param)
+{
+ rt_uint32_t id;
+ struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)param;
+ struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev;
+ struct virtq *queue = &virtio_dev->queues[VIRTIO_BLK_QUEUE];
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ virtio_interrupt_ack(virtio_dev);
+ rt_hw_dsb();
+
+ /* The device increments disk.used->idx when it adds an entry to the used ring */
+ while (queue->used_idx != queue->used->idx)
+ {
+ rt_hw_dsb();
+ id = queue->used->ring[queue->used_idx % queue->num].id;
+
+ RT_ASSERT(virtio_blk_dev->info[id].status == 0);
+
+ /* Done with buffer */
+ virtio_blk_dev->info[id].valid = RT_FALSE;
+
+ queue->used_idx++;
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
+{
+ static int dev_no = 0;
+ char dev_name[RT_NAME_MAX];
+ struct virtio_device *virtio_dev;
+ struct virtio_blk_device *virtio_blk_dev;
+
+ virtio_blk_dev = rt_malloc(sizeof(struct virtio_blk_device));
+
+ if (virtio_blk_dev == RT_NULL)
+ {
+ return -RT_ENOMEM;
+ }
+
+ virtio_dev = &virtio_blk_dev->virtio_dev;
+ virtio_dev->irq = irq;
+ virtio_dev->mmio_base = mmio_base;
+
+ virtio_blk_dev->config = (struct virtio_blk_config *)virtio_dev->mmio_config->config;
+
+#ifdef RT_USING_SMP
+ rt_spin_lock_init(&virtio_dev->spinlock);
+#endif
+
+ virtio_reset_device(virtio_dev);
+ virtio_status_acknowledge_driver(virtio_dev);
+
+ /* Negotiate features */
+ virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
+ (1 << VIRTIO_BLK_F_RO) |
+ (1 << VIRTIO_BLK_F_MQ) |
+ (1 << VIRTIO_BLK_F_SCSI) |
+ (1 << VIRTIO_BLK_F_CONFIG_WCE) |
+ (1 << VIRTIO_F_ANY_LAYOUT) |
+ (1 << VIRTIO_F_RING_EVENT_IDX) |
+ (1 << VIRTIO_F_RING_INDIRECT_DESC));
+
+ /* Tell device that feature negotiation is complete and we're completely ready */
+ virtio_status_driver_ok(virtio_dev);
+
+ if (virtio_queues_alloc(virtio_dev, 1) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ /* Initialize queue 0 */
+ if (virtio_queue_init(virtio_dev, 0, VIRTIO_BLK_QUEUE_RING_SIZE) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ virtio_blk_dev->parent.type = RT_Device_Class_Block;
+#ifdef RT_USING_DEVICE_OPS
+ virtio_blk_dev->parent.ops = &virtio_blk_ops;
+#else
+ virtio_blk_dev->parent.init = RT_NULL;
+ virtio_blk_dev->parent.open = RT_NULL;
+ virtio_blk_dev->parent.close = RT_NULL;
+ virtio_blk_dev->parent.read = virtio_blk_read;
+ virtio_blk_dev->parent.write = virtio_blk_write;
+ virtio_blk_dev->parent.control = virtio_blk_control;
+#endif
+
+ rt_snprintf(dev_name, RT_NAME_MAX, "virtio-blk%d", dev_no++);
+
+ rt_hw_interrupt_install(irq, virtio_blk_isr, virtio_blk_dev, dev_name);
+ rt_hw_interrupt_umask(irq);
+
+ return rt_device_register((rt_device_t)virtio_blk_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
+
+_alloc_fail:
+
+ if (virtio_blk_dev != RT_NULL)
+ {
+ virtio_queues_free(virtio_dev);
+ rt_free(virtio_blk_dev);
+ }
+ return -RT_ENOMEM;
+}
+#endif /* RT_USING_VIRTIO_BLK */
diff --git a/components/drivers/virtio/virtio_blk.h b/components/drivers/virtio/virtio_blk.h
new file mode 100644
index 0000000000..548bcee4c8
--- /dev/null
+++ b/components/drivers/virtio/virtio_blk.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI using virtio common interface
+ */
+
+#ifndef __VIRTIO_BLK_H__
+#define __VIRTIO_BLK_H__
+
+#include <rtdef.h>
+
+#include <virtio.h>
+
+#define VIRTIO_BLK_QUEUE 0
+#define VIRTIO_BLK_BYTES_PER_SECTOR 512
+#define VIRTIO_BLK_QUEUE_RING_SIZE 4
+
+#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
+#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
+#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
+#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
+
+#define VIRTIO_BLK_T_IN 0 /* Read the blk */
+#define VIRTIO_BLK_T_OUT 1 /* Write the blk */
+#define VIRTIO_BLK_T_SCSI_CMD 2
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+#define VIRTIO_BLK_T_FLUSH 4
+#define VIRTIO_BLK_T_FLUSH_OUT 5
+
+struct virtio_blk_req
+{
+ rt_uint32_t type;
+ rt_uint32_t ioprio;
+ rt_uint64_t sector;
+};
+
+struct virtio_blk_config
+{
+ rt_uint64_t capacity; /* The capacity (in 512-byte sectors). */
+ rt_uint32_t size_max; /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+ rt_uint32_t seg_max; /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+
+ /* Geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
+ struct virtio_blk_geometry
+ {
+ rt_uint16_t cylinders;
+ rt_uint8_t heads;
+ rt_uint8_t sectors;
+ } geometry;
+
+ rt_uint32_t blk_size; /* Block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
+
+ struct virtio_blk_topology
+ {
+ /* # Of logical blocks per physical block (log2) */
+ rt_uint8_t physical_block_exp;
+ /* Offset of first aligned logical block */
+ rt_uint8_t alignment_offset;
+ /* Suggested minimum I/O size in blocks */
+ rt_uint16_t min_io_size;
+ /* Optimal (suggested maximum) I/O size in blocks */
+ rt_uint32_t opt_io_size;
+ } topology;
+
+ rt_uint8_t writeback;
+ rt_uint8_t unused0;
+ rt_uint16_t num_queues;
+ rt_uint32_t max_discard_sectors;
+ rt_uint32_t max_discard_seg;
+ rt_uint32_t discard_sector_alignment;
+ rt_uint32_t max_write_zeroes_sectors;
+ rt_uint32_t max_write_zeroes_seg;
+ rt_uint8_t write_zeroes_may_unmap;
+ rt_uint8_t unused1[3];
+ rt_uint32_t max_secure_erase_sectors;
+ rt_uint32_t max_secure_erase_seg;
+ rt_uint32_t secure_erase_sector_alignment;
+} __attribute__((packed));
+
+struct virtio_blk_device
+{
+ struct rt_device parent;
+
+ struct virtio_device virtio_dev;
+
+ struct virtio_blk_config *config;
+
+ struct
+ {
+ rt_bool_t valid;
+ rt_uint8_t status;
+
+ struct virtio_blk_req req;
+
+ } info[VIRTIO_BLK_QUEUE_RING_SIZE];
+};
+
+rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
+
+#endif /* __VIRTIO_BLK_H__ */
diff --git a/components/drivers/virtio/virtio_console.c b/components/drivers/virtio/virtio_console.c
new file mode 100644
index 0000000000..7f1a9b8af5
--- /dev/null
+++ b/components/drivers/virtio/virtio_console.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <cpuport.h>
+
+#ifdef RT_USING_VIRTIO_CONSOLE
+
+#include <virtio_console.h>
+
+struct port_device
+{
+ struct rt_device parent;
+
+ rt_list_t node;
+ rt_uint32_t port_id;
+ rt_bool_t rx_notify;
+ rt_bool_t need_destroy;
+
+ struct virtio_console_device *console;
+
+ struct virtq *queue_rx, *queue_tx;
+ rt_uint32_t queue_rx_index, queue_tx_index;
+
+#ifdef RT_USING_SMP
+ struct rt_spinlock spinlock_rx, spinlock_tx;
+#endif
+
+ struct rt_device_notify rx_notify_helper;
+
+ struct
+ {
+ char rx_char, tx_char;
+ } info[VIRTIO_CONSOLE_QUEUE_SIZE];
+};
+
+static void virtio_console_send_ctrl(struct virtio_console_device *virtio_console_dev,
+ struct virtio_console_control *ctrl)
+{
+ rt_uint16_t id;
+ struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
+ struct virtq *queue_ctrl_tx;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
+
+ id = queue_ctrl_tx->avail->idx % queue_ctrl_tx->num;
+
+ rt_memcpy(&virtio_console_dev->info[id].tx_ctrl, ctrl, sizeof(struct virtio_console_control));
+
+ virtio_free_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id,
+ virtio_console_dev->info[id].tx_ctrl_paddr, sizeof(struct virtio_console_control), 0, 0);
+
+ virtio_submit_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
+
+ virtio_alloc_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+static rt_err_t virtio_console_port_init(rt_device_t dev);
+static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag);
+static rt_err_t virtio_console_port_close(rt_device_t dev);
+static rt_size_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
+static rt_size_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
+static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args);
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_console_port_ops =
+{
+ virtio_console_port_init,
+ virtio_console_port_open,
+ virtio_console_port_close,
+ virtio_console_port_read,
+ virtio_console_port_write,
+ virtio_console_port_control
+};
+#endif
+
+static rt_err_t virtio_console_port_create(struct virtio_console_device *virtio_console_dev)
+{
+ rt_uint32_t port_id;
+ char dev_name[RT_NAME_MAX];
+ struct port_device *port_dev, *prev_port_dev = RT_NULL;
+ struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
+
+ if (virtio_console_dev->port_nr > 0 && !virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (virtio_console_dev->port_nr >= virtio_console_dev->max_port_nr)
+ {
+ return -RT_EFULL;
+ }
+
+ port_id = 0;
+
+ /* The port device list is always ordered, so just find next number for id */
+ rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
+ {
+ if (port_dev->port_id != port_id)
+ {
+ break;
+ }
+ ++port_id;
+ prev_port_dev = port_dev;
+ }
+
+ port_dev = rt_malloc(sizeof(struct port_device));
+
+ if (port_dev == RT_NULL)
+ {
+ return -RT_ENOMEM;
+ }
+
+ port_dev->parent.type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ port_dev->parent.ops = &virtio_console_port_ops;
+#else
+ port_dev->parent.init = virtio_console_port_init;
+ port_dev->parent.open = virtio_console_port_open;
+ port_dev->parent.close = virtio_console_port_close;
+ port_dev->parent.read = virtio_console_port_read;
+ port_dev->parent.write = virtio_console_port_write;
+ port_dev->parent.control = virtio_console_port_control;
+#endif
+
+ port_dev->parent.rx_indicate = RT_NULL;
+ port_dev->parent.tx_complete = RT_NULL;
+
+ rt_list_init(&port_dev->node);
+ port_dev->port_id = port_id;
+ port_dev->need_destroy = RT_FALSE;
+ port_dev->rx_notify = RT_TRUE;
+ port_dev->console = virtio_console_dev;
+ port_dev->queue_rx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
+ port_dev->queue_tx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
+ port_dev->queue_rx = &virtio_dev->queues[port_dev->queue_rx_index];
+ port_dev->queue_tx = &virtio_dev->queues[port_dev->queue_tx_index];
+
+#ifdef RT_USING_SMP
+ rt_spin_lock_init(&port_dev->spinlock_rx);
+ rt_spin_lock_init(&port_dev->spinlock_tx);
+#endif
+
+ rt_snprintf(dev_name, RT_NAME_MAX, "vport%dp%d", virtio_console_dev->console_id, port_id);
+
+ if (rt_device_register((rt_device_t)port_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX) != RT_EOK)
+ {
+ rt_free(port_dev);
+
+ return -RT_ERROR;
+ }
+
+ if (prev_port_dev != RT_NULL)
+ {
+ rt_list_insert_after(&prev_port_dev->node, &port_dev->node);
+ }
+ else
+ {
+ /* Port0 */
+ rt_list_insert_after(&virtio_console_dev->port_head, &port_dev->node);
+ }
+
+ virtio_console_dev->port_nr++;
+
+ return RT_EOK;
+}
+
+static void virtio_console_port_destroy(struct virtio_console_device *virtio_console_dev,
+ struct port_device *port_dev)
+{
+ struct virtio_console_control set_ctrl;
+
+ set_ctrl.id = port_dev->port_id;
+ set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
+ set_ctrl.value = 0;
+
+ virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
+
+ virtio_console_dev->port_nr--;
+
+ rt_list_remove(&port_dev->node);
+
+ rt_device_unregister((rt_device_t)port_dev);
+
+ rt_free(port_dev);
+}
+
+static rt_err_t virtio_console_port_init(rt_device_t dev)
+{
+ rt_uint16_t id;
+ rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
+ rt_uint16_t rx_queue_index, tx_queue_index;
+ struct port_device *port_dev = (struct port_device *)dev;
+ struct virtio_console_device *virtio_console_dev = port_dev->console;
+ struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
+ struct virtq *queue_rx, *queue_tx;
+
+ rx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
+ tx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
+
+ queue_rx = &virtio_dev->queues[rx_queue_index];
+ queue_tx = &virtio_dev->queues[tx_queue_index];
+
+ virtio_alloc_desc_chain(virtio_dev, rx_queue_index, queue_rx->num, idx);
+ virtio_alloc_desc_chain(virtio_dev, tx_queue_index, queue_tx->num, idx);
+
+ for (id = 0; id < queue_rx->num; ++id)
+ {
+ void *addr = &port_dev->info[id].rx_char;
+
+ virtio_fill_desc(virtio_dev, rx_queue_index, id,
+ VIRTIO_VA2PA(addr), sizeof(char), VIRTQ_DESC_F_WRITE, 0);
+
+ queue_rx->avail->ring[id] = id;
+ }
+ rt_hw_dsb();
+
+ queue_rx->avail->flags = 0;
+ queue_rx->avail->idx = queue_rx->num;
+
+ queue_rx->used_idx = queue_rx->used->idx;
+
+ queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
+ queue_tx->avail->idx = 0;
+
+ virtio_queue_notify(virtio_dev, rx_queue_index);
+
+ if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
+ {
+ struct virtio_console_control set_ctrl;
+
+ set_ctrl.id = VIRTIO_CONSOLE_PORT_BAD_ID;
+ set_ctrl.event = VIRTIO_CONSOLE_DEVICE_READY;
+ set_ctrl.value = 1;
+
+ virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ struct port_device *port_dev = (struct port_device *)dev;
+
+ if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
+ {
+ /* Port0 is reserve in multiport */
+ return -RT_ERROR;
+ }
+
+ port_dev->rx_notify = RT_TRUE;
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_console_port_close(rt_device_t dev)
+{
+ struct port_device *port_dev = (struct port_device *)dev;
+
+ if (port_dev->need_destroy)
+ {
+ virtio_console_port_destroy(port_dev->console, port_dev);
+
+ /*
+ * We released the device memory in virtio_console_port_destroy,
+ * rt_device_close has not finished yet, make the return value
+ * to empty so that rt_device_close will not access the device memory.
+ */
+ return -RT_EEMPTY;
+ }
+
+ port_dev->rx_notify = RT_FALSE;
+
+ return RT_EOK;
+}
+
+static rt_size_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_off_t i = 0;
+ rt_uint16_t id;
+ rt_uint32_t len;
+ struct port_device *port_dev = (struct port_device *)dev;
+ struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
+ rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
+ struct virtq *queue_rx = port_dev->queue_rx;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
+#endif
+
+ while (i < size)
+ {
+ if (queue_rx->used_idx == queue_rx->used->idx)
+ {
+ break;
+ }
+ rt_hw_dsb();
+
+ id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
+ len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
+
+ if (len > sizeof(char))
+ {
+ rt_kprintf("%s: Receive buffer's size = %u is too big!\n", port_dev->parent.parent.name, len);
+ len = sizeof(char);
+ }
+
+ *((char *)buffer + i) = port_dev->info[id].rx_char;
+
+ queue_rx->used_idx++;
+
+ virtio_submit_chain(virtio_dev, queue_rx_index, id);
+
+ virtio_queue_notify(virtio_dev, queue_rx_index);
+
+ i += len;
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
+#endif
+
+ size = i;
+
+ return size;
+}
+
+static rt_size_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ char ch = 0;
+ rt_off_t i = 0;
+ rt_uint16_t id;
+ struct port_device *port_dev = (struct port_device *)dev;
+ struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
+ rt_uint32_t queue_tx_index = port_dev->queue_tx_index;
+ struct virtq *queue_tx = port_dev->queue_tx;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_tx);
+#endif
+
+ while (i < size || ch == '\r')
+ {
+ id = queue_tx->avail->idx % queue_tx->num;
+
+ /* Keep the way until 'new line' are unified */
+ if (ch != '\r')
+ {
+ ch = *((const char *)buffer + i);
+ }
+ else
+ {
+ i -= sizeof(char);
+ }
+
+ port_dev->info[id].tx_char = ch;
+
+ ch = (ch == '\n' ? '\r' : 0);
+
+ virtio_free_desc(virtio_dev, queue_tx_index, id);
+
+ virtio_fill_desc(virtio_dev, queue_tx_index, id,
+ VIRTIO_VA2PA(&port_dev->info[id].tx_char), sizeof(char), 0, 0);
+
+ virtio_submit_chain(virtio_dev, queue_tx_index, id);
+
+ virtio_queue_notify(virtio_dev, queue_tx_index);
+
+ virtio_alloc_desc(virtio_dev, queue_tx_index);
+
+ i += sizeof(char);
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&port_dev->spinlock_tx, level);
+#endif
+
+ return size;
+}
+
+static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t status = RT_EOK;
+ struct port_device *port_dev = (struct port_device *)dev;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_NOTIFY_SET:
+ if (args == RT_NULL)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+ rt_memcpy(&port_dev->rx_notify_helper, args, sizeof(port_dev->rx_notify_helper));
+ break;
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* Disable RX */
+ port_dev->rx_notify = RT_FALSE;
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ /* Enable RX */
+ port_dev->rx_notify = RT_TRUE;
+ break;
+ case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY:
+ {
+ port_dev->need_destroy = RT_TRUE;
+ port_dev->rx_notify = RT_FALSE;
+ }
+ break;
+ default:
+ status = -RT_EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+static rt_err_t virtio_console_init(rt_device_t dev)
+{
+ struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
+
+ if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
+ {
+ rt_uint16_t id;
+ rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
+ struct virtq *queue_ctrl_rx, *queue_ctrl_tx;
+
+ queue_ctrl_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
+ queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
+
+ virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, queue_ctrl_rx->num, idx);
+ virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, queue_ctrl_tx->num, idx);
+
+ for (id = 0; id < queue_ctrl_rx->num; ++id)
+ {
+ void *addr = &virtio_console_dev->info[id].rx_ctrl;
+
+ virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, id,
+ VIRTIO_VA2PA(addr), sizeof(struct virtio_console_control), VIRTQ_DESC_F_WRITE, 0);
+
+ queue_ctrl_rx->avail->ring[id] = id;
+ }
+ rt_hw_dsb();
+
+ for (id = 0; id < queue_ctrl_tx->num; ++id)
+ {
+ virtio_console_dev->info[id].tx_ctrl_paddr = VIRTIO_VA2PA(&virtio_console_dev->info[id].tx_ctrl);
+ }
+
+ queue_ctrl_rx->avail->flags = 0;
+ queue_ctrl_rx->avail->idx = queue_ctrl_rx->num;
+
+ queue_ctrl_rx->used_idx = queue_ctrl_rx->used->idx;
+
+ queue_ctrl_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
+ queue_ctrl_tx->avail->idx = 0;
+
+ virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX);
+ }
+
+ return virtio_console_port_create(virtio_console_dev);
+}
+
+static rt_err_t virtio_console_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t status = RT_EOK;
+ struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
+
+ switch (cmd)
+ {
+ case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE:
+ status = virtio_console_port_create(virtio_console_dev);
+ break;
+ default:
+ status = -RT_EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_console_ops =
+{
+ virtio_console_init,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ virtio_console_control
+};
+#endif
+
+static void virtio_console_isr(int irqno, void *param)
+{
+ rt_uint32_t id;
+ rt_uint32_t len;
+ struct port_device *port_dev;
+ struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)param;
+ struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
+ const char *dev_name = virtio_console_dev->parent.parent.name;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ virtio_interrupt_ack(virtio_dev);
+ rt_hw_dsb();
+
+ do {
+ struct virtq *queue_rx;
+ struct virtio_console_control *ctrl, set_ctrl;
+
+ if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
+ {
+ break;
+ }
+
+ queue_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
+
+ if (queue_rx->used_idx == queue_rx->used->idx)
+ {
+ break;
+ }
+ rt_hw_dsb();
+
+ id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
+ len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
+
+ queue_rx->used_idx++;
+
+ if (len != sizeof(struct virtio_console_control))
+ {
+ rt_kprintf("%s: Invalid ctrl!\n", dev_name);
+ break;
+ }
+
+ ctrl = &virtio_console_dev->info[id].rx_ctrl;
+
+ switch (ctrl->event)
+ {
+ case VIRTIO_CONSOLE_PORT_ADD:
+ {
+ set_ctrl.id = ctrl->id;
+ set_ctrl.event = VIRTIO_CONSOLE_PORT_READY;
+ set_ctrl.value = 1;
+
+ #ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+ #endif
+
+ virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
+
+ #ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+ #endif
+ }
+ break;
+ case VIRTIO_CONSOLE_PORT_REMOVE:
+ break;
+ case VIRTIO_CONSOLE_RESIZE:
+ break;
+ case VIRTIO_CONSOLE_PORT_OPEN:
+ {
+ set_ctrl.id = ctrl->id;
+ set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
+ set_ctrl.value = 1;
+
+ #ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+ #endif
+
+ virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
+
+ #ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+ #endif
+ }
+ break;
+ case VIRTIO_CONSOLE_PORT_NAME:
+ break;
+ default:
+ rt_kprintf("%s: Unsupport ctrl[id: %d, event: %d, value: %d]!\n",
+ dev_name, ctrl->id, ctrl->event, ctrl->value);
+ break;
+ }
+
+ } while (0);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+
+ rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
+ {
+ rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
+ struct virtq *queue_rx = port_dev->queue_rx;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
+#endif
+
+ if (queue_rx->used_idx != queue_rx->used->idx)
+ {
+ rt_hw_dsb();
+
+ id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
+ len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
+
+ if (port_dev->rx_notify)
+ {
+ #ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
+ #endif
+ /* Will call virtio_console_port_read to inc used_idx */
+
+ if (port_dev->parent.rx_indicate != RT_NULL)
+ {
+ port_dev->parent.rx_indicate(&port_dev->parent, len);
+ }
+
+ if (port_dev->rx_notify_helper.notify != RT_NULL)
+ {
+ port_dev->rx_notify_helper.notify(port_dev->rx_notify_helper.dev);
+ }
+
+ #ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
+ #endif
+ }
+ else
+ {
+ queue_rx->used_idx++;
+
+ virtio_submit_chain(virtio_dev, queue_rx_index, id);
+
+ virtio_queue_notify(virtio_dev, queue_rx_index);
+ }
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
+#endif
+ }
+}
+
+rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
+{
+ int i;
+ rt_size_t queues_num;
+ static int dev_no = 0;
+ char dev_name[RT_NAME_MAX];
+ struct virtio_device *virtio_dev;
+ struct virtio_console_device *virtio_console_dev;
+
+ RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0);
+
+ virtio_console_dev = rt_malloc(sizeof(struct virtio_console_device));
+
+ if (virtio_console_dev == RT_NULL)
+ {
+ goto _alloc_fail;
+ }
+
+ virtio_dev = &virtio_console_dev->virtio_dev;
+ virtio_dev->irq = irq;
+ virtio_dev->mmio_base = mmio_base;
+
+ virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config;
+
+#ifdef RT_USING_SMP
+ rt_spin_lock_init(&virtio_dev->spinlock);
+#endif
+
+ virtio_reset_device(virtio_dev);
+ virtio_status_acknowledge_driver(virtio_dev);
+
+ virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
+ (1 << VIRTIO_F_RING_EVENT_IDX) |
+ (1 << VIRTIO_F_RING_INDIRECT_DESC));
+
+ virtio_status_driver_ok(virtio_dev);
+
+ if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
+ {
+ virtio_console_dev->max_port_nr = 1;
+ queues_num = 2;
+ }
+ else
+ {
+ if (virtio_console_dev->config->max_nr_ports > RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR)
+ {
+ virtio_console_dev->max_port_nr = RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR;
+ virtio_console_dev->config->max_nr_ports = virtio_console_dev->max_port_nr;
+ }
+ else
+ {
+ virtio_console_dev->max_port_nr = virtio_console_dev->config->max_nr_ports;
+ }
+
+ queues_num = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(virtio_console_dev->max_port_nr, VIRTIO_CONSOLE_QUEUE_DATA_RX);
+ }
+
+ if (virtio_queues_alloc(virtio_dev, queues_num) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ for (i = 0; i < virtio_dev->queues_num; ++i)
+ {
+ if (virtio_queue_init(virtio_dev, i, VIRTIO_CONSOLE_QUEUE_SIZE) != RT_EOK)
+ {
+ for (; i >= 0; --i)
+ {
+ virtio_queue_destroy(virtio_dev, i);
+ }
+ goto _alloc_fail;
+ }
+ }
+
+ virtio_console_dev->parent.type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ virtio_console_dev->parent.ops = &virtio_console_ops;
+#else
+ virtio_console_dev->parent.init = virtio_console_init;
+ virtio_console_dev->parent.open = RT_NULL;
+ virtio_console_dev->parent.close = RT_NULL;
+ virtio_console_dev->parent.read = RT_NULL;
+ virtio_console_dev->parent.write = RT_NULL;
+ virtio_console_dev->parent.control = virtio_console_control;
+#endif
+
+ virtio_console_dev->parent.rx_indicate = RT_NULL;
+ virtio_console_dev->parent.tx_complete = RT_NULL;
+
+ virtio_console_dev->console_id = dev_no;
+ virtio_console_dev->port_nr = 0;
+ rt_list_init(&virtio_console_dev->port_head);
+
+ rt_snprintf(dev_name, RT_NAME_MAX, "virtio-console%d", dev_no++);
+
+ rt_hw_interrupt_install(irq, virtio_console_isr, virtio_console_dev, dev_name);
+ rt_hw_interrupt_umask(irq);
+
+ return rt_device_register((rt_device_t)virtio_console_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
+
+_alloc_fail:
+
+ if (virtio_console_dev != RT_NULL)
+ {
+ virtio_queues_free(virtio_dev);
+ rt_free(virtio_console_dev);
+ }
+ return -RT_ENOMEM;
+}
+#endif /* RT_USING_VIRTIO_CONSOLE */
diff --git a/components/drivers/virtio/virtio_console.h b/components/drivers/virtio/virtio_console.h
new file mode 100644
index 0000000000..f7d8d97e1d
--- /dev/null
+++ b/components/drivers/virtio/virtio_console.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#ifndef __VIRTIO_CONSOLE_H__
+#define __VIRTIO_CONSOLE_H__
+
+#include <rtdef.h>
+
+#include <virtio.h>
+
+#ifndef RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR
+#define RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR 4
+#endif
+
+#define VIRTIO_CONSOLE_QUEUE_DATA_RX 0
+#define VIRTIO_CONSOLE_QUEUE_DATA_TX 1
+#define VIRTIO_CONSOLE_QUEUE_CTRL_RX 2
+#define VIRTIO_CONSOLE_QUEUE_CTRL_TX 3
+#define VIRTIO_CONSOLE_QUEUE_SIZE 64
+
+/* Every port has data rx & tx, and port0 has ctrl rx & tx in multiport */
+#define VIRTIO_CONSOLE_PORT_QUEUE_INDEX(id, queue) ((id) * 2 + (!!(id)) * 2 + (queue))
+
+#define VIRTIO_CONSOLE_PORT_BAD_ID (~(rt_uint32_t)0)
+
+#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */
+#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
+#define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */
+
+struct virtio_console_config
+{
+ rt_uint16_t cols;
+ rt_uint16_t rows;
+ rt_uint32_t max_nr_ports;
+ rt_uint32_t emerg_wr;
+} __attribute__((packed));
+
+struct virtio_console_control
+{
+ rt_uint32_t id; /* Port number */
+ rt_uint16_t event; /* The kind of control event */
+ rt_uint16_t value; /* Extra information for the event */
+};
+
+enum virtio_console_control_event
+{
+ VIRTIO_CONSOLE_DEVICE_READY = 0,
+ VIRTIO_CONSOLE_PORT_ADD,
+ VIRTIO_CONSOLE_PORT_REMOVE,
+ VIRTIO_CONSOLE_PORT_READY,
+ VIRTIO_CONSOLE_CONSOLE_PORT,
+ VIRTIO_CONSOLE_RESIZE,
+ VIRTIO_CONSOLE_PORT_OPEN,
+ VIRTIO_CONSOLE_PORT_NAME,
+};
+
+struct virtio_console_resize
+{
+ rt_uint16_t cols;
+ rt_uint16_t rows;
+};
+
+struct virtio_console_device
+{
+ struct rt_device parent;
+
+ struct virtio_device virtio_dev;
+
+ rt_uint32_t console_id;
+ rt_size_t port_nr;
+ rt_size_t max_port_nr;
+ rt_list_t port_head;
+ struct virtio_console_config *config;
+
+ struct
+ {
+ rt_ubase_t tx_ctrl_paddr;
+ struct virtio_console_control rx_ctrl, tx_ctrl;
+ } info[VIRTIO_CONSOLE_QUEUE_SIZE];
+};
+
+rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
+
+enum
+{
+ VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE = 0x20,
+ VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY,
+};
+
+#endif /* __VIRTIO_CONSOLE_H__ */
diff --git a/components/drivers/virtio/virtio_gpu.c b/components/drivers/virtio/virtio_gpu.c
new file mode 100644
index 0000000000..67ce28a876
--- /dev/null
+++ b/components/drivers/virtio/virtio_gpu.c
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <cpuport.h>
+
+#ifdef RT_USING_VIRTIO_GPU
+
+#include <virtio_gpu.h>
+
+static struct virtio_gpu_device *_primary_virtio_gpu_dev = RT_NULL;
+
+static rt_ubase_t _pixel_format_convert(rt_ubase_t format, rt_bool_t to_virtio_gpu_format)
+{
+ rt_ubase_t ret = 0;
+
+ if (to_virtio_gpu_format)
+ {
+ switch (format)
+ {
+ case RTGRAPHIC_PIXEL_FORMAT_RGB888:
+ ret = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM;
+ break;
+ case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
+ ret = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
+ break;
+ case RTGRAPHIC_PIXEL_FORMAT_ABGR888:
+ ret = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (format)
+ {
+ case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
+ ret = RTGRAPHIC_PIXEL_FORMAT_RGB888;
+ break;
+ case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
+ ret = RTGRAPHIC_PIXEL_FORMAT_ARGB888;
+ break;
+ case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
+ ret = RTGRAPHIC_PIXEL_FORMAT_ABGR888;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_dev,
+ const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len)
+{
+ rt_uint16_t idx[2];
+ void *addr = &virtio_gpu_dev->gpu_request;
+ void *ret_res = ((rt_uint8_t *)addr + cmd_len);
+ struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ while (virtio_alloc_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, 2, idx))
+ {
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ rt_thread_yield();
+
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ }
+
+ rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0],
+ VIRTIO_VA2PA(addr), cmd_len, VIRTQ_DESC_F_NEXT, idx[1]);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[1],
+ VIRTIO_VA2PA(addr) + cmd_len, res_len, VIRTQ_DESC_F_WRITE, 0);
+
+ rt_memset(ret_res, 0, res_len);
+
+ virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
+
+ virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
+
+ while (virtio_gpu_dev->info[idx[0]].ctrl_valid)
+ {
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ rt_thread_yield();
+
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ }
+
+ virtio_free_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
+
+ rt_memcpy(res, ret_res, res_len);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+static void virtio_gpu_cursor_send_command(struct virtio_gpu_device *virtio_gpu_dev,
+ const void *cmd, rt_size_t cmd_len)
+{
+ rt_uint16_t id;
+ void *addr;
+ struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ while ((id = virtio_alloc_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR)) == VIRTQ_INVALID_DESC_ID)
+ {
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ rt_thread_yield();
+
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ }
+
+ addr = &virtio_gpu_dev->info[id].cursor_cmd;
+ virtio_gpu_dev->info[id].cursor_valid = RT_TRUE;
+
+ rt_memcpy(addr, cmd, cmd_len);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id, VIRTIO_VA2PA(addr), cmd_len, 0, 0);
+
+ virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR);
+
+ while (virtio_gpu_dev->info[id].cursor_valid)
+ {
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ rt_thread_yield();
+
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ }
+
+ virtio_free_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu_device *virtio_gpu_dev, enum virtio_gpu_formats format,
+ rt_uint32_t *resource_id, rt_uint32_t width, rt_uint32_t height)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_create_2d req;
+
+ *resource_id = ++virtio_gpu_dev->next_resource_id;
+
+ req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
+ req.resource_id = *resource_id;
+ req.format = format;
+ req.width = width;
+ req.height = height;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
+
+ if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_unref req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF;
+ req.resource_id = resource_id;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
+
+ if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
+ void *buffer, rt_size_t size)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct
+ {
+ struct virtio_gpu_resource_attach_backing req;
+ struct virtio_gpu_mem_entry mem;
+ } req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
+ req.req.resource_id = resource_id;
+ req.req.nr_entries = 1;
+
+ req.mem.addr = VIRTIO_VA2PA(buffer);
+ req.mem.length = size;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
+
+ if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
+ rt_uint32_t resource_id, rt_uint32_t width, rt_uint32_t height)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_set_scanout req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
+ req.r.x = 0;
+ req.r.y = 0;
+ req.r.width = width;
+ req.r.height = height;
+ req.scanout_id = scanout_id;
+ req.resource_id = resource_id;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
+
+ if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
+ rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_flush req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH;
+ req.r.x = x;
+ req.r.y = y;
+ req.r.width = width;
+ req.r.height = height;
+ req.resource_id = resource_id;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
+
+ if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
+ rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height, rt_uint32_t offset)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_transfer_to_host_2d req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
+ req.r.x = x;
+ req.r.y = y;
+ req.r.width = width;
+ req.r.height = height;
+ req.offset = offset;
+ req.resource_id = resource_id;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
+
+ if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_gfx_flush_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
+ rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
+{
+ rt_err_t status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, resource_id, x, y, width, height, 0);
+
+ if (status == RT_EOK)
+ {
+ status = virtio_gpu_flush_resource(virtio_gpu_dev, resource_id, x, y, width, height);
+ }
+
+ return status;
+}
+
+static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
+ rt_uint32_t resource_id, rt_uint32_t hot_x, rt_uint32_t hot_y)
+{
+ struct virtio_gpu_update_cursor req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = VIRTIO_GPU_CMD_UPDATE_CURSOR;
+ req.pos.scanout_id = scanout_id;
+ req.resource_id = resource_id;
+ req.hot_x = hot_x;
+ req.hot_y = hot_y;
+
+ virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
+ rt_uint32_t resource_id, rt_uint32_t x, rt_uint32_t y)
+{
+ struct virtio_gpu_update_cursor req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = VIRTIO_GPU_CMD_MOVE_CURSOR;
+ req.pos.scanout_id = scanout_id;
+ req.pos.x = x;
+ req.pos.y = y;
+ req.resource_id = resource_id;
+
+ virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_cursor_set_img(struct virtio_gpu_device *virtio_gpu_dev, void *img)
+{
+ rt_err_t status;
+
+ rt_memcpy(virtio_gpu_dev->cursor_img, img, VIRTIO_GPU_CURSOR_IMG_SIZE);
+
+ status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
+ virtio_gpu_dev->cursor_resource_id, virtio_gpu_dev->cursor_img, VIRTIO_GPU_CURSOR_IMG_SIZE);
+
+ if (status != RT_EOK)
+ {
+ return status;
+ }
+
+ status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, virtio_gpu_dev->cursor_resource_id,
+ 0, 0, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT, 0);
+
+ return status;
+}
+
+static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu_device *virtio_gpu_dev)
+{
+ int i;
+ struct virtio_gpu_ctrl_hdr req;
+ struct virtio_gpu_resp_display_info info;
+
+ rt_memset(&req, 0, sizeof(req));
+ req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
+
+ virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &info, sizeof(info));
+
+ if (info.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO)
+ {
+ return -RT_ERROR;
+ }
+
+ for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i)
+ {
+ if (info.pmodes[i].enabled)
+ {
+ if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
+ {
+ rt_memcpy(&virtio_gpu_dev->pmode, &info.pmodes[i], sizeof(virtio_gpu_dev->pmode));
+ virtio_gpu_dev->pmode_id = i;
+ }
+ }
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_init(rt_device_t dev)
+{
+ rt_err_t status;
+ struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
+ struct virtq *queue_ctrl, *queue_cursor;
+
+ queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
+ queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
+
+ queue_ctrl->avail->flags = 0;
+ queue_cursor->avail->flags = 0;
+
+ status = virtio_gpu_get_display_info(virtio_gpu_dev);
+
+ if (virtio_gpu_dev->pmode_id != VIRTIO_GPU_INVALID_PMODE_ID && _primary_virtio_gpu_dev == RT_NULL)
+ {
+ /* This device is ready */
+ _primary_virtio_gpu_dev = virtio_gpu_dev;
+ }
+
+ return status;
+}
+
+static rt_size_t virtio_gpu_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
+
+ if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
+ {
+ return 0;
+ }
+
+ rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
+
+ rt_memcpy(buffer, (rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, size);
+
+ rt_mutex_release(&virtio_gpu_dev->rw_mutex);
+
+ return size;
+}
+
+static rt_size_t virtio_gpu_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
+
+ if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
+ {
+ return 0;
+ }
+
+ rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
+
+ rt_memcpy((rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, buffer, size);
+
+ rt_mutex_release(&virtio_gpu_dev->rw_mutex);
+
+ return size;
+}
+
+static rt_err_t virtio_gpu_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t status = RT_EOK;
+ struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
+
+ switch (cmd)
+ {
+ case VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY:
+
+ _primary_virtio_gpu_dev = virtio_gpu_dev;
+
+ return status;
+ }
+
+ if (args == RT_NULL)
+ {
+ return -RT_ERROR;
+ }
+
+ switch (cmd)
+ {
+ case RTGRAPHIC_CTRL_RECT_UPDATE:
+ {
+ struct rt_device_rect_info *info = (struct rt_device_rect_info *)args;
+
+ if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ status = virtio_gpu_gfx_flush_2d(virtio_gpu_dev, virtio_gpu_dev->display_resource_id,
+ info->x, info->y, info->width, info->height);
+ }
+ break;
+ case RTGRAPHIC_CTRL_GET_INFO:
+ {
+ struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
+
+ info->pixel_format = _pixel_format_convert((rt_ubase_t)args, RT_FALSE);
+ info->bits_per_pixel = VIRTIO_GPU_FORMAT_BPP;
+ info->pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
+ info->width = virtio_gpu_dev->pmode.r.width;
+ info->height = virtio_gpu_dev->pmode.r.height;
+ info->framebuffer = virtio_gpu_dev->framebuffer;
+ info->smem_len = virtio_gpu_dev->smem_len;
+ }
+ break;
+ case VIRTIO_DEVICE_CTRL_GPU_CREATE_2D:
+
+ virtio_gpu_dev->format = _pixel_format_convert((rt_ubase_t)args, RT_TRUE);
+
+ if (virtio_gpu_dev->format == 0 || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
+ &virtio_gpu_dev->display_resource_id, virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
+
+ if (status != RT_EOK)
+ {
+ break;
+ }
+
+ virtio_gpu_dev->smem_len =
+ virtio_gpu_dev->pmode.r.width * virtio_gpu_dev->pmode.r.height * VIRTIO_GPU_FORMAT_PIXEL;
+ virtio_gpu_dev->smem_len = RT_ALIGN(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
+ virtio_gpu_dev->framebuffer = rt_malloc_align(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
+
+ if (virtio_gpu_dev->framebuffer == RT_NULL)
+ {
+ virtio_gpu_unref_resource(virtio_gpu_dev, virtio_gpu_dev->display_resource_id);
+
+ status = -RT_ENOMEM;
+ break;
+ }
+
+ status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
+ virtio_gpu_dev->display_resource_id, virtio_gpu_dev->framebuffer, virtio_gpu_dev->smem_len);
+
+ if (status != RT_EOK)
+ {
+ break;
+ }
+
+ status = virtio_gpu_set_scanout(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->display_resource_id,
+ virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
+
+ break;
+ case VIRTIO_DEVICE_CTRL_CURSOR_SETUP:
+
+ if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
+
+ status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
+ &virtio_gpu_dev->cursor_resource_id, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT);
+
+ if (status != RT_EOK)
+ {
+ goto _cursor_setup_end;
+ }
+
+ status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
+
+ if (status != RT_EOK)
+ {
+ goto _cursor_setup_end;
+ }
+
+ virtio_gpu_dev->cursor_x = 0;
+ virtio_gpu_dev->cursor_y = 0;
+
+ status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
+ virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
+
+ if (status == RT_EOK)
+ {
+ virtio_gpu_dev->cursor_enable = RT_TRUE;
+ }
+
+_cursor_setup_end:
+ rt_mutex_release(&virtio_gpu_dev->ops_mutex);
+
+ break;
+ case VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG:
+
+ if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
+
+ status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
+
+ if (status != RT_EOK)
+ {
+ goto _cursor_set_img_end;
+ }
+
+ status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
+ virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
+
+_cursor_set_img_end:
+ rt_mutex_release(&virtio_gpu_dev->ops_mutex);
+
+ break;
+ case VIRTIO_DEVICE_CTRL_CURSOR_MOVE:
+
+ if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
+
+ virtio_gpu_dev->cursor_x = ((rt_uint32_t *)args)[0];
+ virtio_gpu_dev->cursor_y = ((rt_uint32_t *)args)[1];
+
+ status = virtio_gpu_cursor_move(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
+ virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
+
+ rt_mutex_release(&virtio_gpu_dev->ops_mutex);
+
+ break;
+ default:
+ status = -RT_EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_gpu_ops =
+{
+ virtio_gpu_init,
+ RT_NULL,
+ RT_NULL,
+ virtio_gpu_read,
+ virtio_gpu_write,
+ virtio_gpu_control
+};
+#endif
+
+static void virtio_gpu_set_pixel(const char *pixel, int x, int y)
+{
+ rt_uint8_t *fb;
+ struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
+
+ if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
+ {
+ return;
+ }
+
+ fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
+ fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
+ *((rt_uint32_t *)fb) = *((rt_uint32_t *)pixel);
+}
+
+static void virtio_gpu_get_pixel(char *pixel, int x, int y)
+{
+ rt_uint8_t *fb;
+ struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
+
+ if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
+ {
+ return;
+ }
+
+ fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
+ *((rt_uint32_t *)pixel) = *(fb + (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL);
+}
+
+static void virtio_gpu_draw_hline(const char *pixel, int x1, int x2, int y)
+{
+ int i;
+ rt_uint8_t *fb;
+ rt_uint32_t color = *((rt_uint32_t *)pixel);
+ struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
+
+ if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
+ x1 < 0 || x2 < 0 || y < 0)
+ {
+ return;
+ }
+
+ if (x1 > x2)
+ {
+ x1 ^= x2;
+ x2 ^= x1;
+ x1 ^= x2;
+ }
+
+ fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
+ fb += (y * virtio_gpu_dev->pmode.r.width + x1) * VIRTIO_GPU_FORMAT_PIXEL;
+
+ for (i = x1; i < x2; ++i)
+ {
+ *((rt_uint32_t *)fb) = color;
+
+ fb += VIRTIO_GPU_FORMAT_PIXEL;
+ }
+}
+
+static void virtio_gpu_draw_vline(const char *pixel, int x, int y1, int y2)
+{
+ int i;
+ rt_uint8_t *fb;
+ rt_uint16_t pitch;
+ rt_uint32_t color = *((rt_uint32_t *)pixel);
+ struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
+
+ if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
+ x < 0 || y1 < 0 || y2 < 0)
+ {
+ return;
+ }
+
+ if (y1 > y2)
+ {
+ y1 ^= y2;
+ y2 ^= y1;
+ y1 ^= y2;
+ }
+
+ fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
+ fb += (y1 * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
+
+ pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
+
+ for (i = y1; i < y2; ++i)
+ {
+ *((rt_uint32_t *)fb) = color;
+
+ fb += pitch;
+ }
+}
+
+static void virtio_gpu_blit_line(const char *pixel, int x, int y, rt_size_t size)
+{
+ int i;
+ rt_uint8_t *fb;
+ rt_uint32_t *colors = (rt_uint32_t *)pixel;
+ struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
+
+ if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || x < 0 || y < 0)
+ {
+ return;
+ }
+
+ fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
+ fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
+
+ for (i = 0; i < size; ++i)
+ {
+ *((rt_uint32_t *)fb) = *colors++;
+ fb += VIRTIO_GPU_FORMAT_PIXEL;
+ }
+}
+
+static struct rt_device_graphic_ops virtio_gpu_graphic_ops =
+{
+ virtio_gpu_set_pixel,
+ virtio_gpu_get_pixel,
+ virtio_gpu_draw_hline,
+ virtio_gpu_draw_vline,
+ virtio_gpu_blit_line
+};
+
+static void virtio_gpu_isr(int irqno, void *param)
+{
+ rt_uint16_t id;
+ struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)param;
+ struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
+ struct virtq *queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
+ struct virtq *queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ virtio_interrupt_ack(virtio_dev);
+ rt_hw_dsb();
+
+ while (queue_ctrl->used_idx != queue_ctrl->used->idx)
+ {
+ rt_hw_dsb();
+ id = queue_ctrl->used->ring[queue_ctrl->used_idx % queue_ctrl->num].id;
+
+ virtio_gpu_dev->info[id].ctrl_valid = RT_FALSE;
+
+ queue_ctrl->used_idx++;
+ }
+
+ while (queue_cursor->used_idx != queue_cursor->used->idx)
+ {
+ rt_hw_dsb();
+ id = queue_cursor->used->ring[queue_cursor->used_idx % queue_cursor->num].id;
+
+ virtio_gpu_dev->info[id].cursor_valid = RT_FALSE;
+
+ queue_cursor->used_idx++;
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
+{
+ static int dev_no = 0;
+ char dev_name[RT_NAME_MAX];
+ struct virtio_device *virtio_dev;
+ struct virtio_gpu_device *virtio_gpu_dev;
+
+ virtio_gpu_dev = rt_malloc(sizeof(struct virtio_gpu_device));
+
+ if (virtio_gpu_dev == RT_NULL)
+ {
+ goto _alloc_fail;
+ }
+
+ virtio_dev = &virtio_gpu_dev->virtio_dev;
+ virtio_dev->irq = irq;
+ virtio_dev->mmio_base = mmio_base;
+
+ virtio_gpu_dev->pmode_id = VIRTIO_GPU_INVALID_PMODE_ID;
+ virtio_gpu_dev->display_resource_id = 0;
+ virtio_gpu_dev->cursor_resource_id = 0;
+ virtio_gpu_dev->next_resource_id = 0;
+ virtio_gpu_dev->framebuffer = RT_NULL;
+ virtio_gpu_dev->smem_len = 0;
+ virtio_gpu_dev->cursor_enable = RT_FALSE;
+
+#ifdef RT_USING_SMP
+ rt_spin_lock_init(&virtio_dev->spinlock);
+#endif
+
+ virtio_reset_device(virtio_dev);
+ virtio_status_acknowledge_driver(virtio_dev);
+
+ virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
+ (1 << VIRTIO_F_RING_EVENT_IDX) |
+ (1 << VIRTIO_F_RING_INDIRECT_DESC));
+
+ virtio_status_driver_ok(virtio_dev);
+
+ if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
+ {
+ virtio_queue_destroy(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
+
+ goto _alloc_fail;
+ }
+
+ virtio_gpu_dev->parent.type = RT_Device_Class_Graphic;
+#ifdef RT_USING_DEVICE_OPS
+ virtio_gpu_dev->parent.ops = &virtio_gpu_ops;
+#else
+ virtio_gpu_dev->parent.init = virtio_gpu_init;
+ virtio_gpu_dev->parent.open = RT_NULL;
+ virtio_gpu_dev->parent.close = RT_NULL;
+ virtio_gpu_dev->parent.read = virtio_gpu_read;
+ virtio_gpu_dev->parent.write = virtio_gpu_write;
+ virtio_gpu_dev->parent.control = virtio_gpu_control;
+#endif
+ virtio_gpu_dev->parent.user_data = &virtio_gpu_graphic_ops;
+
+ rt_snprintf(dev_name, RT_NAME_MAX, "virtio-gpu%d", dev_no++);
+
+ rt_mutex_init(&virtio_gpu_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
+ rt_mutex_init(&virtio_gpu_dev->ops_mutex, dev_name, RT_IPC_FLAG_PRIO);
+
+ rt_hw_interrupt_install(irq, virtio_gpu_isr, virtio_gpu_dev, dev_name);
+ rt_hw_interrupt_umask(irq);
+
+ return rt_device_register((rt_device_t)virtio_gpu_dev, dev_name, RT_DEVICE_FLAG_RDWR);
+
+_alloc_fail:
+
+ if (virtio_gpu_dev != RT_NULL)
+ {
+ virtio_queues_free(virtio_dev);
+ rt_free(virtio_gpu_dev);
+ }
+ return -RT_ENOMEM;
+}
+#endif /* RT_USING_VIRTIO_GPU */
diff --git a/components/drivers/virtio/virtio_gpu.h b/components/drivers/virtio/virtio_gpu.h
new file mode 100644
index 0000000000..0c49ecbd2f
--- /dev/null
+++ b/components/drivers/virtio/virtio_gpu.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#ifndef __VIRTIO_GPU_H__
+#define __VIRTIO_GPU_H__
+
+#include <rtdef.h>
+
+#include <virtio.h>
+
+#define VIRTIO_GPU_QUEUE_CTRL 0
+#define VIRTIO_GPU_QUEUE_CURSOR 1
+#define VIRTIO_GPU_QUEUE_SIZE 32
+
+#define VIRTIO_GPU_F_VIRGL 0 /* VIRTIO_GPU_CMD_CTX_*, VIRTIO_GPU_CMD_*_3D */
+#define VIRTIO_GPU_F_EDID 1 /* VIRTIO_GPU_CMD_GET_EDID */
+#define VIRTIO_GPU_F_RESOURCE_UUID 2 /* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
+#define VIRTIO_GPU_F_RESOURCE_BLOB 3 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */
+#define VIRTIO_GPU_F_CONTEXT_INIT 4 /* VIRTIO_GPU_CMD_CREATE_CONTEXT with context_init and multiple timelines */
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+#define VIRTIO_GPU_FORMAT_BPP 32
+#define VIRTIO_GPU_FORMAT_PIXEL 4
+#define VIRTIO_GPU_CURSOR_WIDTH 64
+#define VIRTIO_GPU_CURSOR_HEIGHT 64
+#define VIRTIO_GPU_CURSOR_IMG_SIZE (VIRTIO_GPU_CURSOR_WIDTH * VIRTIO_GPU_CURSOR_HEIGHT * VIRTIO_GPU_FORMAT_PIXEL)
+#define VIRTIO_GPU_INVALID_PMODE_ID RT_UINT32_MAX
+
+/* GPU control */
+
+struct virtio_gpu_config
+{
+ rt_uint32_t events_read;
+ rt_uint32_t events_clear;
+ rt_uint32_t num_scanouts; /* 1 ~ 16 */
+ rt_uint32_t reserved;
+};
+
+enum virtio_gpu_ctrl_type
+{
+ VIRTIO_GPU_UNDEFINED = 0,
+
+ /* 2d commands */
+ VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+ VIRTIO_GPU_CMD_RESOURCE_UNREF,
+ VIRTIO_GPU_CMD_SET_SCANOUT,
+ VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+ VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+ VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+ VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+ VIRTIO_GPU_CMD_GET_CAPSET_INFO,
+ VIRTIO_GPU_CMD_GET_CAPSET,
+ VIRTIO_GPU_CMD_GET_EDID,
+ VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB,
+ VIRTIO_GPU_CMD_SET_SCANOUT_BLOB,
+
+ /* 3d commands */
+ VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
+ VIRTIO_GPU_CMD_CTX_DESTROY,
+ VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
+ VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
+ VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
+ VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
+ VIRTIO_GPU_CMD_SUBMIT_3D,
+ VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
+ VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,
+
+ /* cursor commands */
+ VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+ VIRTIO_GPU_CMD_MOVE_CURSOR,
+
+ /* success responses */
+ VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+ VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+ VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+ VIRTIO_GPU_RESP_OK_CAPSET,
+ VIRTIO_GPU_RESP_OK_EDID,
+ VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
+ VIRTIO_GPU_RESP_OK_MAP_INFO,
+
+ /* error responses */
+ VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+ VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+ VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+
+struct virtio_gpu_ctrl_hdr
+{
+ rt_uint32_t type;
+ rt_uint32_t flags;
+ rt_uint64_t fence_id;
+ rt_uint32_t ctx_id;
+ rt_uint8_t ring_idx;
+ rt_uint8_t padding[3];
+};
+
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+
+struct virtio_gpu_rect
+{
+ rt_uint32_t x;
+ rt_uint32_t y;
+ rt_uint32_t width;
+ rt_uint32_t height;
+};
+
+struct virtio_gpu_resp_display_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_display_one
+ {
+ struct virtio_gpu_rect r;
+ rt_uint32_t enabled;
+ rt_uint32_t flags;
+ } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+struct virtio_gpu_get_edid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t scanout;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_resp_edid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t size;
+ rt_uint32_t padding;
+ rt_uint8_t edid[1024];
+};
+
+enum virtio_gpu_formats
+{
+ VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
+ VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
+ VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
+ VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
+
+ VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
+ VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
+
+ VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
+ VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
+};
+
+struct virtio_gpu_resource_create_2d
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t format;
+ rt_uint32_t width;
+ rt_uint32_t height;
+};
+
+struct virtio_gpu_resource_unref
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_set_scanout
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_uint32_t scanout_id;
+ rt_uint32_t resource_id;
+};
+
+struct virtio_gpu_resource_flush
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_transfer_to_host_2d
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_uint64_t offset;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_resource_attach_backing
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t nr_entries;
+};
+
+struct virtio_gpu_mem_entry
+{
+ rt_uint64_t addr;
+ rt_uint32_t length;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_resource_detach_backing
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_get_capset_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t capset_index;
+ rt_uint32_t padding;
+};
+
+#define VIRTIO_GPU_CAPSET_VIRGL 1
+#define VIRTIO_GPU_CAPSET_VIRGL2 2
+#define VIRTIO_GPU_CAPSET_GFXSTREAM 3
+#define VIRTIO_GPU_CAPSET_VENUS 4
+#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
+
+struct virtio_gpu_resp_capset_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t capset_id;
+ rt_uint32_t capset_max_version;
+ rt_uint32_t capset_max_size;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_get_capset
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t capset_id;
+ rt_uint32_t capset_version;
+};
+
+struct virtio_gpu_resp_capset
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint8_t capset_data[];
+};
+
+struct virtio_gpu_resource_assign_uuid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_resp_resource_uuid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint8_t uuid[16];
+};
+
+#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001
+#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002
+#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003
+
+#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001
+#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002
+#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
+
+struct virtio_gpu_resource_create_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t blob_mem;
+ rt_uint32_t blob_flags;
+ rt_uint32_t nr_entries;
+ rt_uint64_t blob_id;
+ rt_uint64_t size;
+};
+
+struct virtio_gpu_set_scanout_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_uint32_t scanout_id;
+ rt_uint32_t resource_id;
+ rt_uint32_t width;
+ rt_uint32_t height;
+ rt_uint32_t format;
+ rt_uint32_t padding;
+ rt_uint32_t strides[4];
+ rt_uint32_t offsets[4];
+};
+
+#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff
+struct virtio_gpu_ctx_create
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t nlen;
+ rt_uint32_t context_init;
+ char debug_name[64];
+};
+
+struct virtio_gpu_resource_map_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+ rt_uint64_t offset;
+};
+
+#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f
+#define VIRTIO_GPU_MAP_CACHE_NONE 0x00
+#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01
+#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02
+#define VIRTIO_GPU_MAP_CACHE_WC 0x03
+
+struct virtio_gpu_resp_map_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t map_info;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_resource_unmap_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t resource_id;
+ rt_uint32_t padding;
+};
+
+/* GPU cursor */
+
+struct virtio_gpu_cursor_pos
+{
+ rt_uint32_t scanout_id;
+ rt_uint32_t x;
+ rt_uint32_t y;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_update_cursor
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_cursor_pos pos;
+ rt_uint32_t resource_id;
+ rt_uint32_t hot_x;
+ rt_uint32_t hot_y;
+ rt_uint32_t padding;
+};
+
+struct virtio_gpu_device
+{
+ struct rt_device parent;
+
+ struct virtio_device virtio_dev;
+
+ /* Current display's info */
+ struct virtio_gpu_display_one pmode;
+ enum virtio_gpu_formats format;
+ rt_uint32_t pmode_id;
+ rt_uint32_t cursor_x, cursor_y;
+ rt_uint32_t display_resource_id;
+ rt_uint32_t cursor_resource_id;
+ rt_uint32_t next_resource_id;
+
+ /* Display framebuffer */
+ struct rt_mutex rw_mutex;
+ void *framebuffer;
+ rt_uint32_t smem_len;
+
+ /* Cursor image info */
+ rt_bool_t cursor_enable;
+ struct rt_mutex ops_mutex;
+ rt_uint8_t cursor_img[VIRTIO_GPU_CURSOR_IMG_SIZE];
+
+ /* GPU request info */
+ struct virtio_gpu_resp_display_info gpu_request;
+
+ struct
+ {
+ rt_bool_t ctrl_valid;
+ rt_bool_t cursor_valid;
+
+ struct virtio_gpu_update_cursor cursor_cmd;
+ } info[VIRTIO_GPU_QUEUE_SIZE];
+};
+
+rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
+
+enum
+{
+ VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY = 0x20,
+ VIRTIO_DEVICE_CTRL_GPU_CREATE_2D,
+
+ VIRTIO_DEVICE_CTRL_CURSOR_SETUP,
+ VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG,
+ VIRTIO_DEVICE_CTRL_CURSOR_MOVE,
+};
+
+#endif /* __VIRTIO_GPU_H__ */
diff --git a/components/drivers/virtio/virtio_input.c b/components/drivers/virtio/virtio_input.c
new file mode 100644
index 0000000000..8de3d9c83f
--- /dev/null
+++ b/components/drivers/virtio/virtio_input.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <cpuport.h>
+
+#ifdef RT_USING_VIRTIO_INPUT
+
+#include <virtio_input.h>
+
+static void _set_bit(rt_uint32_t nr, volatile rt_ubase_t *addr)
+{
+ rt_ubase_t mask = BIT_MASK(nr);
+ rt_ubase_t *p = ((rt_ubase_t *)addr) + BIT_WORD(nr);
+
+ *p |= mask;
+}
+
+static rt_size_t virtio_input_cfg_select(struct virtio_input_device *virtio_input_dev,
+ rt_uint8_t select, rt_uint8_t subsel)
+{
+ struct virtio_input_config *config = virtio_input_dev->config;
+
+ rt_hw_dsb();
+ config->select = select;
+ config->subsel = subsel;
+ rt_hw_dsb();
+
+ return config->size;
+}
+
+static void virtio_input_cfg_bits(struct virtio_input_device *virtio_input_dev,
+ rt_uint8_t select, rt_uint8_t subsel, rt_ubase_t *bits, rt_uint32_t bitcount)
+{
+ int i;
+ rt_uint32_t bit;
+ rt_uint8_t bytes;
+ rt_uint8_t *virtio_bits;
+ void *config_base = virtio_input_dev->config;
+ rt_off_t offset = (rt_size_t)&((struct virtio_input_config *)0)->bitmap;
+
+ bytes = virtio_input_cfg_select(virtio_input_dev, select, subsel);
+
+ if (bytes == 0)
+ {
+ return;
+ }
+
+ if (bitcount > bytes * 8)
+ {
+ bitcount = bytes * 8;
+ }
+
+ /*
+ * Bitmap in virtio config space is a simple stream of bytes,
+ * with the first byte carrying bits 0-7, second bits 8-15 and
+ * so on.
+ */
+ virtio_bits = rt_malloc(bytes);
+
+ if (virtio_bits == RT_NULL)
+ {
+ return;
+ }
+
+ for (i = 0; i < bytes; ++i)
+ {
+ void *buffer = (void *)virtio_bits + i;
+
+ if (virtio_input_dev->virtio_dev.mmio_config->version == 1)
+ {
+ HWREG8(config_base + offset + i) = *((rt_uint8_t *)buffer);
+ }
+ else
+ {
+ rt_memcpy(config_base + offset + i, buffer, sizeof(rt_uint8_t));
+ }
+ }
+
+ for (bit = 0; bit < bitcount; ++bit)
+ {
+ if (virtio_bits[bit / 8] & (1 << (bit % 8)))
+ {
+ _set_bit(bit, bits);
+ }
+ }
+
+ rt_free(virtio_bits);
+
+ if (select == VIRTIO_INPUT_CFG_EV_BITS)
+ {
+ _set_bit(subsel, virtio_input_dev->ev_bit);
+ }
+}
+
+static rt_err_t virtio_input_init(rt_device_t dev)
+{
+ int i;
+ rt_uint16_t idx[VIRTIO_INPUT_QUEUE_MAX_SIZE];
+ struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
+ struct virtq *queue_event, *queue_status;
+
+ virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, virtio_input_dev->key_bit, KEY_CNT);
+ virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, virtio_input_dev->rel_bit, REL_CNT);
+ virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, virtio_input_dev->abs_bit, ABS_CNT);
+
+ queue_event = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT];
+ queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS];
+
+ virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, queue_event->num, idx);
+ virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, queue_status->num, idx);
+
+ for (i = 0; i < queue_event->num; ++i)
+ {
+ rt_uint16_t id = i;
+ void *addr = &virtio_input_dev->recv_events[i];
+
+ virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id,
+ VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), VIRTQ_DESC_F_WRITE, 0);
+
+ virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id);
+ }
+ rt_hw_dsb();
+
+ queue_event->avail->flags = 0;
+ queue_status->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
+
+ virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
+
+ return RT_EOK;
+}
+
+static rt_size_t virtio_input_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
+
+ if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num)
+ {
+ return 0;
+ }
+
+ rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER);
+
+ rt_memcpy(buffer, &virtio_input_dev->bcst_events[pos], size);
+
+ rt_mutex_release(&virtio_input_dev->rw_mutex);
+
+ return size;
+}
+
+static rt_size_t virtio_input_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
+
+ if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num)
+ {
+ return 0;
+ }
+
+ rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER);
+
+ rt_memcpy(&virtio_input_dev->bcst_events[pos], buffer, size);
+
+ rt_mutex_release(&virtio_input_dev->rw_mutex);
+
+ return size;
+}
+
+static rt_err_t virtio_input_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t status = RT_EOK;
+ struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
+ struct virtio_input_config *config = virtio_input_dev->config;
+
+ if (args == RT_NULL)
+ {
+ return -RT_ERROR;
+ }
+
+ switch (cmd)
+ {
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE:
+
+ *(enum virtio_input_type *)args = virtio_input_dev->type;
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER:
+
+ virtio_input_dev->bsct_handler = args;
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO:
+
+ virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_X);
+ rt_memcpy(args, config, sizeof(struct virtio_input_config));
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO:
+
+ virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_Y);
+ rt_memcpy(args, config, sizeof(struct virtio_input_config));
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS:
+ {
+ rt_uint16_t id;
+ void *addr;
+ struct virtq *queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS];
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ id = queue_status->avail->idx % queue_status->num;
+ addr = &virtio_input_dev->xmit_events[id];
+
+ rt_memcpy(addr, args, sizeof(struct virtio_input_event));
+
+ virtio_free_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id,
+ VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), 0, 0);
+
+ virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS);
+
+ virtio_alloc_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ }
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT:
+
+ rt_memcpy(args, virtio_input_dev->ev_bit, sizeof(virtio_input_dev->ev_bit));
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT:
+
+ rt_memcpy(args, virtio_input_dev->key_bit, sizeof(virtio_input_dev->key_bit));
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT:
+
+ rt_memcpy(args, virtio_input_dev->rel_bit, sizeof(virtio_input_dev->rel_bit));
+
+ break;
+ case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT:
+
+ rt_memcpy(args, virtio_input_dev->abs_bit, sizeof(virtio_input_dev->abs_bit));
+
+ break;
+ default:
+ status = -RT_EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_input_ops =
+{
+ virtio_input_init,
+ RT_NULL,
+ RT_NULL,
+ virtio_input_read,
+ virtio_input_write,
+ virtio_input_control
+};
+#endif
+
+static void virtio_input_isr(int irqno, void *param)
+{
+ struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)param;
+ struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
+ struct virtq *event_queue = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT];
+ const char *dev_name = virtio_input_dev->parent.parent.name;
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ virtio_interrupt_ack(virtio_dev);
+ rt_hw_dsb();
+
+ while (event_queue->used_idx != event_queue->used->idx)
+ {
+ rt_uint16_t id = event_queue->used->ring[event_queue->used_idx % event_queue->num].id;
+ rt_uint32_t len = event_queue->used->ring[event_queue->used_idx % event_queue->num].len;
+
+ if (len == sizeof(struct virtio_input_event))
+ {
+ struct virtio_input_event *recv_events = &virtio_input_dev->recv_events[id];
+ struct virtio_input_event *bcst_events = &virtio_input_dev->bcst_events[id];
+
+ if (recv_events->type >= EV_SYN && recv_events->type <= EV_ABS)
+ {
+ bcst_events->type = recv_events->type;
+ bcst_events->code = recv_events->code;
+ bcst_events->value = recv_events->value;
+
+ if (virtio_input_dev->bsct_handler != RT_NULL)
+ {
+ virtio_input_dev->bsct_handler(*bcst_events);
+ }
+ }
+ else
+ {
+ rt_kprintf("%s: Unsupport event[type: %02x, code: %02x, value: %08x]!\n",
+ dev_name, recv_events->type, recv_events->code, recv_events->value);
+ }
+ }
+ else
+ {
+ rt_kprintf("%s: Invalid event!\n", dev_name);
+ }
+
+ event_queue->used_idx++;
+
+ virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
+{
+ rt_uint32_t flag;
+ static int dev_no = 0;
+ char dev_name[RT_NAME_MAX];
+ struct virtio_device *virtio_dev;
+ struct virtio_input_device *virtio_input_dev;
+
+ virtio_input_dev = rt_malloc(sizeof(struct virtio_input_device));
+
+ if (virtio_input_dev == RT_NULL)
+ {
+ goto _alloc_fail;
+ }
+
+ virtio_dev = &virtio_input_dev->virtio_dev;
+ virtio_dev->irq = irq;
+ virtio_dev->mmio_base = mmio_base;
+
+ virtio_input_dev->config = (struct virtio_input_config *)virtio_dev->mmio_config->config;
+ virtio_input_dev->bsct_handler = RT_NULL;
+
+#ifdef RT_USING_SMP
+ rt_spin_lock_init(&virtio_dev->spinlock);
+#endif
+
+ virtio_reset_device(virtio_dev);
+ virtio_status_acknowledge_driver(virtio_dev);
+
+ virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
+ (1 << VIRTIO_F_RING_EVENT_IDX) |
+ (1 << VIRTIO_F_RING_INDIRECT_DESC));
+
+ virtio_status_driver_ok(virtio_dev);
+
+ if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, VIRTIO_INPUT_EVENT_QUEUE_SIZE) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, VIRTIO_INPUT_STATUS_QUEUE_SIZE) != RT_EOK)
+ {
+ virtio_queue_destroy(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
+
+ goto _alloc_fail;
+ }
+
+ virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
+
+ if (virtio_input_dev->config->ids.product == EV_ABS)
+ {
+ virtio_input_dev->type = VIRTIO_INPUT_TYPE_TABLET;
+
+ virtio_input_dev->parent.type = RT_Device_Class_Touch;
+
+ flag = RT_DEVICE_FLAG_STANDALONE | RT_DEVICE_FLAG_INT_RX;
+ }
+ else
+ {
+ if (virtio_input_dev->config->ids.product == EV_KEY)
+ {
+ virtio_input_dev->type = VIRTIO_INPUT_TYPE_KEYBOARD;
+ }
+ else
+ {
+ virtio_input_dev->type = VIRTIO_INPUT_TYPE_MOUSE;
+ }
+
+ /* Replace it to "KeyBoard" or "Mouse" if support in the future */
+ virtio_input_dev->parent.type = RT_Device_Class_Miscellaneous;
+
+ flag = RT_DEVICE_FLAG_RDWR;
+ }
+#ifdef RT_USING_DEVICE_OPS
+ virtio_input_dev->parent.ops = &virtio_input_ops;
+#else
+ virtio_input_dev->parent.init = virtio_input_init;
+ virtio_input_dev->parent.open = RT_NULL;
+ virtio_input_dev->parent.close = RT_NULL;
+ virtio_input_dev->parent.read = virtio_input_read;
+ virtio_input_dev->parent.write = virtio_input_write;
+ virtio_input_dev->parent.control = virtio_input_control;
+#endif
+
+ rt_snprintf(dev_name, RT_NAME_MAX, "virtio-input%d", dev_no++);
+
+ rt_mutex_init(&virtio_input_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
+
+ rt_hw_interrupt_install(irq, virtio_input_isr, virtio_input_dev, dev_name);
+ rt_hw_interrupt_umask(irq);
+
+ return rt_device_register((rt_device_t)virtio_input_dev, dev_name, flag);
+
+_alloc_fail:
+
+ if (virtio_input_dev != RT_NULL)
+ {
+ virtio_queues_free(virtio_dev);
+ rt_free(virtio_input_dev);
+ }
+ return -RT_ENOMEM;
+}
+#endif /* RT_USING_VIRTIO_INPUT */
diff --git a/components/drivers/virtio/virtio_input.h b/components/drivers/virtio/virtio_input.h
new file mode 100644
index 0000000000..367d0a5d6d
--- /dev/null
+++ b/components/drivers/virtio/virtio_input.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#ifndef __VIRTIO_INPUT_H__
+#define __VIRTIO_INPUT_H__
+
+#include <rtdef.h>
+
+#include <virtio.h>
+#include <virtio_input_event_codes.h>
+
+#define VIRTIO_INPUT_QUEUE_EVENT 0
+#define VIRTIO_INPUT_QUEUE_STATUS 1
+#define VIRTIO_INPUT_EVENT_QUEUE_SIZE 64
+#define VIRTIO_INPUT_STATUS_QUEUE_SIZE 8
+#define VIRTIO_INPUT_QUEUE_MAX_SIZE (VIRTIO_INPUT_EVENT_QUEUE_SIZE > VIRTIO_INPUT_STATUS_QUEUE_SIZE ? \
+ VIRTIO_INPUT_EVENT_QUEUE_SIZE : VIRTIO_INPUT_STATUS_QUEUE_SIZE)
+
+#define VIRTIO_INPUT_ABS_AXIS_X 0
+#define VIRTIO_INPUT_ABS_AXIS_Y 1
+
+enum virtio_input_type
+{
+ VIRTIO_INPUT_TYPE_KEYBOARD,
+ VIRTIO_INPUT_TYPE_MOUSE,
+ VIRTIO_INPUT_TYPE_TABLET,
+
+ VIRTIO_INPUT_TYPE_SIZE,
+};
+
+enum virtio_input_config_select
+{
+ VIRTIO_INPUT_CFG_UNSET = 0x00,
+ VIRTIO_INPUT_CFG_ID_NAME = 0x01,
+ VIRTIO_INPUT_CFG_ID_SERIAL = 0x02,
+ VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03,
+ VIRTIO_INPUT_CFG_PROP_BITS = 0x10,
+ VIRTIO_INPUT_CFG_EV_BITS = 0x11,
+ VIRTIO_INPUT_CFG_ABS_INFO = 0x12,
+};
+
+struct virtio_input_absinfo
+{
+ rt_uint32_t min; /* Minimum value for the axis */
+ rt_uint32_t max; /* Maximum value for the axis */
+ rt_uint32_t fuzz; /* Fuzz value that is used to filter noise from the event stream */
+ rt_uint32_t flat; /* Within this value will be discarded by joydev interface and reported as 0 instead */
+ rt_uint32_t res; /* Resolution for the values reported for the axis */
+};
+
+struct virtio_input_devids
+{
+ rt_uint16_t bustype;
+ rt_uint16_t vendor;
+ rt_uint16_t product;
+ rt_uint16_t version;
+};
+
+struct virtio_input_config
+{
+ rt_uint8_t select;
+ rt_uint8_t subsel;
+ rt_uint8_t size;
+ rt_uint8_t reserved[5];
+
+ union
+ {
+ char string[128];
+ rt_uint8_t bitmap[128];
+ struct virtio_input_absinfo abs;
+ struct virtio_input_devids ids;
+ };
+} __attribute__((packed));
+
+struct virtio_input_event
+{
+ rt_uint16_t type;
+ rt_uint16_t code;
+ rt_uint32_t value;
+};
+
+#ifdef ARCH_CPU_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+#define BITS_PER_BYTE 8
+#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
+#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char))
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
+
+struct virtio_input_device
+{
+ struct rt_device parent;
+
+ struct virtio_device virtio_dev;
+
+ rt_ubase_t ev_bit[BITS_TO_LONGS(EV_CNT)];
+ rt_ubase_t key_bit[BITS_TO_LONGS(KEY_CNT)];
+ rt_ubase_t rel_bit[BITS_TO_LONGS(REL_CNT)];
+ rt_ubase_t abs_bit[BITS_TO_LONGS(ABS_CNT)];
+
+ enum virtio_input_type type;
+ struct virtio_input_config *config;
+
+ /* Broadcast events */
+ struct rt_mutex rw_mutex;
+ void (*bsct_handler)(struct virtio_input_event event);
+ struct virtio_input_event bcst_events[VIRTIO_INPUT_EVENT_QUEUE_SIZE];
+
+ /* Receive events */
+ struct virtio_input_event recv_events[VIRTIO_INPUT_EVENT_QUEUE_SIZE];
+
+ /* Transmit status */
+ struct virtio_input_event xmit_events[VIRTIO_INPUT_STATUS_QUEUE_SIZE];
+};
+
+enum
+{
+ VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE = 0x20,
+ VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER,
+ VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO,
+ VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO,
+ VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS,
+
+ VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT,
+ VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT,
+ VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT,
+ VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT,
+};
+
+rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
+
+#endif /* __VIRTIO_INPUT_H__ */
diff --git a/components/drivers/virtio/virtio_input_event_codes.h b/components/drivers/virtio/virtio_input_event_codes.h
new file mode 100644
index 0000000000..b84723374e
--- /dev/null
+++ b/components/drivers/virtio/virtio_input_event_codes.h
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#ifndef __VIRTIO_INPUT_EVENT_CODES__
+#define __VIRTIO_INPUT_EVENT_CODES__
+
+/* Device properties and quirks */
+#define INPUT_PROP_POINTER 0x00 /* Needs a pointer */
+#define INPUT_PROP_DIRECT 0x01 /* Direct input devices */
+#define INPUT_PROP_BUTTONPAD 0x02 /* Has button(s) under pad */
+#define INPUT_PROP_SEMI_MT 0x03 /* Touch rectangle only */
+#define INPUT_PROP_TOPBUTTONPAD 0x04 /* Softbuttons at top of pad */
+#define INPUT_PROP_POINTING_STICK 0x05 /* Is a pointing stick */
+#define INPUT_PROP_ACCELEROMETER 0x06 /* Has accelerometer */
+
+#define INPUT_PROP_MAX 0x1f
+#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
+
+/* Event types */
+#define EV_SYN 0x00 /* Synchronization events */
+#define EV_KEY 0x01 /* Keys and buttons type */
+#define EV_REL 0x02 /* Relative axes events */
+#define EV_ABS 0x03 /* Absolute axes events */
+#define EV_MSC 0x04 /* Misc events */
+#define EV_SW 0x05 /* Switch events */
+#define EV_LED 0x11 /* LEDs events */
+#define EV_SND 0x12 /* Sounds events */
+#define EV_REP 0x14 /* Repeat events */
+#define EV_FF 0x15 /* Force feedback events */
+#define EV_PWR 0x16 /* Power management events */
+#define EV_FF_STATUS 0x17 /* Force feedback state */
+#define EV_MAX 0x1f /* Maximum number of events */
+#define EV_CNT (EV_MAX + 1)/* Event count */
+
+/* Synchronization events.*/
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+#define SYN_MT_REPORT 2
+#define SYN_DROPPED 3
+#define SYN_MAX 0xf
+#define SYN_CNT (SYN_MAX + 1)
+
+/*
+ * Keys and buttons
+ *
+ * Most of the keys/buttons are modeled after USB HUT 1.12
+ * (see http://www.usb.org/developers/hidpage).
+ * Abbreviations in the comments:
+ * AC - Application Control
+ * AL - Application Launch Button
+ * SC - System Control
+ */
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+
+#define KEY_ZENKAKUHANKAKU 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_RO 89
+#define KEY_KATAKANA 90
+#define KEY_HIRAGANA 91
+#define KEY_HENKAN 92
+#define KEY_KATAKANAHIRAGANA 93
+#define KEY_MUHENKAN 94
+#define KEY_KPJPCOMMA 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116 /* SC System Power Down */
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */
+
+#define KEY_KPCOMMA 121
+#define KEY_HANGEUL 122
+#define KEY_HANGUEL KEY_HANGEUL
+#define KEY_HANJA 123
+#define KEY_YEN 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128 /* AC Stop */
+#define KEY_AGAIN 129
+#define KEY_PROPS 130 /* AC Properties */
+#define KEY_UNDO 131 /* AC Undo */
+#define KEY_FRONT 132
+#define KEY_COPY 133 /* AC Copy */
+#define KEY_OPEN 134 /* AC Open */
+#define KEY_PASTE 135 /* AC Paste */
+#define KEY_FIND 136 /* AC Search */
+#define KEY_CUT 137 /* AC Cut */
+#define KEY_HELP 138 /* AL Integrated Help Center */
+#define KEY_MENU 139 /* Menu (show menu) */
+#define KEY_CALC 140 /* AL Calculator */
+#define KEY_SETUP 141
+#define KEY_SLEEP 142 /* SC System Sleep */
+#define KEY_WAKEUP 143 /* System Wake Up */
+#define KEY_FILE 144 /* AL Local Machine Browser */
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150 /* AL Internet Browser */
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */
+#define KEY_SCREENLOCK KEY_COFFEE
+#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */
+#define KEY_DIRECTION KEY_ROTATE_DISPLAY
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156 /* AC Bookmarks */
+#define KEY_COMPUTER 157
+#define KEY_BACK 158 /* AC Back */
+#define KEY_FORWARD 159 /* AC Forward */
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169 /* Media Select Telephone */
+#define KEY_ISO 170
+#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
+#define KEY_HOMEPAGE 172 /* AC Home */
+#define KEY_REFRESH 173 /* AC Refresh */
+#define KEY_EXIT 174 /* AC Exit */
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+#define KEY_NEW 181 /* AC New */
+#define KEY_REDO 182 /* AC Redo/Repeat */
+
+#define KEY_F13 183
+#define KEY_F14 184
+#define KEY_F15 185
+#define KEY_F16 186
+#define KEY_F17 187
+#define KEY_F18 188
+#define KEY_F19 189
+#define KEY_F20 190
+#define KEY_F21 191
+#define KEY_F22 192
+#define KEY_F23 193
+#define KEY_F24 194
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */
+#define KEY_DASHBOARD KEY_ALL_APPLICATIONS
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206 /* AC Close */
+#define KEY_PLAY 207
+#define KEY_FASTFORWARD 208
+#define KEY_BASSBOOST 209
+#define KEY_PRINT 210 /* AC Print */
+#define KEY_HP 211
+#define KEY_CAMERA 212
+#define KEY_SOUND 213
+#define KEY_QUESTION 214
+#define KEY_EMAIL 215
+#define KEY_CHAT 216
+#define KEY_SEARCH 217
+#define KEY_CONNECT 218
+#define KEY_FINANCE 219 /* AL Checkbook/Finance */
+#define KEY_SPORT 220
+#define KEY_SHOP 221
+#define KEY_ALTERASE 222
+#define KEY_CANCEL 223 /* AC Cancel */
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+#define KEY_MEDIA 226
+
+#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
+#define KEY_KBDILLUMTOGGLE 228
+#define KEY_KBDILLUMDOWN 229
+#define KEY_KBDILLUMUP 230
+
+#define KEY_SEND 231 /* AC Send */
+#define KEY_REPLY 232 /* AC Reply */
+#define KEY_FORWARDMAIL 233 /* AC Forward Msg */
+#define KEY_SAVE 234 /* AC Save */
+#define KEY_DOCUMENTS 235
+
+#define KEY_BATTERY 236
+
+#define KEY_BLUETOOTH 237
+#define KEY_WLAN 238
+#define KEY_UWB 239
+
+#define KEY_UNKNOWN 240
+
+#define KEY_VIDEO_NEXT 241 /* Drive next video source */
+#define KEY_VIDEO_PREV 242 /* Drive previous video source */
+#define KEY_BRIGHTNESS_CYCLE 243 /* Brightness up, after max is min */
+#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual brightness control is off, rely on ambient */
+#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
+#define KEY_DISPLAY_OFF 245 /* Display device to off state */
+
+#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
+#define KEY_WIMAX KEY_WWAN
+#define KEY_RFKILL 247 /* Key that controls all radios */
+
+#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
+
+/* Code 255 is reserved for special needs of AT keyboard driver */
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_SOUTH 0x130
+#define BTN_A BTN_SOUTH
+#define BTN_EAST 0x131
+#define BTN_B BTN_EAST
+#define BTN_C 0x132
+#define BTN_NORTH 0x133
+#define BTN_X BTN_NORTH
+#define BTN_WEST 0x134
+#define BTN_Y BTN_WEST
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
+#define BTN_STYLUS3 0x149
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define KEY_OK 0x160
+#define KEY_SELECT 0x161
+#define KEY_GOTO 0x162
+#define KEY_CLEAR 0x163
+#define KEY_POWER2 0x164
+#define KEY_OPTION 0x165
+#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */
+#define KEY_TIME 0x167
+#define KEY_VENDOR 0x168
+#define KEY_ARCHIVE 0x169
+#define KEY_PROGRAM 0x16a /* Media Select Program Guide */
+#define KEY_CHANNEL 0x16b
+#define KEY_FAVORITES 0x16c
+#define KEY_EPG 0x16d
+#define KEY_PVR 0x16e /* Media Select Home */
+#define KEY_MHP 0x16f
+#define KEY_LANGUAGE 0x170
+#define KEY_TITLE 0x171
+#define KEY_SUBTITLE 0x172
+#define KEY_ANGLE 0x173
+#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */
+#define KEY_ZOOM KEY_FULL_SCREEN
+#define KEY_MODE 0x175
+#define KEY_KEYBOARD 0x176
+#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */
+#define KEY_SCREEN KEY_ASPECT_RATIO
+#define KEY_PC 0x178 /* Media Select Computer */
+#define KEY_TV 0x179 /* Media Select TV */
+#define KEY_TV2 0x17a /* Media Select Cable */
+#define KEY_VCR 0x17b /* Media Select VCR */
+#define KEY_VCR2 0x17c /* VCR Plus */
+#define KEY_SAT 0x17d /* Media Select Satellite */
+#define KEY_SAT2 0x17e
+#define KEY_CD 0x17f /* Media Select CD */
+#define KEY_TAPE 0x180 /* Media Select Tape */
+#define KEY_RADIO 0x181
+#define KEY_TUNER 0x182 /* Media Select Tuner */
+#define KEY_PLAYER 0x183
+#define KEY_TEXT 0x184
+#define KEY_DVD 0x185 /* Media Select DVD */
+#define KEY_AUX 0x186
+#define KEY_MP3 0x187
+#define KEY_AUDIO 0x188 /* AL Audio Browser */
+#define KEY_VIDEO 0x189 /* AL Movie Browser */
+#define KEY_DIRECTORY 0x18a
+#define KEY_LIST 0x18b
+#define KEY_MEMO 0x18c /* Media Select Messages */
+#define KEY_CALENDAR 0x18d
+#define KEY_RED 0x18e
+#define KEY_GREEN 0x18f
+#define KEY_YELLOW 0x190
+#define KEY_BLUE 0x191
+#define KEY_CHANNELUP 0x192 /* Channel Increment */
+#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */
+#define KEY_FIRST 0x194
+#define KEY_LAST 0x195 /* Recall Last */
+#define KEY_AB 0x196
+#define KEY_NEXT 0x197
+#define KEY_RESTART 0x198
+#define KEY_SLOW 0x199
+#define KEY_SHUFFLE 0x19a
+#define KEY_BREAK 0x19b
+#define KEY_PREVIOUS 0x19c
+#define KEY_DIGITS 0x19d
+#define KEY_TEEN 0x19e
+#define KEY_TWEN 0x19f
+#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */
+#define KEY_GAMES 0x1a1 /* Media Select Games */
+#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */
+#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */
+#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */
+#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */
+#define KEY_EDITOR 0x1a6 /* AL Text Editor */
+#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */
+#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */
+#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */
+#define KEY_DATABASE 0x1aa /* AL Database App */
+#define KEY_NEWS 0x1ab /* AL Newsreader */
+#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */
+#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
+#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
+#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
+#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE
+#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
+#define KEY_LOGOFF 0x1b1 /* AL Logoff */
+
+#define KEY_DOLLAR 0x1b2
+#define KEY_EURO 0x1b3
+
+#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */
+#define KEY_FRAMEFORWARD 0x1b5
+#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */
+#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */
+#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */
+#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */
+#define KEY_IMAGES 0x1ba /* AL Image Browser */
+#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */
+#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */
+#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */
+
+#define KEY_DEL_EOL 0x1c0
+#define KEY_DEL_EOS 0x1c1
+#define KEY_INS_LINE 0x1c2
+#define KEY_DEL_LINE 0x1c3
+
+#define KEY_FN 0x1d0
+#define KEY_FN_ESC 0x1d1
+#define KEY_FN_F1 0x1d2
+#define KEY_FN_F2 0x1d3
+#define KEY_FN_F3 0x1d4
+#define KEY_FN_F4 0x1d5
+#define KEY_FN_F5 0x1d6
+#define KEY_FN_F6 0x1d7
+#define KEY_FN_F7 0x1d8
+#define KEY_FN_F8 0x1d9
+#define KEY_FN_F9 0x1da
+#define KEY_FN_F10 0x1db
+#define KEY_FN_F11 0x1dc
+#define KEY_FN_F12 0x1dd
+#define KEY_FN_1 0x1de
+#define KEY_FN_2 0x1df
+#define KEY_FN_D 0x1e0
+#define KEY_FN_E 0x1e1
+#define KEY_FN_F 0x1e2
+#define KEY_FN_S 0x1e3
+#define KEY_FN_B 0x1e4
+#define KEY_FN_RIGHT_SHIFT 0x1e5
+
+#define KEY_BRL_DOT1 0x1f1
+#define KEY_BRL_DOT2 0x1f2
+#define KEY_BRL_DOT3 0x1f3
+#define KEY_BRL_DOT4 0x1f4
+#define KEY_BRL_DOT5 0x1f5
+#define KEY_BRL_DOT6 0x1f6
+#define KEY_BRL_DOT7 0x1f7
+#define KEY_BRL_DOT8 0x1f8
+#define KEY_BRL_DOT9 0x1f9
+#define KEY_BRL_DOT10 0x1fa
+
+#define KEY_NUMERIC_0 0x200 /* Used by phones, remote controls, and other keypads */
+#define KEY_NUMERIC_1 0x201
+#define KEY_NUMERIC_2 0x202
+#define KEY_NUMERIC_3 0x203
+#define KEY_NUMERIC_4 0x204
+#define KEY_NUMERIC_5 0x205
+#define KEY_NUMERIC_6 0x206
+#define KEY_NUMERIC_7 0x207
+#define KEY_NUMERIC_8 0x208
+#define KEY_NUMERIC_9 0x209
+#define KEY_NUMERIC_STAR 0x20a
+#define KEY_NUMERIC_POUND 0x20b
+#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */
+#define KEY_NUMERIC_B 0x20d
+#define KEY_NUMERIC_C 0x20e
+#define KEY_NUMERIC_D 0x20f
+
+#define KEY_CAMERA_FOCUS 0x210
+#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */
+
+#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */
+#define KEY_TOUCHPAD_ON 0x213
+#define KEY_TOUCHPAD_OFF 0x214
+
+#define KEY_CAMERA_ZOOMIN 0x215
+#define KEY_CAMERA_ZOOMOUT 0x216
+#define KEY_CAMERA_UP 0x217
+#define KEY_CAMERA_DOWN 0x218
+#define KEY_CAMERA_LEFT 0x219
+#define KEY_CAMERA_RIGHT 0x21a
+
+#define KEY_ATTENDANT_ON 0x21b
+#define KEY_ATTENDANT_OFF 0x21c
+#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */
+#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */
+
+#define BTN_DPAD_UP 0x220
+#define BTN_DPAD_DOWN 0x221
+#define BTN_DPAD_LEFT 0x222
+#define BTN_DPAD_RIGHT 0x223
+
+#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
+#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
+
+#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
+#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
+#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */
+#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */
+#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
+#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
+#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
+#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
+#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */
+#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */
+#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */
+
+#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
+#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
+
+#define KEY_KBDINPUTASSIST_PREV 0x260
+#define KEY_KBDINPUTASSIST_NEXT 0x261
+#define KEY_KBDINPUTASSIST_PREVGROUP 0x262
+#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263
+#define KEY_KBDINPUTASSIST_ACCEPT 0x264
+#define KEY_KBDINPUTASSIST_CANCEL 0x265
+
+/* Diagonal movement keys */
+#define KEY_RIGHT_UP 0x266
+#define KEY_RIGHT_DOWN 0x267
+#define KEY_LEFT_UP 0x268
+#define KEY_LEFT_DOWN 0x269
+
+#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */
+/* Show Top Menu of the Media (e.g. DVD) */
+#define KEY_MEDIA_TOP_MENU 0x26b
+#define KEY_NUMERIC_11 0x26c
+#define KEY_NUMERIC_12 0x26d
+/*
+ * Toggle Audio Description: refers to an audio service that helps blind and
+ * visually impaired consumers understand the action in a program. Note: in
+ * some countries this is referred to as "Video Description".
+ */
+#define KEY_AUDIO_DESC 0x26e
+#define KEY_3D_MODE 0x26f
+#define KEY_NEXT_FAVORITE 0x270
+#define KEY_STOP_RECORD 0x271
+#define KEY_PAUSE_RECORD 0x272
+#define KEY_VOD 0x273 /* Video on Demand */
+#define KEY_UNMUTE 0x274
+#define KEY_FASTREVERSE 0x275
+#define KEY_SLOWREVERSE 0x276
+/*
+ * Control a data application associated with the currently viewed channel,
+ * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
+ */
+#define KEY_DATA 0x277
+#define KEY_ONSCREEN_KEYBOARD 0x278
+/* Electronic privacy screen control */
+#define KEY_PRIVACY_SCREEN_TOGGLE 0x279
+
+/* Select an area of screen to be copied */
+#define KEY_SELECTIVE_SCREENSHOT 0x27a
+
+/* Move the focus to the next or previous user controllable element within a UI container */
+#define KEY_NEXT_ELEMENT 0x27b
+#define KEY_PREVIOUS_ELEMENT 0x27c
+
+/* Toggle Autopilot engagement */
+#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d
+
+/* Shortcut Keys */
+#define KEY_MARK_WAYPOINT 0x27e
+#define KEY_SOS 0x27f
+#define KEY_NAV_CHART 0x280
+#define KEY_FISHING_CHART 0x281
+#define KEY_SINGLE_RANGE_RADAR 0x282
+#define KEY_DUAL_RANGE_RADAR 0x283
+#define KEY_RADAR_OVERLAY 0x284
+#define KEY_TRADITIONAL_SONAR 0x285
+#define KEY_CLEARVU_SONAR 0x286
+#define KEY_SIDEVU_SONAR 0x287
+#define KEY_NAV_INFO 0x288
+#define KEY_BRIGHTNESS_MENU 0x289
+
+/*
+ * Some keyboards have keys which do not have a defined meaning, these keys
+ * are intended to be programmed / bound to macros by the user. For most
+ * keyboards with these macro-keys the key-sequence to inject, or action to
+ * take, is all handled by software on the host side. So from the kernel's
+ * point of view these are just normal keys.
+ *
+ * The KEY_MACRO# codes below are intended for such keys, which may be labeled
+ * e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys
+ * where the marking on the key does indicate a defined meaning / purpose.
+ *
+ * The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing
+ * KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO
+ * define MUST be added.
+ */
+#define KEY_MACRO1 0x290
+#define KEY_MACRO2 0x291
+#define KEY_MACRO3 0x292
+#define KEY_MACRO4 0x293
+#define KEY_MACRO5 0x294
+#define KEY_MACRO6 0x295
+#define KEY_MACRO7 0x296
+#define KEY_MACRO8 0x297
+#define KEY_MACRO9 0x298
+#define KEY_MACRO10 0x299
+#define KEY_MACRO11 0x29a
+#define KEY_MACRO12 0x29b
+#define KEY_MACRO13 0x29c
+#define KEY_MACRO14 0x29d
+#define KEY_MACRO15 0x29e
+#define KEY_MACRO16 0x29f
+#define KEY_MACRO17 0x2a0
+#define KEY_MACRO18 0x2a1
+#define KEY_MACRO19 0x2a2
+#define KEY_MACRO20 0x2a3
+#define KEY_MACRO21 0x2a4
+#define KEY_MACRO22 0x2a5
+#define KEY_MACRO23 0x2a6
+#define KEY_MACRO24 0x2a7
+#define KEY_MACRO25 0x2a8
+#define KEY_MACRO26 0x2a9
+#define KEY_MACRO27 0x2aa
+#define KEY_MACRO28 0x2ab
+#define KEY_MACRO29 0x2ac
+#define KEY_MACRO30 0x2ad
+
+/*
+ * Some keyboards with the macro-keys described above have some extra keys
+ * for controlling the host-side software responsible for the macro handling:
+ * -A macro recording start/stop key. Note that not all keyboards which emit
+ * KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if
+ * KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START
+ * should be interpreted as a recording start/stop toggle;
+ * -Keys for switching between different macro (pre)sets, either a key for
+ * cycling through the configured presets or keys to directly select a preset.
+ */
+#define KEY_MACRO_RECORD_START 0x2b0
+#define KEY_MACRO_RECORD_STOP 0x2b1
+#define KEY_MACRO_PRESET_CYCLE 0x2b2
+#define KEY_MACRO_PRESET1 0x2b3
+#define KEY_MACRO_PRESET2 0x2b4
+#define KEY_MACRO_PRESET3 0x2b5
+
+/*
+ * Some keyboards have a buildin LCD panel where the contents are controlled
+ * by the host. Often these have a number of keys directly below the LCD
+ * intended for controlling a menu shown on the LCD. These keys often don't
+ * have any labeling so we just name them KEY_KBD_LCD_MENU#
+ */
+#define KEY_KBD_LCD_MENU1 0x2b8
+#define KEY_KBD_LCD_MENU2 0x2b9
+#define KEY_KBD_LCD_MENU3 0x2ba
+#define KEY_KBD_LCD_MENU4 0x2bb
+#define KEY_KBD_LCD_MENU5 0x2bc
+
+#define BTN_TRIGGER_HAPPY 0x2c0
+#define BTN_TRIGGER_HAPPY1 0x2c0
+#define BTN_TRIGGER_HAPPY2 0x2c1
+#define BTN_TRIGGER_HAPPY3 0x2c2
+#define BTN_TRIGGER_HAPPY4 0x2c3
+#define BTN_TRIGGER_HAPPY5 0x2c4
+#define BTN_TRIGGER_HAPPY6 0x2c5
+#define BTN_TRIGGER_HAPPY7 0x2c6
+#define BTN_TRIGGER_HAPPY8 0x2c7
+#define BTN_TRIGGER_HAPPY9 0x2c8
+#define BTN_TRIGGER_HAPPY10 0x2c9
+#define BTN_TRIGGER_HAPPY11 0x2ca
+#define BTN_TRIGGER_HAPPY12 0x2cb
+#define BTN_TRIGGER_HAPPY13 0x2cc
+#define BTN_TRIGGER_HAPPY14 0x2cd
+#define BTN_TRIGGER_HAPPY15 0x2ce
+#define BTN_TRIGGER_HAPPY16 0x2cf
+#define BTN_TRIGGER_HAPPY17 0x2d0
+#define BTN_TRIGGER_HAPPY18 0x2d1
+#define BTN_TRIGGER_HAPPY19 0x2d2
+#define BTN_TRIGGER_HAPPY20 0x2d3
+#define BTN_TRIGGER_HAPPY21 0x2d4
+#define BTN_TRIGGER_HAPPY22 0x2d5
+#define BTN_TRIGGER_HAPPY23 0x2d6
+#define BTN_TRIGGER_HAPPY24 0x2d7
+#define BTN_TRIGGER_HAPPY25 0x2d8
+#define BTN_TRIGGER_HAPPY26 0x2d9
+#define BTN_TRIGGER_HAPPY27 0x2da
+#define BTN_TRIGGER_HAPPY28 0x2db
+#define BTN_TRIGGER_HAPPY29 0x2dc
+#define BTN_TRIGGER_HAPPY30 0x2dd
+#define BTN_TRIGGER_HAPPY31 0x2de
+#define BTN_TRIGGER_HAPPY32 0x2df
+#define BTN_TRIGGER_HAPPY33 0x2e0
+#define BTN_TRIGGER_HAPPY34 0x2e1
+#define BTN_TRIGGER_HAPPY35 0x2e2
+#define BTN_TRIGGER_HAPPY36 0x2e3
+#define BTN_TRIGGER_HAPPY37 0x2e4
+#define BTN_TRIGGER_HAPPY38 0x2e5
+#define BTN_TRIGGER_HAPPY39 0x2e6
+#define BTN_TRIGGER_HAPPY40 0x2e7
+
+/* We avoid low common keys in module aliases so they don't get huge. */
+#define KEY_MIN_INTERESTING KEY_MUTE
+#define KEY_MAX 0x2ff
+#define KEY_CNT (KEY_MAX + 1)
+
+/* Relative axes */
+#define REL_X 0x00
+#define REL_Y 0x01
+#define REL_Z 0x02
+#define REL_RX 0x03
+#define REL_RY 0x04
+#define REL_RZ 0x05
+#define REL_HWHEEL 0x06
+#define REL_DIAL 0x07
+#define REL_WHEEL 0x08
+#define REL_MISC 0x09
+/*
+ * 0x0a is reserved and should not be used in input drivers.
+ * It was used by HID as REL_MISC + 1 and userspace needs to detect if
+ * the next REL_* event is correct or is just REL_MISC + n.
+ * We define here REL_RESERVED so userspace can rely on it and detect
+ * the situation described above.
+ */
+#define REL_RESERVED 0x0a
+#define REL_WHEEL_HI_RES 0x0b
+#define REL_HWHEEL_HI_RES 0x0c
+#define REL_MAX 0x0f
+#define REL_CNT (REL_MAX + 1)
+
+/* Absolute axes */
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+
+#define ABS_VOLUME 0x20
+
+#define ABS_MISC 0x28
+
+/*
+ * 0x2e is reserved and should not be used in input drivers.
+ * It was used by HID as ABS_MISC + 6 and userspace needs to detect if
+ * the next ABS_* event is correct or is just ABS_MISC + n.
+ * We define here ABS_RESERVED so userspace can rely on it and detect
+ * the situation described above.
+ */
+#define ABS_RESERVED 0x2e
+
+#define ABS_MT_SLOT 0x2f /* MT slot being modified */
+#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
+#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
+#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
+#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
+#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
+#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
+#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
+#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
+#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
+#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
+#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
+#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
+#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
+#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
+
+
+#define ABS_MAX 0x3f
+#define ABS_CNT (ABS_MAX + 1)
+
+/* Switch events */
+#define SW_LID 0x00 /* Set = lid shut */
+#define SW_TABLET_MODE 0x01 /* Set = tablet mode */
+#define SW_HEADPHONE_INSERT 0x02 /* Set = inserted */
+#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" set = radio enabled */
+#define SW_RADIO SW_RFKILL_ALL /* deprecated */
+#define SW_MICROPHONE_INSERT 0x04 /* Set = inserted */
+#define SW_DOCK 0x05 /* Set = plugged into dock */
+#define SW_LINEOUT_INSERT 0x06 /* Set = inserted */
+#define SW_JACK_PHYSICAL_INSERT 0x07 /* Set = mechanical switch set */
+#define SW_VIDEOOUT_INSERT 0x08 /* Set = inserted */
+#define SW_CAMERA_LENS_COVER 0x09 /* Set = lens covered */
+#define SW_KEYPAD_SLIDE 0x0a /* Set = keypad slide out */
+#define SW_FRONT_PROXIMITY 0x0b /* Set = front proximity sensor active */
+#define SW_ROTATE_LOCK 0x0c /* Set = rotate locked/disabled */
+#define SW_LINEIN_INSERT 0x0d /* Set = inserted */
+#define SW_MUTE_DEVICE 0x0e /* Set = device disabled */
+#define SW_PEN_INSERTED 0x0f /* Set = pen inserted */
+#define SW_MACHINE_COVER 0x10 /* Set = cover closed */
+#define SW_MAX 0x10
+#define SW_CNT (SW_MAX + 1)
+
+/* Misc events */
+#define MSC_SERIAL 0x00
+#define MSC_PULSELED 0x01
+#define MSC_GESTURE 0x02
+#define MSC_RAW 0x03
+#define MSC_SCAN 0x04
+#define MSC_TIMESTAMP 0x05
+#define MSC_MAX 0x07
+#define MSC_CNT (MSC_MAX + 1)
+
+/* LEDs */
+#define LED_NUML 0x00
+#define LED_CAPSL 0x01
+#define LED_SCROLLL 0x02
+#define LED_COMPOSE 0x03
+#define LED_KANA 0x04
+#define LED_SLEEP 0x05
+#define LED_SUSPEND 0x06
+#define LED_MUTE 0x07
+#define LED_MISC 0x08
+#define LED_MAIL 0x09
+#define LED_CHARGING 0x0a
+#define LED_MAX 0x0f
+#define LED_CNT (LED_MAX + 1)
+
+/* Autorepeat values */
+#define REP_DELAY 0x00
+#define REP_PERIOD 0x01
+#define REP_MAX 0x01
+#define REP_CNT (REP_MAX + 1)
+
+/* Sounds */
+#define SND_CLICK 0x00
+#define SND_BELL 0x01
+#define SND_TONE 0x02
+#define SND_MAX 0x07
+#define SND_CNT (SND_MAX + 1)
+
+#endif /* __VIRTIO_INPUT_EVENT_CODES__ */
diff --git a/components/drivers/virtio/virtio_mmio.h b/components/drivers/virtio/virtio_mmio.h
new file mode 100644
index 0000000000..98b92e460c
--- /dev/null
+++ b/components/drivers/virtio/virtio_mmio.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI modify to virtio common interface
+ */
+
+#ifndef __VIRTIO_MMIO_H__
+#define __VIRTIO_MMIO_H__
+
+#include <rtdef.h>
+
+struct virtio_mmio_config
+{
+ rt_uint32_t magic; /* [0x00]<RO> Magic value */
+ rt_uint32_t version; /* [0x04]<RO> Device version number */
+ rt_uint32_t device_id; /* [0x08]<RO> Virtio Subsystem Device ID */
+ rt_uint32_t vendor_id; /* [0x0c]<RO> Virtio Subsystem Vendor ID */
+ rt_uint32_t device_features; /* [0x10]<RO> Flags representing features the device supports */
+ rt_uint32_t device_features_sel; /* [0x14]<WO> Device (host) features word selection. */
+ rt_uint32_t res0[2]; /* [0x18] */
+ rt_uint32_t driver_features; /* [0x20]<WO> Device features understood and activated by the driver */
+ rt_uint32_t driver_features_sel; /* [0x24]<WO> Activated (guest) features word selection */
+ rt_uint32_t guest_page_size; /* [0x28]<WO> Guest page size, this value should be a power of 2 */
+ rt_uint32_t res1[1]; /* [0x2c] */
+ rt_uint32_t queue_sel; /* [0x30]<WO> Virtual queue index */
+ rt_uint32_t queue_num_max; /* [0x34]<RO> Maximum virtual queue size */
+ rt_uint32_t queue_num; /* [0x38]<WO> Virtual queue size */
+ rt_uint32_t queue_align; /* [0x3c]<WO> Used Ring alignment in the virtual queue */
+ rt_uint32_t queue_pfn; /* [0x40]<RW> Guest physical page number of the virtual queue */
+ rt_uint32_t queue_ready; /* [0x44]<RW> Virtual queue ready bit */
+ rt_uint32_t res2[2]; /* [0x48] */
+ rt_uint32_t queue_notify; /* [0x50]<WO> Queue notifier */
+ rt_uint32_t res3[3]; /* [0x54] */
+ rt_uint32_t interrupt_status; /* [0x60]<RO> Interrupt status */
+ rt_uint32_t interrupt_ack; /* [0x64]<WO> Interrupt acknowledge */
+ rt_uint32_t res4[2]; /* [0x68] */
+ rt_uint32_t status; /* [0x70]<RW> Device status */
+ rt_uint32_t res5[3]; /* [0x74] */
+ rt_uint32_t queue_desc_low; /* [0x80]<WO> Virtual queue’s Descriptor Area 64 bit long physical address */
+ rt_uint32_t queue_desc_high; /* [0x84]<WO> */
+ rt_uint32_t res6[2]; /* [0x88] */
+ rt_uint32_t queue_driver_low; /* [0x90]<WO> Virtual queue’s Driver Area 64 bit long physical address */
+ rt_uint32_t queue_driver_high; /* [0x94]<WO> */
+ rt_uint32_t res7[2]; /* [0x98] */
+ rt_uint32_t queue_device_low; /* [0xa0]<WO> Virtual queue’s Device Area 64 bit long physical address */
+ rt_uint32_t queue_device_high; /* [0xa4]<WO> */
+ rt_uint32_t res8[21]; /* [0xa8] */
+ rt_uint32_t config_generation; /* [0xfc]<RO> Configuration atomicity value */
+ rt_uint32_t config[]; /* [0x100+]<RO> Configuration space */
+
+/*
+ * According to the compiler's optimization ways, we should force compiler not
+ * to optimization here, but it will cause some compilers generate memory access
+ * instructions fail. So we allow user to choose a toggle of optimize here.
+ */
+#ifdef RT_USING_VIRTIO_MMIO_ALIGN
+} __attribute__((packed));
+#else
+};
+#endif
+
+#endif /* __VIRTIO_MMIO_H__ */
diff --git a/components/drivers/virtio/virtio_net.c b/components/drivers/virtio/virtio_net.c
new file mode 100644
index 0000000000..9b44cf6bb2
--- /dev/null
+++ b/components/drivers/virtio/virtio_net.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <cpuport.h>
+
+#ifdef RT_USING_VIRTIO_NET
+
+#include <virtio_net.h>
+
+static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p)
+{
+ rt_uint16_t id;
+ struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
+ struct virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ id = (queue_tx->avail->idx * 2) % queue_tx->num;
+
+ virtio_net_dev->info[id].hdr.flags = 0;
+ virtio_net_dev->info[id].hdr.gso_type = 0;
+ virtio_net_dev->info[id].hdr.hdr_len = 0;
+ virtio_net_dev->info[id].hdr.gso_size = 0;
+ virtio_net_dev->info[id].hdr.csum_start = 0;
+ virtio_net_dev->info[id].hdr.csum_offset = 0;
+ virtio_net_dev->info[id].hdr.num_buffers = 0;
+
+ pbuf_copy_partial(p, virtio_net_dev->info[id].rx_buffer, p->tot_len, 0);
+
+ virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
+ virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id,
+ VIRTIO_VA2PA(&virtio_net_dev->info[id].hdr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT, id + 1);
+
+ virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1,
+ VIRTIO_VA2PA(virtio_net_dev->info[id].rx_buffer), p->tot_len, 0, 0);
+
+ virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_TX);
+
+ virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
+ virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+
+ return RT_EOK;
+}
+
+static struct pbuf *virtio_net_rx(rt_device_t dev)
+{
+ rt_uint16_t id;
+ rt_uint32_t len;
+ struct pbuf *p = RT_NULL, *new, *ret = RT_NULL;
+ struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
+ struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
+
+ while (queue_rx->used_idx != queue_rx->used->idx)
+ {
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ id = (queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id + 1) % queue_rx->num;
+ len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len - VIRTIO_NET_HDR_SIZE;
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ if (len > VIRTIO_NET_PAYLOAD_MAX_SIZE)
+ {
+ rt_kprintf("%s: Receive buffer's size = %u is too big!\n", virtio_net_dev->parent.parent.parent.name, len);
+ len = VIRTIO_NET_PAYLOAD_MAX_SIZE;
+ }
+
+ new = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
+
+ if (p != RT_NULL)
+ {
+ p->next = new;
+ p = p->next;
+ }
+ else
+ {
+ p = new;
+ ret = p;
+ }
+
+ if (p != RT_NULL)
+ {
+#ifdef RT_USING_SMP
+ level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+ rt_memcpy(p->payload, (void *)VIRTIO_PA2VA(queue_rx->desc[id].addr), len);
+
+ queue_rx->used_idx++;
+
+ virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, id - 1);
+
+ virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX);
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static rt_err_t virtio_net_init(rt_device_t dev)
+{
+ int i;
+ rt_uint16_t idx[VIRTIO_NET_RTX_QUEUE_SIZE];
+ struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
+ struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
+ struct virtq *queue_rx, *queue_tx;
+
+ queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
+ queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
+
+ virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, queue_rx->num, idx);
+ virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, queue_tx->num, idx);
+
+ for (i = 0; i < queue_rx->num; ++i)
+ {
+ rt_uint16_t id = (i * 2) % queue_rx->num;
+ void *addr = virtio_net_dev->info[i].tx_buffer;
+
+ /* Descriptor for net_hdr */
+ virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id,
+ VIRTIO_VA2PA(addr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE, id + 1);
+
+ /* Descriptor for data */
+ virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id + 1,
+ VIRTIO_VA2PA(addr) + VIRTIO_NET_HDR_SIZE, VIRTIO_NET_MSS, VIRTQ_DESC_F_WRITE, 0);
+
+ queue_rx->avail->ring[i] = id;
+ }
+ rt_hw_dsb();
+
+ queue_rx->avail->flags = 0;
+ queue_rx->avail->idx = queue_rx->num;
+
+ queue_rx->used_idx = queue_rx->used->idx;
+
+ queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
+ queue_tx->avail->idx = 0;
+
+ virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX);
+
+ return eth_device_linkchange(&virtio_net_dev->parent, RT_TRUE);
+}
+
+static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t status = RT_EOK;
+ struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
+
+ switch (cmd)
+ {
+ case NIOCTL_GADDR:
+ if (args == RT_NULL)
+ {
+ status = -RT_ERROR;
+ break;
+ }
+
+ rt_memcpy(args, virtio_net_dev->config->mac, sizeof(virtio_net_dev->config->mac));
+ break;
+ default:
+ status = -RT_EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_net_ops =
+{
+ virtio_net_init,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ virtio_net_control
+};
+#endif
+
+static void virtio_net_isr(int irqno, void *param)
+{
+ struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)param;
+ struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
+ struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
+
+#ifdef RT_USING_SMP
+ rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
+#endif
+
+ virtio_interrupt_ack(virtio_dev);
+ rt_hw_dsb();
+
+ if (queue_rx->used_idx != queue_rx->used->idx)
+ {
+ rt_hw_dsb();
+
+ eth_device_ready(&virtio_net_dev->parent);
+ }
+
+#ifdef RT_USING_SMP
+ rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
+#endif
+}
+
+rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
+{
+ static int dev_no = 0;
+ char dev_name[RT_NAME_MAX];
+ struct virtio_device *virtio_dev;
+ struct virtio_net_device *virtio_net_dev;
+
+ virtio_net_dev = rt_malloc(sizeof(struct virtio_net_device));
+
+ if (virtio_net_dev == RT_NULL)
+ {
+ goto _alloc_fail;
+ }
+
+ virtio_dev = &virtio_net_dev->virtio_dev;
+ virtio_dev->irq = irq;
+ virtio_dev->mmio_base = mmio_base;
+
+ virtio_net_dev->config = (struct virtio_net_config *)virtio_dev->mmio_config->config;
+
+#ifdef RT_USING_SMP
+ rt_spin_lock_init(&virtio_dev->spinlock);
+#endif
+
+ virtio_reset_device(virtio_dev);
+ virtio_status_acknowledge_driver(virtio_dev);
+
+ virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
+ (1 << VIRTIO_NET_F_CTRL_VQ) |
+ (1 << VIRTIO_F_RING_EVENT_IDX));
+
+ virtio_status_driver_ok(virtio_dev);
+
+ if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_RX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK)
+ {
+ goto _alloc_fail;
+ }
+
+ if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_TX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK)
+ {
+ virtio_queue_destroy(virtio_dev, VIRTIO_NET_QUEUE_RX);
+ goto _alloc_fail;
+ }
+
+ virtio_net_dev->parent.parent.type = RT_Device_Class_NetIf;
+#ifdef RT_USING_DEVICE_OPS
+ virtio_net_dev->parent.parent.ops = &virtio_net_ops;
+#else
+ virtio_net_dev->parent.parent.init = virtio_net_init;
+ virtio_net_dev->parent.parent.open = RT_NULL;
+ virtio_net_dev->parent.parent.close = RT_NULL;
+ virtio_net_dev->parent.parent.read = RT_NULL;
+ virtio_net_dev->parent.parent.write = RT_NULL;
+ virtio_net_dev->parent.parent.control = virtio_net_control;
+#endif
+ virtio_net_dev->parent.eth_tx = virtio_net_tx;
+ virtio_net_dev->parent.eth_rx = virtio_net_rx;
+
+ rt_snprintf(dev_name, RT_NAME_MAX, "virtio-net%d", dev_no++);
+
+ rt_hw_interrupt_install(irq, virtio_net_isr, virtio_net_dev, dev_name);
+ rt_hw_interrupt_umask(irq);
+
+ return eth_device_init(&virtio_net_dev->parent, dev_name);
+
+_alloc_fail:
+
+ if (virtio_net_dev != RT_NULL)
+ {
+ virtio_queues_free(virtio_dev);
+ rt_free(virtio_net_dev);
+ }
+ return -RT_ENOMEM;
+}
+#endif /* RT_USING_VIRTIO_NET */
diff --git a/components/drivers/virtio/virtio_net.h b/components/drivers/virtio/virtio_net.h
new file mode 100644
index 0000000000..d00c3edb90
--- /dev/null
+++ b/components/drivers/virtio/virtio_net.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#ifndef __VIRTIO_NET_H__
+#define __VIRTIO_NET_H__
+
+#ifdef RT_USING_VIRTIO_NET
+
+#include <rtdef.h>
+#include <netif/ethernetif.h>
+
+#include <virtio.h>
+
+#define VIRTIO_NET_QUEUE_RX 0
+#define VIRTIO_NET_QUEUE_TX 1
+#define VIRTIO_NET_RTX_QUEUE_SIZE 16
+#define VIRTIO_NET_RTX_BUF_SIZE 2048
+
+#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */
+#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2 /* Dynamic offload configuration */
+#define VIRTIO_NET_F_MTU 3 /* Initial MTU advice */
+#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address */
+#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in */
+#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in */
+#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in */
+#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in */
+#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in */
+#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in */
+#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in */
+#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in */
+#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */
+#define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */
+#define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */
+#define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */
+#define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */
+#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */
+#define VIRTIO_NET_F_GUEST_ANNOUNCE 21 /* Guest can announce device on the network */
+#define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow Steering */
+#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
+
+#define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */
+#define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */
+#define VIRTIO_NET_F_RSC_EXT 61 /* Extended coalescing info */
+#define VIRTIO_NET_F_STANDBY 62 /* Act as standby for another device with the same MAC */
+#define VIRTIO_NET_F_SPEED_DUPLEX 63 /* Device set linkspeed and duplex */
+
+#define VIRTIO_NET_S_LINK_UP (1 << 0)
+#define VIRTIO_NET_S_ANNOUNCE (1 << 1)
+
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1
+#define VIRTIO_NET_HDR_F_DATA_VALID 2
+#define VIRTIO_NET_HDR_F_RSC_INFO 4
+
+#define VIRTIO_NET_HDR_GSO_NONE 0
+#define VIRTIO_NET_HDR_GSO_TCPV4 1
+#define VIRTIO_NET_HDR_GSO_UDP 3
+#define VIRTIO_NET_HDR_GSO_TCPV6 4
+#define VIRTIO_NET_HDR_GSO_ECN 0x80
+
+struct virtio_net_hdr
+{
+ rt_uint8_t flags;
+ rt_uint8_t gso_type;
+ rt_uint16_t hdr_len;
+ rt_uint16_t gso_size;
+ rt_uint16_t csum_start;
+ rt_uint16_t csum_offset;
+ rt_uint16_t num_buffers;
+} __attribute__ ((packed));
+
+#define VIRTIO_NET_MSS 1514
+#define VIRTIO_NET_HDR_SIZE (sizeof(struct virtio_net_hdr))
+#define VIRTIO_NET_PAYLOAD_MAX_SIZE (VIRTIO_NET_HDR_SIZE + VIRTIO_NET_MSS)
+
+struct virtio_net_config
+{
+ rt_uint8_t mac[6];
+ rt_uint16_t status;
+ rt_uint16_t max_virtqueue_pairs;
+ rt_uint16_t mtu;
+ rt_uint32_t speed;
+ rt_uint8_t duplex;
+ rt_uint8_t rss_max_key_size;
+ rt_uint16_t rss_max_indirection_table_length;
+ rt_uint32_t supported_hash_types;
+} __attribute__((packed));
+
+struct virtio_net_device
+{
+ struct eth_device parent;
+
+ struct virtio_device virtio_dev;
+
+ struct virtio_net_config *config;
+
+ struct
+ {
+ /* Transmit hdr */
+ struct virtio_net_hdr hdr;
+ /* Transmit buffer */
+ rt_uint8_t tx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE];
+ /* Receive buffer */
+ rt_uint8_t rx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE];
+ } info[VIRTIO_NET_RTX_QUEUE_SIZE];
+};
+
+rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
+
+#endif /* RT_USING_VIRTIO_NET */
+
+#endif /* __VIRTIO_NET_H__ */
diff --git a/components/drivers/virtio/virtio_queue.h b/components/drivers/virtio/virtio_queue.h
new file mode 100644
index 0000000000..1e416af131
--- /dev/null
+++ b/components/drivers/virtio/virtio_queue.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#ifndef __VIRTIO_QUEUE_H__
+#define __VIRTIO_QUEUE_H__
+
+#include <rtdef.h>
+
+#define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as continuing via the next field. */
+#define VIRTQ_DESC_F_WRITE 2 /* This marks a buffer as write-only (otherwise read-only). */
+#define VIRTQ_DESC_F_INDIRECT 4 /* This means the buffer contains a list of buffer descriptors. */
+
+/*
+ * The device uses this in used->flags to advise the driver: don't kick me
+ * when you add a buffer. It's unreliable, so it's simply an optimization.
+ */
+#define VIRTQ_USED_F_NO_NOTIFY 1
+
+/*
+ * The driver uses this in avail->flags to advise the device: don't
+ * interrupt me when you consume a buffer. It's unreliable, so it's
+ * simply an optimization.
+ */
+#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
+
+/* Virtqueue descriptors: 16 bytes. These can chain together via "next". */
+struct virtq_desc
+{
+ rt_uint64_t addr; /* Address (guest-physical). */
+ rt_uint32_t len; /* Length. */
+ rt_uint16_t flags; /* The flags as indicated above. */
+ rt_uint16_t next; /* We chain unused descriptors via this, too */
+};
+
+struct virtq_avail
+{
+ rt_uint16_t flags; /* Notifications */
+ rt_uint16_t idx; /* Where the driver would put the next descriptor entry in the ring (modulo the queue size) */
+ rt_uint16_t ring[];
+
+ /*
+ * Only if VIRTIO_F_RING_EVENT_IDX
+ * rt_uint16_t used_event;
+ */
+};
+
+struct virtq_used_elem
+{
+ rt_uint32_t id; /* Index of start of used descriptor chain. */
+ rt_uint32_t len; /* Total length of the descriptor chain which was written to. */
+};
+
+struct virtq_used
+{
+ rt_uint16_t flags;
+ rt_uint16_t idx;
+ struct virtq_used_elem ring[];
+
+ /*
+ * Only if VIRTIO_F_RING_EVENT_IDX
+ * rt_uint16_t avail_event;
+ */
+};
+
+struct virtq
+{
+ rt_uint32_t num;
+
+ struct virtq_desc *desc;
+ struct virtq_avail *avail;
+ struct virtq_used *used;
+
+ /* Helper of driver */
+ rt_uint16_t used_idx;
+ rt_bool_t *free;
+ rt_size_t free_count;
+};
+
+#define VIRTQ_DESC_TOTAL_SIZE(ring_size) (sizeof(struct virtq_desc) * (ring_size))
+/* flags, idx, used_event + ring * ring_size */
+#define VIRTQ_AVAIL_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(rt_uint16_t) * (ring_size))
+/* flags, idx, avail_event + ring * ring_size */
+#define VIRTQ_USED_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(struct virtq_used_elem) * (ring_size))
+
+#define VIRTQ_AVAIL_RES_SIZE (sizeof(rt_uint16_t)) /* used_event */
+#define VIRTQ_USED_RES_SIZE (sizeof(rt_uint16_t)) /* avail_event */
+
+#define VIRTQ_INVALID_DESC_ID RT_UINT16_MAX
+
+#endif /* __VIRTIO_QUEUE_H__ */
diff --git a/components/fal/src/fal_rtt.c b/components/fal/src/fal_rtt.c
index 52d276d8c9..98f1c3abe0 100644
--- a/components/fal/src/fal_rtt.c
+++ b/components/fal/src/fal_rtt.c
@@ -397,13 +397,17 @@ const static struct rt_device_ops char_dev_ops =
};
#endif
-#ifdef RT_USING_POSIX
-#include <dfs_posix.h>
+#ifdef RT_USING_POSIX_DEVIO
+#include <dfs_file.h>
+#include <unistd.h>
+#include <stdio.h> /* rename() */
+#include <sys/stat.h>
+#include <sys/statfs.h> /* statfs() */
/* RT-Thread device filesystem interface */
static int char_dev_fopen(struct dfs_fd *fd)
{
- struct fal_char_device *part = (struct fal_char_device *) fd->data;
+ struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
assert(part != RT_NULL);
@@ -427,7 +431,7 @@ static int char_dev_fopen(struct dfs_fd *fd)
static int char_dev_fread(struct dfs_fd *fd, void *buf, size_t count)
{
int ret = 0;
- struct fal_char_device *part = (struct fal_char_device *) fd->data;
+ struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
assert(part != RT_NULL);
@@ -447,7 +451,7 @@ static int char_dev_fread(struct dfs_fd *fd, void *buf, size_t count)
static int char_dev_fwrite(struct dfs_fd *fd, const void *buf, size_t count)
{
int ret = 0;
- struct fal_char_device *part = (struct fal_char_device *) fd->data;
+ struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
assert(part != RT_NULL);
@@ -476,7 +480,7 @@ static const struct dfs_file_ops char_dev_fops =
RT_NULL, /* getdents */
RT_NULL,
};
-#endif /* defined(RT_USING_POSIX) */
+#endif /* defined(RT_USING_POSIX_DEVIO) */
/**
* create RT-Thread char device by specified partition
@@ -527,7 +531,7 @@ struct rt_device *fal_char_device_create(const char *parition_name)
rt_device_register(RT_DEVICE(char_dev), fal_part->name, RT_DEVICE_FLAG_RDWR);
log_i("The FAL char device (%s) created successfully", fal_part->name);
-#ifdef RT_USING_POSIX
+#ifdef RT_USING_POSIX_DEVIO
/* set fops */
char_dev->parent.fops = &char_dev_fops;
#endif
diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c
index 99d601b76d..f2dc3b794e 100644
--- a/components/finsh/cmd.c
+++ b/components/finsh/cmd.c
@@ -213,7 +213,7 @@ long list_thread(void)
#endif /*RT_USING_SMP*/
stat = (thread->stat & RT_THREAD_STAT_MASK);
if (stat == RT_THREAD_READY) rt_kprintf(" ready ");
- else if (stat == RT_THREAD_SUSPEND) rt_kprintf(" suspend");
+ else if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) rt_kprintf(" suspend");
else if (stat == RT_THREAD_INIT) rt_kprintf(" init ");
else if (stat == RT_THREAD_CLOSE) rt_kprintf(" close ");
else if (stat == RT_THREAD_RUNNING) rt_kprintf(" running");
diff --git a/components/finsh/msh.c b/components/finsh/msh.c
index 22e2cf5389..884d408ec3 100644
--- a/components/finsh/msh.c
+++ b/components/finsh/msh.c
@@ -210,7 +210,7 @@ int msh_exec_module(const char *cmd_line, int size)
length = cmd_length + 32;
/* allocate program name memory */
- pg_name = (char *) rt_malloc(length);
+ pg_name = (char *) rt_malloc(length + 3);
if (pg_name == RT_NULL)
return -RT_ENOMEM;
@@ -261,7 +261,22 @@ int msh_exec_module(const char *cmd_line, int size)
rt_free(pg_name);
return ret;
}
-#endif /* defined(RT_USING_MODULE) && defined(DFS_USING_POSIX) */
+
+int system(const char *command)
+{
+ int ret = -RT_ENOMEM;
+ char *cmd = rt_strdup(command);
+
+ if (cmd)
+ {
+ ret = msh_exec(cmd, rt_strlen(cmd));
+ rt_free(cmd);
+ }
+
+ return ret;
+}
+RTM_EXPORT(system);
+#endif
static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp)
{
@@ -294,16 +309,139 @@ static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp)
return 0;
}
+pid_t exec(char*, int, int, char**);
+
#if defined(RT_USING_LWP) && defined(DFS_USING_POSIX)
-static int _msh_exec_lwp(char *cmd, rt_size_t length)
+/* check whether a file of the given path exits */
+static rt_bool_t _msh_lwp_cmd_exists(const char *path)
+{
+ int fd = -1;
+ fd = open(path, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ return RT_FALSE;
+ }
+ close(fd);
+ return RT_TRUE;
+}
+
+/*
+ * search for the file named "pg_name" or "pg_name.elf" at the given directory,
+ * and return its path. return NULL when not found.
+ */
+static char *_msh_exec_search_path(const char *path, const char *pg_name)
+{
+ char *path_buffer = RT_NULL;
+ ssize_t pg_len = strlen(pg_name);
+ ssize_t base_len = 0;
+
+ if (path)
+ {
+ base_len = strlen(path);
+ }
+
+ path_buffer = rt_malloc(base_len + pg_len + 6);
+ if (path_buffer == RT_NULL)
+ {
+ return RT_NULL; /* no mem */
+ }
+
+ if (base_len > 0)
+ {
+ memcpy(path_buffer, path, base_len);
+ path_buffer[base_len] = '/';
+ path_buffer[base_len + 1] = '\0';
+ }
+ else
+ {
+ *path_buffer = '\0';
+ }
+ strcat(path_buffer, pg_name);
+
+ if (_msh_lwp_cmd_exists(path_buffer))
+ {
+ return path_buffer;
+ }
+
+ if (strstr(path_buffer, ".elf") != NULL)
+ {
+ goto not_found;
+ }
+
+ strcat(path_buffer, ".elf");
+ if (_msh_lwp_cmd_exists(path_buffer))
+ {
+ return path_buffer;
+ }
+
+not_found:
+ rt_free(path_buffer);
+ return RT_NULL;
+}
+
+/*
+ * search for the file named "pg_name" or "pg_name.elf" at each env path,
+ * and return its path. return NULL when not found.
+ */
+static char *_msh_exec_search_env(const char *pg_name)
+{
+ char *result = RT_NULL;
+ char *exec_path = RT_NULL;
+ char *search_path = RT_NULL;
+ char *pos = RT_NULL;
+ char tmp_ch = '\0';
+
+ if (!(exec_path = getenv("PATH")))
+ {
+ return RT_NULL;
+ }
+
+ /* exec path may need to be modified */
+ if (!(exec_path = strdup(exec_path)))
+ {
+ return RT_NULL;
+ }
+
+ pos = exec_path;
+ search_path = exec_path;
+
+ /* walk through the entire exec_path until finding the program wanted
+ or hitting its end */
+ while (1)
+ {
+ /* env paths are seperated by ':' */
+ if (*pos == ':' || *pos == '\0')
+ {
+ tmp_ch = *pos;
+ *pos = '\0';
+
+ result = _msh_exec_search_path(search_path, pg_name);
+ if (result || tmp_ch == '\0')
+ {
+ goto ret;
+ }
+
+ pos++;
+ search_path = pos;
+ continue;
+ }
+
+ pos++;
+ }
+
+ /* release the duplicated exec_path and return */
+ret:
+ rt_free(exec_path);
+ return result;
+}
+
+int _msh_exec_lwp(int debug, char *cmd, rt_size_t length)
{
int argc;
int cmd0_size = 0;
char *argv[FINSH_ARG_MAX];
- int fd = -1;
char *pg_name;
-
- extern int exec(char *, int, char **);
+ int ret;
/* find the size of first command */
while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
@@ -317,20 +455,46 @@ static int _msh_exec_lwp(char *cmd, rt_size_t length)
if (argc == 0)
return -1;
- pg_name = argv[0];
- /* try to open program */
- fd = open(pg_name, O_RDONLY, 0);
+ /* try to find program in working directory */
+ pg_name = _msh_exec_search_path("", argv[0]);
+ if (pg_name)
+ {
+ goto found_program;
+ }
- if (fd < 0)
+ /* only check these paths when the first argument doesn't contain path
+ seperator */
+ if (strstr(argv[0], "/"))
+ {
return -1;
+ }
+
+ /* try to find program in /bin */
+ pg_name = _msh_exec_search_path("/bin", argv[0]);
+ if (pg_name)
+ {
+ goto found_program;
+ }
+
+ /* try to find program in dirs registered to env path */
+ pg_name = _msh_exec_search_env(argv[0]);
+ if (pg_name)
+ {
+ goto found_program;
+ }
+
+ /* not found in anywhere */
+ return -1;
/* found program */
- close(fd);
- exec(pg_name, argc, argv);
+found_program:
+ ret = exec(pg_name, debug, argc, argv);
+ rt_free(pg_name);
- return 0;
+ return ret;
}
-#endif /* defined(RT_USING_LWP) && defined(DFS_USING_POSIX) */
+#endif
+
int msh_exec(char *cmd, rt_size_t length)
{
@@ -370,7 +534,9 @@ int msh_exec(char *cmd, rt_size_t length)
#endif /* RT_USING_MODULE */
#ifdef RT_USING_LWP
- if (_msh_exec_lwp(cmd, length) == 0)
+ /* exec from msh_exec , debug = 0*/
+ /* _msh_exec_lwp return is pid , <= 0 means failed */
+ if (_msh_exec_lwp(0, cmd, length) > 0)
{
return 0;
}
@@ -472,6 +638,7 @@ void msh_auto_complete_path(char *path)
}
else
{
+ int multi = 0;
rt_size_t length, min_length;
min_length = 0;
@@ -483,6 +650,7 @@ void msh_auto_complete_path(char *path)
/* matched the prefix string */
if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
{
+ multi ++;
if (min_length == 0)
{
min_length = rt_strlen(dirent->d_name);
@@ -501,7 +669,7 @@ void msh_auto_complete_path(char *path)
if (min_length)
{
- if (min_length < rt_strlen(full_path))
+ if (multi > 1)
{
/* list the candidate */
rewinddir(dir);
@@ -519,6 +687,16 @@ void msh_auto_complete_path(char *path)
length = index - path;
rt_memcpy(index, full_path, min_length);
path[length + min_length] = '\0';
+
+ /* try to locate folder */
+ if (multi == 1)
+ {
+ struct stat buffer = {0};
+ if ((stat(path, &buffer) == 0) && (S_ISDIR(buffer.st_mode)))
+ {
+ strcat(path, "/");
+ }
+ }
}
}
@@ -558,7 +736,7 @@ void msh_auto_complete(char *prefix)
ptr --;
}
-#ifdef RT_USING_MODULE
+#if defined(RT_USING_MODULE) || defined(RT_USING_LWP)
/* There is a chance that the user want to run the module directly. So
* try to complete the file names. If the completed path is not a
* module, the system won't crash anyway. */
diff --git a/components/finsh/msh_file.c b/components/finsh/msh_file.c
index 9deab4f0bc..04255747bd 100644
--- a/components/finsh/msh_file.c
+++ b/components/finsh/msh_file.c
@@ -104,7 +104,7 @@ int msh_exec_script(const char *cmd_line, int size)
int length;
line_buf = (char *) rt_malloc(RT_CONSOLEBUF_SIZE);
- if (line_buf == RT_NULL)
+ if (line_buf == RT_NULL)
{
close(fd);
return -RT_ENOMEM;
@@ -480,6 +480,15 @@ static int cmd_mkfs(int argc, char **argv)
MSH_CMD_EXPORT_ALIAS(cmd_mkfs, mkfs, format disk with file system);
extern struct dfs_filesystem filesystem_table[];
+
+/*
+ * If no argument is specified, display the mount history;
+ * If there are 3 arguments, mount the filesystem.
+ * The order of the arguments is:
+ * argv[1]: device name
+ * argv[2]: mountpoint path
+ * argv[3]: filesystem type
+ */
static int cmd_mount(int argc, char **argv)
{
if (argc == 1)
@@ -519,6 +528,24 @@ static int cmd_mount(int argc, char **argv)
return -1;
}
}
+ else if (argc == 3)
+ {
+ char *path = argv[1];
+ char *fstype = argv[2];
+
+ /* mount a filesystem to the specified directory */
+ rt_kprintf("mount (%s) onto %s ... ", fstype, path);
+ if (dfs_mount(NULL, path, fstype, 0, 0) == 0)
+ {
+ rt_kprintf("succeed!\n");
+ return 0;
+ }
+ else
+ {
+ rt_kprintf("failed!\n");
+ return -1;
+ }
+ }
else
{
rt_kprintf("Usage: mount <device> <mountpoint> <fstype>.\n");
@@ -550,7 +577,7 @@ static int cmd_umount(int argc, char **argv)
return 0;
}
}
-MSH_CMD_EXPORT_ALIAS(cmd_umount, umount, Unmount device from file system);
+MSH_CMD_EXPORT_ALIAS(cmd_umount, umount, Unmount the mountpoint);
extern int df(const char *path);
static int cmd_df(int argc, char **argv)
diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c
index 64e3c9424c..493b502534 100644
--- a/components/libc/compilers/common/ctime.c
+++ b/components/libc/compilers/common/ctime.c
@@ -26,6 +26,9 @@
#include <rtthread.h>
#include <rthw.h>
#include <unistd.h>
+#ifdef RT_USING_LWP
+#include "lwp.h"
+#endif
#ifdef RT_USING_POSIX_DELAY
#include <delay.h>
#endif
@@ -376,7 +379,7 @@ int stime(const time_t *t)
if (t == RT_NULL)
{
rt_set_errno(EFAULT);
- return -1;
+ return -RT_ERROR;
}
tv.tv_sec = *t;
@@ -387,7 +390,7 @@ int stime(const time_t *t)
else
{
rt_set_errno(EFAULT);
- return -1;
+ return -RT_ERROR;
}
}
RTM_EXPORT(stime);
@@ -401,7 +404,7 @@ time_t timegm(struct tm * const t)
if(t == RT_NULL)
{
rt_set_errno(EFAULT);
- return (time_t)-1;
+ return (time_t)-RT_ERROR;
}
years = (time_t)t->tm_year - 70;
@@ -443,7 +446,7 @@ time_t timegm(struct tm * const t)
if (t->tm_year < 70)
{
rt_set_errno(EINVAL);
- return (time_t) -1;
+ return (time_t) -RT_ERROR;
}
/* Days since 1970 is 365 * number of years + number of leap years since 1970 */
@@ -497,7 +500,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
else
{
rt_set_errno(EINVAL);
- return -1;
+ return -RT_ERROR;
}
}
RTM_EXPORT(gettimeofday);
@@ -518,7 +521,7 @@ int settimeofday(const struct timeval *tv, const struct timezone *tz)
else
{
rt_set_errno(EINVAL);
- return -1;
+ return -RT_ERROR;
}
}
RTM_EXPORT(settimeofday);
@@ -526,8 +529,52 @@ RTM_EXPORT(settimeofday);
#ifdef RT_USING_POSIX_DELAY
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
- sleep(rqtp->tv_sec);
- ndelay(rqtp->tv_nsec);
+ if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
+ {
+ rt_set_errno(EINVAL);
+ return -RT_ERROR;
+ }
+#ifdef RT_USING_CPUTIME
+ uint64_t cpu_tick, cpu_tick_old;
+ cpu_tick_old = clock_cpu_gettime();
+ rt_tick_t tick;
+ float unit = clock_cpu_getres();
+
+ cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + ((uint64_t)rqtp->tv_nsec * NANOSECOND_PER_SECOND) / NANOSECOND_PER_SECOND) / unit;
+ tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+ rt_thread_delay(tick);
+
+ if (rt_get_errno() == -RT_EINTR)
+ {
+ if (rmtp)
+ {
+ uint64_t rmtp_cpu_tick = cpu_tick_old + cpu_tick - clock_cpu_gettime();
+ rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
+ rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
+ }
+ rt_set_errno(EINTR);
+ return -RT_ERROR;
+ }
+ else
+ while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
+#else
+ rt_tick_t tick, tick_old = rt_tick_get();
+ tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
+ rt_thread_delay(tick);
+
+ if (rt_get_errno() == -RT_EINTR)
+ {
+ if (rmtp)
+ {
+ tick = tick_old + tick - rt_tick_get();
+ /* get the passed time */
+ rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
+ rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+ }
+ rt_set_errno(EINTR);
+ return -RT_ERROR;
+ }
+#endif
return 0;
}
RTM_EXPORT(nanosleep);
@@ -563,7 +610,7 @@ static int _rt_clock_time_system_init(void)
_timevalue.tv_sec = 0;
rt_hw_interrupt_enable(level);
- return -1;
+ return -RT_ERROR;
}
INIT_COMPONENT_EXPORT(_rt_clock_time_system_init);
#endif /* RT_USING_RTC */
@@ -572,14 +619,14 @@ int clock_getres(clockid_t clockid, struct timespec *res)
{
#ifndef RT_USING_RTC
LOG_W(_WARNING_NO_RTC);
- return -1;
+ return -RT_ERROR;
#else
int ret = 0;
if (res == RT_NULL)
{
rt_set_errno(EFAULT);
- return -1;
+ return -RT_ERROR;
}
switch (clockid)
@@ -599,7 +646,7 @@ int clock_getres(clockid_t clockid, struct timespec *res)
default:
res->tv_sec = 0;
res->tv_nsec = 0;
- ret = -1;
+ ret = -RT_ERROR;
rt_set_errno(EINVAL);
break;
}
@@ -613,14 +660,14 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
{
#ifndef RT_USING_RTC
LOG_W(_WARNING_NO_RTC);
- return -1;
+ return -RT_ERROR;
#else
int ret = 0;
if (tp == RT_NULL)
{
rt_set_errno(EFAULT);
- return -1;
+ return -RT_ERROR;
}
switch (clockid)
@@ -656,7 +703,7 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
tp->tv_sec = 0;
tp->tv_nsec = 0;
rt_set_errno(EINVAL);
- ret = -1;
+ ret = -RT_ERROR;
}
return ret;
@@ -666,20 +713,91 @@ RTM_EXPORT(clock_gettime);
int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp)
{
- if ((clockid != CLOCK_REALTIME) || (rqtp == RT_NULL))
+#ifndef RT_USING_RTC
+ LOG_W(_WARNING_NO_RTC);
+ return -RT_ERROR;
+#else
+ if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
{
rt_set_errno(EINVAL);
- return -1;
+ return -RT_ERROR;
}
+ switch (clockid)
+ {
+ case CLOCK_REALTIME:
+ {
+ rt_tick_t tick, tick_old = rt_tick_get();
+ if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
+ {
+ tick = (rqtp->tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND + (rqtp->tv_nsec - _timevalue.tv_usec) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
+ rt_tick_t rt_tick = rt_tick_get();
+ tick = tick < rt_tick ? 0 : tick - rt_tick;
+ }
+ else
+ {
+ tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)(rqtp->tv_nsec) * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
+ }
+ rt_thread_delay(tick);
+ if (rt_get_errno() == -RT_EINTR)
+ {
+ if (rmtp)
+ {
+ tick = tick_old + tick - rt_tick_get();
+ /* get the passed time */
+ rmtp->tv_sec = tick / RT_TICK_PER_SECOND;
+ rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+ }
+ rt_set_errno(EINTR);
+ return -RT_ERROR;
+ }
+ }
+ break;
+
+#ifdef RT_USING_CPUTIME
+ case CLOCK_MONOTONIC:
+ case CLOCK_CPUTIME_ID:
+ {
+ uint64_t cpu_tick, cpu_tick_old;
+ cpu_tick_old = clock_cpu_gettime();
+ rt_tick_t tick;
+ float unit = clock_cpu_getres();
+
+ cpu_tick = (rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec * (NANOSECOND_PER_SECOND / NANOSECOND_PER_SECOND)) / unit;
+ if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
+ cpu_tick = cpu_tick < cpu_tick_old ? 0 : cpu_tick - cpu_tick_old;
+ tick = (unit * cpu_tick) / (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND);
+ rt_thread_delay(tick);
- return nanosleep(rqtp, rmtp);
+ if (rt_get_errno() == -RT_EINTR)
+ {
+ if (rmtp)
+ {
+ uint64_t rmtp_cpu_tick = cpu_tick_old + cpu_tick - clock_cpu_gettime();
+ rmtp->tv_sec = ((int)(rmtp_cpu_tick * unit)) / NANOSECOND_PER_SECOND;
+ rmtp->tv_nsec = ((int)(rmtp_cpu_tick * unit)) % NANOSECOND_PER_SECOND;
+ }
+ rt_set_errno(EINTR);
+ return -RT_ERROR;
+ }
+ else
+ while (clock_cpu_gettime() - cpu_tick_old < cpu_tick);
+ }
+ break;
+#endif
+ default:
+ rt_set_errno(EINVAL);
+ return -RT_ERROR;
+ }
+ return 0;
+#endif
}
+RTM_EXPORT(clock_nanosleep);
int clock_settime(clockid_t clockid, const struct timespec *tp)
{
#ifndef RT_USING_RTC
LOG_W(_WARNING_NO_RTC);
- return -1;
+ return -RT_ERROR;
#else
rt_base_t level;
int second;
@@ -689,7 +807,7 @@ int clock_settime(clockid_t clockid, const struct timespec *tp)
if ((clockid != CLOCK_REALTIME) || (tp == RT_NULL))
{
rt_set_errno(EFAULT);
- return -1;
+ return -RT_ERROR;
}
/* get second */
@@ -713,7 +831,7 @@ int clock_settime(clockid_t clockid, const struct timespec *tp)
}
}
- return -1;
+ return -RT_ERROR;
#endif /* RT_USING_RTC */
}
RTM_EXPORT(clock_settime);
@@ -764,8 +882,13 @@ struct timer_obj
void (*sigev_notify_function)(union sigval val);
union sigval val;
struct timespec interval; /* Reload value */
+ struct timespec value; /* Reload value */
rt_uint32_t reload; /* Reload value in ms */
rt_uint32_t status;
+ int sigev_signo;
+#ifdef RT_USING_LWP
+ pid_t pid;
+#endif
};
static void rtthread_timer_wrapper(void *timerobj)
@@ -779,10 +902,18 @@ static void rtthread_timer_wrapper(void *timerobj)
timer->status = NOT_ACTIVE;
}
+ timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
+ if (timer->reload)
+ rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
+
+#ifdef RT_USING_LWP
+ sys_kill(timer->pid, timer->sigev_signo);
+#else
if(timer->sigev_notify_function != RT_NULL)
{
(timer->sigev_notify_function)(timer->val);
}
+#endif
}
/**
@@ -799,7 +930,7 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
struct timer_obj *timer;
char timername[RT_NAME_MAX] = {0};
- if (clockid != CLOCK_MONOTONIC || evp == NULL ||
+ if (clockid > CLOCK_ID_MAX ||
(evp->sigev_notify != SIGEV_NONE &&
evp->sigev_notify != SIGEV_SIGNAL))
{
@@ -814,9 +945,12 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
return -RT_ENOMEM;
}
- RT_ASSERT(evp->sigev_notify_function != RT_NULL);
rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
num %= 100;
+ timer->sigev_signo = evp->sigev_signo;
+#ifdef RT_USING_LWP
+ timer->pid = lwp_self()->pid;
+#endif
timer->sigev_notify_function = evp->sigev_notify_function;
timer->val = evp->sigev_value;
timer->interval.tv_sec = 0;
@@ -833,7 +967,7 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
}
- *timerid = (timer_t)timer;
+ *timerid = (timer_t)((uintptr_t)timer >> 1);
return RT_EOK;
}
@@ -846,9 +980,9 @@ RTM_EXPORT(timer_create);
*/
int timer_delete(timer_t timerid)
{
- struct timer_obj *timer = (struct timer_obj *)timerid;
+ struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
- if (timer == RT_NULL)
+ if (timer == RT_NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer)
{
rt_set_errno(EINVAL);
return -RT_ERROR;
@@ -859,7 +993,7 @@ int timer_delete(timer_t timerid)
timer->status = NOT_ACTIVE;
rt_timer_stop(&timer->timer);
}
-
+ rt_timer_detach(&timer->timer);
rt_free(timer);
return RT_EOK;
@@ -873,6 +1007,7 @@ RTM_EXPORT(timer_delete);
**/
int timer_getoverrun(timer_t timerid)
{
+ struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
rt_set_errno(ENOSYS);
return -RT_ERROR;
}
@@ -884,11 +1019,11 @@ int timer_getoverrun(timer_t timerid)
*/
int timer_gettime(timer_t timerid, struct itimerspec *its)
{
- struct timer_obj *timer = (struct timer_obj *)timerid;
+ struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
rt_tick_t remaining;
rt_uint32_t seconds, nanoseconds;
- if (timer == NULL)
+ if (timer == NULL || rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer)
{
rt_set_errno(EINVAL);
return -RT_ERROR;
@@ -951,24 +1086,20 @@ RTM_EXPORT(timer_gettime);
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
struct itimerspec *ovalue)
{
- struct timer_obj *timer = (struct timer_obj *)timerid;
-
+ struct timer_obj *timer = (struct timer_obj *)((uintptr_t)timerid << 1);
if (timer == NULL ||
+ rt_object_get_type(&timer->timer.parent) != RT_Object_Class_Timer ||
value->it_interval.tv_nsec < 0 ||
value->it_interval.tv_nsec >= NANOSECOND_PER_SECOND ||
+ value->it_interval.tv_sec < 0 ||
value->it_value.tv_nsec < 0 ||
- value->it_value.tv_nsec >= NANOSECOND_PER_SECOND)
+ value->it_value.tv_nsec >= NANOSECOND_PER_SECOND ||
+ value->it_value.tv_sec < 0)
{
rt_set_errno(EINVAL);
return -RT_ERROR;
}
- if (value == NULL || ovalue == NULL)
- {
- rt_set_errno(EFAULT);
- return -RT_ERROR;
- }
-
/* Save time to expire and old reload value. */
if (ovalue != NULL)
{
@@ -994,9 +1125,25 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
* RT_TICK_PER_SECOND NANOSECOND_PER_SECOND NANOSECOND_PER_SECOND
*
*/
- timer->reload = (value->it_interval.tv_sec * RT_TICK_PER_SECOND) + (value->it_interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND;
+ if (flags & TIMER_ABSTIME == TIMER_ABSTIME)
+ {
+#ifndef RT_USING_RTC
+ LOG_W(_WARNING_NO_RTC);
+ return -RT_ERROR;
+#else
+ rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND);
+ rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
+ rt_int64_t reload = ts + tns;
+ rt_tick_t rt_tick = rt_tick_get();
+ timer->reload = reload < rt_tick ? 0 : reload - rt_tick;
+#endif
+ }
+ else
+ timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND);
timer->interval.tv_sec = value->it_interval.tv_sec;
timer->interval.tv_nsec = value->it_interval.tv_nsec;
+ timer->value.tv_sec = value->it_value.tv_sec;
+ timer->value.tv_nsec = value->it_value.tv_nsec;
if (timer->status == ACTIVE)
{
@@ -1004,8 +1151,13 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
}
timer->status = ACTIVE;
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, (void *)timer->reload);
- rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL);
+
+ if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0))
+ rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL);
+ else
+ rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL);
+
+ rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
rt_timer_start(&timer->timer);
return RT_EOK;
diff --git a/components/libc/compilers/common/include/sys/signal.h b/components/libc/compilers/common/include/sys/signal.h
index 1a3b9c1beb..f2a21baed7 100644
--- a/components/libc/compilers/common/include/sys/signal.h
+++ b/components/libc/compilers/common/include/sys/signal.h
@@ -24,10 +24,10 @@ extern "C" {
#define SIGEV_NONE 1 /* No asynchronous notification shall be delivered */
/* when the event of interest occurs. */
-#define SIGEV_SIGNAL 2 /* A queued signal, with an application defined */
+#define SIGEV_SIGNAL 0 /* A queued signal, with an application defined */
/* value, shall be delivered when the event of */
/* interest occurs. */
-#define SIGEV_THREAD 3 /* A notification function shall be called to */
+#define SIGEV_THREAD 2 /* A notification function shall be called to */
/* perform notification. */
/* Signal Generation and Delivery, P1003.1b-1993, p. 63
@@ -41,9 +41,9 @@ union sigval
struct sigevent
{
- int sigev_notify; /* Notification type */
+ union sigval sigev_value;
int sigev_signo; /* Signal number */
- union sigval sigev_value; /* Signal value */
+ int sigev_notify; /* Notification type */
void (*sigev_notify_function)( union sigval );
/* Notification function */
void *sigev_notify_attributes; /* Notification Attributes, really pthread_attr_t */
diff --git a/components/libc/compilers/common/include/sys/time.h b/components/libc/compilers/common/include/sys/time.h
index e3bf3ee4ef..8a1ae60909 100644
--- a/components/libc/compilers/common/include/sys/time.h
+++ b/components/libc/compilers/common/include/sys/time.h
@@ -99,8 +99,6 @@ time_t time(time_t* t);
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#endif /* RT_USING_POSIX_DELAY */
-#if defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER)
-/* POSIX clock and timer */
#define MILLISECOND_PER_SECOND 1000UL
#define MICROSECOND_PER_SECOND 1000000UL
#define NANOSECOND_PER_SECOND 1000000000UL
@@ -109,6 +107,9 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#define MICROSECOND_PER_TICK (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND)
#define NANOSECOND_PER_TICK (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND)
+#if defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER)
+/* POSIX clock and timer */
+
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 1
#endif /* CLOCK_REALTIME */
@@ -126,6 +127,12 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 4
#endif /* CLOCK_MONOTONIC */
+
+#ifdef CLOCK_TAI
+#define CLOCK_ID_MAX CLOCK_TAI
+#else
+#define CLOCK_ID_MAX CLOCK_MONOTONIC
+#endif
#endif /* defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) */
#ifdef RT_USING_POSIX_CLOCK
@@ -137,7 +144,7 @@ int rt_timespec_to_tick(const struct timespec *time);
#endif /* RT_USING_POSIX_CLOCK */
#ifdef RT_USING_POSIX_TIMER
-#include "signal.h"
+#include <sys/signal.h>
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
int timer_delete(timer_t timerid);
int timer_getoverrun(timer_t timerid);
diff --git a/components/libc/compilers/musl/fcntl.h b/components/libc/compilers/musl/fcntl.h
new file mode 100644
index 0000000000..05d466f848
--- /dev/null
+++ b/components/libc/compilers/musl/fcntl.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-09-02 Meco Man First version
+ */
+
+#ifndef __FCNTL_H__
+#define __FCNTL_H__
+
+#include_next <fcntl.h>
+
+#ifndef O_DIRECTORY
+#define O_DIRECTORY 0x200000
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0x10000
+#endif
+
+#endif
diff --git a/components/libc/posix/io/mman/mman.c b/components/libc/posix/io/mman/mman.c
index de76bdf314..69a86d9bab 100644
--- a/components/libc/posix/io/mman/mman.c
+++ b/components/libc/posix/io/mman/mman.c
@@ -13,6 +13,7 @@
#include <rtthread.h>
#include <unistd.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/errno.h>
diff --git a/components/libc/posix/io/poll/poll.c b/components/libc/posix/io/poll/poll.c
index 5067817449..9fcf0f2063 100644
--- a/components/libc/posix/io/poll/poll.c
+++ b/components/libc/posix/io/poll/poll.c
@@ -89,20 +89,22 @@ static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
if (timeout != 0 && !pt->triggered)
{
- rt_thread_suspend(thread);
- if (timeout > 0)
+ if (rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE) == RT_EOK)
{
- rt_timer_control(&(thread->thread_timer),
- RT_TIMER_CTRL_SET_TIME,
- &timeout);
- rt_timer_start(&(thread->thread_timer));
- }
+ if (timeout > 0)
+ {
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_SET_TIME,
+ &timeout);
+ rt_timer_start(&(thread->thread_timer));
+ }
- rt_hw_interrupt_enable(level);
+ rt_hw_interrupt_enable(level);
- rt_schedule();
+ rt_schedule();
- level = rt_hw_interrupt_disable();
+ level = rt_hw_interrupt_disable();
+ }
}
ret = !pt->triggered;
@@ -126,23 +128,21 @@ static int do_pollfd(struct pollfd *pollfd, rt_pollreq_t *req)
if (f)
{
mask = POLLMASK_DEFAULT;
- if (f->fops->poll)
+ if (f->vnode->fops->poll)
{
req->_key = pollfd->events | POLLERR | POLLHUP;
- mask = f->fops->poll(f, req);
+ mask = f->vnode->fops->poll(f, req);
/* dealwith the device return error -1*/
if (mask < 0)
{
- fd_put(f);
pollfd->revents = 0;
return mask;
}
}
/* Mask out unneeded events. */
mask &= pollfd->events | POLLERR | POLLHUP;
- fd_put(f);
}
}
pollfd->revents = mask;
diff --git a/components/libc/posix/io/stdio/libc.c b/components/libc/posix/io/stdio/libc.c
index 3c4e9d6e0b..4d3ac6dd8a 100644
--- a/components/libc/posix/io/stdio/libc.c
+++ b/components/libc/posix/io/stdio/libc.c
@@ -20,6 +20,8 @@
#define STDIO_DEVICE_NAME_MAX 32
+int sys_dup2(int oldfd, int new);
+
int libc_system_init(void)
{
#ifdef RT_USING_POSIX_STDIO
@@ -28,7 +30,15 @@ int libc_system_init(void)
dev_console = rt_console_get_device();
if (dev_console)
{
- libc_stdio_set_console(dev_console->parent.name, O_RDWR);
+ int fd = libc_stdio_set_console(dev_console->parent.name, O_RDWR);
+ if (fd < 0)
+ {
+ return -1;
+ }
+ /* set fd (0, 1, 2) */
+ sys_dup2(fd, 0);
+ sys_dup2(fd, 1);
+ sys_dup2(fd, 2);
}
#endif /* RT_USING_POSIX_STDIO */
return 0;
@@ -112,7 +122,6 @@ int libc_stdio_get_console(void)
#elif defined(RT_USING_POSIX_STDIO) && defined(RT_USING_MUSLLIBC)
static FILE* std_console = NULL;
-int sys_dup2(int oldfd, int new);
int libc_stdio_set_console(const char* device_name, int mode)
{
@@ -144,10 +153,6 @@ int libc_stdio_set_console(const char* device_name, int mode)
{
int fd = fileno(std_console);
- // /* set fd (0, 1, 2) */
- // sys_dup2(fd, 0);
- // sys_dup2(fd, 1);
- // sys_dup2(fd, 2);
return fd;
}
diff --git a/components/libc/posix/io/termios/termios.h b/components/libc/posix/io/termios/termios.h
index 8553b01918..8f0275d118 100644
--- a/components/libc/posix/io/termios/termios.h
+++ b/components/libc/posix/io/termios/termios.h
@@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2017/08/30 Bernard The first version
+ * 2021/12/10 linzhenxing put tty system
*/
#ifndef __TERMIOS_H__
@@ -35,6 +36,7 @@ struct termios {
speed_t __c_ospeed;
};
+/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#define VERASE 2
@@ -53,6 +55,7 @@ struct termios {
#define VLNEXT 15
#define VEOL2 16
+/* c_iflag bits */
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
@@ -69,37 +72,42 @@ struct termios {
#define IMAXBEL 0020000
#define IUTF8 0040000
+/* c_oflag bits */
#define OPOST 0000001
-#define OLCUC 0000002
-#define ONLCR 0000004
+#define ONLCR 0000002
+#define OLCUC 0000004
+
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
-#define OFILL 0000100
-#define OFDEL 0000200
-#define NLDLY 0000400
-#define NL0 0000000
-#define NL1 0000400
-#define CRDLY 0003000
-#define CR0 0000000
-#define CR1 0001000
-#define CR2 0002000
-#define CR3 0003000
-#define TABDLY 0014000
-#define TAB0 0000000
-#define TAB1 0004000
-#define TAB2 0010000
-#define TAB3 0014000
-#define BSDLY 0020000
-#define BS0 0000000
-#define BS1 0020000
-#define FFDLY 0100000
-#define FF0 0000000
-#define FF1 0100000
-#define VTDLY 0040000
-#define VT0 0000000
-#define VT1 0040000
+#define OFILL 00000100
+#define OFDEL 00000200
+#define NLDLY 00001400
+#define NL0 00000000
+#define NL1 00000400
+#define NL2 00001000
+#define NL3 00001400
+#define TABDLY 00006000
+#define TAB0 00000000
+#define TAB1 00002000
+#define TAB2 00004000
+#define TAB3 00006000
+#define CRDLY 00030000
+#define KCR0 00000000
+#define KCR1 00010000
+#define KCR2 00020000
+#define KCR3 00030000
+#define FFDLY 00040000
+#define FF0 00000000
+#define FF1 00040000
+#define BSDLY 00100000
+#define BS0 00000000
+#define BS1 00100000
+#define VTDLY 00200000
+#define VT0 00000000
+#define VT1 00200000
+#define XTABS 01000000
#define B0 0000000
#define B50 0000001
@@ -146,15 +154,23 @@ struct termios {
#define HUPCL 0002000
#define CLOCAL 0004000
-#define ISIG 0000001
-#define ICANON 0000002
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define IEXTEN 0100000
+/* c_lflag bits */
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+#define EXTPROC 0200000
#define TCOOFF 0
#define TCOON 1
@@ -185,7 +201,13 @@ struct termios {
#define PENDIN 0040000
#define EXTPROC 0200000
-#define XTABS 0014000
+/* intr=^C quit=^| erase=del kill=^U
+ eof=^D vtime=\0 vmin=\1 sxtc=\0
+ start=^Q stop=^S susp=^Z eol=\0
+ reprint=^R discard=^U werase=^W lnext=^V
+ eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
speed_t cfgetospeed (const struct termios *);
speed_t cfgetispeed (const struct termios *);
diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig
index 5ea3017479..c4178c8274 100644
--- a/components/lwp/Kconfig
+++ b/components/lwp/Kconfig
@@ -1,8 +1,75 @@
-config RT_USING_LWP
- bool "LWP: light-weight process"
- select RT_USING_POSIX_FS
- select RT_USING_POSIX_SELECT
- depends on ARCH_ARM_CORTEX_M || ARCH_ARM_ARM9 || ARCH_ARM_CORTEX_A
+menuconfig RT_USING_LWP
+ bool "light-weight process"
+ select RT_USING_DFS
+ select RT_USING_LIBC
+ select RT_USING_POSIX_CLOCKTIME
+ select RT_USING_TTY
+ select RT_USING_NULL
+ select RT_USING_ZERO
+ select RT_USING_RANDOM
+ select RT_USING_RTC
+ depends on ARCH_ARM_CORTEX_M || ARCH_ARM_ARM9 || ARCH_ARM_CORTEX_A || ARCH_RISCV64
default n
help
The lwP is a light weight process running in user mode.
+
+if RT_USING_LWP
+ config RT_LWP_MAX_NR
+ int "The max number of light-weight process"
+ default 30
+
+ config LWP_TASK_STACK_SIZE
+ int "The lwp thread kernel stack size"
+ default 16384
+
+ config RT_CH_MSG_MAX_NR
+ int "The maximum number of channel messages"
+ default 1024
+
+ config LWP_CONSOLE_INPUT_BUFFER_SIZE
+ int "The input buffer size of lwp console device"
+ default 1024
+
+ config LWP_TID_MAX_NR
+ int "The maximum number of lwp thread id"
+ default 64
+
+ config LWP_ENABLE_ASID
+ bool "The switch of ASID feature"
+ depends on ARCH_ARM_CORTEX_A
+ default y
+
+ if ARCH_MM_MMU
+ config RT_LWP_SHM_MAX_NR
+ int "The maximum number of shared memory"
+ default 64
+ endif
+
+ if ARCH_MM_MPU
+ config RT_LWP_MPU_MAX_NR
+ int "The maximum number of mpu region"
+ default 2
+
+ config RT_LWP_USING_SHM
+ bool "Enable shared memory"
+ default y
+ endif
+
+ config LWP_UNIX98_PTY
+ bool "The unix98 PTY support"
+ default n
+
+ if LWP_UNIX98_PTY
+ config LWP_PTY_INPUT_BFSZ
+ int "The unix98 PTY input buffer size"
+ default 1024
+
+ config LWP_PTY_PTS_SIZE
+ int "The unix98 PTY device max num"
+ default 3
+
+ config LWP_PTY_USING_DEBUG
+ bool "The unix98 PTY debug output"
+ default n
+ endif
+endif
diff --git a/components/lwp/SConscript b/components/lwp/SConscript
index 98a7cf368a..0b44b08eb3 100644
--- a/components/lwp/SConscript
+++ b/components/lwp/SConscript
@@ -1,19 +1,44 @@
Import('rtconfig')
from building import *
+import os
cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]
-support_arch = {"arm": ["cortex-m3", "cortex-m4", "cortex-m7", "arm926", "cortex-a"]}
-platform_file = {'armcc': 'rvds.S', 'gcc': 'gcc.S', 'iccarm': 'iar.S'}
+support_arch = {"arm": ["cortex-m3", "cortex-m4", "cortex-m7", "arm926", "cortex-a"],
+ "aarch64":["cortex-a"],
+ "risc-v": ["rv64"],
+ "x86": ["i386"]}
+platform_file = {'armcc': 'rvds.S', 'gcc': 'gcc.S', 'iar': 'iar.S'}
-if rtconfig.PLATFORM in platform_file.keys(): # support platforms
- if rtconfig.ARCH in support_arch.keys() and rtconfig.CPU in support_arch[rtconfig.ARCH]:
- # arch/arm/cortex-m7/lwp_gcc.S
- asm_path = 'arch/' + rtconfig.ARCH + '/' + rtconfig.CPU + '/*_' + platform_file[rtconfig.PLATFORM]
- src = Glob('*.c') + Glob(asm_path)
+platform = rtconfig.PLATFORM
+arch = rtconfig.ARCH
+cpu = rtconfig.CPU
+
+# fix the cpu for risc-v
+if arch == 'risc-v':
+ rv64 = ['virt64', 'c906']
+ if cpu in rv64:
+ cpu = 'rv64'
+
+if GetDepend('LWP_UNIX98_PTY'):
+ # print("LWP_UNIX98_PTY")
+ src += Glob('unix98pty/*.c')
+ CPPPATH += ['unix98pty/']
+
+if platform in platform_file.keys(): # support platforms
+ if arch in support_arch.keys() and cpu in support_arch[arch]:
+ asm_path = 'arch/' + arch + '/' + cpu + '/*_' + platform_file[platform]
+ arch_common = 'arch/' + arch + '/' + 'common/*.c'
+ if not GetDepend('ARCH_MM_MMU'):
+ excluded_files = ['ioremap.c', 'lwp_futex.c', 'lwp_mm_area.c', 'lwp_pmutex.c', 'lwp_shm.c', 'lwp_user_mm.c']
+ src += [f for f in Glob('*.c') if os.path.basename(str(f)) not in excluded_files] + Glob(asm_path) + Glob(arch_common)
+ else:
+ src += Glob('*.c') + Glob(asm_path) + Glob(arch_common)
+ src += Glob('arch/' + arch + '/' + cpu + '/*.c')
CPPPATH = [cwd]
+ CPPPATH += [cwd + '/arch/' + arch + '/' + cpu]
group = DefineGroup('lwP', src, depend = ['RT_USING_LWP'], CPPPATH = CPPPATH)
diff --git a/components/lwp/arch/aarch64/common/reloc.c b/components/lwp/arch/aarch64/common/reloc.c
new file mode 100644
index 0000000000..4057a5718b
--- /dev/null
+++ b/components/lwp/arch/aarch64/common/reloc.c
@@ -0,0 +1,28 @@
+#include <rtthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <elf.h>
+#ifdef RT_USING_USERSPACE
+#include <mmu.h>
+#include <page.h>
+#endif
+
+#define Elf_Word Elf64_Word
+#define Elf_Addr Elf64_Addr
+#define Elf_Half Elf64_Half
+#define Elf_Ehdr Elf64_Ehdr #define Elf_Phdr Elf64_Phdr
+#define Elf_Shdr Elf64_Shdr
+
+typedef struct
+{
+ Elf_Word st_name;
+ Elf_Addr st_value;
+ Elf_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf_Half st_shndx;
+} Elf_sym;
+
+void arch_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf_sym *dynsym)
+{
+}
diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_arch.c b/components/lwp/arch/aarch64/cortex-a/lwp_arch.c
new file mode 100644
index 0000000000..c5f4cebdb9
--- /dev/null
+++ b/components/lwp/arch/aarch64/cortex-a/lwp_arch.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Jesven first version
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+
+extern size_t MMUTable[];
+
+int arch_user_space_init(struct rt_lwp *lwp)
+{
+ size_t *mmu_table;
+
+ mmu_table = (size_t*)rt_pages_alloc(0);
+ if (!mmu_table)
+ {
+ return -1;
+ }
+
+ lwp->end_heap = USER_HEAP_VADDR;
+ memset(mmu_table, 0, ARCH_PAGE_SIZE);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE);
+ rt_hw_mmu_map_init(&lwp->mmu_info, (void*)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table, PV_OFFSET);
+
+ return 0;
+}
+
+void *arch_kernel_mmu_table_get(void)
+{
+ return (void*)NULL;
+}
+
+void arch_kuser_init(rt_mmu_info *mmu_info, void *vectors)
+{
+}
+
+void arch_user_space_vtable_free(struct rt_lwp *lwp)
+{
+ if (lwp && lwp->mmu_info.vtable)
+ {
+ rt_pages_free(lwp->mmu_info.vtable, 0);
+ }
+}
+
+int arch_expand_user_stack(void *addr)
+{
+ int ret = 0;
+ size_t stack_addr = (size_t)addr;
+
+ stack_addr &= ~ARCH_PAGE_MASK;
+ if ((stack_addr >= (size_t)USER_STACK_VSTART) && (stack_addr < (size_t)USER_STACK_VEND))
+ {
+ void *map = lwp_map_user(lwp_self(), (void*)stack_addr, ARCH_PAGE_SIZE, 0);
+
+ if (map || lwp_user_accessable(addr, 1))
+ {
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+#endif
diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_arch.h b/components/lwp/arch/aarch64/cortex-a/lwp_arch.h
new file mode 100644
index 0000000000..98dcd989b1
--- /dev/null
+++ b/components/lwp/arch/aarch64/cortex-a/lwp_arch.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Jesven first version
+ */
+
+#ifndef LWP_ARCH_H__
+#define LWP_ARCH_H__
+
+#include <lwp.h>
+#include <lwp_arch_comm.h>
+
+#ifdef RT_USING_USERSPACE
+
+#define USER_VADDR_TOP 0x0001000000000000UL
+#define USER_HEAP_VEND 0x0000ffffB0000000UL
+#define USER_HEAP_VADDR 0x0000ffff80000000UL
+#define USER_STACK_VSTART 0x0000ffff70000000UL
+#define USER_STACK_VEND USER_HEAP_VADDR
+#define LDSO_LOAD_VADDR 0x60000000UL
+#define USER_VADDR_START 0x00200000UL
+#define USER_LOAD_VADDR USER_VADDR_START
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned long rt_hw_ffz(unsigned long x);
+
+rt_inline void icache_invalid_all(void)
+{
+ asm volatile ("ic ialluis\n\tisb sy":::"memory");
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /*LWP_ARCH_H__*/
diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S b/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S
new file mode 100644
index 0000000000..c873cd5357
--- /dev/null
+++ b/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Jesven first version
+ */
+
+#include "rtconfig.h"
+
+#include "asm-fpu.h"
+
+/*********************
+ * SPSR BIT *
+ *********************/
+
+#define SPSR_Mode(v) ((v) << 0)
+#define SPSR_A64 (0 << 4)
+#define SPSR_RESEVRED_5 (0 << 5)
+#define SPSR_FIQ_MASKED(v) ((v) << 6)
+#define SPSR_IRQ_MASKED(v) ((v) << 7)
+#define SPSR_SERROR_MASKED(v) ((v) << 8)
+#define SPSR_D_MASKED(v) ((v) << 9)
+#define SPSR_RESEVRED_10_19 (0 << 10)
+#define SPSR_IL(v) ((v) << 20)
+#define SPSR_SS(v) ((v) << 21)
+#define SPSR_RESEVRED_22_27 (0 << 22)
+#define SPSR_V(v) ((v) << 28)
+#define SPSR_C(v) ((v) << 29)
+#define SPSR_Z(v) ((v) << 30)
+#define SPSR_N(v) ((v) << 31)
+
+/*********************
+ * CONTEXT_OFFSET *
+ *********************/
+
+#define CONTEXT_OFFSET_ELR_EL1 0x0
+#define CONTEXT_OFFSET_SPSR_EL1 0x8
+#define CONTEXT_OFFSET_SP_EL0 0x10
+#define CONTEXT_OFFSET_X30 0x18
+#define CONTEXT_OFFSET_FPCR 0x20
+#define CONTEXT_OFFSET_FPSR 0x28
+#define CONTEXT_OFFSET_X28 0x30
+#define CONTEXT_OFFSET_X29 0x38
+#define CONTEXT_OFFSET_X26 0x40
+#define CONTEXT_OFFSET_X27 0x48
+#define CONTEXT_OFFSET_X24 0x50
+#define CONTEXT_OFFSET_X25 0x58
+#define CONTEXT_OFFSET_X22 0x60
+#define CONTEXT_OFFSET_X23 0x68
+#define CONTEXT_OFFSET_X20 0x70
+#define CONTEXT_OFFSET_X21 0x78
+#define CONTEXT_OFFSET_X18 0x80
+#define CONTEXT_OFFSET_X19 0x88
+#define CONTEXT_OFFSET_X16 0x90
+#define CONTEXT_OFFSET_X17 0x98
+#define CONTEXT_OFFSET_X14 0xa0
+#define CONTEXT_OFFSET_X15 0xa8
+#define CONTEXT_OFFSET_X12 0xb0
+#define CONTEXT_OFFSET_X13 0xb8
+#define CONTEXT_OFFSET_X10 0xc0
+#define CONTEXT_OFFSET_X11 0xc8
+#define CONTEXT_OFFSET_X8 0xd0
+#define CONTEXT_OFFSET_X9 0xd8
+#define CONTEXT_OFFSET_X6 0xe0
+#define CONTEXT_OFFSET_X7 0xe8
+#define CONTEXT_OFFSET_X4 0xf0
+#define CONTEXT_OFFSET_X5 0xf8
+#define CONTEXT_OFFSET_X2 0x100
+#define CONTEXT_OFFSET_X3 0x108
+#define CONTEXT_OFFSET_X0 0x110
+#define CONTEXT_OFFSET_X1 0x118
+
+#define CONTEXT_OFFSET_Q15 0x120
+#define CONTEXT_OFFSET_Q14 0x130
+#define CONTEXT_OFFSET_Q13 0x140
+#define CONTEXT_OFFSET_Q12 0x150
+#define CONTEXT_OFFSET_Q11 0x160
+#define CONTEXT_OFFSET_Q10 0x170
+#define CONTEXT_OFFSET_Q9 0x180
+#define CONTEXT_OFFSET_Q8 0x190
+#define CONTEXT_OFFSET_Q7 0x1a0
+#define CONTEXT_OFFSET_Q6 0x1b0
+#define CONTEXT_OFFSET_Q5 0x1c0
+#define CONTEXT_OFFSET_Q4 0x1d0
+#define CONTEXT_OFFSET_Q3 0x1e0
+#define CONTEXT_OFFSET_Q2 0x1f0
+#define CONTEXT_OFFSET_Q1 0x200
+#define CONTEXT_OFFSET_Q0 0x210
+
+#define CONTEXT_FPU_SIZE 0x100
+#define CONTEXT_SIZE 0x220
+
+/**************************************************/
+
+.text
+
+/*
+ * void arch_start_umode(args, text, ustack, kstack);
+ */
+.global arch_start_umode
+.type arch_start_umode, % function
+arch_start_umode:
+ mov sp, x3
+ mov x4, #(SPSR_Mode(0) | SPSR_A64)
+ mov x3, x2 ;/* user stack top */
+ msr daifset, #3
+ dsb sy
+ mrs x30, sp_el0
+ msr spsr_el1, x4
+ msr elr_el1, x1
+ eret
+
+/*
+ * void arch_crt_start_umode(args, text, ustack, kstack);
+ */
+.global arch_crt_start_umode
+.type arch_crt_start_umode, % function
+arch_crt_start_umode:
+ sub x4, x2, #0x10
+ adr x2, lwp_thread_return
+ ldr x5, [x2]
+ str x5, [x4]
+ ldr x5, [x2, #4]
+ str x5, [x4, #4]
+ ldr x5, [x2, #8]
+ str x5, [x4, #8]
+
+ mov x5, x4
+ dc cvau, x5
+ add x5, x5, #8
+ dc cvau, x5
+ dsb sy
+ ic ialluis
+ dsb sy
+
+ msr sp_el0, x4
+
+ mov sp, x3
+ mov x4, #(SPSR_Mode(0) | SPSR_A64)
+ msr daifset, #3
+ dsb sy
+ mrs x30, sp_el0
+ msr spsr_el1, x4
+ msr elr_el1, x1
+ eret
+
+/*
+void arch_set_thread_context(void *exit_addr, void *new_thread_stack, void *user_stack, void **thread_sp);
+*/
+.global arch_set_thread_context
+arch_set_thread_context:
+ sub x1, x1, #CONTEXT_SIZE
+ str x2, [x1, #CONTEXT_OFFSET_SP_EL0]
+ sub x1, x1, #CONTEXT_SIZE
+ str xzr, [x1, #CONTEXT_OFFSET_X0] /* new thread return 0 */
+ mov x4, #((3 << 6) | 0x4 | 0x1) /* el1h, disable interrupt */
+ str x4, [x1, #CONTEXT_OFFSET_SPSR_EL1]
+ str x0, [x1, #CONTEXT_OFFSET_ELR_EL1]
+ str x1, [x3]
+ ret
+
+.global arch_get_user_sp
+arch_get_user_sp:
+ mrs x0, sp_el0
+ ret
+
+.global arch_fork_exit
+.global arch_clone_exit
+arch_fork_exit:
+arch_clone_exit:
+ b arch_syscall_exit
+
+/*
+void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
+*/
+.global lwp_exec_user
+lwp_exec_user:
+ mov sp, x1
+ mov x4, #(SPSR_Mode(0) | SPSR_A64)
+ ldr x3, =0x0000ffff80000000
+ msr daifset, #3
+ msr spsr_el1, x4
+ msr elr_el1, x2
+ eret
+
+/*
+ * void SVC_Handler(regs);
+ */
+.global SVC_Handler
+.type SVC_Handler, % function
+SVC_Handler:
+ /* x0 is initial sp */
+ mov sp, x0
+
+ msr daifclr, #3 /* enable interrupt */
+
+ bl rt_thread_self
+ bl lwp_user_setting_save
+
+ ldp x8, x9, [sp, #(CONTEXT_OFFSET_X8)]
+ and x0, x8, #0xf000
+ cmp x0, #0xe000
+ beq arch_signal_quit
+
+ cmp x0, #0xf000
+ beq ret_from_user
+
+ uxtb x0, w8
+ bl lwp_get_sys_api
+ cmp x0, xzr
+ mov x30, x0
+ beq arch_syscall_exit
+ ldp x0, x1, [sp, #(CONTEXT_OFFSET_X0)]
+ ldp x2, x3, [sp, #(CONTEXT_OFFSET_X2)]
+ ldp x4, x5, [sp, #(CONTEXT_OFFSET_X4)]
+ ldp x6, x7, [sp, #(CONTEXT_OFFSET_X6)]
+ blr x30
+ /* jump explictly, make this code position independant */
+ b arch_syscall_exit
+
+.global arch_syscall_exit
+arch_syscall_exit:
+ msr daifset, #3
+
+ ldp x2, x3, [sp], #0x10 /* SPSR and ELR. */
+ msr spsr_el1, x3
+ msr elr_el1, x2
+
+ ldp x29, x30, [sp], #0x10
+ msr sp_el0, x29
+ ldp x28, x29, [sp], #0x10
+ msr fpcr, x28
+ msr fpsr, x29
+ ldp x28, x29, [sp], #0x10
+ ldp x26, x27, [sp], #0x10
+ ldp x24, x25, [sp], #0x10
+ ldp x22, x23, [sp], #0x10
+ ldp x20, x21, [sp], #0x10
+ ldp x18, x19, [sp], #0x10
+ ldp x16, x17, [sp], #0x10
+ ldp x14, x15, [sp], #0x10
+ ldp x12, x13, [sp], #0x10
+ ldp x10, x11, [sp], #0x10
+ ldp x8, x9, [sp], #0x10
+ add sp, sp, #0x40
+ RESTORE_FPU sp
+
+.global arch_ret_to_user
+arch_ret_to_user:
+ SAVE_FPU sp
+ stp x0, x1, [sp, #-0x10]!
+ stp x2, x3, [sp, #-0x10]!
+ stp x4, x5, [sp, #-0x10]!
+ stp x6, x7, [sp, #-0x10]!
+ stp x8, x9, [sp, #-0x10]!
+ stp x10, x11, [sp, #-0x10]!
+ stp x12, x13, [sp, #-0x10]!
+ stp x14, x15, [sp, #-0x10]!
+ stp x16, x17, [sp, #-0x10]!
+ stp x18, x19, [sp, #-0x10]!
+ stp x20, x21, [sp, #-0x10]!
+ stp x22, x23, [sp, #-0x10]!
+ stp x24, x25, [sp, #-0x10]!
+ stp x26, x27, [sp, #-0x10]!
+ stp x28, x29, [sp, #-0x10]!
+
+ mrs x0, fpcr
+ mrs x1, fpsr
+ stp x0, x1, [sp, #-0x10]!
+ stp x29, x30, [sp, #-0x10]!
+
+ bl lwp_check_debug
+ bl lwp_check_exit_request
+ cbz w0, 1f
+ mov x0, xzr
+ b sys_exit
+1:
+ ldr x0, =rt_dbg_ops
+ ldr x0, [x0]
+ cbz x0, 3f
+ bl dbg_thread_in_debug
+ mov x1, #(1 << 21)
+ mrs x2, spsr_el1
+ cbz w0, 2f
+ orr x2, x2, x1
+ msr spsr_el1, x2
+ b 3f
+2:
+ bic x2, x2, x1
+ msr spsr_el1, x2
+3:
+ bl lwp_signal_check
+ cmp x0, xzr
+
+ ldp x29, x30, [sp], #0x10
+ ldp x0, x1, [sp], #0x10
+ msr fpcr, x0
+ msr fpsr, x1
+
+ ldp x28, x29, [sp], #0x10
+ ldp x26, x27, [sp], #0x10
+ ldp x24, x25, [sp], #0x10
+ ldp x22, x23, [sp], #0x10
+ ldp x20, x21, [sp], #0x10
+ ldp x18, x19, [sp], #0x10
+ ldp x16, x17, [sp], #0x10
+ ldp x14, x15, [sp], #0x10
+ ldp x12, x13, [sp], #0x10
+ ldp x10, x11, [sp], #0x10
+ ldp x8, x9, [sp], #0x10
+ ldp x6, x7, [sp], #0x10
+ ldp x4, x5, [sp], #0x10
+ ldp x2, x3, [sp], #0x10
+ ldp x0, x1, [sp], #0x10
+ RESTORE_FPU sp
+
+ bne user_do_signal
+
+ stp x0, x1, [sp, #-0x10]!
+ ldr x0, =rt_dbg_ops
+ ldr x0, [x0]
+ cmp x0, xzr
+ ldp x0, x1, [sp], #0x10
+ beq 1f
+ SAVE_FPU sp
+ stp x0, x1, [sp, #-0x10]!
+ stp x2, x3, [sp, #-0x10]!
+ stp x4, x5, [sp, #-0x10]!
+ stp x6, x7, [sp, #-0x10]!
+ stp x8, x9, [sp, #-0x10]!
+ stp x10, x11, [sp, #-0x10]!
+ stp x12, x13, [sp, #-0x10]!
+ stp x14, x15, [sp, #-0x10]!
+ stp x16, x17, [sp, #-0x10]!
+ stp x18, x19, [sp, #-0x10]!
+ stp x20, x21, [sp, #-0x10]!
+ stp x22, x23, [sp, #-0x10]!
+ stp x24, x25, [sp, #-0x10]!
+ stp x26, x27, [sp, #-0x10]!
+ stp x28, x29, [sp, #-0x10]!
+ mrs x0, fpcr
+ mrs x1, fpsr
+ stp x0, x1, [sp, #-0x10]!
+ stp x29, x30, [sp, #-0x10]!
+ mrs x0, elr_el1
+ bl dbg_attach_req
+ ldp x29, x30, [sp], #0x10
+ ldp x0, x1, [sp], #0x10
+ msr fpcr, x0
+ msr fpsr, x1
+ ldp x28, x29, [sp], #0x10
+ ldp x26, x27, [sp], #0x10
+ ldp x24, x25, [sp], #0x10
+ ldp x22, x23, [sp], #0x10
+ ldp x20, x21, [sp], #0x10
+ ldp x18, x19, [sp], #0x10
+ ldp x16, x17, [sp], #0x10
+ ldp x14, x15, [sp], #0x10
+ ldp x12, x13, [sp], #0x10
+ ldp x10, x11, [sp], #0x10
+ ldp x8, x9, [sp], #0x10
+ ldp x6, x7, [sp], #0x10
+ ldp x4, x5, [sp], #0x10
+ ldp x2, x3, [sp], #0x10
+ ldp x0, x1, [sp], #0x10
+ RESTORE_FPU sp
+1:
+ eret
+
+/*
+struct rt_hw_exp_stack
+{
+ unsigned long pc; 0
+ unsigned long cpsr;
+ unsigned long sp_el0; 0x10
+ unsigned long x30;
+ unsigned long fpcr; 0x20
+ unsigned long fpsr;
+ unsigned long x28; 0x30
+ unsigned long x29;
+ unsigned long x26; 0x40
+ unsigned long x27;
+ unsigned long x24; 0x50
+ unsigned long x25;
+ unsigned long x22; 0x60
+ unsigned long x23;
+ unsigned long x20; 0x70
+ unsigned long x21;
+ unsigned long x18; 0x80
+ unsigned long x19;
+ unsigned long x16; 0x90
+ unsigned long x17;
+ unsigned long x14; 0xa0
+ unsigned long x15;
+ unsigned long x12; 0xb0
+ unsigned long x13;
+ unsigned long x10; 0xc0
+ unsigned long x11;
+ unsigned long x8; 0xd0
+ unsigned long x9;
+ unsigned long x6; 0xe0
+ unsigned long x7;
+ unsigned long x4; 0xf0
+ unsigned long x5;
+ unsigned long x2; 0x100
+ unsigned long x3;
+ unsigned long x0; 0x110
+ unsigned long x1;
+
+ unsigned long long fpu[16]; 0x120
+ 0x220 = 0x120 + 0x10 * 0x10
+};
+*/
+.global lwp_check_debug
+lwp_check_debug:
+ ldr x0, =rt_dbg_ops
+ ldr x0, [x0]
+ cbnz x0, 1f
+ ret
+1:
+ stp x29, x30, [sp, #-0x10]!
+ bl dbg_check_suspend
+ cbz w0, lwp_check_debug_quit
+
+ mrs x2, sp_el0
+ sub x2, x2, #0x10
+ mov x3, x2
+ msr sp_el0, x2
+ ldr x0, =lwp_debugreturn
+ ldr w1, [x0]
+ str w1, [x2]
+ ldr w1, [x0, #4]
+ str w1, [x2, #4]
+
+ dc cvau, x2
+ add x2, x2, #4
+ dc cvau, x2
+
+ dsb sy
+ isb sy
+
+ ic ialluis
+ isb sy
+
+ mrs x0, elr_el1
+ mrs x1, spsr_el1
+ stp x0, x1, [sp, #-0x10]!
+ msr elr_el1, x3 /* lwp_debugreturn */
+ mov x1, #(SPSR_Mode(0) | SPSR_A64)
+ orr x1, x1, #(1 << 21)
+ msr spsr_el1, x1
+ eret
+ret_from_user:
+ /* sp_el0 += 16 for drop ins lwp_debugreturn */
+ mrs x0, sp_el0
+ add x0, x0, #0x10
+ msr sp_el0, x0
+ /* now is el1, sp is pos(empty) - sizeof(context) */
+ mov x0, sp
+ add x0, x0, #0x220
+ mov sp, x0
+ ldp x0, x1, [sp], #0x10 /* x1 is origin spsr_el1 */
+ msr elr_el1, x0 /* x0 is origin elr_el1 */
+ msr spsr_el1, x1
+lwp_check_debug_quit:
+ ldp x29, x30, [sp], #0x10
+ ret
+
+arch_signal_quit:
+ msr daifset, #3
+/*
+ drop stack data
+*/
+ add sp, sp, #CONTEXT_SIZE
+ bl lwp_signal_restore
+ /* x0 is user_ctx : ori sp, pc, cpsr */
+ ldr x1, [x0]
+ ldr x2, [x0, #8]
+ ldr x3, [x0, #16]
+ msr spsr_el1, x3
+ msr elr_el1, x2
+ add x1, x1, #16
+ msr sp_el0, x1
+
+ msr spsel, #0
+
+ ldp x29, x30, [sp], #0x10
+ ldp x28, x29, [sp], #0x10
+ msr fpcr, x28
+ msr fpsr, x29
+ ldp x28, x29, [sp], #0x10
+ ldp x26, x27, [sp], #0x10
+ ldp x24, x25, [sp], #0x10
+ ldp x22, x23, [sp], #0x10
+ ldp x20, x21, [sp], #0x10
+ ldp x18, x19, [sp], #0x10
+ ldp x16, x17, [sp], #0x10
+ ldp x14, x15, [sp], #0x10
+ ldp x12, x13, [sp], #0x10
+ ldp x10, x11, [sp], #0x10
+ ldp x8, x9, [sp], #0x10
+ ldp x6, x7, [sp], #0x10
+ ldp x4, x5, [sp], #0x10
+ ldp x2, x3, [sp], #0x10
+ ldp x0, x1, [sp], #0x10
+ RESTORE_FPU sp
+
+ msr spsel, #1
+
+ b arch_ret_to_user
+
+user_do_signal:
+ msr spsel, #0
+ SAVE_FPU sp
+ stp x0, x1, [sp, #-0x10]!
+ stp x2, x3, [sp, #-0x10]!
+ stp x4, x5, [sp, #-0x10]!
+ stp x6, x7, [sp, #-0x10]!
+ stp x8, x9, [sp, #-0x10]!
+ stp x10, x11, [sp, #-0x10]!
+ stp x12, x13, [sp, #-0x10]!
+ stp x14, x15, [sp, #-0x10]!
+ stp x16, x17, [sp, #-0x10]!
+ stp x18, x19, [sp, #-0x10]!
+ stp x20, x21, [sp, #-0x10]!
+ stp x22, x23, [sp, #-0x10]!
+ stp x24, x25, [sp, #-0x10]!
+ stp x26, x27, [sp, #-0x10]!
+ stp x28, x29, [sp, #-0x10]!
+ mrs x28, fpcr
+ mrs x29, fpsr
+ stp x28, x29, [sp, #-0x10]!
+ stp x29, x30, [sp, #-0x10]!
+
+ sub sp, sp, #0x10
+ adr x0, lwp_sigreturn
+ ldr w1, [x0]
+ str w1, [sp]
+ ldr w1, [x0, #4]
+ str w1, [sp, #4]
+
+ mov x20, sp /* lwp_sigreturn */
+ mov x0, sp
+
+ dc cvau, x0
+ dsb sy
+ ic ialluis
+ dsb sy
+
+ msr spsel, #1
+
+ mrs x1, elr_el1
+ mrs x2, spsr_el1
+ bl lwp_signal_backup
+ /* x0 is signal */
+ mov x19, x0
+ bl lwp_sighandler_get
+ adds x1, x0, xzr
+ mov x0, x19
+ bne 1f
+ mov x1, x20
+1:
+ msr elr_el1, x1
+ mov x30, x20
+ eret
+
+lwp_debugreturn:
+ mov x8, 0xf000
+ svc #0
+
+lwp_sigreturn:
+ mov x8, #0xe000
+ svc #0
+
+lwp_thread_return:
+ mov x0, xzr
+ mov x8, #0x01
+ svc #0
+
+.globl arch_get_tidr
+arch_get_tidr:
+ mrs x0, tpidr_el0
+ ret
+
+.global arch_set_thread_area
+arch_set_thread_area:
+.globl arch_set_tidr
+arch_set_tidr:
+ msr tpidr_el0, x0
+ ret
diff --git a/components/lwp/arch/arm/arm926/lwp_gcc.S b/components/lwp/arch/arm/arm926/lwp_gcc.S
deleted file mode 100644
index 2a8ce492eb..0000000000
--- a/components/lwp/arch/arm/arm926/lwp_gcc.S
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-12-10 Jesven first version
- */
-
-#define Mode_USR 0x10
-#define Mode_FIQ 0x11
-#define Mode_IRQ 0x12
-#define Mode_SVC 0x13
-#define Mode_MON 0x16
-#define Mode_ABT 0x17
-#define Mode_UDF 0x1B
-#define Mode_SYS 0x1F
-
-#define A_Bit 0x100
-#define I_Bit 0x80 @; when I bit is set, IRQ is disabled
-#define F_Bit 0x40 @; when F bit is set, FIQ is disabled
-#define T_Bit 0x20
-
-.cpu arm9
-.syntax unified
-.text
-
-/*
- * void lwp_user_entry(args, text, data);
- */
-.global lwp_user_entry
-.type lwp_user_entry, % function
-lwp_user_entry:
- mrs r9, cpsr
- mov r8, r9
- bic r9, #0x1f
- orr r9, #Mode_USR
-
- orr r8, #I_Bit
- msr cpsr_c, r8
-
- msr spsr, r9
-
- /* set data address. */
- mov r9, r2
- movs pc, r1
-
-/*
- * void SVC_Handler(void);
- */
-.global SVC_Handler
-.type SVC_Handler, % function
-SVC_Handler:
- push {lr}
- mrs lr, spsr
- push {r4, r5, lr}
-
- mrs r4, cpsr
- bic r4, #I_Bit
- msr cpsr_c, r4
-
- push {r0 - r3, r12}
- and r0, r7, #0xff
- bl lwp_get_sys_api
- cmp r0, #0 /* r0 = api */
- mov r4, r0
- pop {r0 - r3, r12}
- beq svc_exit
- ldr lr, = svc_exit
- bx r4
-
-svc_exit:
- mrs r4, cpsr
- orr r4, #I_Bit
- msr cpsr_c, r4
-
- pop {r4, r5, lr}
- msr spsr_cxsf, lr
- pop {lr}
- movs pc, lr
diff --git a/components/lwp/arch/arm/common/reloc.c b/components/lwp/arch/arm/common/reloc.c
new file mode 100644
index 0000000000..a232df885d
--- /dev/null
+++ b/components/lwp/arch/arm/common/reloc.c
@@ -0,0 +1,120 @@
+#include <rtthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <lwp_elf.h>
+#ifdef RT_USING_USERSPACE
+#include <mmu.h>
+#include <page.h>
+#endif
+
+typedef struct
+{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_sym;
+
+#ifdef RT_USING_USERSPACE
+void arch_elf_reloc(rt_mmu_info *m_info, void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym)
+{
+ size_t rel_off;
+ void* addr;
+
+ if (rel_dyn_size && !dynsym)
+ {
+ return;
+ }
+ for (rel_off = 0; rel_off < rel_dyn_size; rel_off += 8)
+ {
+ uint32_t v1, v2;
+
+ /*
+ memcpy(&v1, rel_dyn_start + rel_off, 4);
+ memcpy(&v2, rel_dyn_start + rel_off + 4, 4);
+ */
+
+ addr = rt_hw_mmu_v2p(m_info, (void*)((char*)rel_dyn_start + rel_off));
+ addr = (void*)((char*)addr - PV_OFFSET);
+ memcpy(&v1, addr, 4);
+ addr = rt_hw_mmu_v2p(m_info, (void*)((char*)rel_dyn_start + rel_off + 4));
+ addr = (void*)((char*)addr - PV_OFFSET);
+ memcpy(&v2, addr, 4);
+
+ addr = rt_hw_mmu_v2p(m_info, (void*)((char*)text_start + v1));
+ addr = (void*)((char*)addr - PV_OFFSET);
+ if ((v2 & 0xff) == R_ARM_RELATIVE)
+ {
+ // *(uint32_t*)(text_start + v1) += (uint32_t)text_start;
+ *(uint32_t*)addr += (uint32_t)text_start;
+ }
+ else if ((v2 & 0xff) == R_ARM_ABS32)
+ {
+ uint32_t t;
+ t = (v2 >> 8);
+ if (t) /* 0 is UDF */
+ {
+ // *(uint32_t*)(text_start + v1) = (uint32_t)(text_start + dynsym[t].st_value);
+ *(uint32_t*)addr = (uint32_t)((char*)text_start + dynsym[t].st_value);
+ }
+ }
+ }
+ /* modify got */
+ if (got_size)
+ {
+ uint32_t *got_item = (uint32_t*)got_start;
+
+ for (rel_off = 0; rel_off < got_size; rel_off += 4, got_item++)
+ {
+ //*got_item += (uint32_t)text_start;
+ addr = rt_hw_mmu_v2p(m_info, got_item);
+ addr = (void*)((char*)addr - PV_OFFSET);
+ *(uint32_t *)addr += (uint32_t)text_start;
+ }
+ }
+}
+#else
+
+void arch_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym)
+{
+ size_t rel_off;
+
+ if (rel_dyn_size && !dynsym)
+ {
+ return;
+ }
+ for (rel_off = 0; rel_off < rel_dyn_size; rel_off += 8)
+ {
+ uint32_t v1, v2;
+
+ memcpy(&v1, (void*)((char*)rel_dyn_start + rel_off), 4);
+ memcpy(&v2, (void*)((char*)rel_dyn_start + rel_off + 4), 4);
+
+ if ((v2 & 0xff) == R_ARM_RELATIVE)
+ {
+ *(uint32_t*)((char*)text_start + v1) += (uint32_t)text_start;
+ }
+ else if ((v2 & 0xff) == R_ARM_ABS32)
+ {
+ uint32_t t;
+ t = (v2 >> 8);
+ if (t) /* 0 is UDF */
+ {
+ *(uint32_t*)((char*)text_start + v1) = (uint32_t)((char*)text_start + dynsym[t].st_value);
+ }
+ }
+ }
+ /* modify got */
+ if (got_size)
+ {
+ uint32_t *got_item = (uint32_t*)got_start;
+
+ for (rel_off = 0; rel_off < got_size; rel_off += 4, got_item++)
+ {
+ *got_item += (uint32_t)text_start;
+ }
+ }
+}
+#endif
diff --git a/components/lwp/arch/arm/cortex-a/lwp_arch.c b/components/lwp/arch/arm/cortex-a/lwp_arch.c
new file mode 100644
index 0000000000..814c1513ed
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-a/lwp_arch.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-28 Jesven first version
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+
+extern size_t MMUTable[];
+
+int arch_user_space_init(struct rt_lwp *lwp)
+{
+ size_t *mmu_table;
+
+ mmu_table = (size_t*)rt_pages_alloc(2);
+ if (!mmu_table)
+ {
+ return -1;
+ }
+
+ lwp->end_heap = USER_HEAP_VADDR;
+ rt_memcpy(mmu_table + (KERNEL_VADDR_START >> ARCH_SECTION_SHIFT), MMUTable + (KERNEL_VADDR_START >> ARCH_SECTION_SHIFT), ARCH_PAGE_SIZE);
+ rt_memset(mmu_table, 0, 3 * ARCH_PAGE_SIZE);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, 4 * ARCH_PAGE_SIZE);
+ rt_hw_mmu_map_init(&lwp->mmu_info, (void*)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table, PV_OFFSET);
+
+ return 0;
+}
+
+void *arch_kernel_mmu_table_get(void)
+{
+ return (void*)((char*)MMUTable + PV_OFFSET);
+}
+
+void arch_kuser_init(rt_mmu_info *mmu_info, void *vectors)
+{
+ extern char __kuser_helper_start[], __kuser_helper_end[];
+ int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+
+ rt_hw_mmu_map_auto(mmu_info, vectors, 0x1000, MMU_MAP_U_RO);
+
+ rt_memcpy((void*)((char*)vectors + 0x1000 - kuser_sz), __kuser_helper_start, kuser_sz);
+ /*
+ * vectors + 0xfe0 = __kuser_get_tls
+ * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
+ */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void*)((char*)vectors + 0x1000 - kuser_sz), kuser_sz);
+ rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, (void*)((char*)vectors + 0x1000 - kuser_sz), kuser_sz);
+}
+
+void arch_user_space_vtable_free(struct rt_lwp *lwp)
+{
+ if (lwp && lwp->mmu_info.vtable)
+ {
+ rt_pages_free(lwp->mmu_info.vtable, 2);
+ }
+}
+
+int arch_expand_user_stack(void *addr)
+{
+ int ret = 0;
+ size_t stack_addr = (size_t)addr;
+
+ stack_addr &= ~ARCH_PAGE_MASK;
+ if ((stack_addr >= (size_t)USER_STACK_VSTART) && (stack_addr < (size_t)USER_STACK_VEND))
+ {
+ void *map = lwp_map_user(lwp_self(), (void*)stack_addr, ARCH_PAGE_SIZE, 0);
+
+ if (map || lwp_user_accessable(addr, 1))
+ {
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+#ifdef LWP_ENABLE_ASID
+#define MAX_ASID_BITS 8
+#define MAX_ASID (1 << MAX_ASID_BITS)
+static uint64_t global_generation = 1;
+static char asid_valid_bitmap[MAX_ASID];
+unsigned int arch_get_asid(struct rt_lwp *lwp)
+{
+ if (lwp == RT_NULL)
+ {
+ // kernel
+ return 0;
+ }
+
+ if (lwp->generation == global_generation)
+ {
+ return lwp->asid;
+ }
+
+ if (lwp->asid && !asid_valid_bitmap[lwp->asid])
+ {
+ asid_valid_bitmap[lwp->asid] = 1;
+ return lwp->asid;
+ }
+
+ for (unsigned i = 1; i < MAX_ASID; i++)
+ {
+ if (asid_valid_bitmap[i] == 0)
+ {
+ asid_valid_bitmap[i] = 1;
+ lwp->generation = global_generation;
+ lwp->asid = i;
+ return lwp->asid;
+ }
+ }
+
+ global_generation++;
+ memset(asid_valid_bitmap, 0, MAX_ASID * sizeof(char));
+
+ asid_valid_bitmap[1] = 1;
+ lwp->generation = global_generation;
+ lwp->asid = 1;
+
+ asm volatile ("mcr p15, 0, r0, c8, c7, 0\ndsb\nisb" ::: "memory");
+
+ return lwp->asid;
+}
+#endif
+
+#endif
diff --git a/components/lwp/arch/arm/cortex-a/lwp_arch.h b/components/lwp/arch/arm/cortex-a/lwp_arch.h
new file mode 100644
index 0000000000..d627632493
--- /dev/null
+++ b/components/lwp/arch/arm/cortex-a/lwp_arch.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef LWP_ARCH_H__
+#define LWP_ARCH_H__
+
+#include <lwp.h>
+#include <lwp_arch_comm.h>
+
+#ifdef RT_USING_USERSPACE
+
+#define USER_VADDR_TOP 0xC0000000UL
+#define USER_HEAP_VEND 0xB0000000UL
+#define USER_HEAP_VADDR 0x80000000UL
+#define USER_STACK_VSTART 0x70000000UL
+#define USER_STACK_VEND USER_HEAP_VADDR
+#define LDSO_LOAD_VADDR 0x60000000UL
+#define USER_VADDR_START 0x00100000UL
+#define USER_LOAD_VADDR USER_VADDR_START
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+rt_inline unsigned long rt_hw_ffz(unsigned long x)
+{
+ return __builtin_ffsl(~x) - 1;
+}
+
+rt_inline void icache_invalid_all(void)
+{
+ asm volatile ("mcr p15, 0, r0, c7, c5, 0\ndsb\nisb":::"memory");//iciallu
+}
+
+unsigned int arch_get_asid(struct rt_lwp *lwp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /*LWP_ARCH_H__*/
diff --git a/components/lwp/arch/arm/cortex-a/lwp_gcc.S b/components/lwp/arch/arm/cortex-a/lwp_gcc.S
index 395974a2b7..30839e5970 100644
--- a/components/lwp/arch/arm/cortex-a/lwp_gcc.S
+++ b/components/lwp/arch/arm/cortex-a/lwp_gcc.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
+ * Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -8,6 +8,8 @@
* 2018-12-10 Jesven first version
*/
+#include "rtconfig.h"
+
#define Mode_USR 0x10
#define Mode_FIQ 0x11
#define Mode_IRQ 0x12
@@ -27,22 +29,126 @@
.text
/*
- * void lwp_user_entry(args, text, data);
+ * void arch_start_umode(args, text, ustack, kstack);
*/
-.global lwp_user_entry
-.type lwp_user_entry, % function
-lwp_user_entry:
+.global arch_start_umode
+.type arch_start_umode, % function
+arch_start_umode:
mrs r9, cpsr
bic r9, #0x1f
orr r9, #Mode_USR
cpsid i
msr spsr, r9
+ mov sp, r3
+ mov r3, r2 ;/* user stack top */
/* set data address. */
- mov r9, r2
movs pc, r1
/*
+ * void arch_crt_start_umode(args, text, ustack, kstack);
+ */
+.global arch_crt_start_umode
+.type arch_crt_start_umode, % function
+arch_crt_start_umode:
+ cps #Mode_SYS
+ sub sp, r2, #16
+ ldr r2, =lwp_thread_return
+ ldr r4, [r2]
+ str r4, [sp]
+ ldr r4, [r2, #4]
+ str r4, [sp, #4]
+ ldr r4, [r2, #8]
+ str r4, [sp, #8]
+
+ mov r4, sp
+ mcr p15, 0, r4, c7, c11, 1 ;//dc cmvau
+ add r4, #4
+ mcr p15, 0, r4, c7, c11, 1 ;//dc cmvau
+ add r4, #4
+ mcr p15, 0, r4, c7, c11, 1 ;//dc cmvau
+ dsb
+ isb
+ mcr p15, 0, r4, c7, c5, 0 ;//iciallu
+ dsb
+ isb
+
+ mov lr, sp
+ cps #Mode_SVC
+
+ mrs r9, cpsr
+ bic r9, #0x1f
+ orr r9, #Mode_USR
+ cpsid i
+ msr spsr, r9
+ mov sp, r3
+
+ /* set data address. */
+ movs pc, r1
+
+/*
+void arch_set_thread_context(void *exit_addr, void *new_thread_stack, void *user_stack, void **thread_sp);
+*/
+.global arch_set_thread_context
+arch_set_thread_context:
+ sub r1, #(10 * 4 + 4 * 4) /* {r4 - r12, lr} , {r4, r5, spsr, u_pc} */
+ stmfd r1!, {r0}
+ mov r12, #0
+ stmfd r1!, {r12}
+ stmfd r1!, {r1 - r12}
+ stmfd r1!, {r12} /* new thread return value */
+ mrs r12, cpsr
+ orr r12, #(1 << 7) /* disable irq */
+ stmfd r1!, {r12} /* spsr */
+ mov r12, #0
+ stmfd r1!, {r12} /* now user lr is 0 */
+ stmfd r1!, {r2} /* user sp */
+#ifdef RT_USING_FPU
+ stmfd r1!, {r12} /* not use fpu */
+#endif
+ str r1, [r3]
+ mov pc, lr
+
+.global arch_get_user_sp
+arch_get_user_sp:
+ cps #Mode_SYS
+ mov r0, sp
+ cps #Mode_SVC
+ mov pc, lr
+
+.global sys_fork
+.global sys_vfork
+.global arch_fork_exit
+sys_fork:
+sys_vfork:
+ push {r4 - r12, lr}
+ bl _sys_fork
+arch_fork_exit:
+ pop {r4 - r12, lr}
+ b arch_syscall_exit
+
+.global sys_clone
+.global arch_clone_exit
+sys_clone:
+ push {r4 - r12, lr}
+ bl _sys_clone
+arch_clone_exit:
+ pop {r4 - r12, lr}
+ b arch_syscall_exit
+/*
+void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
+*/
+.global lwp_exec_user
+lwp_exec_user:
+ cpsid i
+ mov sp, r1
+ mov lr, r2
+ mov r2, #Mode_USR
+ msr spsr_cxsf, r2
+ ldr r3, =0x80000000
+ b arch_ret_to_user
+
+/*
* void SVC_Handler(void);
*/
.global vector_swi
@@ -51,20 +157,277 @@ vector_swi:
push {lr}
mrs lr, spsr
push {r4, r5, lr}
+
cpsie i
push {r0 - r3, r12}
+
+ bl rt_thread_self
+ bl lwp_user_setting_save
+
+ and r0, r7, #0xf000
+ cmp r0, #0xe000
+ beq arch_signal_quit
+
+ cmp r0, #0xf000
+ beq ret_from_user
and r0, r7, #0xff
bl lwp_get_sys_api
cmp r0, #0 /* r0 = api */
mov lr, r0
+
pop {r0 - r3, r12}
- beq svc_exit
+ beq arch_syscall_exit
blx lr
-svc_exit:
+.global arch_syscall_exit
+arch_syscall_exit:
cpsid i
pop {r4, r5, lr}
msr spsr_cxsf, lr
pop {lr}
+
+.global arch_ret_to_user
+arch_ret_to_user:
+ push {r0-r3, r12, lr}
+ bl lwp_check_debug
+ bl lwp_check_exit_request
+ cmp r0, #0
+ beq 1f
+ mov r0, #0
+ b sys_exit
+1:
+ bl lwp_signal_check
+ cmp r0, #0
+ pop {r0-r3, r12, lr}
+ bne user_do_signal
+
+ push {r0}
+ ldr r0, =rt_dbg_ops
+ ldr r0, [r0]
+ cmp r0, #0
+ pop {r0}
+ beq 2f
+ push {r0-r3, r12, lr}
+ mov r0, lr
+ bl dbg_attach_req
+ pop {r0-r3, r12, lr}
+2:
movs pc, lr
+
+#ifdef RT_USING_LWP
+.global lwp_check_debug
+lwp_check_debug:
+ ldr r0, =rt_dbg_ops
+ ldr r0, [r0]
+ cmp r0, #0
+ bne 1f
+ bx lr
+1:
+ push {lr}
+ bl dbg_check_suspend
+ cmp r0, #0
+ beq lwp_check_debug_quit
+
+ cps #Mode_SYS
+ sub sp, #8
+ ldr r0, =lwp_debugreturn
+ ldr r1, [r0]
+ str r1, [sp]
+ ldr r1, [r0, #4]
+ str r1, [sp, #4]
+
+ mov r1, sp
+ mcr p15, 0, r1, c7, c11, 1 ;//dc cmvau
+ add r1, #4
+ mcr p15, 0, r1, c7, c11, 1 ;//dc cmvau
+ dsb
+ isb
+ mcr p15, 0, r0, c7, c5, 0 ;//iciallu
+ dsb
+ isb
+
+ mov r0, sp /* lwp_debugreturn */
+ cps #Mode_SVC
+
+ mrs r1, spsr
+ push {r1}
+ mov r1, #Mode_USR
+ msr spsr_cxsf, r1
+ movs pc, r0
+ret_from_user:
+ cps #Mode_SYS
+ add sp, #8
+ cps #Mode_SVC
+ /*
+ pop {r0 - r3, r12}
+ pop {r4 - r6, lr}
+ */
+ add sp, #(4*9)
+ pop {r4}
+ msr spsr_cxsf, r4
+lwp_check_debug_quit:
+ pop {pc}
+
+arch_signal_quit:
+ cpsid i
+ pop {r0 - r3, r12}
+ pop {r4, r5, lr}
+ pop {lr}
+ bl lwp_signal_restore
+ /* r0 is user_ctx : ori sp, pc, cpsr*/
+ ldr r1, [r0]
+ ldr r2, [r0, #4]
+ ldr r3, [r0, #8]
+ msr spsr_cxsf, r3
+ mov lr, r2
+ cps #Mode_SYS
+ mov sp, r1
+ pop {r0-r12, lr}
+ cps #Mode_SVC
+ b arch_ret_to_user
+
+user_do_signal:
+ mov r0, r0
+ cps #Mode_SYS
+ push {r0-r12, lr}
+
+ sub sp, #8
+ ldr r0, =lwp_sigreturn
+ ldr r1, [r0]
+ str r1, [sp]
+ ldr r1, [r0, #4]
+ str r1, [sp, #4]
+
+ mov r1, sp
+ mcr p15, 0, r1, c7, c11, 1 ;//dc cmvau
+ add r1, #4
+ mcr p15, 0, r1, c7, c11, 1 ;//dc cmvau
+ dsb
+ isb
+ mcr p15, 0, r0, c7, c5, 0 ;//iciallu
+ dsb
+ isb
+
+ mov r5, sp ;//if func is 0
+ mov lr, sp
+
+ add r0, sp, #8 /* lwp_sigreturn */
+ cps #Mode_SVC
+ mov r1, lr
+ mrs r2, spsr
+ bl lwp_signal_backup
+ /* r0 is signal */
+ mov r4, r0
+ bl lwp_sighandler_get
+ mov lr, r0
+ cmp lr, #0
+ moveq lr, r5
+ mov r0, r4
+ movs pc, lr
+
+lwp_debugreturn:
+ mov r7, #0xf000
+ svc #0
+
+lwp_sigreturn:
+ mov r7, #0xe000
+ svc #0
+
+lwp_thread_return:
+ mov r0, #0
+ mov r7, #0x01
+ svc #0
+#endif
+
+.global check_vfp
+check_vfp:
+#ifdef RT_USING_FPU
+ vmrs r0, fpexc
+ ubfx r0, r0, #30, #1
+#else
+ mov r0, #0
+#endif
+ mov pc, lr
+
+.global get_vfp
+get_vfp:
+#ifdef RT_USING_FPU
+ vstmia r0!, {d0-d15}
+ vstmia r0!, {d16-d31}
+ vmrs r1, fpscr
+ str r1, [r0]
+#endif
+ mov pc, lr
+
+.globl arch_get_tidr
+arch_get_tidr:
+ mrc p15, 0, r0, c13, c0, 3
+ bx lr
+
+.global arch_set_thread_area
+arch_set_thread_area:
+.globl arch_set_tidr
+arch_set_tidr:
+ mcr p15, 0, r0, c13, c0, 3
+ bx lr
+
+/* kuser suppurt */
+ .macro kuser_pad, sym, size
+ .if (. - \sym) & 3
+ .rept 4 - (. - \sym) & 3
+ .byte 0
+ .endr
+ .endif
+ .rept (\size - (. - \sym)) / 4
+ .word 0xe7fddef1
+ .endr
+ .endm
+
+.align 5
+.globl __kuser_helper_start
+__kuser_helper_start:
+__kuser_cmpxchg64: @ 0xffff0f60
+ stmfd sp!, {r4, r5, r6, lr}
+ ldmia r0, {r4, r5} @ load old val
+ ldmia r1, {r6, lr} @ load new val
+1: ldmia r2, {r0, r1} @ load current val
+ eors r3, r0, r4 @ compare with oldval (1)
+ eorseq r3, r1, r5 @ compare with oldval (2)
+2: stmiaeq r2, {r6, lr} @ store newval if eq
+ rsbs r0, r3, #0 @ set return val and C flag
+ ldmfd sp!, {r4, r5, r6, pc}
+
+ kuser_pad __kuser_cmpxchg64, 64
+
+__kuser_memory_barrier: @ 0xffff0fa0
+ dmb
+ mov pc, lr
+
+ kuser_pad __kuser_memory_barrier, 32
+
+__kuser_cmpxchg: @ 0xffff0fc0
+1: ldr r3, [r2] @ load current val
+ subs r3, r3, r0 @ compare with oldval
+2: streq r1, [r2] @ store newval if eq
+ rsbs r0, r3, #0 @ set return val and C flag
+ mov pc, lr
+
+kuser_pad __kuser_cmpxchg, 32
+
+__kuser_get_tls: @ 0xffff0fe0
+ mrc p15, 0, r0, c13, c0, 3 @ 0xffff0fe8 hardware TLS code
+ mov pc, lr
+ ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init
+
+ kuser_pad __kuser_get_tls, 16
+
+ .rep 3
+ .word 0 @ 0xffff0ff0 software TLS value, then
+ .endr @ pad up to __kuser_helper_version
+
+__kuser_helper_version: @ 0xffff0ffc
+ .word ((__kuser_helper_end - __kuser_helper_start) >> 5)
+
+ .globl __kuser_helper_end
+__kuser_helper_end:
diff --git a/components/lwp/arch/arm/cortex-a9/lwp_gcc.S b/components/lwp/arch/arm/cortex-a9/lwp_gcc.S
deleted file mode 100644
index 93e88f7c97..0000000000
--- a/components/lwp/arch/arm/cortex-a9/lwp_gcc.S
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-12-10 Jesven first version
- */
-
-#define Mode_USR 0x10
-#define Mode_FIQ 0x11
-#define Mode_IRQ 0x12
-#define Mode_SVC 0x13
-#define Mode_MON 0x16
-#define Mode_ABT 0x17
-#define Mode_UDF 0x1B
-#define Mode_SYS 0x1F
-
-#define A_Bit 0x100
-#define I_Bit 0x80 @; when I bit is set, IRQ is disabled
-#define F_Bit 0x40 @; when F bit is set, FIQ is disabled
-#define T_Bit 0x20
-
-.cpu cortex-a9
-.syntax unified
-.text
-
-/*
- * void lwp_user_entry(args, text, data);
- */
-.global lwp_user_entry
-.type lwp_user_entry, % function
-lwp_user_entry:
- mrs r9, cpsr
- bic r9, #0x1f
- orr r9, #Mode_USR
- cpsid i
- msr spsr, r9
-
- /* set data address. */
- mov r9, r2
- movs pc, r1
-
-/*
- * void vector_swi(void);
- */
-.global vector_swi
-.type vector_swi, % function
-vector_swi:
- push {lr}
- mrs lr, spsr
- push {r4, r5, lr}
- cpsie i
-
- push {r0 - r3, r12}
- and r0, r7, #0xff
- bl lwp_get_sys_api
- cmp r0, #0 /* r0 = api */
- mov lr, r0
- pop {r0 - r3, r12}
- beq svc_exit
- blx lr
-
-svc_exit:
- cpsid i
- pop {r4, r5, lr}
- msr spsr_cxsf, lr
- pop {lr}
- movs pc, lr
diff --git a/components/lwp/arch/arm/cortex-m3/lwp_gcc.S b/components/lwp/arch/arm/cortex-m3/lwp_gcc.S
deleted file mode 100644
index 846b06bb26..0000000000
--- a/components/lwp/arch/arm/cortex-m3/lwp_gcc.S
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-10-30 heyuanjie first version
- */
-
-.cpu cortex-m3
-.syntax unified
-.thumb
-.text
-
-/*
- * void* lwp_get_sys_api(rt_uint32_t number);
- */
-.global lwp_get_sys_api
-.global lwp_get_kernel_sp
-.global lwp_set_kernel_sp
-
-
-/*
- * void lwp_user_entry(args, text, data);
- */
-.global lwp_user_entry
-.type lwp_user_entry, % function
-lwp_user_entry:
- PUSH {R0-R3} @; push text&data addr.
-
- MOV R0, SP @; v1 = SP
- BL lwp_set_kernel_sp @; lwp_set_kernel_sp(v1)
-
- @; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 @; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} @; pop app address to R1.
- @; set data address.
- MOV R9, R2
-
- @; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
-/*
- * void SVC_Handler(void);
- */
-.global SVC_Handler
-.type SVC_Handler, % function
-SVC_Handler:
- PUSH {LR}
-
- @; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} @; push app SP.
-
- @; get SVC number.
- mov R0, R7
-
- @; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} @; push api
-
- @; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} @; pop api to R2.
- POP {R1} @; pop app SP to R1.
-
- stmfd r0!, {r1} @; save app SP to kernel SP
-
- @;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- @; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} @; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} @; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] @; update LR
- STR R2, [R0, #24] @; update api to PC
- MSR PSP, R0 @; update SP, API is executed with kernel SP
-
- @; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} @; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-/*
-* void svc_exit(void);
-*/
-.global svc_exit
-.type svc_exit, % function
-svc_exit:
- @; get user SP.
- PUSH {R0} @; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] @; load pc
- add r3, #32 @; exception_stack_frame size
- MSR PSP, R3 @; restore app stack pointer
- @; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- @; return to lwp.
- ORR R1, R1, #0x01 @; only Thumb-mode.
- BX R1 @; return to user app.
diff --git a/components/lwp/arch/arm/cortex-m3/lwp_iar.S b/components/lwp/arch/arm/cortex-m3/lwp_iar.S
deleted file mode 100644
index a218569375..0000000000
--- a/components/lwp/arch/arm/cortex-m3/lwp_iar.S
+++ /dev/null
@@ -1,123 +0,0 @@
-;/*
-; * Copyright (c) 2006-2018, RT-Thread Development Team
-; *
-; * SPDX-License-Identifier: Apache-2.0
-; *
-; * Change Logs:
-; * Date Author Notes
-; * 2018-10-30 heyuanjie first version
-; */
-
- SECTION .text:CODE(2)
- THUMB
- REQUIRE8
- PRESERVE8
-
-;/*
-; * void* lwp_get_sys_api(rt_uint32_t number);
-; */
- IMPORT lwp_get_sys_api
- IMPORT lwp_get_kernel_sp
- IMPORT lwp_set_kernel_sp
-
-;/*
-; * void lwp_user_entry(args, text, data);
-; */
- EXPORT lwp_user_entry
-lwp_user_entry:
- PUSH {R0-R3} ; push text&data addr.
-
- MOV R0, SP ; v1 = SP
- BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
-
- ; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 ; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} ; pop app address to R1.
- ; set data address.
- MOV R9, R2
-
- ; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
-;/*
-; * void SVC_Handler(void);
-; */
- EXPORT SVC_Handler
-SVC_Handler:
- PUSH {LR}
-
- ; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} ; push app SP.
-
- ; get SVC number.
- mov R0, R7
-
- ; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} ; push api
-
- ; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} ; pop api to R2.
- POP {R1} ; pop app SP to R1.
-
- stmfd r0!, {r1} ; save app SP to kernel SP
-
- ;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- ; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] ; update LR
- STR R2, [R0, #24] ; update api to PC
- MSR PSP, R0 ; update SP, API is executed with kernel SP
-
- ; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} ; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-
-;/*
-; * void svc_exit(void);
-; */
- EXPORT svc_exit
-svc_exit:
- ; get user SP.
- PUSH {R0} ; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] ; load pc
- add r3, r3, #32 ; exception_stack_frame size
- MSR PSP, R3 ; restore app stack pointer
- ; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- ; return to lwp.
- ORR R1, R1, #0x01 ; only Thumb-mode.
- BX R1 ; return to user app.
-
- END
diff --git a/components/lwp/arch/arm/cortex-m3/lwp_rvds.S b/components/lwp/arch/arm/cortex-m3/lwp_rvds.S
deleted file mode 100644
index 246751a847..0000000000
--- a/components/lwp/arch/arm/cortex-m3/lwp_rvds.S
+++ /dev/null
@@ -1,135 +0,0 @@
-;/*
-; * Copyright (c) 2006-2018, RT-Thread Development Team
-; *
-; * SPDX-License-Identifier: Apache-2.0
-; *
-; * Change Logs:
-; * Date Author Notes
-; * 2018-10-30 heyuanjie first version
-; */
-
- AREA |.text|, CODE, READONLY, ALIGN=2
- THUMB
- REQUIRE8
- PRESERVE8
-
-;/*
-; * void* lwp_get_sys_api(rt_uint32_t number);
-; */
- IMPORT lwp_get_sys_api
- IMPORT lwp_get_kernel_sp
- IMPORT lwp_set_kernel_sp
-
-;/*
-; * void lwp_user_entry(args, text, data);
-; */
-lwp_user_entry PROC
- EXPORT lwp_user_entry
-
- PUSH {R0-R3} ; push text&data addr.
-
- MOV R0, SP ; v1 = SP
- BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
-
- ; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 ; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} ; pop app address to R1.
- ; set data address.
- MOV R9, R2
-
- ; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
- ; never reach here!
- ENDP
-
-;/*
-; * void SVC_Handler(void);
-; */
-SVC_Handler PROC
- EXPORT SVC_Handler
-
- PUSH {LR}
-
- ; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} ; push app SP.
-
- ; get SVC number.
- mov R0, R7
-
- ; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} ; push api
-
- ; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} ; pop api to R2.
- POP {R1} ; pop app SP to R1.
-
- stmfd r0!, {r1} ; save app SP to kernel SP
-
- ;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- ; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] ; update LR
- STR R2, [R0, #24] ; update api to PC
- MSR PSP, R0 ; update SP, API is executed with kernel SP
-
- ; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} ; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-
- ENDP
-
-;/*
-; * void svc_exit(void);
-; */
-svc_exit PROC
- EXPORT svc_exit
-
- ; get user SP.
- PUSH {R0} ; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] ; load pc
- add r3, #32 ; exception_stack_frame size
- MSR PSP, R3 ; restore app stack pointer
- ; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- ; return to lwp.
- ORR R1, R1, #0x01 ; only Thumb-mode.
- BX R1 ; return to user app.
-
- ENDP
-
- ALIGN
-
- END
diff --git a/components/lwp/arch/arm/cortex-m4/lwp_gcc.S b/components/lwp/arch/arm/cortex-m4/lwp_gcc.S
deleted file mode 100644
index e71dbb82c9..0000000000
--- a/components/lwp/arch/arm/cortex-m4/lwp_gcc.S
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-10-30 heyuanjie first version
- */
-
-.cpu cortex-m4
-.syntax unified
-.thumb
-.text
-
-/*
- * void* lwp_get_sys_api(rt_uint32_t number);
- */
-.global lwp_get_sys_api
-.global lwp_get_kernel_sp
-.global lwp_set_kernel_sp
-
-
-/*
- * void lwp_user_entry(args, text, data);
- */
-.global lwp_user_entry
-.type lwp_user_entry, % function
-lwp_user_entry:
- PUSH {R0-R3} @; push text&data addr.
-
- MOV R0, SP @; v1 = SP
- BL lwp_set_kernel_sp @; lwp_set_kernel_sp(v1)
-
- @; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 @; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} @; pop app address to R1.
- @; set data address.
- MOV R9, R2
-
- @; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
-/*
- * void SVC_Handler(void);
- */
-.global SVC_Handler
-.type SVC_Handler, % function
-SVC_Handler:
- PUSH {LR}
-
- @; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} @; push app SP.
-
- @; get SVC number.
- mov R0, R7
-
- @; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} @; push api
-
- @; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} @; pop api to R2.
- POP {R1} @; pop app SP to R1.
-
- stmfd r0!, {r1} @; save app SP to kernel SP
-
- @;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- @; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} @; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} @; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] @; update LR
- STR R2, [R0, #24] @; update api to PC
- MSR PSP, R0 @; update SP, API is executed with kernel SP
-
- @; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} @; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-/*
-* void svc_exit(void);
-*/
-.global svc_exit
-.type svc_exit, % function
-svc_exit:
- @; get user SP.
- PUSH {R0} @; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] @; load pc
- add r3, #32 @; exception_stack_frame size
- MSR PSP, R3 @; restore app stack pointer
- @; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- @; return to lwp.
- ORR R1, R1, #0x01 @; only Thumb-mode.
- BX R1 @; return to user app.
diff --git a/components/lwp/arch/arm/cortex-m4/lwp_iar.S b/components/lwp/arch/arm/cortex-m4/lwp_iar.S
deleted file mode 100644
index a218569375..0000000000
--- a/components/lwp/arch/arm/cortex-m4/lwp_iar.S
+++ /dev/null
@@ -1,123 +0,0 @@
-;/*
-; * Copyright (c) 2006-2018, RT-Thread Development Team
-; *
-; * SPDX-License-Identifier: Apache-2.0
-; *
-; * Change Logs:
-; * Date Author Notes
-; * 2018-10-30 heyuanjie first version
-; */
-
- SECTION .text:CODE(2)
- THUMB
- REQUIRE8
- PRESERVE8
-
-;/*
-; * void* lwp_get_sys_api(rt_uint32_t number);
-; */
- IMPORT lwp_get_sys_api
- IMPORT lwp_get_kernel_sp
- IMPORT lwp_set_kernel_sp
-
-;/*
-; * void lwp_user_entry(args, text, data);
-; */
- EXPORT lwp_user_entry
-lwp_user_entry:
- PUSH {R0-R3} ; push text&data addr.
-
- MOV R0, SP ; v1 = SP
- BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
-
- ; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 ; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} ; pop app address to R1.
- ; set data address.
- MOV R9, R2
-
- ; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
-;/*
-; * void SVC_Handler(void);
-; */
- EXPORT SVC_Handler
-SVC_Handler:
- PUSH {LR}
-
- ; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} ; push app SP.
-
- ; get SVC number.
- mov R0, R7
-
- ; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} ; push api
-
- ; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} ; pop api to R2.
- POP {R1} ; pop app SP to R1.
-
- stmfd r0!, {r1} ; save app SP to kernel SP
-
- ;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- ; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] ; update LR
- STR R2, [R0, #24] ; update api to PC
- MSR PSP, R0 ; update SP, API is executed with kernel SP
-
- ; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} ; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-
-;/*
-; * void svc_exit(void);
-; */
- EXPORT svc_exit
-svc_exit:
- ; get user SP.
- PUSH {R0} ; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] ; load pc
- add r3, r3, #32 ; exception_stack_frame size
- MSR PSP, R3 ; restore app stack pointer
- ; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- ; return to lwp.
- ORR R1, R1, #0x01 ; only Thumb-mode.
- BX R1 ; return to user app.
-
- END
diff --git a/components/lwp/arch/arm/cortex-m4/lwp_rvds.S b/components/lwp/arch/arm/cortex-m4/lwp_rvds.S
deleted file mode 100644
index 246751a847..0000000000
--- a/components/lwp/arch/arm/cortex-m4/lwp_rvds.S
+++ /dev/null
@@ -1,135 +0,0 @@
-;/*
-; * Copyright (c) 2006-2018, RT-Thread Development Team
-; *
-; * SPDX-License-Identifier: Apache-2.0
-; *
-; * Change Logs:
-; * Date Author Notes
-; * 2018-10-30 heyuanjie first version
-; */
-
- AREA |.text|, CODE, READONLY, ALIGN=2
- THUMB
- REQUIRE8
- PRESERVE8
-
-;/*
-; * void* lwp_get_sys_api(rt_uint32_t number);
-; */
- IMPORT lwp_get_sys_api
- IMPORT lwp_get_kernel_sp
- IMPORT lwp_set_kernel_sp
-
-;/*
-; * void lwp_user_entry(args, text, data);
-; */
-lwp_user_entry PROC
- EXPORT lwp_user_entry
-
- PUSH {R0-R3} ; push text&data addr.
-
- MOV R0, SP ; v1 = SP
- BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
-
- ; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 ; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} ; pop app address to R1.
- ; set data address.
- MOV R9, R2
-
- ; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
- ; never reach here!
- ENDP
-
-;/*
-; * void SVC_Handler(void);
-; */
-SVC_Handler PROC
- EXPORT SVC_Handler
-
- PUSH {LR}
-
- ; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} ; push app SP.
-
- ; get SVC number.
- mov R0, R7
-
- ; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} ; push api
-
- ; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} ; pop api to R2.
- POP {R1} ; pop app SP to R1.
-
- stmfd r0!, {r1} ; save app SP to kernel SP
-
- ;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- ; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] ; update LR
- STR R2, [R0, #24] ; update api to PC
- MSR PSP, R0 ; update SP, API is executed with kernel SP
-
- ; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} ; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-
- ENDP
-
-;/*
-; * void svc_exit(void);
-; */
-svc_exit PROC
- EXPORT svc_exit
-
- ; get user SP.
- PUSH {R0} ; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] ; load pc
- add r3, #32 ; exception_stack_frame size
- MSR PSP, R3 ; restore app stack pointer
- ; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- ; return to lwp.
- ORR R1, R1, #0x01 ; only Thumb-mode.
- BX R1 ; return to user app.
-
- ENDP
-
- ALIGN
-
- END
diff --git a/components/lwp/arch/arm/cortex-m7/lwp_gcc.S b/components/lwp/arch/arm/cortex-m7/lwp_gcc.S
deleted file mode 100644
index 848c592919..0000000000
--- a/components/lwp/arch/arm/cortex-m7/lwp_gcc.S
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-10-30 heyuanjie first version
- */
-
-.cpu cortex-m7
-.syntax unified
-.thumb
-.text
-
-/*
- * void* lwp_get_sys_api(rt_uint32_t number);
- */
-.global lwp_get_sys_api
-.global lwp_get_kernel_sp
-.global lwp_set_kernel_sp
-
-
-/*
- * void lwp_user_entry(args, text, data);
- */
-.global lwp_user_entry
-.type lwp_user_entry, % function
-lwp_user_entry:
- PUSH {R0-R3} @; push text&data addr.
-
- MOV R0, SP @; v1 = SP
- BL lwp_set_kernel_sp @; lwp_set_kernel_sp(v1)
-
- @; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 @; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} @; pop app address to R1.
- @; set data address.
- MOV R9, R2
-
- @; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
-/*
- * void SVC_Handler(void);
- */
-.global SVC_Handler
-.type SVC_Handler, % function
-SVC_Handler:
- PUSH {LR}
-
- @; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} @; push app SP.
-
- @; get SVC number.
- mov R0, R7
-
- @; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} @; push api
-
- @; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} @; pop api to R2.
- POP {R1} @; pop app SP to R1.
-
- stmfd r0!, {r1} @; save app SP to kernel SP
-
- @;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- @; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} @; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} @; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] @; update LR
- STR R2, [R0, #24] @; update api to PC
- MSR PSP, R0 @; update SP, API is executed with kernel SP
-
- @; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} @; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-/*
-* void svc_exit(void);
-*/
-.global svc_exit
-.type svc_exit, % function
-svc_exit:
- @; get user SP.
- PUSH {R0} @; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] @; load pc
- add r3, #32 @; exception_stack_frame size
- MSR PSP, R3 @; restore app stack pointer
- @; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- @; return to lwp.
- ORR R1, R1, #0x01 @; only Thumb-mode.
- BX R1 @; return to user app.
diff --git a/components/lwp/arch/arm/cortex-m7/lwp_iar.S b/components/lwp/arch/arm/cortex-m7/lwp_iar.S
deleted file mode 100644
index a218569375..0000000000
--- a/components/lwp/arch/arm/cortex-m7/lwp_iar.S
+++ /dev/null
@@ -1,123 +0,0 @@
-;/*
-; * Copyright (c) 2006-2018, RT-Thread Development Team
-; *
-; * SPDX-License-Identifier: Apache-2.0
-; *
-; * Change Logs:
-; * Date Author Notes
-; * 2018-10-30 heyuanjie first version
-; */
-
- SECTION .text:CODE(2)
- THUMB
- REQUIRE8
- PRESERVE8
-
-;/*
-; * void* lwp_get_sys_api(rt_uint32_t number);
-; */
- IMPORT lwp_get_sys_api
- IMPORT lwp_get_kernel_sp
- IMPORT lwp_set_kernel_sp
-
-;/*
-; * void lwp_user_entry(args, text, data);
-; */
- EXPORT lwp_user_entry
-lwp_user_entry:
- PUSH {R0-R3} ; push text&data addr.
-
- MOV R0, SP ; v1 = SP
- BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
-
- ; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 ; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} ; pop app address to R1.
- ; set data address.
- MOV R9, R2
-
- ; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
-;/*
-; * void SVC_Handler(void);
-; */
- EXPORT SVC_Handler
-SVC_Handler:
- PUSH {LR}
-
- ; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} ; push app SP.
-
- ; get SVC number.
- mov R0, R7
-
- ; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} ; push api
-
- ; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} ; pop api to R2.
- POP {R1} ; pop app SP to R1.
-
- stmfd r0!, {r1} ; save app SP to kernel SP
-
- ;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- ; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] ; update LR
- STR R2, [R0, #24] ; update api to PC
- MSR PSP, R0 ; update SP, API is executed with kernel SP
-
- ; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} ; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-
-;/*
-; * void svc_exit(void);
-; */
- EXPORT svc_exit
-svc_exit:
- ; get user SP.
- PUSH {R0} ; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] ; load pc
- add r3, r3, #32 ; exception_stack_frame size
- MSR PSP, R3 ; restore app stack pointer
- ; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- ; return to lwp.
- ORR R1, R1, #0x01 ; only Thumb-mode.
- BX R1 ; return to user app.
-
- END
diff --git a/components/lwp/arch/arm/cortex-m7/lwp_rvds.S b/components/lwp/arch/arm/cortex-m7/lwp_rvds.S
deleted file mode 100644
index 246751a847..0000000000
--- a/components/lwp/arch/arm/cortex-m7/lwp_rvds.S
+++ /dev/null
@@ -1,135 +0,0 @@
-;/*
-; * Copyright (c) 2006-2018, RT-Thread Development Team
-; *
-; * SPDX-License-Identifier: Apache-2.0
-; *
-; * Change Logs:
-; * Date Author Notes
-; * 2018-10-30 heyuanjie first version
-; */
-
- AREA |.text|, CODE, READONLY, ALIGN=2
- THUMB
- REQUIRE8
- PRESERVE8
-
-;/*
-; * void* lwp_get_sys_api(rt_uint32_t number);
-; */
- IMPORT lwp_get_sys_api
- IMPORT lwp_get_kernel_sp
- IMPORT lwp_set_kernel_sp
-
-;/*
-; * void lwp_user_entry(args, text, data);
-; */
-lwp_user_entry PROC
- EXPORT lwp_user_entry
-
- PUSH {R0-R3} ; push text&data addr.
-
- MOV R0, SP ; v1 = SP
- BL lwp_set_kernel_sp ; lwp_set_kernel_sp(v1)
-
- ; set CPU to user-thread mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03 ; use PSP, user-thread mode.
- MSR CONTROL, R2
-
- POP {R0-R3} ; pop app address to R1.
- ; set data address.
- MOV R9, R2
-
- ; run app, only Thumb-mode.
- ORR R1, R1, #0x01
- BX R1
-
- ; never reach here!
- ENDP
-
-;/*
-; * void SVC_Handler(void);
-; */
-SVC_Handler PROC
- EXPORT SVC_Handler
-
- PUSH {LR}
-
- ; get user SP.
- TST LR, #0x4
- ITE EQ
- MRSEQ R1, MSP
- MRSNE R1, PSP
- PUSH {R1} ; push app SP.
-
- ; get SVC number.
- mov R0, R7
-
- ; get kernel system API
- BL lwp_get_sys_api
-
- PUSH {R0} ; push api
-
- ; get kernel SP to R0.
- BL lwp_get_kernel_sp
-
- POP {R2} ; pop api to R2.
- POP {R1} ; pop app SP to R1.
-
- stmfd r0!, {r1} ; save app SP to kernel SP
-
- ;push app parm5~6 to kernel SP
- STMFD R0!, {R4 - R5}
- ; copy R1(app SP) to R0(kernel SP).
- push {r8-r11}
- LDMFD R1, {R4 - R11} ; pop exception_stack_frame to r4 - r11 register
- STMFD R0!, {R4 - R11} ; push exception_stack_frame to server SP.
- pop {r8-r11}
-
- LDR R3, =svc_exit
- STR R3, [R0, #20] ; update LR
- STR R2, [R0, #24] ; update api to PC
- MSR PSP, R0 ; update SP, API is executed with kernel SP
-
- ; set to thread-privilege mode.
- MRS R3, CONTROL
- BIC R3, R3, #0x01
- ORR R3, R3, #0x02
- MSR CONTROL, R3
-
- POP {LR} ; 0xFFFFFFED
- ORR LR, LR, #0x10
- BX LR
-
- ENDP
-
-;/*
-; * void svc_exit(void);
-; */
-svc_exit PROC
- EXPORT svc_exit
-
- ; get user SP.
- PUSH {R0} ; push result to SP.
- BL lwp_get_kernel_sp
- ldr r3, [r0, #-4]
- pop {r0}
-
- ldr lr, [r3, #20]
- ldr r1, [r3, #24] ; load pc
- add r3, #32 ; exception_stack_frame size
- MSR PSP, R3 ; restore app stack pointer
- ; restore to PSP & thread-unprivilege mode.
- MRS R2, CONTROL
- ORR R2, R2, #0x03
- MSR CONTROL, R2
-
- ; return to lwp.
- ORR R1, R1, #0x01 ; only Thumb-mode.
- BX R1 ; return to user app.
-
- ENDP
-
- ALIGN
-
- END
diff --git a/components/lwp/arch/risc-v/rv64/SConscript b/components/lwp/arch/risc-v/rv64/SConscript
new file mode 100644
index 0000000000..e98e7650b1
--- /dev/null
+++ b/components/lwp/arch/risc-v/rv64/SConscript
@@ -0,0 +1,11 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.S')
+CPPPATH = [cwd]
+
+group = DefineGroup('lwp-riscv', src, depend = ['RT_USING_LWP'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/lwp/arch/risc-v/rv64/lwp_arch.c b/components/lwp/arch/risc-v/rv64/lwp_arch.c
new file mode 100644
index 0000000000..a1e0b8f31a
--- /dev/null
+++ b/components/lwp/arch/risc-v/rv64/lwp_arch.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-11-18 Jesven first version
+ * 2021-02-03 lizhirui port to riscv64
+ * 2021-02-06 lizhirui add thread filter
+ * 2021-02-19 lizhirui port to new version of rt-smart
+ * 2021-03-02 lizhirui add a auxillary function for interrupt
+ * 2021-03-04 lizhirui delete thread filter
+ * 2021-03-04 lizhirui modify for new version of rt-smart
+ * 2021-11-22 JasonHu add lwp_set_thread_context
+ * 2021-11-30 JasonHu add clone/fork support
+ */
+
+#include <rthw.h>
+#include <stddef.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+
+#include <stack.h>
+#include <cpuport.h>
+#include <encoding.h>
+
+extern rt_ubase_t MMUTable[];
+
+int arch_expand_user_stack(void *addr)
+{
+ int ret = 0;
+ rt_ubase_t stack_addr = (rt_ubase_t)addr;
+
+ stack_addr &= ~PAGE_OFFSET_MASK;
+ if ((stack_addr >= (rt_ubase_t)USER_STACK_VSTART) && (stack_addr < (rt_ubase_t)USER_STACK_VEND))
+ {
+ void *map = lwp_map_user(lwp_self(), (void *)stack_addr, PAGE_SIZE, RT_FALSE);
+
+ if (map || lwp_user_accessable(addr, 1))
+ {
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+void *lwp_copy_return_code_to_user_stack()
+{
+ void lwp_thread_return();
+ void lwp_thread_return_end();
+ rt_thread_t tid = rt_thread_self();
+
+ if (tid->user_stack != RT_NULL)
+ {
+ rt_size_t size = (rt_size_t)lwp_thread_return_end - (rt_size_t)lwp_thread_return;
+ rt_size_t userstack = (rt_size_t)tid->user_stack + tid->user_stack_size - size;
+ rt_memcpy((void *)userstack, lwp_thread_return, size);
+ return (void *)userstack;
+ }
+
+ return RT_NULL;
+}
+
+rt_mmu_info *arch_kernel_get_mmu_info(void)
+{
+ extern rt_mmu_info *mmu_info;
+
+ return mmu_info;
+}
+
+rt_ubase_t lwp_fix_sp(rt_ubase_t cursp)
+{
+ void lwp_thread_return();
+ void lwp_thread_return_end();
+
+ if (cursp == 0)
+ {
+ return 0;
+ }
+
+ return cursp - ((rt_size_t)lwp_thread_return_end - (rt_size_t)lwp_thread_return);
+}
+
+rt_thread_t rt_thread_sp_to_thread(void *spmember_addr)
+{
+ return (rt_thread_t)(((rt_ubase_t)spmember_addr) - (offsetof(struct rt_thread, sp)));
+}
+
+void *get_thread_kernel_stack_top(rt_thread_t thread)
+{
+ return (void *)(((rt_size_t)thread->stack_addr) + ((rt_size_t)thread->stack_size));
+}
+
+void *arch_get_user_sp(void)
+{
+ /* user sp saved in interrupt context */
+ rt_thread_t self = rt_thread_self();
+ rt_uint8_t *stack_top = (rt_uint8_t *)self->stack_addr + self->stack_size;
+ struct rt_hw_stack_frame *frame = (struct rt_hw_stack_frame *)(stack_top - sizeof(struct rt_hw_stack_frame));
+
+ return (void *)frame->user_sp_exc_stack;
+}
+
+int arch_user_space_init(struct rt_lwp *lwp)
+{
+ rt_ubase_t *mmu_table;
+
+ mmu_table = (rt_ubase_t *)rt_pages_alloc(0);
+ if (!mmu_table)
+ {
+ return -1;
+ }
+
+ lwp->end_heap = USER_HEAP_VADDR;
+
+ rt_memcpy(mmu_table, MMUTable, PAGE_SIZE);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, 4 * PAGE_SIZE);
+ rt_hw_mmu_map_init(&lwp->mmu_info, (void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, (rt_size_t *)mmu_table, 0);
+
+ return 0;
+}
+
+void *arch_kernel_mmu_table_get(void)
+{
+ return (void *)((char *)MMUTable);
+}
+
+void arch_user_space_vtable_free(struct rt_lwp *lwp)
+{
+ if (lwp && lwp->mmu_info.vtable)
+ {
+ rt_pages_free(lwp->mmu_info.vtable, 0);
+ }
+}
+
+long _sys_clone(void *arg[]);
+long sys_clone(void *arg[])
+{
+ return _sys_clone(arg);
+}
+
+long _sys_fork(void);
+long sys_fork(void)
+{
+ return _sys_fork();
+}
+
+long _sys_vfork(void);
+long sys_vfork(void)
+{
+ return _sys_fork();
+}
+
+/**
+ * set exec context for fork/clone.
+ */
+int arch_set_thread_context(void (*exit)(void), void *new_thread_stack,
+ void *user_stack, void **thread_sp)
+{
+ RT_ASSERT(exit != RT_NULL);
+ RT_ASSERT(user_stack != RT_NULL);
+ RT_ASSERT(new_thread_stack != RT_NULL);
+ RT_ASSERT(thread_sp != RT_NULL);
+ struct rt_hw_stack_frame *syscall_frame;
+ struct rt_hw_stack_frame *thread_frame;
+
+ rt_uint8_t *stk;
+ rt_uint8_t *syscall_stk;
+
+ stk = (rt_uint8_t *)new_thread_stack;
+ /* reserve syscall context, all the registers are copyed from parent */
+ stk -= CTX_REG_NR * REGBYTES;
+ syscall_stk = stk;
+
+ syscall_frame = (struct rt_hw_stack_frame *)stk;
+
+ /* modify user sp */
+ syscall_frame->user_sp_exc_stack = (rt_ubase_t)user_stack;
+
+ /* skip ecall */
+ syscall_frame->epc += 4;
+
+ /* child return value is 0 */
+ syscall_frame->a0 = 0;
+ syscall_frame->a1 = 0;
+
+ /* reset thread area */
+ rt_thread_t thread = rt_container_of((unsigned long)thread_sp, struct rt_thread, sp);
+ syscall_frame->tp = (rt_ubase_t)thread->thread_idr;
+
+#ifdef ARCH_USING_NEW_CTX_SWITCH
+ extern void *_rt_hw_stack_init(rt_ubase_t *sp, rt_ubase_t ra, rt_ubase_t sstatus);
+ rt_ubase_t sstatus = read_csr(sstatus) | SSTATUS_SPP;
+ sstatus &= ~SSTATUS_SIE;
+
+ /* compatible to RESTORE_CONTEXT */
+ stk = (void *)_rt_hw_stack_init((rt_ubase_t *)stk, (rt_ubase_t)exit, sstatus);
+#else
+ /* build temp thread context */
+ stk -= sizeof(struct rt_hw_stack_frame);
+
+ thread_frame = (struct rt_hw_stack_frame *)stk;
+
+ int i;
+ for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
+ {
+ ((rt_ubase_t *)thread_frame)[i] = 0xdeadbeaf;
+ }
+
+ /* set pc for thread */
+ thread_frame->epc = (rt_ubase_t)exit;
+
+ /* set old exception mode as supervisor, because in kernel */
+ thread_frame->sstatus = read_csr(sstatus) | SSTATUS_SPP;
+ thread_frame->sstatus &= ~SSTATUS_SIE; /* must disable interrupt */
+
+ /* set stack as syscall stack */
+ thread_frame->user_sp_exc_stack = (rt_ubase_t)syscall_stk;
+
+#endif /* ARCH_USING_NEW_CTX_SWITCH */
+ /* save new stack top */
+ *thread_sp = (void *)stk;
+
+ /**
+ * The stack for child thread:
+ *
+ * +------------------------+ --> kernel stack top
+ * | syscall stack |
+ * | |
+ * | @sp | --> `user_stack`
+ * | @epc | --> user ecall addr + 4 (skip ecall)
+ * | @a0&a1 | --> 0 (for child return 0)
+ * | |
+ * +------------------------+ --> temp thread stack top
+ * | temp thread stack | ^
+ * | | |
+ * | @sp | ---------/
+ * | @epc | --> `exit` (arch_clone_exit/arch_fork_exit)
+ * | |
+ * +------------------------+ --> thread sp
+ */
+}
+
+/**
+ * void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
+ */
+void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
+{
+ arch_start_umode(args, user_entry, (void*)USER_STACK_VEND, kernel_stack);
+}
+
+void *arch_get_usp_from_uctx(struct rt_user_context *uctx)
+{
+ return uctx->sp;
+}
+
+#endif /* RT_USING_USERSPACE */
diff --git a/components/lwp/arch/risc-v/rv64/lwp_arch.h b/components/lwp/arch/risc-v/rv64/lwp_arch.h
new file mode 100644
index 0000000000..9e12aa5ba7
--- /dev/null
+++ b/components/lwp/arch/risc-v/rv64/lwp_arch.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef LWP_ARCH_H__
+#define LWP_ARCH_H__
+
+#include <lwp.h>
+#include <lwp_arch_comm.h>
+#include <riscv_mmu.h>
+
+#ifdef RT_USING_USERSPACE
+
+#ifdef RT_USING_USERSPACE_32BIT_LIMIT
+#define USER_HEAP_VADDR 0xF0000000UL
+#define USER_HEAP_VEND 0xFE000000UL
+#define USER_STACK_VSTART 0xE0000000UL
+#define USER_STACK_VEND USER_HEAP_VADDR
+#define USER_VADDR_START 0xC0000000UL
+#define USER_VADDR_TOP 0xFF000000UL
+#define USER_LOAD_VADDR 0xD0000000UL
+#define LDSO_LOAD_VADDR USER_LOAD_VADDR
+#else
+#define USER_HEAP_VADDR 0x300000000UL
+#define USER_HEAP_VEND 0xffffffffffff0000UL
+#define USER_STACK_VSTART 0x270000000UL
+#define USER_STACK_VEND USER_HEAP_VADDR
+#define USER_VADDR_START 0x100000000UL
+#define USER_VADDR_TOP 0xfffffffffffff000UL
+#define USER_LOAD_VADDR 0x200000000
+#define LDSO_LOAD_VADDR 0x200000000
+#endif
+
+/* this attribution is cpu specified, and it should be defined in riscv_mmu.h */
+#ifndef MMU_MAP_U_RWCB
+#define MMU_MAP_U_RWCB 0
+#endif
+
+#ifndef MMU_MAP_U_RW
+#define MMU_MAP_U_RW 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+rt_mmu_info* arch_kernel_get_mmu_info(void);
+
+rt_inline unsigned long rt_hw_ffz(unsigned long x)
+{
+ return __builtin_ffsl(~x) - 1;
+}
+
+rt_inline void icache_invalid_all(void)
+{
+ //TODO:
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /*LWP_ARCH_H__*/
diff --git a/components/lwp/arch/risc-v/rv64/lwp_gcc.S b/components/lwp/arch/risc-v/rv64/lwp_gcc.S
new file mode 100644
index 0000000000..edf8166e77
--- /dev/null
+++ b/components/lwp/arch/risc-v/rv64/lwp_gcc.S
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-12-10 Jesven first version
+ * 2021-02-03 lizhirui port to riscv64
+ * 2021-02-19 lizhirui port to new version of rt-smart
+ * 2022-11-08 Wangxiaoyao Cleanup codes;
+ * Support new context switch
+ */
+
+#include "rtconfig.h"
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif /* __ASSEMBLY__ */
+
+#include "cpuport.h"
+#include "encoding.h"
+#include "stackframe.h"
+
+.section .text.lwp
+
+/*
+ * void arch_start_umode(args, text, ustack, kstack);
+ */
+.global arch_start_umode
+.type arch_start_umode, % function
+arch_start_umode:
+ // load kstack for user process
+ csrw sscratch, a3
+ li t0, SSTATUS_SPP | SSTATUS_SIE // set as user mode, close interrupt
+ csrc sstatus, t0
+ li t0, SSTATUS_SPIE // enable interrupt when return to user mode
+ csrs sstatus, t0
+
+ csrw sepc, a1
+ mv a3, a2
+ sret//enter user mode
+
+/*
+ * void arch_crt_start_umode(args, text, ustack, kstack);
+ */
+.global arch_crt_start_umode
+.type arch_crt_start_umode, % function
+arch_crt_start_umode:
+ li t0, SSTATUS_SPP | SSTATUS_SIE // set as user mode, close interrupt
+ csrc sstatus, t0
+ li t0, SSTATUS_SPIE // enable interrupt when return to user mode
+ csrs sstatus, t0
+
+ csrw sepc, a1
+ mv s0, a0
+ mv s1, a1
+ mv s2, a2
+ mv s3, a3
+ mv a0, s2
+ call lwp_copy_return_code_to_user_stack
+ mv a0, s2
+ call lwp_fix_sp
+ mv sp, a0//user_sp
+ mv ra, a0//return address
+ mv a0, s0//args
+
+ csrw sscratch, s3
+ sret//enter user mode
+
+/**
+ * Unify exit point from kernel mode to enter user space
+ * we handle following things here:
+ * 1. restoring user mode debug state (not support yet)
+ * 2. handling thread's exit request
+ * 3. handling POSIX signal
+ * 4. restoring user context
+ * 5. jump to user mode
+ */
+.global arch_ret_to_user
+arch_ret_to_user:
+ // TODO: we don't support kernel gdb server in risc-v yet
+ // so we don't check debug state here and handle debugging bussiness
+
+ call lwp_check_exit_request
+ beqz a0, 1f
+ mv a0, x0
+ call sys_exit
+
+1:
+ call lwp_signal_check
+ beqz a0, ret_to_user_exit
+ J user_do_signal
+
+ret_to_user_exit:
+ RESTORE_ALL
+ // `RESTORE_ALL` also reset sp to user sp, and setup sscratch
+ sret
+
+/**
+ * Restore user context from exception frame stroraged in ustack
+ * And handle pending signals;
+ */
+arch_signal_quit:
+ call lwp_signal_restore
+ call arch_get_usp_from_uctx
+ // return value is user sp
+ mv sp, a0
+
+ // restore user sp before enter trap
+ addi a0, sp, CTX_REG_NR * REGBYTES
+ csrw sscratch, a0
+
+ RESTORE_ALL
+ SAVE_ALL
+ j arch_ret_to_user
+
+/**
+ * Prepare and enter user signal handler
+ * Move user exception frame and setup signal return
+ * routine in user stack
+ */
+user_do_signal:
+ /** restore and backup kernel sp carefully to avoid leaking */
+ addi t0, sp, CTX_REG_NR * REGBYTES
+ csrw sscratch, t0
+
+ RESTORE_ALL
+ SAVE_ALL
+
+ /**
+ * save lwp_sigreturn in user memory
+ */
+ mv s0, sp
+ la t0, lwp_sigreturn
+ la t1, lwp_sigreturn_end
+ // t1 <- size
+ sub t1, t1, t0
+ // s0 <- dst
+ sub s0, s0, t1
+ mv s2, t1
+lwp_sigreturn_copy_loop:
+ addi t2, t1, -1
+ add t3, t0, t2
+ add t4, s0, t2
+ lb t5, 0(t3)
+ sb t5, 0(t4)
+ mv t1, t2
+ bnez t1, lwp_sigreturn_copy_loop
+
+ /**
+ * 1. clear sscratch & restore kernel sp to
+ * enter kernel mode routine
+ * 2. storage exp frame address to restore context,
+ * by calling to lwp_signal_backup
+ * 3. storage lwp_sigreturn entry address
+ * 4. get signal id as param for signal handler
+ */
+ mv s1, sp
+ csrrw sp, sscratch, x0
+
+ /**
+ * synchronize dcache & icache if target is
+ * a Harvard Architecture machine, otherwise
+ * do nothing
+ */
+ mv a0, s0
+ mv a1, s2
+ call rt_hw_sync_cache_local
+
+ /**
+ * backup user sp (point to saved exception frame, skip sigreturn routine)
+ * And get signal id
+
+ * a0: user sp
+ * a1: user_pc (not used, marked as 0 to avoid abuse)
+ * a2: user_flag (not used, marked as 0 to avoid abuse)
+ */
+ mv a0, s1
+ mv a1, zero
+ mv a2, zero
+ call lwp_signal_backup
+
+ /**
+ * backup signal id in s2,
+ * and get sighandler by signal id
+ */
+ mv s2, a0
+ call lwp_sighandler_get
+
+ /**
+ * set regiter RA to user signal handler
+ * set sp to user sp & save kernel sp in sscratch
+ */
+ mv ra, s0
+ csrw sscratch, sp
+ mv sp, s0
+
+ /**
+ * a0 is signal_handler,
+ * s1 = s0 == NULL ? lwp_sigreturn : s0;
+ */
+ mv s1, s0
+ beqz a0, skip_user_signal_handler
+ mv s1, a0
+
+skip_user_signal_handler:
+ // enter user mode and enable interrupt when return to user mode
+ li t0, SSTATUS_SPP
+ csrc sstatus, t0
+ li t0, SSTATUS_SPIE
+ csrs sstatus, t0
+
+ // sepc <- signal_handler
+ csrw sepc, s1
+ // a0 <- signal id
+ mv a0, s2
+ sret
+
+.align 3
+lwp_debugreturn:
+ li a7, 0xff
+ ecall
+
+.align 3
+lwp_sigreturn:
+ li a7, 0xfe
+ ecall
+
+.align 3
+lwp_sigreturn_end:
+
+.align 3
+.global lwp_thread_return
+lwp_thread_return:
+ li a0, 0
+ li a7, 1
+ ecall
+
+.align 3
+.global lwp_thread_return_end
+lwp_thread_return_end:
+
+.globl arch_get_tidr
+arch_get_tidr:
+ mv a0, tp
+ ret
+
+.global arch_set_thread_area
+arch_set_thread_area:
+.globl arch_set_tidr
+arch_set_tidr:
+ mv tp, a0
+ ret
+
+.global arch_clone_exit
+.global arch_fork_exit
+arch_fork_exit:
+arch_clone_exit:
+ j arch_syscall_exit
+
+.global syscall_entry
+syscall_entry:
+#ifndef ARCH_USING_NEW_CTX_SWITCH
+ //swap to thread kernel stack
+ csrr t0, sstatus
+ andi t0, t0, 0x100
+ beqz t0, __restore_sp_from_tcb
+
+__restore_sp_from_sscratch: // from kernel
+ csrr t0, sscratch
+ j __move_stack_context
+
+__restore_sp_from_tcb: // from user
+ la a0, rt_current_thread
+ LOAD a0, 0(a0)
+ jal get_thread_kernel_stack_top
+ mv t0, a0
+
+__move_stack_context:
+ mv t1, sp//src
+ mv sp, t0//switch stack
+ addi sp, sp, -CTX_REG_NR * REGBYTES
+ //copy context
+ li s0, CTX_REG_NR//cnt
+ mv t2, sp//dst
+
+copy_context_loop:
+ LOAD t0, 0(t1)
+ STORE t0, 0(t2)
+ addi s0, s0, -1
+ addi t1, t1, 8
+ addi t2, t2, 8
+ bnez s0, copy_context_loop
+#endif /* ARCH_USING_NEW_CTX_SWITCH */
+
+ /* fetch SYSCALL ID */
+ LOAD a7, 17 * REGBYTES(sp)
+ addi a7, a7, -0xfe
+ beqz a7, arch_signal_quit
+
+#ifdef RT_USING_USERSPACE
+ /* save setting when syscall enter */
+ call rt_thread_self
+ call lwp_user_setting_save
+#endif
+
+ mv a0, sp
+ OPEN_INTERRUPT
+ call syscall_handler
+ j arch_syscall_exit
+
+.global arch_syscall_exit
+arch_syscall_exit:
+ CLOSE_INTERRUPT
+
+ #if defined(RT_USING_USERSPACE)
+ LOAD s0, 2 * REGBYTES(sp)
+ andi s0, s0, 0x100
+ bnez s0, dont_ret_to_user
+ j arch_ret_to_user
+ #endif
+dont_ret_to_user:
+
+#ifdef RT_USING_USERSPACE
+ /* restore setting when syscall exit */
+ call rt_thread_self
+ call lwp_user_setting_restore
+
+ /* after restore the reg `tp`, need modify context */
+ STORE tp, 4 * REGBYTES(sp)
+#endif
+
+ //restore context
+ RESTORE_ALL
+ csrw sscratch, zero
+ sret
diff --git a/components/lwp/arch/risc-v/rv64/reloc.c b/components/lwp/arch/risc-v/rv64/reloc.c
new file mode 100644
index 0000000000..b35f8bef27
--- /dev/null
+++ b/components/lwp/arch/risc-v/rv64/reloc.c
@@ -0,0 +1,108 @@
+#include <rtthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <elf.h>
+#ifdef RT_USING_USERSPACE
+#include <mmu.h>
+#include <page.h>
+#endif
+
+typedef struct
+{
+ Elf64_Word st_name;
+ Elf64_Addr st_value;
+ Elf64_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf64_Half st_shndx;
+} Elf64_sym;
+
+#ifdef RT_USING_USERSPACE
+void arch_elf_reloc(rt_mmu_info *m_info, void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf64_sym *dynsym)
+{
+ size_t rel_off;
+ void* addr;
+
+ if (rel_dyn_size && !dynsym)
+ {
+ return;
+ }
+ for (rel_off = 0; rel_off < rel_dyn_size; rel_off += 8)
+ {
+ uint32_t v1, v2;
+
+ addr = rt_hw_mmu_v2p(m_info, (void *)(((rt_size_t)rel_dyn_start) + rel_off));
+ memcpy(&v1, addr, 4);
+ addr = rt_hw_mmu_v2p(m_info, (void *)(((rt_size_t)rel_dyn_start) + rel_off + 4));
+ memcpy(&v2, addr, 4);
+
+ addr = rt_hw_mmu_v2p(m_info, (void *)((rt_size_t)text_start + v1));
+ if ((v2 & 0xff) == R_ARM_RELATIVE)
+ {
+ *(rt_size_t*)addr += (rt_size_t)text_start;
+ }
+ else if ((v2 & 0xff) == R_ARM_ABS32)
+ {
+ uint32_t t;
+ t = (v2 >> 8);
+ if (t) /* 0 is UDF */
+ {
+ *(rt_size_t*)addr = (((rt_size_t)text_start) + dynsym[t].st_value);
+ }
+ }
+ }
+ /* modify got */
+ if (got_size)
+ {
+ uint32_t *got_item = (uint32_t*)got_start;
+
+ for (rel_off = 0; rel_off < got_size; rel_off += 4, got_item++)
+ {
+ addr = rt_hw_mmu_v2p(m_info, got_item);
+ *(rt_size_t *)addr += (rt_size_t)text_start;
+ }
+ }
+}
+#else
+
+void arch_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf64_sym *dynsym)
+{
+ size_t rel_off;
+
+ if (rel_dyn_size && !dynsym)
+ {
+ return;
+ }
+ for (rel_off = 0; rel_off < rel_dyn_size; rel_off += 8)
+ {
+ uint32_t v1, v2;
+
+ memcpy(&v1, ((rt_uint8_t *)rel_dyn_start) + rel_off, 4);
+ memcpy(&v2, ((rt_uint8_t *)rel_dyn_start) + rel_off + 4, 4);
+
+ if ((v2 & 0xff) == R_ARM_RELATIVE)
+ {
+ *(uint32_t*)(((rt_size_t)text_start) + v1) += (uint32_t)text_start;
+ }
+ else if ((v2 & 0xff) == R_ARM_ABS32)
+ {
+ uint32_t t;
+ t = (v2 >> 8);
+ if (t) /* 0 is UDF */
+ {
+ *(uint32_t*)(((rt_size_t)text_start) + v1) = (uint32_t)(((rt_size_t)text_start) + dynsym[t].st_value);
+ }
+ }
+ }
+ /* modify got */
+ if (got_size)
+ {
+ uint32_t *got_item = (uint32_t*)got_start;
+
+ for (rel_off = 0; rel_off < got_size; rel_off += 4, got_item++)
+ {
+ *got_item += (uint32_t)text_start;
+ }
+ }
+}
+#endif
diff --git a/components/lwp/arch/x86/i386/SConscript b/components/lwp/arch/x86/i386/SConscript
new file mode 100644
index 0000000000..c0d3aead77
--- /dev/null
+++ b/components/lwp/arch/x86/i386/SConscript
@@ -0,0 +1,11 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.S')
+CPPPATH = [cwd]
+
+group = DefineGroup('lwp-x86-i386', src, depend = ['RT_USING_LWP'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/lwp/arch/x86/i386/lwp_arch.c b/components/lwp/arch/x86/i386/lwp_arch.c
new file mode 100644
index 0000000000..5ad150121b
--- /dev/null
+++ b/components/lwp/arch/x86/i386/lwp_arch.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-7-14 JasonHu first version
+ */
+
+#include <rthw.h>
+#include <stddef.h>
+#include <rtconfig.h>
+#include <rtdbg.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <stackframe.h>
+#include <interrupt.h>
+#include <segment.h>
+
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+
+#ifdef RT_USING_SIGNALS
+#include <lwp_signal.h>
+#endif /* RT_USING_SIGNALS */
+
+extern size_t g_mmu_table[];
+
+int arch_expand_user_stack(void *addr)
+{
+ int ret = 0;
+ size_t stack_addr = (size_t)addr;
+
+ stack_addr &= ~PAGE_OFFSET_MASK;
+ if ((stack_addr >= (size_t)USER_STACK_VSTART) && (stack_addr < (size_t)USER_STACK_VEND))
+ {
+ void *map = lwp_map_user(lwp_self(), (void *)stack_addr, PAGE_SIZE, RT_FALSE);
+
+ if (map || lwp_user_accessable(addr, 1))
+ {
+ ret = 1; /* map success */
+ }
+ else /* map failed, send signal SIGSEGV */
+ {
+#ifdef RT_USING_SIGNALS
+ dbg_log(DBG_ERROR, "[fault] thread %s mapped addr %p failed!\n", rt_thread_self()->name, addr);
+ lwp_thread_kill(rt_thread_self(), SIGSEGV);
+ ret = 1; /* return 1, will return back to intr, then check exit */
+#endif
+ }
+ }
+ else /* not stack, send signal SIGSEGV */
+ {
+#ifdef RT_USING_SIGNALS
+ dbg_log(DBG_ERROR, "[fault] thread %s access unmapped addr %p!\n", rt_thread_self()->name, addr);
+ lwp_thread_kill(rt_thread_self(), SIGSEGV);
+ ret = 1; /* return 1, will return back to intr, then check exit */
+#endif
+ }
+ return ret;
+}
+
+void *get_thread_kernel_stack_top(rt_thread_t thread)
+{
+ return RT_NULL;
+}
+
+/**
+ * don't support this in i386, it's ok!
+ */
+void *arch_get_user_sp()
+{
+ return RT_NULL;
+}
+
+int arch_user_space_init(struct rt_lwp *lwp)
+{
+ rt_size_t *mmu_table;
+
+ mmu_table = (rt_size_t *)rt_pages_alloc(0);
+ if (!mmu_table)
+ {
+ return -1;
+ }
+ rt_memset(mmu_table, 0, ARCH_PAGE_SIZE);
+
+ lwp->end_heap = USER_HEAP_VADDR;
+ memcpy(mmu_table, g_mmu_table, ARCH_PAGE_SIZE / 4);
+ memset((rt_uint8_t *)mmu_table + ARCH_PAGE_SIZE / 4, 0, ARCH_PAGE_SIZE / 4 * 3);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE);
+ if (rt_hw_mmu_map_init(&lwp->mmu_info, (void*)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table, PV_OFFSET) < 0)
+ {
+ rt_pages_free(mmu_table, 0);
+ return -1;
+ }
+ return 0;
+}
+
+void *arch_kernel_mmu_table_get(void)
+{
+ return (void *)((char *)g_mmu_table);
+}
+
+void arch_user_space_vtable_free(struct rt_lwp *lwp)
+{
+ if (lwp && lwp->mmu_info.vtable)
+ {
+ rt_pages_free(lwp->mmu_info.vtable, 0);
+ lwp->mmu_info.vtable = NULL;
+ }
+}
+
+void arch_set_thread_area(void *p)
+{
+ rt_hw_seg_tls_set((rt_ubase_t) p);
+ rt_thread_t cur = rt_thread_self();
+ cur->thread_idr = p; /* update thread idr after first set */
+}
+
+void *arch_get_tidr(void)
+{
+ rt_thread_t cur = rt_thread_self();
+ if (!cur->lwp) /* no lwp, don't get thread idr from tls seg */
+ return NULL;
+ return (void *)rt_hw_seg_tls_get(); /* get thread idr from tls seg */
+}
+
+void arch_set_tidr(void *p)
+{
+ rt_thread_t cur = rt_thread_self();
+ if (!cur->lwp) /* no lwp, don't set thread idr to tls seg */
+ return;
+ rt_hw_seg_tls_set((rt_ubase_t) p); /* set tls seg addr as thread idr */
+}
+
+static void lwp_user_stack_init(rt_hw_stack_frame_t *frame)
+{
+ frame->ds = frame->es = USER_DATA_SEL;
+ frame->cs = USER_CODE_SEL;
+ frame->ss = USER_STACK_SEL;
+ frame->gs = USER_TLS_SEL;
+ frame->fs = 0; /* unused */
+
+ frame->edi = frame->esi = \
+ frame->ebp = frame->esp_dummy = 0;
+ frame->eax = frame->ebx = \
+ frame->ecx = frame->edx = 0;
+
+ frame->error_code = 0;
+ frame->vec_no = 0;
+
+ frame->eflags = (EFLAGS_MBS | EFLAGS_IF_1 | EFLAGS_IOPL_3);
+}
+
+extern void lwp_switch_to_user(void *frame);
+/**
+ * user entry, set frame.
+ * at the end of execute, we need enter user mode,
+ * in x86, we can set stack, arg, text entry in a stack frame,
+ * then pop then into register, final use iret to switch kernel mode to user mode.
+ */
+void arch_start_umode(void *args, const void *text, void *ustack, void *k_stack)
+{
+ rt_uint8_t *stk = k_stack;
+ stk -= sizeof(struct rt_hw_stack_frame);
+ struct rt_hw_stack_frame *frame = (struct rt_hw_stack_frame *)stk;
+
+ lwp_user_stack_init(frame);
+ frame->esp = (rt_uint32_t)ustack - 32;
+ frame->ebx = (rt_uint32_t)args;
+ frame->eip = (rt_uint32_t)text;
+ lwp_switch_to_user(frame);
+ /* should never return */
+}
+
+void lwp_exec_user(void *args, void *kernel_stack, void *user_entry)
+{
+ arch_start_umode(args, (const void *)user_entry, (void *)USER_STACK_VEND, kernel_stack);
+}
+
+extern void lwp_thread_return();
+extern void lwp_thread_return_end();
+
+static void *lwp_copy_return_code_to_user_stack(void *ustack)
+{
+ size_t size = (size_t)lwp_thread_return_end - (size_t)lwp_thread_return;
+ void *retcode = (void *)((size_t)ustack - size);
+ memcpy(retcode, (void *)lwp_thread_return, size);
+ return retcode;
+}
+
+/**
+ * when called sys_thread_create, need create a thread, after thread stared, will come here,
+ * like arch_start_umode, will enter user mode, but we must set thread exit function. it looks like:
+ * void func(void *arg)
+ * {
+ * ...
+ * }
+ * when thread func return, we must call exit code to exit thread, or not the program runs away.
+ * so we need copy exit code to user and call exit code when func return.
+ */
+void arch_crt_start_umode(void *args, const void *text, void *ustack, void *k_stack)
+{
+ RT_ASSERT(ustack != NULL);
+
+ rt_uint8_t *stk;
+ stk = (rt_uint8_t *)((rt_uint8_t *)k_stack + sizeof(rt_ubase_t));
+ stk = (rt_uint8_t *)RT_ALIGN_DOWN(((rt_ubase_t)stk), sizeof(rt_ubase_t));
+ stk -= sizeof(struct rt_hw_stack_frame);
+ struct rt_hw_stack_frame *frame = (struct rt_hw_stack_frame *)stk;
+
+ lwp_user_stack_init(frame);
+
+ /* make user thread stack */
+ unsigned long *retcode = lwp_copy_return_code_to_user_stack(ustack); /* copy ret code */
+ unsigned long *retstack = (unsigned long *)RT_ALIGN_DOWN(((rt_ubase_t)retcode), sizeof(rt_ubase_t));
+
+ /**
+ * x86 call stack
+ *
+ * retcode here
+ *
+ * arg n
+ * arg n - 1
+ * ...
+ * arg 2
+ * arg 1
+ * arg 0
+ * eip (caller return addr, point to retcode)
+ * esp
+ */
+ *(--retstack) = (unsigned long) args; /* arg */
+ *(--retstack) = (unsigned long) retcode; /* ret eip */
+
+ frame->esp = (rt_uint32_t)retstack;
+ frame->eip = (rt_uint32_t)text;
+ lwp_switch_to_user(frame);
+ /* should never return */
+}
+
+rt_thread_t rt_thread_sp_to_thread(void *spmember_addr)
+{
+ return (rt_thread_t)(((rt_ubase_t)spmember_addr) - (offsetof(struct rt_thread, sp)));
+}
+
+/**
+ * set exec context for fork/clone.
+ * user_stack(unused)
+ */
+void arch_set_thread_context(void *exit_addr, void *new_thread_stack, void *user_stack, void **thread_sp)
+{
+ /**
+ * thread kernel stack was set to tss.esp0, when intrrupt/syscall occur,
+ * the stack frame will store in kernel stack top, so we can get the stack
+ * frame by kernel stack top.
+ */
+ rt_hw_stack_frame_t *frame = (rt_hw_stack_frame_t *)((rt_ubase_t)new_thread_stack - sizeof(rt_hw_stack_frame_t));
+
+ frame->eax = 0; /* child return 0 */
+
+ rt_hw_context_t *context = (rt_hw_context_t *) (((rt_uint32_t *)frame) - HW_CONTEXT_MEMBER_NR);
+ context->eip = (void *)exit_addr; /* when thread started, jump to intr exit for enter user mode */
+ context->ebp = context->ebx = context->esi = context->edi = 0;
+
+ /**
+ * set sp as the address of first member of rt_hw_context,
+ * when scheduler call switch, pop stack from context stack.
+ */
+ *thread_sp = (void *)&context->ebp;
+
+ /**
+ * after set context, the stack like this:
+ *
+ * -----------
+ * stack frame| eax = 0
+ * -----------
+ * context(only HW_CONTEXT_MEMBER_NR)| eip = rt_hw_intr_exit
+ * -----------
+ * thread sp | to <- rt_hw_context_switch(from, to)
+ * -----------
+ */
+}
+
+#ifdef RT_USING_SIGNALS
+
+#define SIGNAL_RET_CODE_SIZE 16
+
+struct rt_signal_frame
+{
+ char *ret_addr; /* return addr when handler return */
+ int signo; /* signal for user handler arg */
+ rt_hw_stack_frame_t frame; /* save kernel signal stack */
+ char ret_code[SIGNAL_RET_CODE_SIZE]; /* save return code */
+};
+typedef struct rt_signal_frame rt_signal_frame_t;
+
+extern void lwp_signal_return();
+extern void lwp_signal_return_end();
+
+void lwp_try_do_signal(rt_hw_stack_frame_t *frame)
+{
+ if (!lwp_signal_check())
+ return;
+
+ /* 1. backup signal mask */
+ int signal = lwp_signal_backup((void *) frame->esp, (void *) frame->eip, (void *) frame->eflags);
+
+ /* 2. get signal handler */
+ lwp_sighandler_t handler = lwp_sighandler_get(signal);
+ if (handler == RT_NULL) /* no handler, ignore */
+ {
+ lwp_signal_restore();
+ return;
+ }
+
+ rt_base_t level = rt_hw_interrupt_disable();
+ /* 3. backup frame */
+ rt_signal_frame_t *sig_frame = (rt_signal_frame_t *)((frame->esp - sizeof(rt_signal_frame_t)) & -8UL);
+ memcpy(&sig_frame->frame, frame, sizeof(rt_hw_stack_frame_t));
+ sig_frame->signo = signal;
+
+ /**
+ * 4. copy user return code into user stack
+ *
+ * save current frame on user stack. the user stack like:
+ *
+ * ----------
+ * user code stack
+ * ----------+ -> esp before enter kernel
+ * signal frame
+ * ----------+ -> esp when handle signal handler
+ * signal handler stack
+ * ----------
+ */
+ size_t ret_code_size = (size_t)lwp_signal_return_end - (size_t)lwp_signal_return;
+ memcpy(sig_frame->ret_code, (void *)lwp_signal_return, ret_code_size);
+ sig_frame->ret_addr = sig_frame->ret_code;
+
+ /* 5. jmp to user execute handler, update frame register info */
+ lwp_user_stack_init(frame);
+ frame->eip = (rt_uint32_t) handler;
+ frame->esp = (rt_uint32_t) sig_frame;
+
+ rt_hw_interrupt_enable(level);
+}
+
+void lwp_signal_do_return(rt_hw_stack_frame_t *frame)
+{
+ /**
+ * ASSUME: in x86, each stack push and pop element is 4 byte. so STACK_ELEM_SIZE = sizeof(int) => 4.
+ * when signal handler return, the stack move to the buttom of signal frame.
+ * but return will pop eip from esp, then {esp += STACK_ELEM_SIZE}, thus {esp = (signal frame) + STACK_ELEM_SIZE}.
+ * so {(signal frame) = esp - STACK_ELEM_SIZE}
+ */
+ rt_signal_frame_t *sig_frame = (rt_signal_frame_t *)(frame->esp - sizeof(rt_uint32_t));
+ memcpy(frame, &sig_frame->frame, sizeof(rt_hw_stack_frame_t));
+
+ /**
+ * restore signal info, but don't use rt_user_context,
+ * we use sig_frame to restore stack frame
+ */
+ lwp_signal_restore();
+}
+#endif /* RT_USING_SIGNALS */
+
+#endif /* RT_USING_USERSPACE */
diff --git a/components/lwp/arch/x86/i386/lwp_arch.h b/components/lwp/arch/x86/i386/lwp_arch.h
new file mode 100644
index 0000000000..f9a56ca3f5
--- /dev/null
+++ b/components/lwp/arch/x86/i386/lwp_arch.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-07-18 JasonHu first version
+ */
+
+#ifndef LWP_ARCH_H__
+#define LWP_ARCH_H__
+
+#include <lwp.h>
+#include <lwp_arch_comm.h>
+#include <stackframe.h>
+
+#ifdef RT_USING_USERSPACE
+#define USER_VADDR_TOP 0xFFFFF000UL
+#define USER_HEAP_VEND 0xE0000000UL
+#define USER_HEAP_VADDR 0x90000000UL
+#define USER_STACK_VSTART 0x80000000UL
+#define USER_STACK_VEND USER_HEAP_VADDR
+#define LDSO_LOAD_VADDR 0x70000000UL
+#define USER_VADDR_START 0x40000000UL
+#define USER_LOAD_VADDR USER_VADDR_START
+
+#define SIGNAL_RETURN_SYSCAL_ID 0xe000
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+rt_thread_t rt_thread_sp_to_thread(void *spmember_addr);
+
+void lwp_signal_do_return(rt_hw_stack_frame_t *frame);
+
+rt_inline unsigned long rt_hw_ffz(unsigned long x)
+{
+ return __builtin_ffsl(~x) - 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RT_USING_USERSPACE */
+
+#endif /*LWP_ARCH_H__*/
diff --git a/components/lwp/arch/x86/i386/lwp_gcc.S b/components/lwp/arch/x86/i386/lwp_gcc.S
new file mode 100644
index 0000000000..c1245ebe11
--- /dev/null
+++ b/components/lwp/arch/x86/i386/lwp_gcc.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-7-14 JasonHu first version
+ */
+
+#include "rtconfig.h"
+
+.section .text.lwp
+
+/*
+ * void lwp_switch_to_user(frame);
+ */
+.global lwp_switch_to_user
+lwp_switch_to_user:
+ movl 0x4(%esp), %esp
+ addl $4,%esp // skip intr no
+ popal
+ popl %gs
+ popl %fs
+ popl %es
+ popl %ds
+ addl $4, %esp // skip error_code
+ iret // enter to user mode
+
+.extern arch_syscall_exit
+.global sys_fork
+.global sys_vfork
+.global arch_fork_exit
+sys_fork:
+sys_vfork:
+ jmp _sys_fork
+arch_fork_exit:
+ jmp arch_syscall_exit
+
+.global sys_clone
+.global arch_clone_exit
+sys_clone:
+ jmp _sys_clone
+arch_clone_exit:
+ jmp arch_syscall_exit
+
+/**
+ * rt thread return code
+ */
+.align 4
+.global lwp_thread_return
+lwp_thread_return:
+ movl $1, %eax // eax = 1, sys_exit
+ movl $0, %ebx
+ int $0x80
+.align 4
+.global lwp_thread_return_end
+lwp_thread_return_end:
+
+#ifdef RT_USING_SIGNALS
+/**
+ * signal return code
+ */
+.align 4
+.global lwp_signal_return
+lwp_signal_return:
+ movl $0xe000, %eax // special syscall id for return code
+ int $0x80
+.align 4
+.global lwp_signal_return_end
+lwp_signal_return_end:
+
+#endif /* RT_USING_SIGNALS */
diff --git a/components/lwp/arch/x86/i386/reloc.c b/components/lwp/arch/x86/i386/reloc.c
new file mode 100644
index 0000000000..9677bd65c6
--- /dev/null
+++ b/components/lwp/arch/x86/i386/reloc.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-07-28 JasonHu first version
+ */
+
+#include <rtthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <elf.h>
+#ifdef RT_USING_USERSPACE
+#include <mmu.h>
+#include <page.h>
+#endif
+
+typedef struct
+{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_sym;
+
+#ifdef RT_USING_USERSPACE
+void arch_elf_reloc(rt_mmu_info *m_info, void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym)
+{
+
+}
+#else
+
+void arch_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym)
+{
+
+}
+#endif
diff --git a/components/lwp/ioremap.c b/components/lwp/ioremap.c
new file mode 100644
index 0000000000..7bdd187103
--- /dev/null
+++ b/components/lwp/ioremap.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-06 Jesven first version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+
+#include <ioremap.h>
+
+#ifdef RT_USING_USERSPACE
+#include <mmu.h>
+#include <lwp_mm_area.h>
+#include <lwp_mm.h>
+
+static struct lwp_avl_struct *k_map_area;
+extern rt_mmu_info mmu_info;
+
+static void _iounmap_range(void *addr, size_t size)
+{
+ void *va = RT_NULL, *pa = RT_NULL;
+ int i = 0;
+
+ for (va = addr, i = 0; i < size; va = (void *)((char *)va + ARCH_PAGE_SIZE), i += ARCH_PAGE_SIZE)
+ {
+ pa = rt_hw_mmu_v2p(&mmu_info, va);
+ if (pa)
+ {
+ rt_hw_mmu_unmap(&mmu_info, va, ARCH_PAGE_SIZE);
+ }
+ }
+}
+
+static void *_ioremap_type(void *paddr, size_t size, int type)
+{
+ void *v_addr = NULL;
+ size_t attr;
+
+ switch (type)
+ {
+ case MM_AREA_TYPE_PHY:
+ attr = MMU_MAP_K_DEVICE;
+ break;
+ case MM_AREA_TYPE_PHY_CACHED:
+ attr = MMU_MAP_K_RWCB;
+ break;
+ default:
+ return v_addr;
+ }
+
+ rt_mm_lock();
+ v_addr = rt_hw_mmu_map(&mmu_info, 0, paddr, size, attr);
+ if (v_addr)
+ {
+ int ret = lwp_map_area_insert(&k_map_area, (size_t)v_addr, size, type);
+ if (ret != 0)
+ {
+ _iounmap_range(v_addr, size);
+ v_addr = NULL;
+ }
+ }
+ rt_mm_unlock();
+ return v_addr;
+}
+
+void *rt_ioremap(void *paddr, size_t size)
+{
+ return _ioremap_type(paddr, size, MM_AREA_TYPE_PHY);
+}
+
+void *rt_ioremap_nocache(void *paddr, size_t size)
+{
+ return _ioremap_type(paddr, size, MM_AREA_TYPE_PHY);
+}
+
+void *rt_ioremap_cached(void *paddr, size_t size)
+{
+ return _ioremap_type(paddr, size, MM_AREA_TYPE_PHY_CACHED);
+}
+
+void rt_iounmap(volatile void *vaddr)
+{
+ struct lwp_avl_struct *ma_avl_node;
+
+ rt_mm_lock();
+ ma_avl_node = lwp_map_find(k_map_area, (size_t)vaddr);
+ if (ma_avl_node)
+ {
+ struct rt_mm_area_struct *ma = (struct rt_mm_area_struct *)ma_avl_node->data;
+
+ _iounmap_range((void *)ma->addr, ma->size);
+ lwp_map_area_remove(&k_map_area, (size_t)vaddr);
+ }
+ rt_mm_unlock();
+}
+
+#else
+void *rt_ioremap(void *paddr, size_t size)
+{
+ return paddr;
+}
+
+void *rt_ioremap_nocache(void *paddr, size_t size)
+{
+ return paddr;
+}
+
+void *rt_ioremap_cached(void *paddr, size_t size)
+{
+ return paddr;
+}
+
+void rt_iounmap(volatile void *vaddr)
+{
+}
+#endif
diff --git a/components/lwp/ioremap.h b/components/lwp/ioremap.h
new file mode 100644
index 0000000000..a2d64523f1
--- /dev/null
+++ b/components/lwp/ioremap.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-06 Jesven first version
+ */
+#ifndef __IOREMAP_H__
+#define __IOREMAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *rt_ioremap(void *paddr, size_t size);
+void *rt_ioremap_nocache(void *paddr, size_t size);
+void *rt_ioremap_cached (void *paddr, size_t size);
+void rt_iounmap(volatile void *addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__LWP_IOREMAP_H__*/
diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c
index 4b91538b68..c59d1c8261 100644
--- a/components/lwp/lwp.c
+++ b/components/lwp/lwp.c
@@ -7,375 +7,1374 @@
* Date Author Notes
* 2006-03-12 Bernard first version
* 2018-11-02 heyuanjie fix complie error in iar
+ * 2021-02-03 lizhirui add 64-bit arch support and riscv64 arch support
+ * 2021-08-26 linzhenxing add lwp_setcwd\lwp_getcwd
*/
-#include <rtthread.h>
#include <rthw.h>
+#include <rtthread.h>
+
#include <dfs_file.h>
#include <unistd.h>
+#include <stdio.h> /* rename() */
+#include <fcntl.h>
#include <sys/stat.h>
-#include <sys/statfs.h>
+#include <sys/statfs.h> /* statfs() */
+
+#include <lwp_elf.h>
#ifndef RT_USING_DFS
- #error "lwp need file system(RT_USING_DFS)"
+#error "lwp need file system(RT_USING_DFS)"
#endif
#include "lwp.h"
+#include "lwp_arch.h"
+#include "lwp_arch_comm.h"
+#include "console.h"
-#define DBG_TAG "LWP"
-#define DBG_LVL DBG_WARNING
+#define DBG_TAG "LWP"
+#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
-extern void lwp_user_entry(void *args, const void *text, void *data);
+#ifdef RT_USING_USERSPACE
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#endif /* end of RT_USING_USERSPACE */
+
+
+#ifndef O_DIRECTORY
+#define O_DIRECTORY 0x200000
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0x10000
+#endif
+
+
+static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
+#ifdef DFS_USING_WORKDIR
+extern char working_directory[];
+#endif
+static struct termios stdin_termios, old_stdin_termios;
+
+int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]);
+
+struct termios *get_old_termios(void)
+{
+ return &old_stdin_termios;
+}
+
+void lwp_setcwd(char *buf)
+{
+ struct rt_lwp *lwp = RT_NULL;
+
+ if(strlen(buf) >= DFS_PATH_MAX)
+ {
+ rt_kprintf("buf too long!\n");
+ return ;
+ }
+
+ lwp = (struct rt_lwp *)rt_thread_self()->lwp;
+ if (lwp)
+ {
+ rt_strncpy(lwp->working_directory, buf, DFS_PATH_MAX);
+ }
+ else
+ {
+ rt_strncpy(working_directory, buf, DFS_PATH_MAX);
+ }
+
+ return ;
+}
+
+char *lwp_getcwd(void)
+{
+ char *dir_buf = RT_NULL;
+ struct rt_lwp *lwp = RT_NULL;
+
+ lwp = (struct rt_lwp *)rt_thread_self()->lwp;
+ if (lwp)
+ {
+ if(lwp->working_directory[0] != '/')
+ {
+ dir_buf = &working_directory[0];
+ }
+ else
+ {
+ dir_buf = &lwp->working_directory[0];
+ }
+ }
+ else
+ dir_buf = &working_directory[0];
+
+ return dir_buf;
+}
/**
* RT-Thread light-weight process
*/
void lwp_set_kernel_sp(uint32_t *sp)
{
- struct rt_lwp *user_data;
- user_data = (struct rt_lwp *)rt_thread_self()->lwp;
- user_data->kernel_sp = sp;
+ rt_thread_self()->kernel_sp = (rt_uint32_t *)sp;
}
uint32_t *lwp_get_kernel_sp(void)
{
- struct rt_lwp *user_data;
- user_data = (struct rt_lwp *)rt_thread_self()->lwp;
-
- return user_data->kernel_sp;
+#ifdef RT_USING_USERSPACE
+ return (uint32_t *)rt_thread_self()->sp;
+#else
+ uint32_t* kernel_sp;
+ extern rt_uint32_t rt_interrupt_from_thread;
+ extern rt_uint32_t rt_thread_switch_interrupt_flag;
+ if (rt_thread_switch_interrupt_flag)
+ {
+ kernel_sp = (uint32_t *)((rt_thread_t)rt_container_of(rt_interrupt_from_thread, struct rt_thread, sp))->kernel_sp;
+ }
+ else
+ {
+ kernel_sp = (uint32_t *)rt_thread_self()->kernel_sp;
+ }
+ return kernel_sp;
+#endif
}
-static int lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv)
+#ifdef RT_USING_USERSPACE
+struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
+{
+ int size = sizeof(size_t) * 5; /* store argc, argv, envp, aux, NULL */
+ int *args;
+ char *str;
+ char *str_k;
+ char **new_argve;
+ int i;
+ int len;
+ size_t *args_k;
+ struct process_aux *aux;
+
+ for (i = 0; i < argc; i++)
+ {
+ size += (rt_strlen(argv[i]) + 1);
+ }
+ size += (sizeof(size_t) * argc);
+
+ i = 0;
+ if (envp)
+ {
+ while (envp[i] != 0)
+ {
+ size += (rt_strlen(envp[i]) + 1);
+ size += sizeof(size_t);
+ i++;
+ }
+ }
+
+ /* for aux */
+ size += sizeof(struct process_aux);
+
+ if (size > ARCH_PAGE_SIZE)
+ {
+ return RT_NULL;
+ }
+
+ /* args = (int *)lwp_map_user(lwp, 0, size); */
+ args = (int *)lwp_map_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE), size, 0);
+ if (args == RT_NULL)
+ {
+ return RT_NULL;
+ }
+
+ args_k = (size_t *)rt_hw_mmu_v2p(&lwp->mmu_info, args);
+ args_k = (size_t *)((size_t)args_k - PV_OFFSET);
+
+ /* argc, argv[], 0, envp[], 0 , aux[] */
+ str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(size_t));
+ str_k = (char *)((size_t)args_k + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(size_t));
+
+ new_argve = (char **)&args_k[1];
+ args_k[0] = argc;
+
+ for (i = 0; i < argc; i++)
+ {
+ len = rt_strlen(argv[i]) + 1;
+ new_argve[i] = str;
+ rt_memcpy(str_k, argv[i], len);
+ str += len;
+ str_k += len;
+ }
+ new_argve[i] = 0;
+ i++;
+
+ new_argve[i] = 0;
+ if (envp)
+ {
+ int j;
+
+ for (j = 0; envp[j] != 0; j++)
+ {
+ len = rt_strlen(envp[j]) + 1;
+ new_argve[i] = str;
+ rt_memcpy(str_k, envp[j], len);
+ str += len;
+ str_k += len;
+ i++;
+ }
+ new_argve[i] = 0;
+ }
+ i++;
+
+ /* aux */
+ aux = (struct process_aux *)(new_argve + i);
+ aux->item[0].key = AT_EXECFN;
+ aux->item[0].value = (size_t)(size_t)new_argve[0];
+ i += AUX_ARRAY_ITEMS_NR * 2;
+ new_argve[i] = 0;
+
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, args_k, size);
+
+ lwp->args = args;
+
+ return aux;
+}
+#else
+static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
{
- int size = sizeof(int)*3; /* store argc, argv, NULL */
+#ifdef ARCH_MM_MMU
+ int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */
+ struct process_aux *aux;
+#else
+ int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */
+#endif /* ARCH_MM_MMU */
int *args;
char *str;
- char **new_argv;
+ char **new_argve;
int i;
int len;
- for (i = 0; i < argc; i ++)
+ for (i = 0; i < argc; i++)
{
size += (rt_strlen(argv[i]) + 1);
}
- size += (sizeof(int) * argc);
+ size += (sizeof(int) * argc);
- args = (int*)rt_malloc(size);
+ i = 0;
+ if (envp)
+ {
+ while (envp[i] != 0)
+ {
+ size += (rt_strlen(envp[i]) + 1);
+ size += sizeof(int);
+ i++;
+ }
+ }
+
+#ifdef ARCH_MM_MMU
+ /* for aux */
+ size += sizeof(struct process_aux);
+
+ args = (int *)rt_malloc(size);
if (args == RT_NULL)
- return -1;
+ {
+ return RT_NULL;
+ }
- str = (char*)((int)args + (argc + 3) * sizeof(int));
- new_argv = (char**)&args[2];
+ /* argc, argv[], 0, envp[], 0 */
+ str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int));
+#else
+ args = (int *)rt_malloc(size);
+ if (args == RT_NULL)
+ {
+ return RT_NULL;
+ }
+ str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int));
+#endif /* ARCH_MM_MMU */
+
+ new_argve = (char **)&args[1];
args[0] = argc;
- args[1] = (int)new_argv;
- for (i = 0; i < argc; i ++)
+ for (i = 0; i < argc; i++)
{
len = rt_strlen(argv[i]) + 1;
- new_argv[i] = str;
+ new_argve[i] = str;
rt_memcpy(str, argv[i], len);
str += len;
}
- new_argv[i] = 0;
+ new_argve[i] = 0;
+ i++;
+
+ new_argve[i] = 0;
+ if (envp)
+ {
+ int j;
+ for (j = 0; envp[j] != 0; j++)
+ {
+ len = rt_strlen(envp[j]) + 1;
+ new_argve[i] = str;
+ rt_memcpy(str, envp[j], len);
+ str += len;
+ i++;
+ }
+ new_argve[i] = 0;
+ }
+#ifdef ARCH_MM_MMU
+ /* aux */
+ aux = (struct process_aux *)(new_argve + i);
+ aux->item[0].key = AT_EXECFN;
+ aux->item[0].value = (uint32_t)(size_t)new_argve[0];
+ i += AUX_ARRAY_ITEMS_NR * 2;
+ new_argve[i] = 0;
+
lwp->args = args;
- return 0;
+ return aux;
+#else
+ lwp->args = args;
+ lwp->args_length = size;
+
+ return (struct process_aux *)(new_argve + i);
+#endif /* ARCH_MM_MMU */
}
+#endif
+
+#ifdef ARCH_MM_MMU
+#define check_off(voff, vlen) \
+ do \
+ { \
+ if (voff > vlen) \
+ { \
+ result = -RT_ERROR; \
+ goto _exit; \
+ } \
+ } while (0)
+
+#define check_read(vrlen, vrlen_want) \
+ do \
+ { \
+ if (vrlen < vrlen_want) \
+ { \
+ result = -RT_ERROR; \
+ goto _exit; \
+ } \
+ } while (0)
-static int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size)
+static size_t load_fread(void *ptr, size_t size, size_t nmemb, int fd)
{
- int fd;
- uint8_t *ptr;
- int result = RT_EOK;
- int nbytes;
- struct lwp_header header;
- struct lwp_chunk chunk;
+ size_t read_block = 0;
- /* check file name */
- RT_ASSERT(filename != RT_NULL);
- /* check lwp control block */
- RT_ASSERT(lwp != RT_NULL);
+ while (nmemb)
+ {
+ size_t count;
- if (load_addr != RT_NULL)
+ count = read(fd, ptr, size * nmemb) / size;
+ if (count < nmemb)
+ {
+ LOG_E("ERROR: file size error!");
+ break;
+ }
+
+ ptr = (void *)((uint8_t *)ptr + (count * size));
+ nmemb -= count;
+ read_block += count;
+ }
+
+ return read_block;
+}
+
+typedef struct
+{
+ Elf_Word st_name;
+ Elf_Addr st_value;
+ Elf_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf_Half st_shndx;
+} Elf_sym;
+
+#ifdef RT_USING_USERSPACE
+struct map_range
+{
+ void *start;
+ size_t size;
+};
+
+static void expand_map_range(struct map_range *m, void *start, size_t size)
+{
+ if (!m->start)
{
- lwp->lwp_type = LWP_TYPE_FIX_ADDR;
- ptr = load_addr;
+ m->start = start;
+ m->size = size;
}
else
{
- lwp->lwp_type = LWP_TYPE_DYN_ADDR;
- ptr = RT_NULL;
+ void *end = (void *)((char*)start + size);
+ void *mend = (void *)((char*)m->start + m->size);
+
+ if (m->start > start)
+ {
+ m->start = start;
+ }
+ if (mend < end)
+ {
+ mend = end;
+ }
+ m->size = (char *)mend - (char *)m->start;
}
+}
- /* open lwp */
- fd = open(filename, 0, O_RDONLY);
- if (fd < 0)
+static int map_range_ckeck(struct map_range *m1, struct map_range *m2)
+{
+ void *m1_start = (void *)((size_t)m1->start & ~ARCH_PAGE_MASK);
+ void *m1_end = (void *)((((size_t)m1->start + m1->size) + ARCH_PAGE_MASK) & ~ARCH_PAGE_MASK);
+ void *m2_start = (void *)((size_t)m2->start & ~ARCH_PAGE_MASK);
+ void *m2_end = (void *)((((size_t)m2->start + m2->size) + ARCH_PAGE_MASK) & ~ARCH_PAGE_MASK);
+
+ if (m1->size)
+ {
+ if (m1_start < (void *)USER_LOAD_VADDR)
+ {
+ return -1;
+ }
+ if (m1_start > (void *)USER_STACK_VSTART)
+ {
+ return -1;
+ }
+ if (m1_end < (void *)USER_LOAD_VADDR)
+ {
+ return -1;
+ }
+ if (m1_end > (void *)USER_STACK_VSTART)
+ {
+ return -1;
+ }
+ }
+ if (m2->size)
+ {
+ if (m2_start < (void *)USER_LOAD_VADDR)
+ {
+ return -1;
+ }
+ if (m2_start > (void *)USER_STACK_VSTART)
+ {
+ return -1;
+ }
+ if (m2_end < (void *)USER_LOAD_VADDR)
+ {
+ return -1;
+ }
+ if (m2_end > (void *)USER_STACK_VSTART)
+ {
+ return -1;
+ }
+ }
+
+ if ((m1->size != 0) && (m2->size != 0))
{
- dbg_log(DBG_ERROR, "open file:%s failed!\n", filename);
- result = -RT_ENOSYS;
- goto _exit;
+ if (m1_start < m2_start)
+ {
+ if (m1_end > m2_start)
+ {
+ return -1;
+ }
+ }
+ else /* m2_start <= m1_start */
+ {
+ if (m2_end > m1_start)
+ {
+ return -1;
+ }
+ }
}
+ return 0;
+}
+#endif
- /* read lwp header */
- nbytes = read(fd, &header, sizeof(struct lwp_header));
- if (nbytes != sizeof(struct lwp_header))
+static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, struct process_aux *aux)
+{
+ uint32_t i;
+ uint32_t off = 0;
+ size_t load_off = 0;
+ char *p_section_str = 0;
+ Elf_sym *dynsym = 0;
+ Elf_Ehdr eheader;
+ Elf_Phdr pheader;
+ Elf_Shdr sheader;
+ int result = RT_EOK;
+ uint32_t magic;
+ size_t read_len;
+ void *got_start = 0;
+ size_t got_size = 0;
+ void *rel_dyn_start = 0;
+ size_t rel_dyn_size = 0;
+ size_t dynsym_off = 0;
+ size_t dynsym_size = 0;
+#ifdef RT_USING_USERSPACE
+ struct map_range user_area[2] = {{NULL, 0}, {NULL, 0}}; /* 0 is text, 1 is data */
+ void *pa, *va;
+ void *va_self;
+
+ rt_mmu_info *m_info = &lwp->mmu_info;
+#endif
+
+ if (len < sizeof eheader)
{
- dbg_log(DBG_ERROR, "read lwp header return error size: %d!\n", nbytes);
- result = -RT_EIO;
- goto _exit;
+ LOG_E("len < sizeof eheader!");
+ return -RT_ERROR;
}
- /* check file header */
- if (header.magic != LWP_MAGIC)
+ lseek(fd, 0, SEEK_SET);
+ read_len = load_fread(&magic, 1, sizeof magic, fd);
+ check_read(read_len, sizeof magic);
+
+ if (memcmp(elf_magic, &magic, 4) != 0)
{
- dbg_log(DBG_ERROR, "erro header magic number: 0x%02X\n", header.magic);
- result = -RT_EINVAL;
- goto _exit;
+ LOG_E("elf_magic not same, magic:0x%x!", magic);
+ return -RT_ERROR;
+ }
+
+ lseek(fd, off, SEEK_SET);
+ read_len = load_fread(&eheader, 1, sizeof eheader, fd);
+ check_read(read_len, sizeof eheader);
+
+#ifndef ARCH_CPU_64BIT
+ if (eheader.e_ident[4] != 1)
+ { /* not 32bit */
+ LOG_E("elf not 32bit, %d!", eheader.e_ident[4]);
+ return -RT_ERROR;
+ }
+#else
+ if (eheader.e_ident[4] != 2)
+ { /* not 64bit */
+ LOG_E("elf not 64bit, %d!", eheader.e_ident[4]);
+ return -RT_ERROR;
+ }
+#endif
+
+ if (eheader.e_ident[6] != 1)
+ { /* ver not 1 */
+ LOG_E("elf Version not 1,ver:%d!", eheader.e_ident[6]);
+ return -RT_ERROR;
}
- /* read text chunk info */
- nbytes = read(fd, &chunk, sizeof(struct lwp_chunk));
- if (nbytes != sizeof(struct lwp_chunk))
+ if ((eheader.e_type != ET_DYN)
+#ifdef RT_USING_USERSPACE
+ && (eheader.e_type != ET_EXEC)
+#endif
+ )
{
- dbg_log(DBG_ERROR, "read text chunk info failed!\n");
- result = -RT_EIO;
- goto _exit;
+ /* not pie or exec elf */
+ LOG_E("elf type not pie or exec, type:%d!", eheader.e_type);
+ return -RT_ERROR;
}
- dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n",
- "text", /*chunk.name*/ chunk.total_len, chunk.data_len, chunk.data_len_space);
+#ifdef RT_USING_USERSPACE
+ {
+ off = eheader.e_phoff;
+ for (i = 0; i < eheader.e_phnum; i++, off += sizeof pheader)
+ {
+ check_off(off, len);
+ lseek(fd, off, SEEK_SET);
+ read_len = load_fread(&pheader, 1, sizeof pheader, fd);
+ check_read(read_len, sizeof pheader);
- /* load text */
+ if (pheader.p_type == PT_DYNAMIC)
+ {
+ /* load ld.so */
+ return 1; /* 1 means dynamic */
+ }
+ }
+ }
+#endif
+
+ if (eheader.e_entry != 0)
{
- lwp->text_size = RT_ALIGN(chunk.data_len_space, 4);
- if (load_addr)
- lwp->text_entry = ptr;
- else
+ if ((eheader.e_entry != USER_LOAD_VADDR)
+ && (eheader.e_entry != LDSO_LOAD_VADDR))
{
-#ifdef RT_USING_CACHE
- lwp->text_entry = (rt_uint8_t *)rt_malloc_align(lwp->text_size, RT_CPU_CACHE_LINE_SZ);
+ /* the entry is invalidate */
+ LOG_E("elf entry is invalidate, entry:0x%x!", eheader.e_entry);
+ return -RT_ERROR;
+ }
+ }
+
+ { /* load aux */
+ uint8_t *process_header;
+ size_t process_header_size;
+
+ off = eheader.e_phoff;
+ process_header_size = eheader.e_phnum * sizeof pheader;
+#ifdef RT_USING_USERSPACE
+ if (process_header_size > ARCH_PAGE_SIZE - sizeof(char[16]))
+ {
+ LOG_E("process_header_size too big, size:0x%x!", process_header_size);
+ return -RT_ERROR;
+ }
+ va = (uint8_t *)lwp_map_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), process_header_size, 0);
+ if (!va)
+ {
+ LOG_E("lwp map user failed!");
+ return -RT_ERROR;
+ }
+ pa = rt_hw_mmu_v2p(m_info, va);
+ process_header = (uint8_t *)pa - PV_OFFSET;
+#else
+ process_header = (uint8_t *)rt_malloc(process_header_size + sizeof(char[16]));
+ if (!process_header)
+ {
+ LOG_E("process_header malloc failed, size:0x%x!", process_header_size + sizeof(char[16]));
+ return -RT_ERROR;
+ }
+#endif
+ check_off(off, len);
+ lseek(fd, off, SEEK_SET);
+ read_len = load_fread(process_header, 1, process_header_size, fd);
+ check_read(read_len, process_header_size);
+#ifdef RT_USING_USERSPACE
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, process_header, process_header_size);
+#endif
+
+ aux->item[1].key = AT_PAGESZ;
+#ifdef RT_USING_USERSPACE
+ aux->item[1].value = ARCH_PAGE_SIZE;
#else
- lwp->text_entry = (rt_uint8_t *)rt_malloc(lwp->text_size);
+ aux->item[1].value = RT_MM_PAGE_SIZE;
#endif
+ aux->item[2].key = AT_RANDOM;
+ {
+ uint32_t random_value = rt_tick_get();
+ uint8_t *random;
+#ifdef RT_USING_USERSPACE
+ uint8_t *krandom;
+
+ random = (uint8_t *)(USER_VADDR_TOP - ARCH_PAGE_SIZE - sizeof(char[16]));
- if (lwp->text_entry == RT_NULL)
+ krandom = (uint8_t *)rt_hw_mmu_v2p(m_info, random);
+ krandom = (uint8_t *)krandom - PV_OFFSET;
+ rt_memcpy(krandom, &random_value, sizeof random_value);
+#else
+ random = (uint8_t *)(process_header + process_header_size);
+ rt_memcpy(random, &random_value, sizeof random_value);
+#endif
+ aux->item[2].value = (size_t)random;
+ }
+ aux->item[3].key = AT_PHDR;
+#ifdef RT_USING_USERSPACE
+ aux->item[3].value = (size_t)va;
+#else
+ aux->item[3].value = (size_t)process_header;
+#endif
+ aux->item[4].key = AT_PHNUM;
+ aux->item[4].value = eheader.e_phnum;
+ aux->item[5].key = AT_PHENT;
+ aux->item[5].value = sizeof pheader;
+#ifdef RT_USING_USERSPACE
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, aux, sizeof *aux);
+#endif
+ }
+
+ if (load_addr)
+ {
+ load_off = (size_t)load_addr;
+ }
+#ifdef RT_USING_USERSPACE
+ else
+ {
+ /* map user */
+ off = eheader.e_shoff;
+ for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
+ {
+ check_off(off, len);
+ lseek(fd, off, SEEK_SET);
+ read_len = load_fread(&sheader, 1, sizeof sheader, fd);
+ check_read(read_len, sizeof sheader);
+
+ if ((sheader.sh_flags & SHF_ALLOC) == 0)
{
- dbg_log(DBG_ERROR, "alloc text memory faild!\n");
- result = -RT_ENOMEM;
- goto _exit;
+ continue;
}
- else
+
+ switch (sheader.sh_type)
{
- dbg_log(DBG_LOG, "lwp text malloc : %p, size: %d!\n", lwp->text_entry, lwp->text_size);
+ case SHT_PROGBITS:
+ if ((sheader.sh_flags & SHF_WRITE) == 0)
+ {
+ expand_map_range(&user_area[0], (void *)sheader.sh_addr, sheader.sh_size);
+ }
+ else
+ {
+ expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size);
+ }
+ break;
+ case SHT_NOBITS:
+ expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size);
+ break;
+ default:
+ expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size);
+ break;
}
}
- dbg_log(DBG_INFO, "load text %d => (0x%08x, 0x%08x)\n", lwp->text_size, (uint32_t)lwp->text_entry, (uint32_t)lwp->text_entry + lwp->text_size);
- nbytes = read(fd, lwp->text_entry, chunk.data_len);
- if (nbytes != chunk.data_len)
+ if (user_area[0].size == 0)
{
- dbg_log(DBG_ERROR, "read text region from file failed!\n");
- result = -RT_EIO;
+ /* no code */
+ result = -RT_ERROR;
goto _exit;
}
-#ifdef RT_USING_CACHE
- else
+
+ if (user_area[0].start == NULL)
{
- rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size);
- rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size);
+ /* DYN */
+ load_off = USER_LOAD_VADDR;
+ user_area[0].start = (void *)((char*)user_area[0].start + load_off);
+ user_area[1].start = (void *)((char*)user_area[1].start + load_off);
}
-#endif
- if (ptr != RT_NULL) ptr += nbytes;
+ if (map_range_ckeck(&user_area[0], &user_area[1]) != 0)
+ {
+ result = -RT_ERROR;
+ goto _exit;
+ }
- /* skip text hole */
- if ((chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len))
+ /* text and data */
+ for (i = 0; i < 2; i++)
{
- dbg_log(DBG_LOG, "skip text hole %d!\n", (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len));
- lseek(fd, (chunk.total_len - sizeof(struct lwp_chunk) - chunk.data_len), SEEK_CUR);
+ if (user_area[i].size != 0)
+ {
+ va = lwp_map_user(lwp, user_area[i].start, user_area[i].size, (int)(i == 0));
+ if (!va || (va != user_area[i].start))
+ {
+ result = -RT_ERROR;
+ goto _exit;
+ }
+ }
}
+ lwp->text_size = user_area[0].size;
}
-
- /* load data */
- nbytes = read(fd, &chunk, sizeof(struct lwp_chunk));
- if (nbytes != sizeof(struct lwp_chunk))
+#else
+ else
{
- dbg_log(DBG_ERROR, "read data chunk info failed!\n");
- result = -RT_EIO;
- goto _exit;
- }
-
- dbg_log(DBG_LOG, "chunk name: %s, total len %d, data %d, need space %d!\n",
- chunk.name, chunk.total_len, chunk.data_len, chunk.data_len_space);
+ size_t start = -1UL;
+ size_t end = 0UL;
+ size_t total_size;
- {
- lwp->data_size = RT_ALIGN(chunk.data_len_space, 4);
- if (load_addr)
- lwp->data = ptr;
- else
+ off = eheader.e_shoff;
+ for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
{
- lwp->data = rt_malloc(lwp->data_size);
- if (lwp->data == RT_NULL)
+ check_off(off, len);
+ lseek(fd, off, SEEK_SET);
+ read_len = load_fread(&sheader, 1, sizeof sheader, fd);
+ check_read(read_len, sizeof sheader);
+
+ if ((sheader.sh_flags & SHF_ALLOC) == 0)
{
- dbg_log(DBG_ERROR, "alloc data memory faild!\n");
- result = -RT_ENOMEM;
- goto _exit;
+ continue;
}
- else
+
+ switch (sheader.sh_type)
{
- dbg_log(DBG_LOG, "lwp data malloc : %p, size: %d!\n", lwp->data, lwp->data_size);
- rt_memset(lwp->data, 0, lwp->data_size);
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ if (start > sheader.sh_addr)
+ {
+ start = sheader.sh_addr;
+ }
+ if (sheader.sh_addr + sheader.sh_size > end)
+ {
+ end = sheader.sh_addr + sheader.sh_size;
+ }
+ break;
+ default:
+ break;
}
}
- dbg_log(DBG_INFO, "load data %d => (0x%08x, 0x%08x)\n", lwp->data_size, (uint32_t)lwp->data, (uint32_t)lwp->data + lwp->data_size);
- nbytes = read(fd, lwp->data, chunk.data_len);
- if (nbytes != chunk.data_len)
+ total_size = end - start;
+
+#ifdef RT_USING_CACHE
+ load_off = (size_t)rt_malloc_align(total_size, RT_CPU_CACHE_LINE_SZ);
+#else
+ load_off = (size_t)rt_malloc(total_size);
+#endif
+ if (load_off == 0)
{
- dbg_log(DBG_ERROR, "read data region from file failed!\n");
- result = -RT_ERROR;
+ LOG_E("alloc text memory faild!");
+ result = -RT_ENOMEM;
goto _exit;
}
+ else
+ {
+ LOG_D("lwp text malloc : %p, size: %d!", (void *)load_off, lwp->text_size);
+ }
+ lwp->load_off = load_off; /* for free */
+ lwp->text_size = total_size;
}
+#endif
+ lwp->text_entry = (void *)(eheader.e_entry + load_off);
-_exit:
- if (fd >= 0)
- close(fd);
-
- if (result != RT_EOK)
+ off = eheader.e_phoff;
+ for (i = 0; i < eheader.e_phnum; i++, off += sizeof pheader)
{
- if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
+ check_off(off, len);
+ lseek(fd, off, SEEK_SET);
+ read_len = load_fread(&pheader, 1, sizeof pheader, fd);
+ check_read(read_len, sizeof pheader);
+
+ if (pheader.p_type == PT_LOAD)
{
- dbg_log(DBG_ERROR, "lwp dynamic load faild, %d\n", result);
- if (lwp->text_entry)
+ if (pheader.p_filesz > pheader.p_memsz)
{
- dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry);
-#ifdef RT_USING_CACHE
- rt_free_align(lwp->text_entry);
+ LOG_E("pheader.p_filesz > pheader.p_memsz, p_filesz:0x%x;p_memsz:0x%x!", pheader.p_filesz, pheader.p_memsz);
+ return -RT_ERROR;
+ }
+
+ check_off(pheader.p_offset, len);
+ lseek(fd, pheader.p_offset, SEEK_SET);
+#ifdef RT_USING_USERSPACE
+ {
+ uint32_t size = pheader.p_filesz;
+ size_t tmp_len = 0;
+
+ va = (void *)(pheader.p_vaddr + load_addr);
+ read_len = 0;
+ while (size)
+ {
+ pa = rt_hw_mmu_v2p(m_info, va);
+ va_self = (void *)((char *)pa - PV_OFFSET);
+ LOG_D("va_self = %p pa = %p", va_self, pa);
+ tmp_len = (size < ARCH_PAGE_SIZE) ? size : ARCH_PAGE_SIZE;
+ tmp_len = load_fread(va_self, 1, tmp_len, fd);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, va_self, tmp_len);
+ read_len += tmp_len;
+ size -= tmp_len;
+ va = (void *)((char *)va + ARCH_PAGE_SIZE);
+ }
+ }
+#else
+ read_len = load_fread((void*)(pheader.p_vaddr + load_off), 1, pheader.p_filesz, fd);
+#endif
+ check_read(read_len, pheader.p_filesz);
+
+ if (pheader.p_filesz < pheader.p_memsz)
+ {
+#ifdef RT_USING_USERSPACE
+ uint32_t size = pheader.p_memsz - pheader.p_filesz;
+ uint32_t size_s;
+ uint32_t off;
+
+ off = pheader.p_filesz & ARCH_PAGE_MASK;
+ va = (void *)((pheader.p_vaddr + pheader.p_filesz + load_off) & ~ARCH_PAGE_MASK);
+ while (size)
+ {
+ size_s = (size < ARCH_PAGE_SIZE - off) ? size : ARCH_PAGE_SIZE - off;
+ pa = rt_hw_mmu_v2p(m_info, va);
+ va_self = (void *)((char *)pa - PV_OFFSET);
+ memset((void *)((char *)va_self + off), 0, size_s);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)((char *)va_self + off), size_s);
+ off = 0;
+ size -= size_s;
+ va = (void *)((char *)va + ARCH_PAGE_SIZE);
+ }
#else
- rt_free(lwp->text_entry);
+ memset((uint8_t *)pheader.p_vaddr + pheader.p_filesz + load_off, 0, (size_t)(pheader.p_memsz - pheader.p_filesz));
#endif
}
- if (lwp->data)
+ }
+ }
+
+ /* relocate */
+ if (eheader.e_type == ET_DYN)
+ {
+ /* section info */
+ off = eheader.e_shoff;
+ /* find section string table */
+ check_off(off, len);
+ lseek(fd, off + (sizeof sheader) * eheader.e_shstrndx, SEEK_SET);
+ read_len = load_fread(&sheader, 1, sizeof sheader, fd);
+ check_read(read_len, sizeof sheader);
+
+ p_section_str = (char *)rt_malloc(sheader.sh_size);
+ if (!p_section_str)
+ {
+ LOG_E("out of memory!");
+ result = -ENOMEM;
+ goto _exit;
+ }
+
+ check_off(sheader.sh_offset, len);
+ lseek(fd, sheader.sh_offset, SEEK_SET);
+ read_len = load_fread(p_section_str, 1, sheader.sh_size, fd);
+ check_read(read_len, sheader.sh_size);
+
+ check_off(off, len);
+ lseek(fd, off, SEEK_SET);
+ for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
+ {
+ read_len = load_fread(&sheader, 1, sizeof sheader, fd);
+ check_read(read_len, sizeof sheader);
+
+ if (strcmp(p_section_str + sheader.sh_name, ".got") == 0)
+ {
+ got_start = (void *)((uint8_t *)sheader.sh_addr + load_off);
+ got_size = (size_t)sheader.sh_size;
+ }
+ else if (strcmp(p_section_str + sheader.sh_name, ".rel.dyn") == 0)
+ {
+ rel_dyn_start = (void *)((uint8_t *)sheader.sh_addr + load_off);
+ rel_dyn_size = (size_t)sheader.sh_size;
+ }
+ else if (strcmp(p_section_str + sheader.sh_name, ".dynsym") == 0)
{
- dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data);
- rt_free(lwp->data);
+ dynsym_off = (size_t)sheader.sh_offset;
+ dynsym_size = (size_t)sheader.sh_size;
}
}
+ /* reloc */
+ if (dynsym_size)
+ {
+ dynsym = rt_malloc(dynsym_size);
+ if (!dynsym)
+ {
+ LOG_E("ERROR: Malloc error!");
+ result = -ENOMEM;
+ goto _exit;
+ }
+ check_off(dynsym_off, len);
+ lseek(fd, dynsym_off, SEEK_SET);
+ read_len = load_fread(dynsym, 1, dynsym_size, fd);
+ check_read(read_len, dynsym_size);
+ }
+#ifdef RT_USING_USERSPACE
+ arch_elf_reloc(m_info, (void *)load_off, rel_dyn_start, rel_dyn_size, got_start, got_size, dynsym);
+#else
+ arch_elf_reloc((void *)load_off, rel_dyn_start, rel_dyn_size, got_start, got_size, dynsym);
+
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size);
+ rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size);
+#endif
}
+ LOG_D("lwp->text_entry = 0x%p", lwp->text_entry);
+ LOG_D("lwp->text_size = 0x%p", lwp->text_size);
+_exit:
+ if (dynsym)
+ {
+ rt_free(dynsym);
+ }
+ if (p_section_str)
+ {
+ rt_free(p_section_str);
+ }
+ if (result != RT_EOK)
+ {
+ LOG_E("lwp load faild, %d", result);
+ }
return result;
}
+#endif /* ARCH_MM_MMU */
-static void lwp_cleanup(struct rt_thread *tid)
+RT_WEAK int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux)
{
+ uint8_t *ptr;
+ int ret = -1;
+ int len;
+ int fd = -1;
+
+ /* check file name */
+ RT_ASSERT(filename != RT_NULL);
+ /* check lwp control block */
+ RT_ASSERT(lwp != RT_NULL);
+
+ /* copy file name to process name */
+ rt_strncpy(lwp->cmd, filename, RT_NAME_MAX);
+
+ if (load_addr != RT_NULL)
+ {
+ lwp->lwp_type = LWP_TYPE_FIX_ADDR;
+ ptr = load_addr;
+ }
+ else
+ {
+ lwp->lwp_type = LWP_TYPE_DYN_ADDR;
+ ptr = RT_NULL;
+ }
+
+ fd = open(filename, O_BINARY | O_RDONLY, 0);
+ if (fd < 0)
+ {
+ LOG_E("ERROR: Can't open elf file %s!", filename);
+ goto out;
+ }
+ len = lseek(fd, 0, SEEK_END);
+ if (len < 0)
+ {
+ LOG_E("ERROR: File %s size error!", filename);
+ goto out;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+
+ ret = load_elf(fd, len, lwp, ptr, aux);
+ if ((ret != RT_EOK) && (ret != 1))
+ {
+ LOG_E("lwp load ret = %d", ret);
+ }
+
+out:
+ if (fd > 0)
+ {
+ close(fd);
+ }
+ return ret;
+}
+
+void lwp_cleanup(struct rt_thread *tid)
+{
+ rt_base_t level;
struct rt_lwp *lwp;
+ struct tty_node *tty_head = RT_NULL;
+
+ if (tid == NULL)
+ {
+ return;
+ }
- dbg_log(DBG_INFO, "thread: %s, stack_addr: %08X\n", tid->name, tid->stack_addr);
+ LOG_I("cleanup thread: %s, stack_addr: %08X", tid->name, tid->stack_addr);
+ level = rt_hw_interrupt_disable();
lwp = (struct rt_lwp *)tid->lwp;
- if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
+ lwp_tid_put(tid->tid);
+ rt_list_remove(&tid->sibling);
+ rt_hw_interrupt_enable(level);
+ if (lwp->tty != RT_NULL)
{
- dbg_log(DBG_INFO, "dynamic lwp\n");
- if (lwp->text_entry)
- {
- dbg_log(DBG_LOG, "lwp text free: %p\n", lwp->text_entry);
-#ifdef RT_USING_CACHE
- rt_free_align(lwp->text_entry);
-#else
- rt_free(lwp->text_entry);
-#endif
- }
- if (lwp->data)
+ tty_head = lwp->tty->head;
+ }
+ if (!lwp_ref_dec(lwp))
+ {
+ if (tty_head)
{
- dbg_log(DBG_LOG, "lwp data free: %p\n", lwp->data);
- rt_free(lwp->data);
+ tty_pop(&tty_head, lwp);
}
}
+
+ return;
+}
- dbg_log(DBG_LOG, "lwp free memory pages\n");
- rt_lwp_mem_deinit(lwp);
-
- /* cleanup fd table */
- rt_free(lwp->fdt.fds);
- rt_free(lwp->args);
+static void lwp_copy_stdio_fdt(struct rt_lwp *lwp)
+{
+ struct dfs_fd *d;
+ struct dfs_fdtable *lwp_fdt;
- dbg_log(DBG_LOG, "lwp free: %p\n", lwp);
- rt_free(lwp);
+ lwp_fdt = &lwp->fdt;
+ /* init 4 fds */
+ lwp_fdt->fds = rt_calloc(4, sizeof(void *));
+ if (lwp_fdt->fds)
+ {
+ lwp_fdt->maxfd = 4;
+ d = fd_get(0);
+ fd_associate(lwp_fdt, 0, d);
+ d = fd_get(1);
+ fd_associate(lwp_fdt, 1, d);
+ d = fd_get(2);
+ fd_associate(lwp_fdt, 2, d);
+ }
- /* TODO: cleanup fd table */
+ return;
}
-static void lwp_thread(void *parameter)
+static void _lwp_thread_entry(void *parameter)
{
rt_thread_t tid;
struct rt_lwp *lwp;
- lwp = (struct rt_lwp *)parameter;
- rt_lwp_mem_init(lwp);
tid = rt_thread_self();
- tid->lwp = lwp;
+ lwp = (struct rt_lwp *)tid->lwp;
tid->cleanup = lwp_cleanup;
+ tid->user_stack = RT_NULL;
+
+ if (lwp->debug)
+ {
+ lwp->bak_first_ins = *(uint32_t *)lwp->text_entry;
+ *(uint32_t *)lwp->text_entry = dbg_get_ins();
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, sizeof(uint32_t));
+ icache_invalid_all();
+ }
- lwp_user_entry(lwp->args, lwp->text_entry, lwp->data);
+#ifdef ARCH_MM_MMU
+ arch_start_umode(lwp->args, lwp->text_entry, (void *)USER_STACK_VEND, tid->stack_addr + tid->stack_size);
+#else
+ arch_start_umode(lwp->args, lwp->text_entry, lwp->data_entry, (void *)((uint32_t)lwp->data_entry + lwp->data_size));
+#endif /* ARCH_MM_MMU */
}
-struct rt_lwp *rt_lwp_self(void)
+struct rt_lwp *lwp_self(void)
{
- return (struct rt_lwp *)rt_thread_self()->lwp;
+ rt_thread_t tid;
+
+ tid = rt_thread_self();
+ if (tid)
+ {
+ return (struct rt_lwp *)tid->lwp;
+ }
+
+ return RT_NULL;
}
-int exec(char *filename, int argc, char **argv)
+pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
{
- struct rt_lwp *lwp;
int result;
+ rt_base_t level;
+ struct rt_lwp *lwp;
+ char *thread_name;
+ char *argv_last = argv[argc - 1];
+ int bg = 0;
+ struct process_aux *aux;
+ int tid = 0;
+ int ret;
if (filename == RT_NULL)
+ {
return -RT_ERROR;
+ }
+
+ lwp = lwp_new();
- lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
if (lwp == RT_NULL)
{
dbg_log(DBG_ERROR, "lwp struct out of memory!\n");
return -RT_ENOMEM;
}
- dbg_log(DBG_INFO, "lwp malloc : %p, size: %d!\n", lwp, sizeof(struct rt_lwp));
+ LOG_D("lwp malloc : %p, size: %d!", lwp, sizeof(struct rt_lwp));
+
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ lwp_ref_dec(lwp);
+ return -ENOMEM;
+ }
+#ifdef RT_USING_USERSPACE
+ if (lwp_user_space_init(lwp) != 0)
+ {
+ lwp_tid_put(tid);
+ lwp_ref_dec(lwp);
+ return -ENOMEM;
+ }
+#endif
+
+ if (argv_last[0] == '&' && argv_last[1] == '\0')
+ {
+ argc--;
+ bg = 1;
+ }
- rt_memset(lwp, 0, sizeof(*lwp));
- if (lwp_argscopy(lwp, argc, argv) != 0)
+ if ((aux = lwp_argscopy(lwp, argc, argv, envp)) == RT_NULL)
{
- rt_free(lwp);
+ lwp_tid_put(tid);
+ lwp_ref_dec(lwp);
return -ENOMEM;
}
- result = lwp_load(filename, lwp, RT_NULL, 0);
+ result = lwp_load(filename, lwp, RT_NULL, 0, aux);
+#ifdef ARCH_MM_MMU
+ if (result == 1)
+ {
+ /* dynmaic */
+ lwp_unmap_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE));
+ result = load_ldso(lwp, filename, argv, envp);
+ }
+#endif /* ARCH_MM_MMU */
if (result == RT_EOK)
{
- rt_thread_t tid;
+ rt_thread_t thread = RT_NULL;
+ rt_uint32_t priority = 25, tick = 200;
- tid = rt_thread_create("user", lwp_thread, (void *)lwp,
- 1024 * 4, 2, 200);
- if (tid != RT_NULL)
+ lwp_copy_stdio_fdt(lwp);
+
+ /* obtain the base name */
+ thread_name = strrchr(filename, '/');
+ thread_name = thread_name ? thread_name + 1 : filename;
+#ifndef ARCH_MM_MMU
+ struct lwp_app_head *app_head = lwp->text_entry;
+ if (app_head->priority)
{
- dbg_log(DBG_LOG, "lwp kernel => (0x%08x, 0x%08x)\n", (rt_uint32_t)tid->stack_addr, (rt_uint32_t)tid->stack_addr + tid->stack_size);
- rt_thread_startup(tid);
- return RT_EOK;
+ priority = app_head->priority;
}
- else
+ if (app_head->tick)
{
-#ifdef RT_USING_CACHE
- rt_free_align(lwp->text_entry);
-#else
- rt_free(lwp->text_entry);
-#endif
- rt_free(lwp->data);
+ tick = app_head->tick;
+ }
+#endif /* not defined ARCH_MM_MMU */
+ thread = rt_thread_create(thread_name, _lwp_thread_entry, RT_NULL,
+ LWP_TASK_STACK_SIZE, priority, tick);
+ if (thread != RT_NULL)
+ {
+ struct rt_lwp *self_lwp;
+
+ thread->tid = tid;
+ lwp_tid_set_thread(tid, thread);
+ LOG_D("lwp kernel => (0x%08x, 0x%08x)\n", (rt_size_t)thread->stack_addr,
+ (rt_size_t)thread->stack_addr + thread->stack_size);
+ level = rt_hw_interrupt_disable();
+ self_lwp = lwp_self();
+ if (self_lwp)
+ {
+ //lwp->tgroup_leader = &thread; //add thread group leader for lwp
+ lwp->__pgrp = tid;
+ lwp->session = self_lwp->session;
+ /* lwp add to children link */
+ lwp->sibling = self_lwp->first_child;
+ self_lwp->first_child = lwp;
+ lwp->parent = self_lwp;
+ }
+ else
+ {
+ //lwp->tgroup_leader = &thread; //add thread group leader for lwp
+ lwp->__pgrp = tid;
+ }
+ if (!bg)
+ {
+ if (lwp->session == -1)
+ {
+ struct tty_struct *tty = RT_NULL;
+ struct rt_lwp *old_lwp;
+ tty = (struct tty_struct *)console_tty_get();
+ old_lwp = tty->foreground;
+ rt_mutex_take(&tty->lock, RT_WAITING_FOREVER);
+ ret = tty_push(&tty->head, old_lwp);
+ rt_mutex_release(&tty->lock);
+ if (ret < 0)
+ {
+ lwp_tid_put(tid);
+ lwp_ref_dec(lwp);
+ LOG_E("malloc fail!\n");
+ return -ENOMEM;
+ }
+
+ lwp->tty = tty;
+ lwp->tty->pgrp = lwp->__pgrp;
+ lwp->tty->session = lwp->session;
+ lwp->tty->foreground = lwp;
+ tcgetattr(1, &stdin_termios);
+ old_stdin_termios = stdin_termios;
+ stdin_termios.c_lflag |= ICANON | ECHO | ECHOCTL;
+ tcsetattr(1, 0, &stdin_termios);
+ }
+ else
+ {
+ if (self_lwp != RT_NULL)
+ {
+ rt_mutex_take(&self_lwp->tty->lock, RT_WAITING_FOREVER);
+ ret = tty_push(&self_lwp->tty->head, self_lwp);
+ rt_mutex_release(&self_lwp->tty->lock);
+ if (ret < 0)
+ {
+ lwp_tid_put(tid);
+ lwp_ref_dec(lwp);
+ LOG_E("malloc fail!\n");
+ return -ENOMEM;
+ }
+
+ lwp->tty = self_lwp->tty;
+ lwp->tty->pgrp = lwp->__pgrp;
+ lwp->tty->session = lwp->session;
+ lwp->tty->foreground = lwp;
+ }
+ else
+ {
+ lwp->tty = RT_NULL;
+ }
+
+ }
+ }
+ thread->lwp = lwp;
+#ifndef ARCH_MM_MMU
+ struct lwp_app_head *app_head = (struct lwp_app_head*)lwp->text_entry;
+ thread->user_stack = app_head->stack_offset ?
+ (void *)(app_head->stack_offset -
+ app_head->data_offset +
+ (uint32_t)lwp->data_entry) : RT_NULL;
+ thread->user_stack_size = app_head->stack_size;
+ /* init data area */
+ rt_memset(lwp->data_entry, 0, lwp->data_size);
+ /* init user stack */
+ rt_memset(thread->user_stack, '#', thread->user_stack_size);
+#endif /* not defined ARCH_MM_MMU */
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+
+ if (debug && rt_dbg_ops)
+ {
+ lwp->debug = debug;
+ rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
+ }
+ rt_hw_interrupt_enable(level);
+
+ rt_thread_startup(thread);
+ return lwp_to_pid(lwp);
}
}
- rt_free(lwp->args);
- rt_free(lwp);
+ lwp_tid_put(tid);
+ lwp_ref_dec(lwp);
return -RT_ERROR;
}
+
+#ifdef RT_USING_MUSL
+extern char **__environ;
+#else
+char __environ = 0;
+#endif
+
+pid_t exec(char *filename, int debug, int argc, char **argv)
+{
+ return lwp_execve(filename, debug, argc, argv, __environ);
+}
+
+#ifdef ARCH_MM_MMU
+void lwp_user_setting_save(rt_thread_t thread)
+{
+ if (thread)
+ {
+ thread->thread_idr = arch_get_tidr();
+ }
+}
+
+void lwp_user_setting_restore(rt_thread_t thread)
+{
+ if (!thread)
+ {
+ return;
+ }
+#if !defined(ARCH_RISCV64)
+ /* tidr will be set in RESTORE_ALL in risc-v */
+ arch_set_tidr(thread->thread_idr);
+#endif
+
+ if (rt_dbg_ops)
+ {
+ struct rt_lwp *l = (struct rt_lwp *)thread->lwp;
+
+ if (l != 0)
+ {
+ rt_hw_set_process_id((size_t)l->pid);
+ }
+ else
+ {
+ rt_hw_set_process_id(0);
+ }
+ if (l && l->debug)
+ {
+ uint32_t step_type = 0;
+
+ step_type = dbg_step_type();
+
+ if ((step_type == 2) || (thread->step_exec && (step_type == 1)))
+ {
+ dbg_activate_step();
+ }
+ else
+ {
+ dbg_deactivate_step();
+ }
+ }
+ }
+}
+#endif /* ARCH_MM_MMU */
diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h
index 3607f89b17..da8ff0eef2 100644
--- a/components/lwp/lwp.h
+++ b/components/lwp/lwp.h
@@ -6,11 +6,50 @@
* Change Logs:
* Date Author Notes
* 2018-06-29 heyuanjie first version
+ * 2019-10-12 Jesven Add MMU and userspace support
+ * 2020-10-08 Bernard Architecture and code cleanup
+ * 2021-08-26 linzhenxing add lwp_setcwd\lwp_getcwd
*/
+/*
+ * RT-Thread light-weight process
+ */
#ifndef __LWP_H__
#define __LWP_H__
+#include <stdint.h>
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <dfs.h>
+
+#include "lwp_pid.h"
+#include "lwp_ipc.h"
+#include "lwp_signal.h"
+#include "lwp_syscall.h"
+#include "lwp_avl.h"
+
+#ifdef RT_USING_USERSPACE
+#include "lwp_shm.h"
+
+#include "mmu.h"
+#include "page.h"
+#else
+#include "lwp_mpu.h"
+#endif
+#include "lwp_arch.h"
+
+#ifdef RT_USING_MUSL
+#include <locale.h>
+#endif
+#ifdef RT_USING_TTY
+struct tty_struct;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define LWP_MAGIC 0x5A
#define LWP_TYPE_FIX_ADDR 0x01
@@ -18,54 +57,244 @@
#define LWP_ARG_MAX 8
-#include <stdint.h>
-#include <rtthread.h>
-#include <dfs.h>
-#include <lwp_memheap.h>
-
struct rt_lwp
{
+#ifdef RT_USING_USERSPACE
+ rt_mmu_info mmu_info;
+ struct lwp_avl_struct *map_area;
+ size_t end_heap;
+#else
+#ifdef ARCH_MM_MPU
+ struct rt_mpu_info mpu_info;
+#endif /* ARCH_MM_MPU */
+#endif
+
+#ifdef RT_USING_SMP
+ int bind_cpu;
+#endif
+
uint8_t lwp_type;
- uint8_t heap_cnt;
- uint8_t reserv[2];
+ uint8_t reserv[3];
- rt_list_t hlist; /**< headp list */
+ struct rt_lwp *parent;
+ struct rt_lwp *first_child;
+ struct rt_lwp *sibling;
- uint8_t *text_entry;
- uint32_t text_size;
+ rt_list_t wait_list;
+ int32_t finish;
+ int lwp_ret;
- uint8_t *data;
+ void *text_entry;
+ uint32_t text_size;
+ void *data_entry;
uint32_t data_size;
- uint32_t *kernel_sp; /**< kernel stack point */
- struct dfs_fdtable fdt;
+ int ref;
void *args;
+ uint32_t args_length;
+ pid_t pid;
+ pid_t __pgrp; /*Accessed via process_group()*/
+ pid_t tty_old_pgrp;
+ pid_t session;
+ rt_list_t t_grp;
+
+ int leader; /*boolean value for session group_leader*/
+ struct dfs_fdtable fdt;
+ char cmd[RT_NAME_MAX];
+
+ int sa_flags;
+ lwp_sigset_t signal;
+ lwp_sigset_t signal_mask;
+ int signal_mask_bak;
+ rt_uint32_t signal_in_process;
+ lwp_sighandler_t signal_handler[_LWP_NSIG];
+
+ struct lwp_avl_struct *object_root;
+ struct rt_mutex object_mutex;
+ struct rt_user_context user_ctx;
+
+ struct rt_wqueue wait_queue; /*for console */
+ struct tty_struct *tty; /* NULL if no tty */
+
+ struct lwp_avl_struct *address_search_head; /* for addressed object fast rearch */
+ char working_directory[DFS_PATH_MAX];
+ int debug;
+ uint32_t bak_first_ins;
+
+#ifdef LWP_ENABLE_ASID
+ uint64_t generation;
+ unsigned int asid;
+#endif
};
-struct lwp_header
+struct rt_lwp *lwp_self(void);
+
+enum lwp_exit_request_type
{
- uint8_t magic;
- uint8_t compress_encrypt_algo;
- uint16_t reserved;
+ LWP_EXIT_REQUEST_NONE = 0,
+ LWP_EXIT_REQUEST_TRIGGERED,
+ LWP_EXIT_REQUEST_IN_PROCESS,
+};
+struct termios *get_old_termios(void);
+void lwp_setcwd(char *buf);
+char *lwp_getcwd(void);
+void lwp_request_thread_exit(rt_thread_t thread_to_exit);
+int lwp_check_exit_request(void);
+void lwp_terminate(struct rt_lwp *lwp);
+void lwp_wait_subthread_exit(void);
- uint32_t crc32;
+int lwp_tid_get(void);
+void lwp_tid_put(int tid);
+rt_thread_t lwp_tid_get_thread(int tid);
+void lwp_tid_set_thread(int tid, rt_thread_t thread);
+
+size_t lwp_user_strlen(const char *s, int *err);
+int lwp_execve(char *filename, int debug, int argc, char **argv, char **envp);
+
+/*create by lwp_setsid.c*/
+int setsid(void);
+#ifdef RT_USING_USERSPACE
+void lwp_mmu_switch(struct rt_thread *thread);
+#endif
+void lwp_user_setting_save(rt_thread_t thread);
+void lwp_user_setting_restore(rt_thread_t thread);
+int lwp_setaffinity(pid_t pid, int cpu);
+
+#ifdef RT_USING_USERSPACE
+struct __pthread {
+ /* Part 1 -- these fields may be external or
+ * * internal (accessed via asm) ABI. Do not change. */
+ struct pthread *self;
+ uintptr_t *dtv;
+ struct pthread *prev, *next; /* non-ABI */
+ uintptr_t sysinfo;
+ uintptr_t canary, canary2;
+
+ /* Part 2 -- implementation details, non-ABI. */
+ int tid;
+ int errno_val;
+ volatile int detach_state;
+ volatile int cancel;
+ volatile unsigned char canceldisable, cancelasync;
+ unsigned char tsd_used:1;
+ unsigned char dlerror_flag:1;
+ unsigned char *map_base;
+ size_t map_size;
+ void *stack;
+ size_t stack_size;
+ size_t guard_size;
+ void *result;
+ struct __ptcb *cancelbuf;
+ void **tsd;
+ struct {
+ volatile void *volatile head;
+ long off;
+ volatile void *volatile pending;
+ } robust_list;
+ volatile int timer_id;
+ locale_t locale;
+ volatile int killlock[1];
+ char *dlerror_buf;
+ void *stdio_locks;
+
+ /* Part 3 -- the positions of these fields relative to
+ * * the end of the structure is external and internal ABI. */
+ uintptr_t canary_at_end;
+ uintptr_t *dtv_copy;
};
+#endif
-struct lwp_chunk
+/* for futex op */
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+/* for pmutex op */
+#define PMUTEX_INIT 0
+#define PMUTEX_LOCK 1
+#define PMUTEX_UNLOCK 2
+#define PMUTEX_DESTROY 3
+
+#ifdef __cplusplus
+}
+#endif
+
+#define AUX_ARRAY_ITEMS_NR 6
+
+/* aux key */
+#define AT_NULL 0
+#define AT_IGNORE 1
+#define AT_EXECFD 2
+#define AT_PHDR 3
+#define AT_PHENT 4
+#define AT_PHNUM 5
+#define AT_PAGESZ 6
+#define AT_BASE 7
+#define AT_FLAGS 8
+#define AT_ENTRY 9
+#define AT_NOTELF 10
+#define AT_UID 11
+#define AT_EUID 12
+#define AT_GID 13
+#define AT_EGID 14
+#define AT_CLKTCK 17
+#define AT_PLATFORM 15
+#define AT_HWCAP 16
+#define AT_FPUCW 18
+#define AT_DCACHEBSIZE 19
+#define AT_ICACHEBSIZE 20
+#define AT_UCACHEBSIZE 21
+#define AT_IGNOREPPC 22
+#define AT_SECURE 23
+#define AT_BASE_PLATFORM 24
+#define AT_RANDOM 25
+#define AT_HWCAP2 26
+#define AT_EXECFN 31
+
+struct process_aux_item
+{
+ size_t key;
+ size_t value;
+};
+
+struct process_aux
{
- uint32_t total_len;
+ struct process_aux_item item[AUX_ARRAY_ITEMS_NR];
+};
- char name[4];
- uint32_t data_len;
- uint32_t data_len_space;
+struct lwp_args_info
+{
+ char **argv;
+ char **envp;
+ int argc;
+ int envc;
+ int size;
+};
+
+struct dbg_ops_t
+{
+ int (*dbg)(int argc, char **argv);
+ uint32_t (*arch_get_ins)(void);
+ void (*arch_activate_step)(void);
+ void (*arch_deactivate_step)(void);
+ int (*check_debug_event)(struct rt_hw_exp_stack *regs, unsigned long esr);
+ rt_channel_t (*gdb_get_server_channel)(void);
+ int (*gdb_get_step_type)(void);
+ void (*lwp_check_debug_attach_req)(void *pc);
+ int (*lwp_check_debug_suspend)(void);
};
+extern struct dbg_ops_t *rt_dbg_ops;
-extern struct rt_lwp *rt_lwp_self(void);
+int dbg_thread_in_debug(void);
+void dbg_register(struct dbg_ops_t *dbg_ops);
-extern void rt_lwp_mem_init(struct rt_lwp *lwp);
-extern void rt_lwp_mem_deinit(struct rt_lwp *lwp);
-extern void *rt_lwp_mem_malloc(rt_uint32_t size);
-extern void rt_lwp_mem_free(void *addr);
-extern void *rt_lwp_mem_realloc(void *rmem, rt_size_t newsize);
+uint32_t dbg_get_ins(void);
+void dbg_activate_step(void);
+void dbg_deactivate_step(void);
+int dbg_check_event(struct rt_hw_exp_stack *regs, unsigned long arg);
+rt_channel_t gdb_server_channel(void);
+int dbg_step_type(void);
+void dbg_attach_req(void *pc);
+int dbg_check_suspend(void);
+void rt_hw_set_process_id(int pid);
#endif
diff --git a/components/lwp/lwp_arch_comm.h b/components/lwp/lwp_arch_comm.h
new file mode 100644
index 0000000000..91b4a9523e
--- /dev/null
+++ b/components/lwp/lwp_arch_comm.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef __LWP_ARCH_COMM__
+#define __LWP_ARCH_COMM__
+
+#include <rtthread.h>
+
+/**
+ * APIs that must port to all architectures
+ */
+
+/* syscall handlers */
+void arch_clone_exit(void);
+void arch_fork_exit(void);
+void arch_syscall_exit();
+void arch_ret_to_user();
+
+/* ELF relocation */
+#ifdef RT_USING_USERSPACE
+void arch_elf_reloc(rt_mmu_info *m_info, void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, void *dynsym);
+#else
+void arch_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, void *dynsym);
+#endif
+
+/* User entry. enter user program code for the first time */
+void arch_crt_start_umode(void *args, const void *text, void *ustack, void *user_stack);
+void arch_start_umode(void *args, const void *text, void *ustack, void *k_stack);
+
+/* lwp create and setup */
+int arch_set_thread_context(void (*exit)(void), void *new_thread_stack,
+ void *user_stack, void **thread_sp);
+void *arch_get_user_sp(void);
+
+/* user space setup and control */
+int arch_user_space_init(struct rt_lwp *lwp);
+void arch_user_space_vtable_free(struct rt_lwp *lwp);
+void *arch_kernel_mmu_table_get(void);
+void arch_kuser_init(rt_mmu_info *mmu_info, void *vectors);
+int arch_expand_user_stack(void *addr);
+
+/* thread id register */
+void arch_set_thread_area(void *p);
+void* arch_get_tidr(void);
+void arch_set_tidr(void *p);
+
+#endif /* __LWP_ARCH_COMM__ */
diff --git a/components/lwp/lwp_avl.c b/components/lwp/lwp_avl.c
new file mode 100644
index 0000000000..71eb089264
--- /dev/null
+++ b/components/lwp/lwp_avl.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-12 Jesven first version
+ */
+#include <rtthread.h>
+#include <lwp_avl.h>
+
+static void lwp_avl_rebalance(struct lwp_avl_struct ***nodeplaces_ptr, int count)
+{
+ for (; count > 0; count--)
+ {
+ struct lwp_avl_struct **nodeplace = *--nodeplaces_ptr;
+ struct lwp_avl_struct *node = *nodeplace;
+ struct lwp_avl_struct *nodeleft = node->avl_left;
+ struct lwp_avl_struct *noderight = node->avl_right;
+ int heightleft = heightof(nodeleft);
+ int heightright = heightof(noderight);
+ if (heightright + 1 < heightleft)
+ {
+ struct lwp_avl_struct *nodeleftleft = nodeleft->avl_left;
+ struct lwp_avl_struct *nodeleftright = nodeleft->avl_right;
+ int heightleftright = heightof(nodeleftright);
+ if (heightof(nodeleftleft) >= heightleftright)
+ {
+ node->avl_left = nodeleftright;
+ nodeleft->avl_right = node;
+ nodeleft->avl_height = 1 + (node->avl_height = 1 + heightleftright);
+ *nodeplace = nodeleft;
+ }
+ else
+ {
+ nodeleft->avl_right = nodeleftright->avl_left;
+ node->avl_left = nodeleftright->avl_right;
+ nodeleftright->avl_left = nodeleft;
+ nodeleftright->avl_right = node;
+ nodeleft->avl_height = node->avl_height = heightleftright;
+ nodeleftright->avl_height = heightleft;
+ *nodeplace = nodeleftright;
+ }
+ }
+ else if (heightleft + 1 < heightright)
+ {
+ struct lwp_avl_struct *noderightright = noderight->avl_right;
+ struct lwp_avl_struct *noderightleft = noderight->avl_left;
+ int heightrightleft = heightof(noderightleft);
+ if (heightof(noderightright) >= heightrightleft)
+ {
+ node->avl_right = noderightleft;
+ noderight->avl_left = node;
+ noderight->avl_height = 1 + (node->avl_height = 1 + heightrightleft);
+ *nodeplace = noderight;
+ }
+ else
+ {
+ noderight->avl_left = noderightleft->avl_right;
+ node->avl_right = noderightleft->avl_left;
+ noderightleft->avl_right = noderight;
+ noderightleft->avl_left = node;
+ noderight->avl_height = node->avl_height = heightrightleft;
+ noderightleft->avl_height = heightright;
+ *nodeplace = noderightleft;
+ }
+ }
+ else
+ {
+ int height = (heightleft < heightright ? heightright : heightleft) + 1;
+ if (height == node->avl_height)
+ break;
+ node->avl_height = height;
+ }
+ }
+}
+
+void lwp_avl_remove(struct lwp_avl_struct *node_to_delete, struct lwp_avl_struct **ptree)
+{
+ avl_key_t key = node_to_delete->avl_key;
+ struct lwp_avl_struct **nodeplace = ptree;
+ struct lwp_avl_struct **stack[avl_maxheight];
+ uint32_t stack_count = 0;
+ struct lwp_avl_struct ***stack_ptr = &stack[0]; /* = &stack[stackcount] */
+ struct lwp_avl_struct **nodeplace_to_delete;
+ for (;;)
+ {
+ struct lwp_avl_struct *node = *nodeplace;
+ if (node == AVL_EMPTY)
+ {
+ return;
+ }
+
+ *stack_ptr++ = nodeplace;
+ stack_count++;
+ if (key == node->avl_key)
+ break;
+ if (key < node->avl_key)
+ nodeplace = &node->avl_left;
+ else
+ nodeplace = &node->avl_right;
+ }
+ nodeplace_to_delete = nodeplace;
+ if (node_to_delete->avl_left == AVL_EMPTY)
+ {
+ *nodeplace_to_delete = node_to_delete->avl_right;
+ stack_ptr--;
+ stack_count--;
+ }
+ else
+ {
+ struct lwp_avl_struct ***stack_ptr_to_delete = stack_ptr;
+ struct lwp_avl_struct **nodeplace = &node_to_delete->avl_left;
+ struct lwp_avl_struct *node;
+ for (;;)
+ {
+ node = *nodeplace;
+ if (node->avl_right == AVL_EMPTY)
+ break;
+ *stack_ptr++ = nodeplace;
+ stack_count++;
+ nodeplace = &node->avl_right;
+ }
+ *nodeplace = node->avl_left;
+ node->avl_left = node_to_delete->avl_left;
+ node->avl_right = node_to_delete->avl_right;
+ node->avl_height = node_to_delete->avl_height;
+ *nodeplace_to_delete = node;
+ *stack_ptr_to_delete = &node->avl_left;
+ }
+ lwp_avl_rebalance(stack_ptr, stack_count);
+}
+
+void lwp_avl_insert(struct lwp_avl_struct *new_node, struct lwp_avl_struct **ptree)
+{
+ avl_key_t key = new_node->avl_key;
+ struct lwp_avl_struct **nodeplace = ptree;
+ struct lwp_avl_struct **stack[avl_maxheight];
+ int stack_count = 0;
+ struct lwp_avl_struct ***stack_ptr = &stack[0]; /* = &stack[stackcount] */
+ for (;;)
+ {
+ struct lwp_avl_struct *node = *nodeplace;
+ if (node == AVL_EMPTY)
+ break;
+ *stack_ptr++ = nodeplace;
+ stack_count++;
+ if (key < node->avl_key)
+ nodeplace = &node->avl_left;
+ else
+ nodeplace = &node->avl_right;
+ }
+ new_node->avl_left = AVL_EMPTY;
+ new_node->avl_right = AVL_EMPTY;
+ new_node->avl_height = 1;
+ *nodeplace = new_node;
+ lwp_avl_rebalance(stack_ptr, stack_count);
+}
+
+struct lwp_avl_struct *lwp_avl_find(avl_key_t key, struct lwp_avl_struct *ptree)
+{
+ for (;;)
+ {
+ if (ptree == AVL_EMPTY)
+ {
+ return (struct lwp_avl_struct *)0;
+ }
+ if (key == ptree->avl_key)
+ break;
+ if (key < ptree->avl_key)
+ ptree = ptree->avl_left;
+ else
+ ptree = ptree->avl_right;
+ }
+ return ptree;
+}
+
+int lwp_avl_traversal(struct lwp_avl_struct *ptree, int (*fun)(struct lwp_avl_struct *, void *), void *arg)
+{
+ int ret;
+
+ if (!ptree)
+ {
+ return 0;
+ }
+ if (ptree->avl_left)
+ {
+ ret = lwp_avl_traversal(ptree->avl_left, fun, arg);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ }
+ ret = (*fun)(ptree, arg);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ if (ptree->avl_right)
+ {
+ ret = lwp_avl_traversal(ptree->avl_right, fun, arg);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ }
+ return ret;
+}
+
+RT_WEAK struct lwp_avl_struct* lwp_map_find_first(struct lwp_avl_struct* ptree)
+{
+ if (ptree == AVL_EMPTY)
+ {
+ return (struct lwp_avl_struct *)0;
+ }
+ while (1)
+ {
+ if (!ptree->avl_left)
+ {
+ break;
+ }
+ ptree = ptree->avl_left;
+ }
+ return ptree;
+}
+
diff --git a/components/lwp/lwp_avl.h b/components/lwp/lwp_avl.h
new file mode 100644
index 0000000000..2d555794d6
--- /dev/null
+++ b/components/lwp/lwp_avl.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-12 Jesven first version
+ */
+#ifndef LWP_AVL_H__
+#define LWP_AVL_H__
+
+#include <rtthread.h>
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define avl_key_t size_t
+#define AVL_EMPTY (struct lwp_avl_struct *)0
+#define avl_maxheight 32
+#define heightof(tree) ((tree) == AVL_EMPTY ? 0 : (tree)->avl_height)
+
+struct lwp_avl_struct
+{
+ struct lwp_avl_struct *avl_left;
+ struct lwp_avl_struct *avl_right;
+ int avl_height;
+ avl_key_t avl_key;
+ void *data;
+};
+
+void lwp_avl_remove(struct lwp_avl_struct * node_to_delete, struct lwp_avl_struct ** ptree);
+void lwp_avl_insert (struct lwp_avl_struct * new_node, struct lwp_avl_struct ** ptree);
+struct lwp_avl_struct* lwp_avl_find(avl_key_t key, struct lwp_avl_struct* ptree);
+int lwp_avl_traversal(struct lwp_avl_struct* ptree, int (*fun)(struct lwp_avl_struct*, void *), void *arg);
+struct lwp_avl_struct* lwp_map_find_first(struct lwp_avl_struct* ptree);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWP_AVL_H__ */
diff --git a/components/lwp/lwp_dbg.c b/components/lwp/lwp_dbg.c
new file mode 100644
index 0000000000..c630f3291e
--- /dev/null
+++ b/components/lwp/lwp_dbg.c
@@ -0,0 +1,119 @@
+#include <rtthread.h>
+#include <rthw.h>
+#include <lwp.h>
+
+int dbg_thread_in_debug(void)
+{
+ int ret = 0;
+ struct rt_lwp *lwp = lwp_self();
+
+ if (lwp && lwp->debug)
+ {
+ ret = 1;
+ }
+ return ret;
+}
+
+struct dbg_ops_t *rt_dbg_ops = RT_NULL;
+RTM_EXPORT(rt_dbg_ops);
+
+void dbg_register(struct dbg_ops_t *dbg_ops)
+{
+ rt_dbg_ops = dbg_ops;
+}
+RTM_EXPORT(dbg_register);
+
+static int dbg(int argc, char **argv)
+{
+ int ret = -1;
+
+ if (rt_dbg_ops)
+ {
+ ret = rt_dbg_ops->dbg(argc, argv);
+ }
+ else
+ {
+ rt_kprintf("Error: DBG command is not enabled!\n");
+ }
+ return ret;
+}
+MSH_CMD_EXPORT(dbg, dbg);
+
+uint32_t dbg_get_ins(void)
+{
+ uint32_t ins = 0;
+
+ if (rt_dbg_ops)
+ {
+ ins = rt_dbg_ops->arch_get_ins();
+ }
+ return ins;
+}
+
+void dbg_activate_step(void)
+{
+ if (rt_dbg_ops)
+ {
+ rt_dbg_ops->arch_activate_step();
+ }
+}
+
+void dbg_deactivate_step(void)
+{
+ if (rt_dbg_ops)
+ {
+ rt_dbg_ops->arch_deactivate_step();
+ }
+}
+
+int dbg_check_event(struct rt_hw_exp_stack *regs, unsigned long esr)
+{
+ int ret = 0;
+
+ if (rt_dbg_ops)
+ {
+ ret = rt_dbg_ops->check_debug_event(regs, esr);
+ }
+ return ret;
+}
+
+rt_channel_t gdb_server_channel(void)
+{
+ rt_channel_t ret = RT_NULL;
+
+ if (rt_dbg_ops)
+ {
+ ret = rt_dbg_ops->gdb_get_server_channel();
+ }
+ return ret;
+}
+
+int dbg_step_type(void)
+{
+ int ret = 0;
+
+ if (rt_dbg_ops)
+ {
+ ret = rt_dbg_ops->gdb_get_step_type();
+ }
+ return ret;
+}
+
+void dbg_attach_req(void *pc)
+{
+ if (rt_dbg_ops)
+ {
+ rt_dbg_ops->lwp_check_debug_attach_req(pc);
+ }
+}
+
+int dbg_check_suspend(void)
+{
+ int ret = 0;
+
+ if (rt_dbg_ops)
+ {
+ ret = rt_dbg_ops->lwp_check_debug_suspend();
+ }
+ return ret;
+}
diff --git a/components/lwp/lwp_elf.h b/components/lwp/lwp_elf.h
new file mode 100644
index 0000000000..e4817fe6f9
--- /dev/null
+++ b/components/lwp/lwp_elf.h
@@ -0,0 +1,3520 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-28 Jesven first version
+ */
+#ifndef LWP_ELF_H__
+#define LWP_ELF_H__
+
+#include <stdint.h>
+#include <rtthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ARCH_CPU_64BIT
+#define elfhdr elf64_hdr
+#define elf_phdr elf64_phdr
+#define elf_shdr elf64_shdr
+#define elf_note elf64_note
+#define elf_addr_t Elf64_Off
+#define Elf_Word Elf64_Word
+#define Elf_Addr Elf64_Addr
+#define Elf_Half Elf64_Half
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Phdr Elf64_Phdr
+#define Elf_Shdr Elf64_Shdr
+#else
+#define elfhdr elf32_hdr
+#define elf_phdr elf32_phdr
+#define elf_shdr elf32_shdr
+#define elf_note elf32_note
+#define elf_addr_t Elf32_Off
+#define Elf_Word Elf32_Word
+#define Elf_Addr Elf32_Addr
+#define Elf_Half Elf32_Half
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Phdr Elf32_Phdr
+#define Elf_Shdr Elf32_Shdr
+#endif
+
+/* Type for a 16-bit quantity. */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities. */
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities. */
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+/* Type of addresses. */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets. */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities. */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information. */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header. This appears at the start of every ELF file. */
+
+#define EI_NIDENT (16)
+
+typedef struct elfhdr
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf64_Half e_type; /* Object file type */
+ Elf64_Half e_machine; /* Architecture */
+ Elf64_Word e_version; /* Object file version */
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags; /* Processor-specific flags */
+ Elf64_Half e_ehsize; /* ELF header size in bytes */
+ Elf64_Half e_phentsize; /* Program header table entry size */
+ Elf64_Half e_phnum; /* Program header table entry count */
+ Elf64_Half e_shentsize; /* Section header table entry size */
+ Elf64_Half e_shnum; /* Section header table entry count */
+ Elf64_Half e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array. The EI_* macros are indices into the
+ array. The macros under each EI_* macro are the values the byte
+ may have. */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7f /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word. */
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFCLASSNUM 3
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+#define ELFDATANUM 3
+
+#define EI_VERSION 6 /* File version byte index */
+ /* Value must be EV_CURRENT */
+
+#define EI_OSABI 7 /* OS ABI identification */
+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
+#define ELFOSABI_SYSV 0 /* Alias. */
+#define ELFOSABI_HPUX 1 /* HP-UX */
+#define ELFOSABI_NETBSD 2 /* NetBSD. */
+#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */
+#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */
+#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
+#define ELFOSABI_AIX 7 /* IBM AIX. */
+#define ELFOSABI_IRIX 8 /* SGI Irix. */
+#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
+#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
+#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
+#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
+#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+#define EI_ABIVERSION 8 /* ABI version */
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type). */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_NUM 5 /* Number of defined types */
+#define ET_LOOS 0xfe00 /* OS-specific range start */
+#define ET_HIOS 0xfeff /* OS-specific range end */
+#define ET_LOPROC 0xff00 /* Processor-specific range start */
+#define ET_HIPROC 0xffff /* Processor-specific range end */
+
+/* Legal values for e_machine (architecture). */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_S370 9 /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
+
+#define EM_PARISC 15 /* HPPA */
+#define EM_VPP500 17 /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_960 19 /* Intel 80960 */
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC 64-bit */
+#define EM_S390 22 /* IBM S390 */
+
+#define EM_V800 36 /* NEC V800 series */
+#define EM_FR20 37 /* Fujitsu FR20 */
+#define EM_RH32 38 /* TRW RH-32 */
+#define EM_RCE 39 /* Motorola RCE */
+#define EM_ARM 40 /* ARM */
+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
+#define EM_SH 42 /* Hitachi SH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_TRICORE 44 /* Siemens Tricore */
+#define EM_ARC 45 /* Argonaut RISC Core */
+#define EM_H8_300 46 /* Hitachi H8/300 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+#define EM_H8_500 49 /* Hitachi H8/500 */
+#define EM_IA_64 50 /* Intel Merced */
+#define EM_MIPS_X 51 /* Stanford MIPS-X */
+#define EM_COLDFIRE 52 /* Motorola Coldfire */
+#define EM_68HC12 53 /* Motorola M68HC12 */
+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP 55 /* Siemens PCP */
+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
+#define EM_STARCORE 58 /* Motorola Start*Core processor */
+#define EM_ME16 59 /* Toyota ME16 processor */
+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64 62 /* AMD x86-64 architecture */
+#define EM_PDSP 63 /* Sony DSP Processor */
+
+#define EM_FX66 66 /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
+#define EM_SVX 73 /* Silicon Graphics SVx */
+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX 75 /* Digital VAX */
+#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY 81 /* Harvard University machine-independent object files */
+#define EM_PRISM 82 /* SiTera Prism */
+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30 84 /* Fujitsu FR30 */
+#define EM_D10V 85 /* Mitsubishi D10V */
+#define EM_D30V 86 /* Mitsubishi D30V */
+#define EM_V850 87 /* NEC v850 */
+#define EM_M32R 88 /* Mitsubishi M32R */
+#define EM_MN10300 89 /* Matsushita MN10300 */
+#define EM_MN10200 90 /* Matsushita MN10200 */
+#define EM_PJ 91 /* picoJava */
+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
+#define EM_ALTERA_NIOS2 113 /* Altera Nios II */
+#define EM_AARCH64 183 /* ARM AARCH64 */
+#define EM_TILEPRO 188 /* Tilera TILEPro */
+#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
+#define EM_TILEGX 191 /* Tilera TILE-Gx */
+#define EM_NUM 192
+
+/* If it is necessary to assign new unofficial EM_* values, please
+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+ chances of collision with official or non-GNU unofficial values. */
+
+#define EM_ALPHA 0x9026
+
+/* Legal values for e_version (version). */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+#define EV_NUM 2
+
+/* Section header. */
+
+typedef struct
+{
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+ Elf64_Word sh_name; /* Section name (string tbl index) */
+ Elf64_Word sh_type; /* Section type */
+ Elf64_Xword sh_flags; /* Section flags */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Xword sh_size; /* Section size in bytes */
+ Elf64_Word sh_link; /* Link to another section */
+ Elf64_Word sh_info; /* Additional section information */
+ Elf64_Xword sh_addralign; /* Section alignment */
+ Elf64_Xword sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices. */
+
+#define SHN_UNDEF 0 /* Undefined section */
+#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
+#define SHN_LOPROC 0xff00 /* Start of processor-specific */
+#define SHN_BEFORE 0xff00 /* Order section before all others
+ (Solaris). */
+#define SHN_AFTER 0xff01 /* Order section after all others
+ (Solaris). */
+#define SHN_HIPROC 0xff1f /* End of processor-specific */
+#define SHN_LOOS 0xff20 /* Start of OS-specific */
+#define SHN_HIOS 0xff3f /* End of OS-specific */
+#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xfff2 /* Associated symbol is common */
+#define SHN_XINDEX 0xffff /* Index is in extra table. */
+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
+
+/* Legal values for sh_type (section type). */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Dynamic linking information */
+#define SHT_NOTE 7 /* Notes */
+#define SHT_NOBITS 8 /* Program space with no data (bss) */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY 14 /* Array of constructors */
+#define SHT_FINI_ARRAY 15 /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
+#define SHT_GROUP 17 /* Section group */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+#define SHT_NUM 19 /* Number of defined types. */
+#define SHT_LOOS 0x60000000 /* Start OS-specific. */
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
+#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
+#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
+#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
+#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
+#define SHT_SUNW_move 0x6ffffffa
+#define SHT_SUNW_COMDAT 0x6ffffffb
+#define SHT_SUNW_syminfo 0x6ffffffc
+#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
+#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
+#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
+#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
+#define SHT_HIOS 0x6fffffff /* End OS-specific type */
+#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
+#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
+#define SHT_LOUSER 0x80000000 /* Start of application-specific */
+#define SHT_HIUSER 0x8fffffff /* End of application-specific */
+
+/* Legal values for sh_flags (section flags). */
+
+#define SHF_WRITE (1 << 0) /* Writable */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_MERGE (1 << 4) /* Might be merged */
+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling
+ required */
+#define SHF_GROUP (1 << 9) /* Section is member of a group. */
+#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
+#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
+#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
+#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
+#define SHF_ORDERED (1 << 30) /* Special ordering requirement
+ (Solaris). */
+#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless
+ referenced or allocated (Solaris).*/
+
+/* Section compression header. Used when SHF_COMPRESSED is set. */
+
+typedef struct
+{
+ Elf32_Word ch_type; /* Compression format. */
+ Elf32_Word ch_size; /* Uncompressed data size. */
+ Elf32_Word ch_addralign; /* Uncompressed data alignment. */
+} Elf32_Chdr;
+
+typedef struct
+{
+ Elf64_Word ch_type; /* Compression format. */
+ Elf64_Word ch_reserved;
+ Elf64_Xword ch_size; /* Uncompressed data size. */
+ Elf64_Xword ch_addralign; /* Uncompressed data alignment. */
+} Elf64_Chdr;
+
+/* Legal values for ch_type (compression algorithm). */
+#define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */
+#define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */
+#define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */
+#define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */
+#define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */
+
+/* Section group handling. */
+#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
+
+/* Symbol table entry. */
+
+typedef struct
+{
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+ Elf64_Word st_name; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf64_Section st_shndx; /* Section index */
+ Elf64_Addr st_value; /* Symbol value */
+ Elf64_Xword st_size; /* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+ every dynamic symbol. */
+
+typedef struct
+{
+ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf32_Half si_flags; /* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf64_Half si_flags; /* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto. */
+#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
+#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags. */
+#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
+ loaded */
+/* Syminfo version values. */
+#define SYMINFO_NONE 0
+#define SYMINFO_CURRENT 1
+#define SYMINFO_NUM 2
+
+
+/* How to extract and insert information held in the st_info field. */
+
+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val) ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types. */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_GNU_UNIQUE 10 /* Unique symbol. */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol's name is file name */
+#define STT_COMMON 5 /* Symbol is a common data object */
+#define STT_TLS 6 /* Symbol is thread-local data object*/
+#define STT_NUM 7 /* Number of defined types. */
+#define STT_LOOS 10 /* Start of OS-specific */
+#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
+#define STT_HIOS 12 /* End of OS-specific */
+#define STT_LOPROC 13 /* Start of processor-specific */
+#define STT_HIPROC 15 /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+ of a symbol hash table section. This special index value indicates
+ the end of a chain, meaning no further symbols are found in that bucket. */
+
+#define STN_UNDEF 0 /* End of a chain. */
+
+
+/* How to extract and insert information held in the st_other field. */
+
+#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
+
+/* For ELF64 the definitions are the same. */
+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field. */
+#define STV_DEFAULT 0 /* Default symbol visibility rules */
+#define STV_INTERNAL 1 /* Processor specific hidden class */
+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
+#define STV_PROTECTED 3 /* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+ Elf64_Rela structures, so we'll leave them out until Novell (or
+ whoever) gets their act together. */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+ Elf64_Sxword r_addend; /* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field. */
+
+#define ELF32_R_SYM(val) ((val) >> 8)
+#define ELF32_R_TYPE(val) ((val) & 0xff)
+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header. */
+
+typedef struct elf_phdr
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf64_Word p_type; /* Segment type */
+ Elf64_Word p_flags; /* Segment flags */
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment */
+} Elf64_Phdr;
+
+/* Special value for e_phnum. This indicates that the real number of
+ program headers is too large to fit into e_phnum. Instead the real
+ value is in the field sh_info of section 0. */
+
+#define PN_XNUM 0xffff
+
+/* Legal values for p_type (segment type). */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_TLS 7 /* Thread-local storage segment */
+#define PT_NUM 8 /* Number of defined types */
+#define PT_LOOS 0x60000000 /* Start of OS-specific */
+#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
+#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
+#define PT_LOSUNW 0x6ffffffa
+#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
+#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
+#define PT_HISUNW 0x6fffffff
+#define PT_HIOS 0x6fffffff /* End of OS-specific */
+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags). */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKOS 0x0ff00000 /* OS-specific */
+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+#define NT_PRXREG 4 /* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
+#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV 6 /* Contains copy of auxv array */
+#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
+#define NT_ASRS 8 /* Contains copy of asrset struct */
+#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
+#define NT_PSINFO 13 /* Contains copy of psinfo struct */
+#define NT_PRCRED 14 /* Contains copy of prcred struct */
+#define NT_UTSNAME 15 /* Contains copy of utsname struct */
+#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */
+#define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t,
+ size might increase */
+#define NT_FILE 0x46494c45 /* Contains information about mapped
+ files */
+#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */
+#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
+#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
+#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
+#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
+#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
+#define NT_S390_TIMER 0x301 /* s390 timer register */
+#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
+#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */
+#define NT_S390_CTRS 0x304 /* s390 control registers */
+#define NT_S390_PREFIX 0x305 /* s390 prefix register */
+#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
+#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
+#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
+#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
+#define NT_ARM_TLS 0x401 /* ARM TLS register */
+#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
+#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
+
+/* Legal values for the note segment descriptor types for object files. */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+
+/* Dynamic section entry. */
+
+typedef struct
+{
+ Elf32_Sword d_tag; /* Dynamic entry type */
+ union
+ {
+ Elf32_Word d_val; /* Integer value */
+ Elf32_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+ Elf64_Sxword d_tag; /* Dynamic entry type */
+ union
+ {
+ Elf64_Xword d_val; /* Integer value */
+ Elf64_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type). */
+
+#define DT_NULL 0 /* Marks end of dynamic section */
+#define DT_NEEDED 1 /* Name of needed library */
+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
+#define DT_PLTGOT 3 /* Processor defined value */
+#define DT_HASH 4 /* Address of symbol hash table */
+#define DT_STRTAB 5 /* Address of string table */
+#define DT_SYMTAB 6 /* Address of symbol table */
+#define DT_RELA 7 /* Address of Rela relocs */
+#define DT_RELASZ 8 /* Total size of Rela relocs */
+#define DT_RELAENT 9 /* Size of one Rela reloc */
+#define DT_STRSZ 10 /* Size of string table */
+#define DT_SYMENT 11 /* Size of one symbol table entry */
+#define DT_INIT 12 /* Address of init function */
+#define DT_FINI 13 /* Address of termination function */
+#define DT_SONAME 14 /* Name of shared object */
+#define DT_RPATH 15 /* Library search path (deprecated) */
+#define DT_SYMBOLIC 16 /* Start symbol search here */
+#define DT_REL 17 /* Address of Rel relocs */
+#define DT_RELSZ 18 /* Total size of Rel relocs */
+#define DT_RELENT 19 /* Size of one Rel reloc */
+#define DT_PLTREL 20 /* Type of reloc in PLT */
+#define DT_DEBUG 21 /* For debugging; unspecified */
+#define DT_TEXTREL 22 /* Reloc might modify .text */
+#define DT_JMPREL 23 /* Address of PLT relocs */
+#define DT_BIND_NOW 24 /* Process relocations of object */
+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH 29 /* Library search path */
+#define DT_FLAGS 30 /* Flags for the object being loaded */
+#define DT_ENCODING 32 /* Start of encoded range */
+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
+#define DT_NUM 34 /* Number used */
+#define DT_LOOS 0x6000000d /* Start of OS-specific */
+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
+#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
+ approach. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
+#define DT_CHECKSUM 0x6ffffdf8
+#define DT_PLTPADSZ 0x6ffffdf9
+#define DT_MOVEENT 0x6ffffdfa
+#define DT_MOVESZ 0x6ffffdfb
+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
+#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
+ the following DT_* entry. */
+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
+#define DT_VALRNGHI 0x6ffffdff
+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+ If any adjustment is made to the ELF object after it has been
+ built these entries will need to be adjusted. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
+#define DT_MOVETAB 0x6ffffefe /* Move table. */
+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
+#define DT_ADDRRNGHI 0x6ffffeff
+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
+#define DT_ADDRNUM 11
+
+/* The versioning entry types. The next are defined as part of the
+ GNU extension. */
+#define DT_VERSYM 0x6ffffff0
+
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+
+/* These were chosen by Sun. */
+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
+#define DT_VERDEF 0x6ffffffc /* Address of version definition
+ table */
+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
+#define DT_VERNEED 0x6ffffffe /* Address of table with needed
+ versions */
+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+ range. Be compatible. */
+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM 3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry. */
+#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
+#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
+#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
+#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+ entry in the dynamic section. */
+#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
+#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
+#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
+#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
+#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
+#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
+#define DF_1_TRANS 0x00000200
+#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
+#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
+#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
+#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
+#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
+#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
+#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
+#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */
+#define DF_1_IGNMULDEF 0x00040000
+#define DF_1_NOKSYMS 0x00080000
+#define DF_1_NOHDR 0x00100000
+#define DF_1_EDITED 0x00200000 /* Object is modified after built. */
+#define DF_1_NORELOC 0x00400000
+#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
+#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
+#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
+
+/* Flags for the feature selection in DT_FEATURE_1. */
+#define DTF_1_PARINIT 0x00000001
+#define DTF_1_CONFEXP 0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
+#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
+#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not
+ generally available. */
+
+/* Version definition sections. */
+
+typedef struct
+{
+ Elf32_Half vd_version; /* Version revision */
+ Elf32_Half vd_flags; /* Version information */
+ Elf32_Half vd_ndx; /* Version Index */
+ Elf32_Half vd_cnt; /* Number of associated aux entries */
+ Elf32_Word vd_hash; /* Version name hash value */
+ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf32_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+ Elf64_Half vd_version; /* Version revision */
+ Elf64_Half vd_flags; /* Version information */
+ Elf64_Half vd_ndx; /* Version Index */
+ Elf64_Half vd_cnt; /* Number of associated aux entries */
+ Elf64_Word vd_hash; /* Version name hash value */
+ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf64_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision). */
+#define VER_DEF_NONE 0 /* No version */
+#define VER_DEF_CURRENT 1 /* Current version */
+#define VER_DEF_NUM 2 /* Given version number */
+
+/* Legal values for vd_flags (version information flags). */
+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+/* Versym symbol index values. */
+#define VER_NDX_LOCAL 0 /* Symbol is local. */
+#define VER_NDX_GLOBAL 1 /* Symbol is global. */
+#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
+#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
+
+/* Auxialiary version information. */
+
+typedef struct
+{
+ Elf32_Word vda_name; /* Version or dependency names */
+ Elf32_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+ Elf64_Word vda_name; /* Version or dependency names */
+ Elf64_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section. */
+
+typedef struct
+{
+ Elf32_Half vn_version; /* Version of structure */
+ Elf32_Half vn_cnt; /* Number of associated aux entries */
+ Elf32_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf32_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+ Elf64_Half vn_version; /* Version of structure */
+ Elf64_Half vn_cnt; /* Number of associated aux entries */
+ Elf64_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf64_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision). */
+#define VER_NEED_NONE 0 /* No version */
+#define VER_NEED_CURRENT 1 /* Current version */
+#define VER_NEED_NUM 2 /* Given version number */
+
+/* Auxiliary needed version information. */
+
+typedef struct
+{
+ Elf32_Word vna_hash; /* Hash value of dependency name */
+ Elf32_Half vna_flags; /* Dependency specific information */
+ Elf32_Half vna_other; /* Unused */
+ Elf32_Word vna_name; /* Dependency name string offset */
+ Elf32_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+ Elf64_Word vna_hash; /* Hash value of dependency name */
+ Elf64_Half vna_flags; /* Dependency specific information */
+ Elf64_Half vna_other; /* Unused */
+ Elf64_Word vna_name; /* Dependency name string offset */
+ Elf64_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags. */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+
+/* Auxiliary vector. */
+
+/* This vector is normally only used by the program interpreter. The
+ usual definition in an ABI supplement uses the name auxv_t. The
+ vector is not usually defined in a standard <elf.h> file, but it
+ can't hurt. We rename it to avoid conflicts. The sizes of these
+ types are an arrangement between the exec server and the program
+ interpreter, so we don't fully specify them here. */
+
+typedef struct
+{
+ uint32_t a_type; /* Entry type */
+ union
+ {
+ uint32_t a_val; /* Integer value */
+ /* We use to have pointer elements added here. We cannot do that,
+ though, since it does not work when using 32-bit definitions
+ on 64-bit platforms and vice versa. */
+ } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+ uint64_t a_type; /* Entry type */
+ union
+ {
+ uint64_t a_val; /* Integer value */
+ /* We use to have pointer elements added here. We cannot do that,
+ though, since it does not work when using 32-bit definitions
+ on 64-bit platforms and vice versa. */
+ } a_un;
+} Elf64_auxv_t;
+
+//#include <bits/auxv.h>
+/* Note section contents. Each entry in the note section begins with
+ a header of a fixed form. */
+
+typedef struct
+{
+ Elf32_Word n_namesz; /* Length of the note's name. */
+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
+ Elf32_Word n_type; /* Type of the note. */
+} Elf32_Nhdr;
+
+typedef struct
+{
+ Elf64_Word n_namesz; /* Length of the note's name. */
+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
+ Elf64_Word n_type; /* Type of the note. */
+} Elf64_Nhdr;
+
+/* Known names of notes. */
+
+/* Solaris entries in the note section have this name. */
+#define ELF_NOTE_SOLARIS "SUNW Solaris"
+
+/* Note entries for GNU systems have this name. */
+#define ELF_NOTE_GNU "GNU"
+
+
+/* Defined types of notes for Solaris. */
+
+/* Value of descriptor (one word) is desired pagesize for the binary. */
+#define ELF_NOTE_PAGESIZE_HINT 1
+
+
+/* Defined note types for GNU systems. */
+
+/* ABI information. The descriptor consists of words:
+ word 0: OS descriptor
+ word 1: major version of the ABI
+ word 2: minor version of the ABI
+ word 3: subminor version of the ABI
+*/
+#define NT_GNU_ABI_TAG 1
+#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */
+
+/* Known OSes. These values can appear in word 0 of an
+ NT_GNU_ABI_TAG note section entry. */
+#define ELF_NOTE_OS_LINUX 0
+#define ELF_NOTE_OS_GNU 1
+#define ELF_NOTE_OS_SOLARIS2 2
+#define ELF_NOTE_OS_FREEBSD 3
+
+/* Synthetic hwcap information. The descriptor begins with two words:
+ word 0: number of entries
+ word 1: bitmask of enabled entries
+ Then follow variable-length entries, one byte followed by a
+ '\0'-terminated hwcap name string. The byte gives the bit
+ number to test if enabled, (1U << bit) & bitmask. */
+#define NT_GNU_HWCAP 2
+
+/* Build ID bits as generated by ld --build-id.
+ The descriptor consists of any nonzero number of bytes. */
+#define NT_GNU_BUILD_ID 3
+
+/* Version note generated by GNU gold containing a version string. */
+#define NT_GNU_GOLD_VERSION 4
+
+
+/* Move records. */
+typedef struct
+{
+ Elf32_Xword m_value; /* Symbol value. */
+ Elf32_Word m_info; /* Size and index. */
+ Elf32_Word m_poffset; /* Symbol offset. */
+ Elf32_Half m_repeat; /* Repeat count. */
+ Elf32_Half m_stride; /* Stride info. */
+} Elf32_Move;
+
+typedef struct
+{
+ Elf64_Xword m_value; /* Symbol value. */
+ Elf64_Xword m_info; /* Size and index. */
+ Elf64_Xword m_poffset; /* Symbol offset. */
+ Elf64_Half m_repeat; /* Repeat count. */
+ Elf64_Half m_stride; /* Stride info. */
+} Elf64_Move;
+
+/* Macro to construct move records. */
+#define ELF32_M_SYM(info) ((info) >> 8)
+#define ELF32_M_SIZE(info) ((unsigned char) (info))
+#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info) ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions. */
+
+/* Values for Elf32_Ehdr.e_flags. */
+#define EF_CPU32 0x00810000
+
+/* m68k relocs. */
+
+#define R_68K_NONE 0 /* No reloc */
+#define R_68K_32 1 /* Direct 32 bit */
+#define R_68K_16 2 /* Direct 16 bit */
+#define R_68K_8 3 /* Direct 8 bit */
+#define R_68K_PC32 4 /* PC relative 32 bit */
+#define R_68K_PC16 5 /* PC relative 16 bit */
+#define R_68K_PC8 6 /* PC relative 8 bit */
+#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
+#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
+#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O 10 /* 32 bit GOT offset */
+#define R_68K_GOT16O 11 /* 16 bit GOT offset */
+#define R_68K_GOT8O 12 /* 8 bit GOT offset */
+#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
+#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
+#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
+#define R_68K_PLT32O 16 /* 32 bit PLT offset */
+#define R_68K_PLT16O 17 /* 16 bit PLT offset */
+#define R_68K_PLT8O 18 /* 8 bit PLT offset */
+#define R_68K_COPY 19 /* Copy symbol at runtime */
+#define R_68K_GLOB_DAT 20 /* Create GOT entry */
+#define R_68K_JMP_SLOT 21 /* Create PLT entry */
+#define R_68K_RELATIVE 22 /* Adjust by program base */
+#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32 37 /* 32 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_LE16 38 /* 16 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_LE8 39 /* 8 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */
+#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */
+/* Keep this the last entry. */
+#define R_68K_NUM 43
+
+/* Intel 80386 specific definitions. */
+
+/* i386 relocs. */
+
+#define R_386_NONE 0 /* No reloc */
+#define R_386_32 1 /* Direct 32 bit */
+#define R_386_PC32 2 /* PC relative 32 bit */
+#define R_386_GOT32 3 /* 32 bit GOT entry */
+#define R_386_PLT32 4 /* 32 bit PLT address */
+#define R_386_COPY 5 /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6 /* Create GOT entry */
+#define R_386_JMP_SLOT 7 /* Create PLT entry */
+#define R_386_RELATIVE 8 /* Adjust by program base */
+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
+#define R_386_32PLT 11
+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
+#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
+ block offset */
+#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
+ offset */
+#define R_386_TLS_LE 17 /* Offset relative to static TLS
+ block */
+#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
+ general dynamic thread local data */
+#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
+ local dynamic thread local data
+ in LE code */
+#define R_386_16 20
+#define R_386_PC16 21
+#define R_386_8 22
+#define R_386_PC8 23
+#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
+ thread local data */
+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL 26 /* Relocation for call to
+ __tls_get_addr() */
+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
+ thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
+ __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
+#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
+ block offset */
+#define R_386_TLS_LE_32 34 /* Negated offset relative to static
+ TLS block */
+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
+#define R_386_SIZE32 38 /* 32-bit symbol size */
+#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */
+#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS
+ descriptor for
+ relaxation. */
+#define R_386_TLS_DESC 41 /* TLS descriptor containing
+ pointer to code and to
+ argument, returning the TLS
+ offset for the symbol. */
+#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
+/* Keep this the last entry. */
+#define R_386_NUM 43
+
+/* SUN SPARC specific definitions. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs. */
+
+#define R_SPARC_NONE 0 /* No reloc */
+#define R_SPARC_8 1 /* Direct 8 bit */
+#define R_SPARC_16 2 /* Direct 16 bit */
+#define R_SPARC_32 3 /* Direct 32 bit */
+#define R_SPARC_DISP8 4 /* PC relative 8 bit */
+#define R_SPARC_DISP16 5 /* PC relative 16 bit */
+#define R_SPARC_DISP32 6 /* PC relative 32 bit */
+#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
+#define R_SPARC_HI22 9 /* High 22 bit */
+#define R_SPARC_22 10 /* Direct 22 bit */
+#define R_SPARC_13 11 /* Direct 13 bit */
+#define R_SPARC_LO10 12 /* Truncated 10 bit */
+#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
+#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
+#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY 19 /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
+#define R_SPARC_RELATIVE 22 /* Adjust by program base */
+#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs. */
+
+#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10 30 /* Direct 10 bit */
+#define R_SPARC_11 31 /* Direct 11 bit */
+#define R_SPARC_64 32 /* Direct 64 bit */
+#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
+#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
+#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */
+#define R_SPARC_7 43 /* Direct 7 bit */
+#define R_SPARC_5 44 /* Direct 5 bit */
+#define R_SPARC_6 45 /* Direct 6 bit */
+#define R_SPARC_DISP64 46 /* PC relative 64 bit */
+#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22 48 /* High 22 bit complemented */
+#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
+#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
+#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
+#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER 53 /* Global register usage */
+#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
+#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22 56
+#define R_SPARC_TLS_GD_LO10 57
+#define R_SPARC_TLS_GD_ADD 58
+#define R_SPARC_TLS_GD_CALL 59
+#define R_SPARC_TLS_LDM_HI22 60
+#define R_SPARC_TLS_LDM_LO10 61
+#define R_SPARC_TLS_LDM_ADD 62
+#define R_SPARC_TLS_LDM_CALL 63
+#define R_SPARC_TLS_LDO_HIX22 64
+#define R_SPARC_TLS_LDO_LOX10 65
+#define R_SPARC_TLS_LDO_ADD 66
+#define R_SPARC_TLS_IE_HI22 67
+#define R_SPARC_TLS_IE_LO10 68
+#define R_SPARC_TLS_IE_LD 69
+#define R_SPARC_TLS_IE_LDX 70
+#define R_SPARC_TLS_IE_ADD 71
+#define R_SPARC_TLS_LE_HIX22 72
+#define R_SPARC_TLS_LE_LOX10 73
+#define R_SPARC_TLS_DTPMOD32 74
+#define R_SPARC_TLS_DTPMOD64 75
+#define R_SPARC_TLS_DTPOFF32 76
+#define R_SPARC_TLS_DTPOFF64 77
+#define R_SPARC_TLS_TPOFF32 78
+#define R_SPARC_TLS_TPOFF64 79
+#define R_SPARC_GOTDATA_HIX22 80
+#define R_SPARC_GOTDATA_LOX10 81
+#define R_SPARC_GOTDATA_OP_HIX22 82
+#define R_SPARC_GOTDATA_OP_LOX10 83
+#define R_SPARC_GOTDATA_OP 84
+#define R_SPARC_H34 85
+#define R_SPARC_SIZE32 86
+#define R_SPARC_SIZE64 87
+#define R_SPARC_WDISP10 88
+#define R_SPARC_JMP_IREL 248
+#define R_SPARC_IRELATIVE 249
+#define R_SPARC_GNU_VTINHERIT 250
+#define R_SPARC_GNU_VTENTRY 251
+#define R_SPARC_REV32 252
+/* Keep this the last entry. */
+#define R_SPARC_NUM 253
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM 2
+
+/* MIPS R3000 specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
+#define EF_MIPS_PIC 2 /* Contains PIC code. */
+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
+#define EF_MIPS_XGOT 8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2 32
+#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
+#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
+
+/* Legal values for MIPS architecture level. */
+
+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
+#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
+#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
+#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */
+#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */
+
+/* The following are unofficial names and should not be used. */
+
+#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1
+#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2
+#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3
+#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4
+#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5
+#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32
+#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64
+
+/* Special section indices. */
+
+#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */
+#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
+#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
+#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */
+#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */
+#define SHT_MIPS_MSYM 0x70000001
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */
+#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */
+#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */
+#define SHT_MIPS_PACKAGE 0x70000007
+#define SHT_MIPS_PACKSYM 0x70000008
+#define SHT_MIPS_RELD 0x70000009
+#define SHT_MIPS_IFACE 0x7000000b
+#define SHT_MIPS_CONTENT 0x7000000c
+#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
+#define SHT_MIPS_SHDR 0x70000010
+#define SHT_MIPS_FDESC 0x70000011
+#define SHT_MIPS_EXTSYM 0x70000012
+#define SHT_MIPS_DENSE 0x70000013
+#define SHT_MIPS_PDESC 0x70000014
+#define SHT_MIPS_LOCSYM 0x70000015
+#define SHT_MIPS_AUXSYM 0x70000016
+#define SHT_MIPS_OPTSYM 0x70000017
+#define SHT_MIPS_LOCSTR 0x70000018
+#define SHT_MIPS_LINE 0x70000019
+#define SHT_MIPS_RFDESC 0x7000001a
+#define SHT_MIPS_DELTASYM 0x7000001b
+#define SHT_MIPS_DELTAINST 0x7000001c
+#define SHT_MIPS_DELTACLASS 0x7000001d
+#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
+#define SHT_MIPS_DELTADECL 0x7000001f
+#define SHT_MIPS_SYMBOL_LIB 0x70000020
+#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
+#define SHT_MIPS_TRANSLATE 0x70000022
+#define SHT_MIPS_PIXIE 0x70000023
+#define SHT_MIPS_XLATE 0x70000024
+#define SHT_MIPS_XLATE_DEBUG 0x70000025
+#define SHT_MIPS_WHIRL 0x70000026
+#define SHT_MIPS_EH_REGION 0x70000027
+#define SHT_MIPS_XLATE_OLD 0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */
+#define SHF_MIPS_MERGE 0x20000000
+#define SHF_MIPS_ADDR 0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL 0x04000000
+#define SHF_MIPS_NAMES 0x02000000
+#define SHF_MIPS_NODUPE 0x01000000
+
+
+/* Symbol tables. */
+
+/* MIPS specific values for `st_other'. */
+#define STO_MIPS_DEFAULT 0x0
+#define STO_MIPS_INTERNAL 0x1
+#define STO_MIPS_HIDDEN 0x2
+#define STO_MIPS_PROTECTED 0x3
+#define STO_MIPS_PLT 0x8
+#define STO_MIPS_SC_ALIGN_UNUSED 0xff
+
+/* MIPS specific values for `st_info'. */
+#define STB_MIPS_SPLIT_COMMON 13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB. */
+
+typedef union
+{
+ struct
+ {
+ Elf32_Word gt_current_g_value; /* -G value used for compilation. */
+ Elf32_Word gt_unused; /* Not used. */
+ } gt_header; /* First entry in section. */
+ struct
+ {
+ Elf32_Word gt_g_value; /* If this value were used for -G. */
+ Elf32_Word gt_bytes; /* This many bytes would be used. */
+ } gt_entry; /* Subsequent entries in section. */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO. */
+
+typedef struct
+{
+ Elf32_Word ri_gprmask; /* General registers used. */
+ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used. */
+ Elf32_Sword ri_gp_value; /* $gp register value. */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS. */
+
+typedef struct
+{
+ unsigned char kind; /* Determines interpretation of the
+ variable part of descriptor. */
+ unsigned char size; /* Size of descriptor, including header. */
+ Elf32_Section section; /* Section header index of section affected,
+ 0 for global options. */
+ Elf32_Word info; /* Kind-specific information. */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options. */
+
+#define ODK_NULL 0 /* Undefined. */
+#define ODK_REGINFO 1 /* Register usage information. */
+#define ODK_EXCEPTIONS 2 /* Exception processing options. */
+#define ODK_PAD 3 /* Section padding options. */
+#define ODK_HWPATCH 4 /* Hardware workarounds performed */
+#define ODK_FILL 5 /* record the fill value used by the linker. */
+#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
+#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
+#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
+
+#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
+#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
+#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
+#define OEX_SMM 0x20000 /* Force sequential memory mode? */
+#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
+#define OEX_PRECISEFP OEX_FPDBUG
+#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
+
+#define OEX_FPU_INVAL 0x10
+#define OEX_FPU_DIV0 0x08
+#define OEX_FPU_OFLO 0x04
+#define OEX_FPU_UFLO 0x02
+#define OEX_FPU_INEX 0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
+
+#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
+#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
+#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
+#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
+
+#define OPAD_PREFIX 0x1
+#define OPAD_POSTFIX 0x2
+#define OPAD_SYMBOL 0x4
+
+/* Entry found in `.options' section. */
+
+typedef struct
+{
+ Elf32_Word hwp_flags1; /* Extra flags. */
+ Elf32_Word hwp_flags2; /* Extra flags. */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
+
+#define OHWA0_R4KEOP_CHECKED 0x00000001
+#define OHWA1_R4KEOP_CLEAN 0x00000002
+
+/* MIPS relocs. */
+
+#define R_MIPS_NONE 0 /* No reloc */
+#define R_MIPS_16 1 /* Direct 16 bit */
+#define R_MIPS_32 2 /* Direct 32 bit */
+#define R_MIPS_REL32 3 /* PC relative 32 bit */
+#define R_MIPS_26 4 /* Direct 26 bit shifted */
+#define R_MIPS_HI16 5 /* High 16 bit */
+#define R_MIPS_LO16 6 /* Low 16 bit */
+#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
+#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
+#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
+#define R_MIPS_PC16 10 /* PC relative 16 bit */
+#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+#define R_MIPS_GOT_HI16 22
+#define R_MIPS_GOT_LO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+#define R_MIPS_CALL_HI16 30
+#define R_MIPS_CALL_LO16 31
+#define R_MIPS_SCN_DISP 32
+#define R_MIPS_REL16 33
+#define R_MIPS_ADD_IMMEDIATE 34
+#define R_MIPS_PJUMP 35
+#define R_MIPS_RELGOT 36
+#define R_MIPS_JALR 37
+#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */
+#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */
+#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */
+#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */
+#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */
+#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */
+#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */
+#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */
+#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */
+#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */
+#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */
+#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */
+#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */
+#define R_MIPS_GLOB_DAT 51
+#define R_MIPS_COPY 126
+#define R_MIPS_JUMP_SLOT 127
+/* Keep this the last entry. */
+#define R_MIPS_NUM 128
+
+/* Legal values for p_type field of Elf32_Phdr. */
+
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */
+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */
+
+/* Special program header types. */
+
+#define PF_MIPS_LOCAL 0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn. */
+
+#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
+#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
+#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS 0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
+#define DT_MIPS_MSYM 0x70000007
+#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
+#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
+#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
+#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
+ DT_MIPS_DELTA_CLASS. */
+#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+ DT_MIPS_DELTA_INSTANCE. */
+#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+ DT_MIPS_DELTA_RELOC. */
+#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
+ relocations refer to. */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+ DT_MIPS_DELTA_SYM. */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+ class declaration. */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+ DT_MIPS_DELTA_CLASSSYM. */
+#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
+#define DT_MIPS_PIXIE_INIT 0x70000023
+#define DT_MIPS_SYMBOL_LIB 0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
+#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+ function stored in GOT. */
+#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added
+ by rld on dlopen() calls. */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
+#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
+/* The address of .got.plt in an executable using the new non-PIC ABI. */
+#define DT_MIPS_PLTGOT 0x70000032
+/* The base of the PLT in an executable using the new non-PIC ABI if that
+ PLT is writable. For a non-writable PLT, this is omitted or has a zero
+ value. */
+#define DT_MIPS_RWPLT 0x70000034
+/* An alternative description of the classic MIPS RLD_MAP that is usable
+ in a PIE as it stores a relative offset from the address of the tag
+ rather than an absolute address. */
+#define DT_MIPS_RLD_MAP_REL 0x70000035
+#define DT_MIPS_NUM 0x36
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
+
+#define RHF_NONE 0 /* No flags */
+#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
+#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE (1 << 3)
+#define RHF_SGI_ONLY (1 << 4)
+#define RHF_GUARANTEE_INIT (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
+#define RHF_GUARANTEE_START_INIT (1 << 7)
+#define RHF_PIXIE (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
+#define RHF_REQUICKSTART (1 << 10)
+#define RHF_REQUICKSTARTED (1 << 11)
+#define RHF_CORD (1 << 12)
+#define RHF_NO_UNRES_UNDEF (1 << 13)
+#define RHF_RLD_ORDER_SAFE (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST. */
+
+typedef struct
+{
+ Elf32_Word l_name; /* Name (string table index) */
+ Elf32_Word l_time_stamp; /* Timestamp */
+ Elf32_Word l_checksum; /* Checksum */
+ Elf32_Word l_version; /* Interface version */
+ Elf32_Word l_flags; /* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+ Elf64_Word l_name; /* Name (string table index) */
+ Elf64_Word l_time_stamp; /* Timestamp */
+ Elf64_Word l_checksum; /* Checksum */
+ Elf64_Word l_version; /* Interface version */
+ Elf64_Word l_flags; /* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags. */
+
+#define LL_NONE 0
+#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
+#define LL_REQUIRE_MINOR (1 << 2)
+#define LL_EXPORTS (1 << 3)
+#define LL_DELAY_LOAD (1 << 4)
+#define LL_DELTA (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT. */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+typedef struct
+{
+ /* Version of flags structure. */
+ Elf32_Half version;
+ /* The level of the ISA: 1-5, 32, 64. */
+ unsigned char isa_level;
+ /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
+ unsigned char isa_rev;
+ /* The size of general purpose registers. */
+ unsigned char gpr_size;
+ /* The size of co-processor 1 registers. */
+ unsigned char cpr1_size;
+ /* The size of co-processor 2 registers. */
+ unsigned char cpr2_size;
+ /* The floating-point ABI. */
+ unsigned char fp_abi;
+ /* Processor-specific extension. */
+ Elf32_Word isa_ext;
+ /* Mask of ASEs used. */
+ Elf32_Word ases;
+ /* Mask of general flags. */
+ Elf32_Word flags1;
+ Elf32_Word flags2;
+} Elf_MIPS_ABIFlags_v0;
+
+/* Values for the register size bytes of an abi flags structure. */
+
+#define MIPS_AFL_REG_NONE 0x00 /* No registers. */
+#define MIPS_AFL_REG_32 0x01 /* 32-bit registers. */
+#define MIPS_AFL_REG_64 0x02 /* 64-bit registers. */
+#define MIPS_AFL_REG_128 0x03 /* 128-bit registers. */
+
+/* Masks for the ases word of an ABI flags structure. */
+
+#define MIPS_AFL_ASE_DSP 0x00000001 /* DSP ASE. */
+#define MIPS_AFL_ASE_DSPR2 0x00000002 /* DSP R2 ASE. */
+#define MIPS_AFL_ASE_EVA 0x00000004 /* Enhanced VA Scheme. */
+#define MIPS_AFL_ASE_MCU 0x00000008 /* MCU (MicroController) ASE. */
+#define MIPS_AFL_ASE_MDMX 0x00000010 /* MDMX ASE. */
+#define MIPS_AFL_ASE_MIPS3D 0x00000020 /* MIPS-3D ASE. */
+#define MIPS_AFL_ASE_MT 0x00000040 /* MT ASE. */
+#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 /* SmartMIPS ASE. */
+#define MIPS_AFL_ASE_VIRT 0x00000100 /* VZ ASE. */
+#define MIPS_AFL_ASE_MSA 0x00000200 /* MSA ASE. */
+#define MIPS_AFL_ASE_MIPS16 0x00000400 /* MIPS16 ASE. */
+#define MIPS_AFL_ASE_MICROMIPS 0x00000800 /* MICROMIPS ASE. */
+#define MIPS_AFL_ASE_XPA 0x00001000 /* XPA ASE. */
+#define MIPS_AFL_ASE_MASK 0x00001fff /* All ASEs. */
+
+/* Values for the isa_ext word of an ABI flags structure. */
+
+#define MIPS_AFL_EXT_XLR 1 /* RMI Xlr instruction. */
+#define MIPS_AFL_EXT_OCTEON2 2 /* Cavium Networks Octeon2. */
+#define MIPS_AFL_EXT_OCTEONP 3 /* Cavium Networks OcteonP. */
+#define MIPS_AFL_EXT_LOONGSON_3A 4 /* Loongson 3A. */
+#define MIPS_AFL_EXT_OCTEON 5 /* Cavium Networks Octeon. */
+#define MIPS_AFL_EXT_5900 6 /* MIPS R5900 instruction. */
+#define MIPS_AFL_EXT_4650 7 /* MIPS R4650 instruction. */
+#define MIPS_AFL_EXT_4010 8 /* LSI R4010 instruction. */
+#define MIPS_AFL_EXT_4100 9 /* NEC VR4100 instruction. */
+#define MIPS_AFL_EXT_3900 10 /* Toshiba R3900 instruction. */
+#define MIPS_AFL_EXT_10000 11 /* MIPS R10000 instruction. */
+#define MIPS_AFL_EXT_SB1 12 /* Broadcom SB-1 instruction. */
+#define MIPS_AFL_EXT_4111 13 /* NEC VR4111/VR4181 instruction. */
+#define MIPS_AFL_EXT_4120 14 /* NEC VR4120 instruction. */
+#define MIPS_AFL_EXT_5400 15 /* NEC VR5400 instruction. */
+#define MIPS_AFL_EXT_5500 16 /* NEC VR5500 instruction. */
+#define MIPS_AFL_EXT_LOONGSON_2E 17 /* ST Microelectronics Loongson 2E. */
+#define MIPS_AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */
+
+/* Masks for the flags1 word of an ABI flags structure. */
+#define MIPS_AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */
+
+/* Object attribute values. */
+enum
+{
+ /* Not tagged or not using any ABIs affected by the differences. */
+ Val_GNU_MIPS_ABI_FP_ANY = 0,
+ /* Using hard-float -mdouble-float. */
+ Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+ /* Using hard-float -msingle-float. */
+ Val_GNU_MIPS_ABI_FP_SINGLE = 2,
+ /* Using soft-float. */
+ Val_GNU_MIPS_ABI_FP_SOFT = 3,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_OLD_64 = 4,
+ /* Using -mfpxx. */
+ Val_GNU_MIPS_ABI_FP_XX = 5,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_64 = 6,
+ /* Using -mips32r2 -mfp64 -mno-odd-spreg. */
+ Val_GNU_MIPS_ABI_FP_64A = 7,
+ /* Maximum allocated FP ABI value. */
+ Val_GNU_MIPS_ABI_FP_MAX = 7
+};
+
+/* HPPA specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
+#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
+ prediction. */
+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
+
+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
+
+/* Additional section indeces. */
+
+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
+ symbols in ANSI C. */
+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
+
+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
+#define STT_HP_STUB (STT_LOOS + 0x2)
+
+/* HPPA relocs. */
+
+#define R_PARISC_NONE 0 /* No reloc. */
+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
+#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */
+#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */
+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LORESERVE 128
+#define R_PARISC_COPY 128 /* Copy relocation. */
+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_GNU_VTENTRY 232
+#define R_PARISC_GNU_VTINHERIT 233
+#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */
+#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */
+#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */
+#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */
+#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */
+#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */
+#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */
+#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */
+#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */
+#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */
+#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L
+#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R
+#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L
+#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R
+#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32
+#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64
+#define R_PARISC_HIRESERVE 255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PT_HP_TLS (PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
+#define PT_HP_STACK (PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT 0x70000000
+#define PT_PARISC_UNWIND 0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PF_PARISC_SBP 0x08000000
+
+#define PF_HP_PAGE_SIZE 0x00100000
+#define PF_HP_FAR_SHARED 0x00200000
+#define PF_HP_NEAR_SHARED 0x00400000
+#define PF_HP_CODE 0x01000000
+#define PF_HP_MODIFY 0x02000000
+#define PF_HP_LAZYSWAP 0x04000000
+#define PF_HP_SBP 0x08000000
+
+
+/* Alpha specific definitions. */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
+
+/* Legal values for sh_type field of Elf64_Shdr. */
+
+/* These two are primerily concerned with ECOFF debugging info. */
+#define SHT_ALPHA_DEBUG 0x70000001
+#define SHT_ALPHA_REGINFO 0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr. */
+
+#define SHF_ALPHA_GPREL 0x10000000
+
+/* Legal values for st_other field of Elf64_Sym. */
+#define STO_ALPHA_NOPV 0x80 /* No PV required. */
+#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
+
+/* Alpha relocs. */
+
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI 28
+#define R_ALPHA_TLSGD 29
+#define R_ALPHA_TLS_LDM 30
+#define R_ALPHA_DTPMOD64 31
+#define R_ALPHA_GOTDTPREL 32
+#define R_ALPHA_DTPREL64 33
+#define R_ALPHA_DTPRELHI 34
+#define R_ALPHA_DTPRELLO 35
+#define R_ALPHA_DTPREL16 36
+#define R_ALPHA_GOTTPREL 37
+#define R_ALPHA_TPREL64 38
+#define R_ALPHA_TPRELHI 39
+#define R_ALPHA_TPRELLO 40
+#define R_ALPHA_TPREL16 41
+/* Keep this the last entry. */
+#define R_ALPHA_NUM 46
+
+/* Magic values of the LITUSE relocation addend. */
+#define LITUSE_ALPHA_ADDR 0
+#define LITUSE_ALPHA_BASE 1
+#define LITUSE_ALPHA_BYTOFF 2
+#define LITUSE_ALPHA_JSR 3
+#define LITUSE_ALPHA_TLS_GD 4
+#define LITUSE_ALPHA_TLS_LDM 5
+
+/* Legal values for d_tag of Elf64_Dyn. */
+#define DT_ALPHA_PLTRO (DT_LOPROC + 0)
+#define DT_ALPHA_NUM 1
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags. */
+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
+ flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE 0
+#define R_PPC_ADDR32 1 /* 32bit absolute address */
+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
+#define R_PPC_ADDR16 3 /* 16bit absolute address */
+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN 8
+#define R_PPC_ADDR14_BRNTAKEN 9
+#define R_PPC_REL24 10 /* PC relative 26 bit */
+#define R_PPC_REL14 11 /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN 12
+#define R_PPC_REL14_BRNTAKEN 13
+#define R_PPC_GOT16 14
+#define R_PPC_GOT16_LO 15
+#define R_PPC_GOT16_HI 16
+#define R_PPC_GOT16_HA 17
+#define R_PPC_PLTREL24 18
+#define R_PPC_COPY 19
+#define R_PPC_GLOB_DAT 20
+#define R_PPC_JMP_SLOT 21
+#define R_PPC_RELATIVE 22
+#define R_PPC_LOCAL24PC 23
+#define R_PPC_UADDR32 24
+#define R_PPC_UADDR16 25
+#define R_PPC_REL32 26
+#define R_PPC_PLT32 27
+#define R_PPC_PLTREL32 28
+#define R_PPC_PLT16_LO 29
+#define R_PPC_PLT16_HI 30
+#define R_PPC_PLT16_HA 31
+#define R_PPC_SDAREL16 32
+#define R_PPC_SECTOFF 33
+#define R_PPC_SECTOFF_LO 34
+#define R_PPC_SECTOFF_HI 35
+#define R_PPC_SECTOFF_HA 36
+
+/* PowerPC relocations defined for the TLS access ABI. */
+#define R_PPC_TLS 67 /* none (sym+add)@tls */
+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
+#define R_PPC_TLSGD 95 /* none (sym+add)@tlsgd */
+#define R_PPC_TLSLD 96 /* none (sym+add)@tlsld */
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+ in the SVR4 ELF ABI. */
+#define R_PPC_EMB_NADDR32 101
+#define R_PPC_EMB_NADDR16 102
+#define R_PPC_EMB_NADDR16_LO 103
+#define R_PPC_EMB_NADDR16_HI 104
+#define R_PPC_EMB_NADDR16_HA 105
+#define R_PPC_EMB_SDAI16 106
+#define R_PPC_EMB_SDA2I16 107
+#define R_PPC_EMB_SDA2REL 108
+#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF 110
+#define R_PPC_EMB_RELSEC16 111
+#define R_PPC_EMB_RELST_LO 112
+#define R_PPC_EMB_RELST_HI 113
+#define R_PPC_EMB_RELST_HA 114
+#define R_PPC_EMB_BIT_FLD 115
+#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
+
+/* Diab tool relocations. */
+#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
+
+/* GNU extension to support local ifunc. */
+#define R_PPC_IRELATIVE 248
+
+/* GNU relocs used in PIC code sequences. */
+#define R_PPC_REL16 249 /* half16 (sym+add-.) */
+#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */
+#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */
+#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+ that may still be in object files. */
+#define R_PPC_TOC16 255
+
+/* PowerPC specific values for the Dyn d_tag field. */
+#define DT_PPC_GOT (DT_LOPROC + 0)
+#define DT_PPC_OPT (DT_LOPROC + 1)
+#define DT_PPC_NUM 2
+
+/* PowerPC specific values for the DT_PPC_OPT Dyn entry. */
+#define PPC_OPT_TLS 1
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE R_PPC_NONE
+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16 R_PPC_GOT16
+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
+
+#define R_PPC64_COPY R_PPC_COPY
+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32 R_PPC_UADDR32
+#define R_PPC64_UADDR16 R_PPC_UADDR16
+#define R_PPC64_REL32 R_PPC_REL32
+#define R_PPC64_PLT32 R_PPC_PLT32
+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI. */
+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
+#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */
+#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */
+#define R_PPC64_TOCSAVE 109 /* none */
+
+/* Added when HA and HI relocs were changed to report overflows. */
+#define R_PPC64_ADDR16_HIGH 110
+#define R_PPC64_ADDR16_HIGHA 111
+#define R_PPC64_TPREL16_HIGH 112
+#define R_PPC64_TPREL16_HIGHA 113
+#define R_PPC64_DTPREL16_HIGH 114
+#define R_PPC64_DTPREL16_HIGHA 115
+
+/* GNU extension to support local ifunc. */
+#define R_PPC64_JMP_IREL 247
+#define R_PPC64_IRELATIVE 248
+#define R_PPC64_REL16 249 /* half16 (sym+add-.) */
+#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */
+#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
+#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
+/* e_flags bits specifying ABI.
+ 1 for original function descriptor using ABI,
+ 2 for revised ABI without function descriptors,
+ 0 for unspecified or not using any features affected by the differences. */
+#define EF_PPC64_ABI 3
+
+/* PowerPC64 specific values for the Dyn d_tag field. */
+#define DT_PPC64_GLINK (DT_LOPROC + 0)
+#define DT_PPC64_OPD (DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_OPT (DT_LOPROC + 3)
+#define DT_PPC64_NUM 4
+
+/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */
+#define PPC64_OPT_TLS 1
+#define PPC64_OPT_MULTI_TOC 2
+
+/* PowerPC64 specific values for the Elf64_Sym st_other field. */
+#define STO_PPC64_LOCAL_BIT 5
+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
+#define PPC64_LOCAL_ENTRY_OFFSET(other) \
+ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_ARM_RELEXEC 0x01
+#define EF_ARM_HASENTRY 0x02
+#define EF_ARM_INTERWORK 0x04
+#define EF_ARM_APCS_26 0x08
+#define EF_ARM_APCS_FLOAT 0x10
+#define EF_ARM_PIC 0x20
+#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI 0x80
+#define EF_ARM_OLD_ABI 0x100
+#define EF_ARM_SOFT_FLOAT 0x200
+#define EF_ARM_VFP_FLOAT 0x400
+#define EF_ARM_MAVERICK_FLOAT 0x800
+
+#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */
+#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */
+
+
+/* Other constants defined in the ARM ELF spec. version B-01. */
+/* NB. These conflict with values defined above. */
+#define EF_ARM_SYMSARESORTED 0x04
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
+#define EF_ARM_MAPSYMSFIRST 0x10
+#define EF_ARM_EABIMASK 0XFF000000
+
+/* Constants defined in AAELF. */
+#define EF_ARM_BE8 0x00800000
+#define EF_ARM_LE8 0x00400000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN 0x00000000
+#define EF_ARM_EABI_VER1 0x01000000
+#define EF_ARM_EABI_VER2 0x02000000
+#define EF_ARM_EABI_VER3 0x03000000
+#define EF_ARM_EABI_VER4 0x04000000
+#define EF_ARM_EABI_VER5 0x05000000
+
+/* Additional symbol types for Thumb. */
+#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */
+#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
+#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
+ in the input to a link step. */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB 0x10000000 /* Segment contains the location
+ addressed by the static base. */
+#define PF_ARM_PI 0x20000000 /* Position-independent segment. */
+#define PF_ARM_ABS 0x40000000 /* Absolute segment. */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
+#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
+#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
+
+
+/* AArch64 relocs. */
+
+#define R_AARCH64_NONE 0 /* No relocation. */
+
+/* ILP32 AArch64 relocs. */
+#define R_AARCH64_P32_ABS32 1 /* Direct 32 bit. */
+#define R_AARCH64_P32_COPY 180 /* Copy symbol at runtime. */
+#define R_AARCH64_P32_GLOB_DAT 181 /* Create GOT entry. */
+#define R_AARCH64_P32_JUMP_SLOT 182 /* Create PLT entry. */
+#define R_AARCH64_P32_RELATIVE 183 /* Adjust by program base. */
+#define R_AARCH64_P32_TLS_DTPMOD 184 /* Module number, 32 bit. */
+#define R_AARCH64_P32_TLS_DTPREL 185 /* Module-relative offset, 32 bit. */
+#define R_AARCH64_P32_TLS_TPREL 186 /* TP-relative offset, 32 bit. */
+#define R_AARCH64_P32_TLSDESC 187 /* TLS Descriptor. */
+#define R_AARCH64_P32_IRELATIVE 188 /* STT_GNU_IFUNC relocation. */
+
+/* LP64 AArch64 relocs. */
+#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
+#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
+#define R_AARCH64_ABS16 259 /* Direct 16-bit. */
+#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */
+#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */
+#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */
+#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */
+#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */
+#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */
+#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */
+#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */
+#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */
+#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */
+#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */
+#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */
+#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */
+#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */
+#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */
+#define R_AARCH64_CALL26 283 /* Likewise for CALL. */
+#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */
+#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */
+#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */
+#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */
+#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */
+#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */
+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */
+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */
+#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */
+#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */
+#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */
+#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */
+#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */
+#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */
+#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */
+#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */
+#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */
+#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */
+#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */
+#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */
+#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */
+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */
+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */
+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */
+#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */
+#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */
+#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */
+#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */
+#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */
+#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */
+#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */
+#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
+#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
+#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
+#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */
+#define R_AARCH64_TLS_DTPMOD 1028 /* Module number, 64 bit. */
+#define R_AARCH64_TLS_DTPREL 1029 /* Module-relative offset, 64 bit. */
+#define R_AARCH64_TLS_TPREL 1030 /* TP-relative offset, 64 bit. */
+#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
+#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
+
+/* ARM relocs. */
+
+#define R_ARM_NONE 0 /* No reloc */
+#define R_ARM_PC24 1 /* Deprecated PC relative 26
+ bit branch. */
+#define R_ARM_ABS32 2 /* Direct 32 bit */
+#define R_ARM_REL32 3 /* PC relative 32 bit */
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5 /* Direct 16 bit */
+#define R_ARM_ABS12 6 /* Direct 12 bit */
+#define R_ARM_THM_ABS5 7 /* Direct & 0x7C (LDR, STR). */
+#define R_ARM_ABS8 8 /* Direct 8 bit */
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10 /* PC relative 24 bit (Thumb32 BL). */
+#define R_ARM_THM_PC8 11 /* PC relative & 0x3FC
+ (Thumb16 LDR, ADD, ADR). */
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13 /* Obsolete static relocation. */
+#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */
+#define R_ARM_THM_SWI8 14 /* Reserved. */
+#define R_ARM_XPC25 15 /* Reserved. */
+#define R_ARM_THM_XPC22 16 /* Reserved. */
+#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */
+#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */
+#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */
+#define R_ARM_COPY 20 /* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
+#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
+#define R_ARM_RELATIVE 23 /* Adjust by program base */
+#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
+#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32 26 /* 32 bit GOT entry */
+#define R_ARM_PLT32 27 /* Deprecated, 32 bit PLT address. */
+#define R_ARM_CALL 28 /* PC relative 24 bit (BL, BLX). */
+#define R_ARM_JUMP24 29 /* PC relative 24 bit
+ (B, BL<cond>). */
+#define R_ARM_THM_JUMP24 30 /* PC relative 24 bit (Thumb32 B.W). */
+#define R_ARM_BASE_ABS 31 /* Adjust by program base. */
+#define R_ARM_ALU_PCREL_7_0 32 /* Obsolete. */
+#define R_ARM_ALU_PCREL_15_8 33 /* Obsolete. */
+#define R_ARM_ALU_PCREL_23_15 34 /* Obsolete. */
+#define R_ARM_LDR_SBREL_11_0 35 /* Deprecated, prog. base relative. */
+#define R_ARM_ALU_SBREL_19_12 36 /* Deprecated, prog. base relative. */
+#define R_ARM_ALU_SBREL_27_20 37 /* Deprecated, prog. base relative. */
+#define R_ARM_TARGET1 38
+#define R_ARM_SBREL31 39 /* Program base relative. */
+#define R_ARM_V4BX 40
+#define R_ARM_TARGET2 41
+#define R_ARM_PREL31 42 /* 32 bit PC relative. */
+#define R_ARM_MOVW_ABS_NC 43 /* Direct 16-bit (MOVW). */
+#define R_ARM_MOVT_ABS 44 /* Direct high 16-bit (MOVT). */
+#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */
+#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */
+#define R_ARM_THM_MOVW_ABS_NC 47 /* Direct 16 bit (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_ABS 48 /* Direct high 16 bit
+ (Thumb32 MOVT). */
+#define R_ARM_THM_MOVW_PREL_NC 49 /* PC relative 16 bit
+ (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_PREL 50 /* PC relative high 16 bit
+ (Thumb32 MOVT). */
+#define R_ARM_THM_JUMP19 51 /* PC relative 20 bit
+ (Thumb32 B<cond>.W). */
+#define R_ARM_THM_JUMP6 52 /* PC relative X & 0x7E
+ (Thumb16 CBZ, CBNZ). */
+#define R_ARM_THM_ALU_PREL_11_0 53 /* PC relative 12 bit
+ (Thumb32 ADR.W). */
+#define R_ARM_THM_PC12 54 /* PC relative 12 bit
+ (Thumb32 LDR{D,SB,H,SH}). */
+#define R_ARM_ABS32_NOI 55 /* Direct 32-bit. */
+#define R_ARM_REL32_NOI 56 /* PC relative 32-bit. */
+#define R_ARM_ALU_PC_G0_NC 57 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G0 58 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G1_NC 59 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G1 60 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G2 61 /* PC relative (ADD, SUB). */
+#define R_ARM_LDR_PC_G1 62 /* PC relative (LDR,STR,LDRB,STRB). */
+#define R_ARM_LDR_PC_G2 63 /* PC relative (LDR,STR,LDRB,STRB). */
+#define R_ARM_LDRS_PC_G0 64 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDRS_PC_G1 65 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDRS_PC_G2 66 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDC_PC_G0 67 /* PC relative (LDC, STC). */
+#define R_ARM_LDC_PC_G1 68 /* PC relative (LDC, STC). */
+#define R_ARM_LDC_PC_G2 69 /* PC relative (LDC, STC). */
+#define R_ARM_ALU_SB_G0_NC 70 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G0 71 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G1_NC 72 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G1 73 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G2 74 /* Program base relative (ADD,SUB). */
+#define R_ARM_LDR_SB_G0 75 /* Program base relative (LDR,
+ STR, LDRB, STRB). */
+#define R_ARM_LDR_SB_G1 76 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDR_SB_G2 77 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G0 78 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G1 79 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G2 80 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDC_SB_G0 81 /* Program base relative (LDC,STC). */
+#define R_ARM_LDC_SB_G1 82 /* Program base relative (LDC,STC). */
+#define R_ARM_LDC_SB_G2 83 /* Program base relative (LDC,STC). */
+#define R_ARM_MOVW_BREL_NC 84 /* Program base relative 16
+ bit (MOVW). */
+#define R_ARM_MOVT_BREL 85 /* Program base relative high
+ 16 bit (MOVT). */
+#define R_ARM_MOVW_BREL 86 /* Program base relative 16
+ bit (MOVW). */
+#define R_ARM_THM_MOVW_BREL_NC 87 /* Program base relative 16
+ bit (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_BREL 88 /* Program base relative high
+ 16 bit (Thumb32 MOVT). */
+#define R_ARM_THM_MOVW_BREL 89 /* Program base relative 16
+ bit (Thumb32 MOVW). */
+#define R_ARM_TLS_GOTDESC 90
+#define R_ARM_TLS_CALL 91
+#define R_ARM_TLS_DESCSEQ 92 /* TLS relaxation. */
+#define R_ARM_THM_TLS_CALL 93
+#define R_ARM_PLT32_ABS 94
+#define R_ARM_GOT_ABS 95 /* GOT entry. */
+#define R_ARM_GOT_PREL 96 /* PC relative GOT entry. */
+#define R_ARM_GOT_BREL12 97 /* GOT entry relative to GOT
+ origin (LDR). */
+#define R_ARM_GOTOFF12 98 /* 12 bit, GOT entry relative
+ to GOT origin (LDR, STR). */
+#define R_ARM_GOTRELAX 99
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_THM_PC11 102 /* PC relative & 0xFFE (Thumb16 B). */
+#define R_ARM_THM_PC9 103 /* PC relative & 0x1FE
+ (Thumb16 B/B<cond>). */
+#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic
+ thread local data */
+#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic
+ thread local data */
+#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS
+ block */
+#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of
+ static TLS block offset */
+#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static
+ TLS block */
+#define R_ARM_TLS_LDO12 109 /* 12 bit relative to TLS
+ block (LDR, STR). */
+#define R_ARM_TLS_LE12 110 /* 12 bit relative to static
+ TLS block (LDR, STR). */
+#define R_ARM_TLS_IE12GP 111 /* 12 bit GOT entry relative
+ to GOT origin (LDR). */
+#define R_ARM_ME_TOO 128 /* Obsolete. */
+#define R_ARM_THM_TLS_DESCSEQ 129
+#define R_ARM_THM_TLS_DESCSEQ16 129
+#define R_ARM_THM_TLS_DESCSEQ32 130
+#define R_ARM_THM_GOT_BREL12 131 /* GOT entry relative to GOT
+ origin, 12 bit (Thumb32 LDR). */
+#define R_ARM_IRELATIVE 160
+#define R_ARM_RXPC25 249
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS22 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+/* Keep this the last entry. */
+#define R_ARM_NUM 256
+
+/* IA-64 specific declarations. */
+
+/* Processor specific flags for the Ehdr e_flags field. */
+#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
+#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
+#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
+#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK (PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field. */
+#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field. */
+#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
+#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field. */
+#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
+#define DT_IA_64_NUM 1
+
+/* IA-64 relocations. */
+#define R_IA64_NONE 0x00 /* none */
+#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
+#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
+#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
+#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
+#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
+#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
+#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY 0x84 /* copy relocation */
+#define R_IA64_SUB 0x85 /* Addend and symbol difference */
+#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
+#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
+#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_SH_MACH_MASK 0x1f
+#define EF_SH_UNKNOWN 0x0
+#define EF_SH1 0x1
+#define EF_SH2 0x2
+#define EF_SH3 0x3
+#define EF_SH_DSP 0x4
+#define EF_SH3_DSP 0x5
+#define EF_SH4AL_DSP 0x6
+#define EF_SH3E 0x8
+#define EF_SH4 0x9
+#define EF_SH2E 0xb
+#define EF_SH4A 0xc
+#define EF_SH2A 0xd
+#define EF_SH4_NOFPU 0x10
+#define EF_SH4A_NOFPU 0x11
+#define EF_SH4_NOMMU_NOFPU 0x12
+#define EF_SH2A_NOFPU 0x13
+#define EF_SH3_NOMMU 0x14
+#define EF_SH2A_SH4_NOFPU 0x15
+#define EF_SH2A_SH3_NOFPU 0x16
+#define EF_SH2A_SH4 0x17
+#define EF_SH2A_SH3E 0x18
+
+/* SH relocs. */
+#define R_SH_NONE 0
+#define R_SH_DIR32 1
+#define R_SH_REL32 2
+#define R_SH_DIR8WPN 3
+#define R_SH_IND12W 4
+#define R_SH_DIR8WPL 5
+#define R_SH_DIR8WPZ 6
+#define R_SH_DIR8BP 7
+#define R_SH_DIR8W 8
+#define R_SH_DIR8L 9
+#define R_SH_SWITCH16 25
+#define R_SH_SWITCH32 26
+#define R_SH_USES 27
+#define R_SH_COUNT 28
+#define R_SH_ALIGN 29
+#define R_SH_CODE 30
+#define R_SH_DATA 31
+#define R_SH_LABEL 32
+#define R_SH_SWITCH8 33
+#define R_SH_GNU_VTINHERIT 34
+#define R_SH_GNU_VTENTRY 35
+#define R_SH_TLS_GD_32 144
+#define R_SH_TLS_LD_32 145
+#define R_SH_TLS_LDO_32 146
+#define R_SH_TLS_IE_32 147
+#define R_SH_TLS_LE_32 148
+#define R_SH_TLS_DTPMOD32 149
+#define R_SH_TLS_DTPOFF32 150
+#define R_SH_TLS_TPOFF32 151
+#define R_SH_GOT32 160
+#define R_SH_PLT32 161
+#define R_SH_COPY 162
+#define R_SH_GLOB_DAT 163
+#define R_SH_JMP_SLOT 164
+#define R_SH_RELATIVE 165
+#define R_SH_GOTOFF 166
+#define R_SH_GOTPC 167
+/* Keep this the last entry. */
+#define R_SH_NUM 256
+
+/* S/390 specific definitions. */
+
+/* Valid values for the e_flags field. */
+
+#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */
+
+/* Additional s390 relocs */
+
+#define R_390_NONE 0 /* No reloc. */
+#define R_390_8 1 /* Direct 8 bit. */
+#define R_390_12 2 /* Direct 12 bit. */
+#define R_390_16 3 /* Direct 16 bit. */
+#define R_390_32 4 /* Direct 32 bit. */
+#define R_390_PC32 5 /* PC relative 32 bit. */
+#define R_390_GOT12 6 /* 12 bit GOT offset. */
+#define R_390_GOT32 7 /* 32 bit GOT offset. */
+#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
+#define R_390_COPY 9 /* Copy symbol at runtime. */
+#define R_390_GLOB_DAT 10 /* Create GOT entry. */
+#define R_390_JMP_SLOT 11 /* Create PLT entry. */
+#define R_390_RELATIVE 12 /* Adjust by program base. */
+#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
+#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
+#define R_390_GOT16 15 /* 16 bit GOT offset. */
+#define R_390_PC16 16 /* PC relative 16 bit. */
+#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
+#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
+#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
+#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
+#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
+#define R_390_64 22 /* Direct 64 bit. */
+#define R_390_PC64 23 /* PC relative 64 bit. */
+#define R_390_GOT64 24 /* 64 bit GOT offset. */
+#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
+#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
+#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
+#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
+#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
+#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
+#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
+#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
+#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL 38 /* Tag for function call in general
+ dynamic TLS code. */
+#define R_390_TLS_LDCALL 39 /* Tag for function call in local
+ dynamic TLS code. */
+#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
+ thread local data. */
+#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
+ thread local data. */
+#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
+ thread local data in LE code. */
+#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
+ thread local data in LE code. */
+#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
+ static TLS block. */
+#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
+ static TLS block. */
+#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
+ block. */
+#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
+ block. */
+#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
+#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
+#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS
+ block. */
+#define R_390_20 57 /* Direct 20 bit. */
+#define R_390_GOT20 58 /* 20 bit GOT offset. */
+#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
+#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS
+ block offset. */
+#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */
+/* Keep this the last entry. */
+#define R_390_NUM 62
+
+
+/* CRIS relocations. */
+#define R_CRIS_NONE 0
+#define R_CRIS_8 1
+#define R_CRIS_16 2
+#define R_CRIS_32 3
+#define R_CRIS_8_PCREL 4
+#define R_CRIS_16_PCREL 5
+#define R_CRIS_32_PCREL 6
+#define R_CRIS_GNU_VTINHERIT 7
+#define R_CRIS_GNU_VTENTRY 8
+#define R_CRIS_COPY 9
+#define R_CRIS_GLOB_DAT 10
+#define R_CRIS_JUMP_SLOT 11
+#define R_CRIS_RELATIVE 12
+#define R_CRIS_16_GOT 13
+#define R_CRIS_32_GOT 14
+#define R_CRIS_16_GOTPLT 15
+#define R_CRIS_32_GOTPLT 16
+#define R_CRIS_32_GOTREL 17
+#define R_CRIS_32_PLT_GOTREL 18
+#define R_CRIS_32_PLT_PCREL 19
+
+#define R_CRIS_NUM 20
+
+
+/* AMD x86-64 relocations. */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
+ offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
+ to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
+ to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
+ to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
+#define R_X86_64_PC64 24 /* PC relative 64 bit */
+#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
+ offset to GOT */
+#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
+ to GOT entry */
+#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
+ to PLT entry */
+#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
+#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
+ descriptor. */
+#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
+#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */
+
+#define R_X86_64_NUM 39
+
+
+/* AM33 relocations. */
+#define R_MN10300_NONE 0 /* No reloc. */
+#define R_MN10300_32 1 /* Direct 32 bit. */
+#define R_MN10300_16 2 /* Direct 16 bit. */
+#define R_MN10300_8 3 /* Direct 8 bit. */
+#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */
+#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */
+#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */
+#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */
+#define R_MN10300_24 9 /* Direct 24 bit. */
+#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */
+#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */
+#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */
+#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */
+#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */
+#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */
+#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */
+#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */
+#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */
+#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */
+#define R_MN10300_COPY 20 /* Copy symbol at runtime. */
+#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */
+#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */
+#define R_MN10300_RELATIVE 23 /* Adjust by program base. */
+#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */
+#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */
+#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */
+#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block
+ offset. */
+#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block
+ offset. */
+#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS
+ block. */
+#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */
+#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */
+#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */
+#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed
+ by linker relaxation. */
+#define R_MN10300_ALIGN 34 /* Alignment requirement for linker
+ relaxation. */
+#define R_MN10300_NUM 35
+
+
+/* M32R relocs. */
+#define R_M32R_NONE 0 /* No reloc. */
+#define R_M32R_16 1 /* Direct 16 bit. */
+#define R_M32R_32 2 /* Direct 32 bit. */
+#define R_M32R_24 3 /* Direct 24 bit. */
+#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */
+#define R_M32R_LO16 9 /* Low 16 bit. */
+#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT 11
+#define R_M32R_GNU_VTENTRY 12
+/* M32R relocs use SHT_RELA. */
+#define R_M32R_16_RELA 33 /* Direct 16 bit. */
+#define R_M32R_32_RELA 34 /* Direct 32 bit. */
+#define R_M32R_24_RELA 35 /* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */
+#define R_M32R_LO16_RELA 41 /* Low 16 bit */
+#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT 43
+#define R_M32R_RELA_GNU_VTENTRY 44
+#define R_M32R_REL32 45 /* PC relative 32 bit. */
+
+#define R_M32R_GOT24 48 /* 24 bit GOT entry */
+#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY 50 /* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT 51 /* Create GOT entry */
+#define R_M32R_JMP_SLOT 52 /* Create PLT entry */
+#define R_M32R_RELATIVE 53 /* Adjust by program base */
+#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */
+#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned
+ low */
+#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed
+ low */
+#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to
+ GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to
+ GOT with signed low */
+#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to
+ GOT */
+#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT
+ with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT
+ with signed low */
+#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */
+#define R_M32R_NUM 256 /* Keep this the last entry. */
+
+/* MicroBlaze relocations */
+#define R_MICROBLAZE_NONE 0 /* No reloc. */
+#define R_MICROBLAZE_32 1 /* Direct 32 bit. */
+#define R_MICROBLAZE_32_PCREL 2 /* PC relative 32 bit. */
+#define R_MICROBLAZE_64_PCREL 3 /* PC relative 64 bit. */
+#define R_MICROBLAZE_32_PCREL_LO 4 /* Low 16 bits of PCREL32. */
+#define R_MICROBLAZE_64 5 /* Direct 64 bit. */
+#define R_MICROBLAZE_32_LO 6 /* Low 16 bit. */
+#define R_MICROBLAZE_SRO32 7 /* Read-only small data area. */
+#define R_MICROBLAZE_SRW32 8 /* Read-write small data area. */
+#define R_MICROBLAZE_64_NONE 9 /* No reloc. */
+#define R_MICROBLAZE_32_SYM_OP_SYM 10 /* Symbol Op Symbol relocation. */
+#define R_MICROBLAZE_GNU_VTINHERIT 11 /* GNU C++ vtable hierarchy. */
+#define R_MICROBLAZE_GNU_VTENTRY 12 /* GNU C++ vtable member usage. */
+#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset. */
+#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset. */
+#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative). */
+#define R_MICROBLAZE_REL 16 /* Adjust by program base. */
+#define R_MICROBLAZE_JUMP_SLOT 17 /* Create PLT entry. */
+#define R_MICROBLAZE_GLOB_DAT 18 /* Create GOT entry. */
+#define R_MICROBLAZE_GOTOFF_64 19 /* 64 bit offset to GOT. */
+#define R_MICROBLAZE_GOTOFF_32 20 /* 32 bit offset to GOT. */
+#define R_MICROBLAZE_COPY 21 /* Runtime copy. */
+#define R_MICROBLAZE_TLS 22 /* TLS Reloc. */
+#define R_MICROBLAZE_TLSGD 23 /* TLS General Dynamic. */
+#define R_MICROBLAZE_TLSLD 24 /* TLS Local Dynamic. */
+#define R_MICROBLAZE_TLSDTPMOD32 25 /* TLS Module ID. */
+#define R_MICROBLAZE_TLSDTPREL32 26 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSDTPREL64 27 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSGOTTPREL32 28 /* TLS Offset From Thread Pointer. */
+#define R_MICROBLAZE_TLSTPREL32 29 /* TLS Offset From Thread Pointer. */
+
+/* Legal values for d_tag (dynamic entry type). */
+#define DT_NIOS2_GP 0x70000002 /* Address of _gp. */
+
+/* Nios II relocations. */
+#define R_NIOS2_NONE 0 /* No reloc. */
+#define R_NIOS2_S16 1 /* Direct signed 16 bit. */
+#define R_NIOS2_U16 2 /* Direct unsigned 16 bit. */
+#define R_NIOS2_PCREL16 3 /* PC relative 16 bit. */
+#define R_NIOS2_CALL26 4 /* Direct call. */
+#define R_NIOS2_IMM5 5 /* 5 bit constant expression. */
+#define R_NIOS2_CACHE_OPX 6 /* 5 bit expression, shift 22. */
+#define R_NIOS2_IMM6 7 /* 6 bit constant expression. */
+#define R_NIOS2_IMM8 8 /* 8 bit constant expression. */
+#define R_NIOS2_HI16 9 /* High 16 bit. */
+#define R_NIOS2_LO16 10 /* Low 16 bit. */
+#define R_NIOS2_HIADJ16 11 /* High 16 bit, adjusted. */
+#define R_NIOS2_BFD_RELOC_32 12 /* 32 bit symbol value + addend. */
+#define R_NIOS2_BFD_RELOC_16 13 /* 16 bit symbol value + addend. */
+#define R_NIOS2_BFD_RELOC_8 14 /* 8 bit symbol value + addend. */
+#define R_NIOS2_GPREL 15 /* 16 bit GP pointer offset. */
+#define R_NIOS2_GNU_VTINHERIT 16 /* GNU C++ vtable hierarchy. */
+#define R_NIOS2_GNU_VTENTRY 17 /* GNU C++ vtable member usage. */
+#define R_NIOS2_UJMP 18 /* Unconditional branch. */
+#define R_NIOS2_CJMP 19 /* Conditional branch. */
+#define R_NIOS2_CALLR 20 /* Indirect call through register. */
+#define R_NIOS2_ALIGN 21 /* Alignment requirement for
+ linker relaxation. */
+#define R_NIOS2_GOT16 22 /* 16 bit GOT entry. */
+#define R_NIOS2_CALL16 23 /* 16 bit GOT entry for function. */
+#define R_NIOS2_GOTOFF_LO 24 /* %lo of offset to GOT pointer. */
+#define R_NIOS2_GOTOFF_HA 25 /* %hiadj of offset to GOT pointer. */
+#define R_NIOS2_PCREL_LO 26 /* %lo of PC relative offset. */
+#define R_NIOS2_PCREL_HA 27 /* %hiadj of PC relative offset. */
+#define R_NIOS2_TLS_GD16 28 /* 16 bit GOT offset for TLS GD. */
+#define R_NIOS2_TLS_LDM16 29 /* 16 bit GOT offset for TLS LDM. */
+#define R_NIOS2_TLS_LDO16 30 /* 16 bit module relative offset. */
+#define R_NIOS2_TLS_IE16 31 /* 16 bit GOT offset for TLS IE. */
+#define R_NIOS2_TLS_LE16 32 /* 16 bit LE TP-relative offset. */
+#define R_NIOS2_TLS_DTPMOD 33 /* Module number. */
+#define R_NIOS2_TLS_DTPREL 34 /* Module-relative offset. */
+#define R_NIOS2_TLS_TPREL 35 /* TP-relative offset. */
+#define R_NIOS2_COPY 36 /* Copy symbol at runtime. */
+#define R_NIOS2_GLOB_DAT 37 /* Create GOT entry. */
+#define R_NIOS2_JUMP_SLOT 38 /* Create PLT entry. */
+#define R_NIOS2_RELATIVE 39 /* Adjust by program base. */
+#define R_NIOS2_GOTOFF 40 /* 16 bit offset to GOT pointer. */
+#define R_NIOS2_CALL26_NOAT 41 /* Direct call in .noat section. */
+#define R_NIOS2_GOT_LO 42 /* %lo() of GOT entry. */
+#define R_NIOS2_GOT_HA 43 /* %hiadj() of GOT entry. */
+#define R_NIOS2_CALL_LO 44 /* %lo() of function GOT entry. */
+#define R_NIOS2_CALL_HA 45 /* %hiadj() of function GOT entry. */
+
+/* TILEPro relocations. */
+#define R_TILEPRO_NONE 0 /* No reloc */
+#define R_TILEPRO_32 1 /* Direct 32 bit */
+#define R_TILEPRO_16 2 /* Direct 16 bit */
+#define R_TILEPRO_8 3 /* Direct 8 bit */
+#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */
+#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */
+#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */
+#define R_TILEPRO_LO16 7 /* Low 16 bit */
+#define R_TILEPRO_HI16 8 /* High 16 bit */
+#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */
+#define R_TILEPRO_COPY 10 /* Copy relocation */
+#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */
+#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */
+#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */
+#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */
+#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */
+#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */
+#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */
+#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */
+#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */
+#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */
+#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */
+#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */
+#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */
+#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */
+#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */
+#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */
+#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */
+#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */
+#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */
+/* Relocs 56-59 are currently not defined. */
+#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */
+#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */
+#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */
+#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */
+#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */
+#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */
+#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */
+
+#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
+#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
+
+#define R_TILEPRO_NUM 130
+
+
+/* TILE-Gx relocations. */
+#define R_TILEGX_NONE 0 /* No reloc */
+#define R_TILEGX_64 1 /* Direct 64 bit */
+#define R_TILEGX_32 2 /* Direct 32 bit */
+#define R_TILEGX_16 3 /* Direct 16 bit */
+#define R_TILEGX_8 4 /* Direct 8 bit */
+#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */
+#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */
+#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */
+#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */
+#define R_TILEGX_HW0 9 /* hword 0 16-bit */
+#define R_TILEGX_HW1 10 /* hword 1 16-bit */
+#define R_TILEGX_HW2 11 /* hword 2 16-bit */
+#define R_TILEGX_HW3 12 /* hword 3 16-bit */
+#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */
+#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */
+#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */
+#define R_TILEGX_COPY 16 /* Copy relocation */
+#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */
+#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */
+#define R_TILEGX_RELATIVE 19 /* Adjust by program base */
+#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */
+#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */
+#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */
+#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */
+#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */
+#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */
+#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */
+#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */
+#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */
+#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */
+#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */
+#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */
+#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */
+#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */
+#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */
+#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */
+#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */
+#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */
+#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */
+#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */
+#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */
+#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */
+#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */
+#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
+/* Relocs 90-91 are currently not defined. */
+#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
+/* Relocs 104-105 are currently not defined. */
+#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */
+#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */
+#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */
+#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */
+#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */
+#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */
+
+#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
+#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
+
+#define R_TILEGX_NUM 130
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__LWP_ELF_H__*/
diff --git a/components/lwp/lwp_futex.c b/components/lwp/lwp_futex.c
new file mode 100644
index 0000000000..ed03f43717
--- /dev/null
+++ b/components/lwp/lwp_futex.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021/01/02 bernard the first version
+ */
+
+#include <rtthread.h>
+#include <lwp.h>
+#ifdef RT_USING_USERSPACE
+#include <lwp_user_mm.h>
+#endif
+#include "sys/time.h"
+
+struct rt_futex
+{
+ int *uaddr;
+ rt_list_t waiting_thread;
+ struct lwp_avl_struct node;
+ struct rt_object *custom_obj;
+};
+
+static struct rt_mutex _futex_lock;
+
+static int futex_system_init(void)
+{
+ rt_mutex_init(&_futex_lock, "futexList", RT_IPC_FLAG_FIFO);
+ return 0;
+}
+INIT_PREV_EXPORT(futex_system_init);
+
+rt_err_t futex_destory(void *data)
+{
+ rt_err_t ret = -1;
+ rt_base_t level;
+ struct rt_futex *futex = (struct rt_futex *)data;
+
+ if (futex)
+ {
+ level = rt_hw_interrupt_disable();
+ /* remove futex from futext avl */
+ lwp_avl_remove(&futex->node, (struct lwp_avl_struct **)futex->node.data);
+ rt_hw_interrupt_enable(level);
+
+ /* release object */
+ rt_free(futex);
+ ret = 0;
+ }
+ return ret;
+}
+
+struct rt_futex *futex_create(int *uaddr, struct rt_lwp *lwp)
+{
+ struct rt_futex *futex = RT_NULL;
+ struct rt_object *obj = RT_NULL;
+
+ if (!lwp)
+ {
+ return RT_NULL;
+ }
+ futex = (struct rt_futex *)rt_malloc(sizeof(struct rt_futex));
+ if (!futex)
+ {
+ return RT_NULL;
+ }
+ obj = rt_custom_object_create("futex", (void *)futex, futex_destory);
+ if (!obj)
+ {
+ rt_free(futex);
+ return RT_NULL;
+ }
+
+ futex->uaddr = uaddr;
+ futex->node.avl_key = (avl_key_t)uaddr;
+ futex->node.data = &lwp->address_search_head;
+ futex->custom_obj = obj;
+ rt_list_init(&(futex->waiting_thread));
+
+ /* insert into futex head */
+ lwp_avl_insert(&futex->node, &lwp->address_search_head);
+ return futex;
+}
+
+static struct rt_futex *futex_get(void *uaddr, struct rt_lwp *lwp)
+{
+ struct rt_futex *futex = RT_NULL;
+ struct lwp_avl_struct *node = RT_NULL;
+
+ node = lwp_avl_find((avl_key_t)uaddr, lwp->address_search_head);
+ if (!node)
+ {
+ return RT_NULL;
+ }
+ futex = rt_container_of(node, struct rt_futex, node);
+ return futex;
+}
+
+int futex_wait(struct rt_futex *futex, int value, const struct timespec *timeout)
+{
+ rt_base_t level = 0;
+ rt_err_t ret = -RT_EINTR;
+
+ if (*(futex->uaddr) == value)
+ {
+ rt_thread_t thread = rt_thread_self();
+
+ level = rt_hw_interrupt_disable();
+ ret = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
+
+ if (ret < 0)
+ {
+ rt_mutex_release(&_futex_lock);
+ rt_hw_interrupt_enable(level);
+ rt_set_errno(EINTR);
+ return ret;
+ }
+
+ /* add into waiting thread list */
+ rt_list_insert_before(&(futex->waiting_thread), &(thread->tlist));
+
+ /* with timeout */
+ if (timeout)
+ {
+ rt_int32_t time = rt_timespec_to_tick(timeout);
+
+ /* start the timer of thread */
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_SET_TIME,
+ &time);
+ rt_timer_start(&(thread->thread_timer));
+ }
+ rt_mutex_release(&_futex_lock);
+ rt_hw_interrupt_enable(level);
+
+ /* do schedule */
+ rt_schedule();
+
+ ret = thread->error;
+ /* check errno */
+ }
+ else
+ {
+ rt_mutex_release(&_futex_lock);
+ rt_set_errno(EAGAIN);
+ }
+
+ return ret;
+}
+
+void futex_wake(struct rt_futex *futex, int number)
+{
+ rt_base_t level = rt_hw_interrupt_disable();
+ while (!rt_list_isempty(&(futex->waiting_thread)) && number)
+ {
+ rt_thread_t thread;
+
+ thread = rt_list_entry(futex->waiting_thread.next, struct rt_thread, tlist);
+ /* remove from waiting list */
+ rt_list_remove(&(thread->tlist));
+
+ thread->error = RT_EOK;
+ /* resume the suspended thread */
+ rt_thread_resume(thread);
+
+ number--;
+ }
+ rt_mutex_release(&_futex_lock);
+ rt_hw_interrupt_enable(level);
+
+ /* do schedule */
+ rt_schedule();
+}
+
+int sys_futex(int *uaddr, int op, int val, const struct timespec *timeout,
+ int *uaddr2, int val3)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_futex *futex = RT_NULL;
+ int ret = 0;
+ rt_err_t lock_ret = 0;
+
+ if (!lwp_user_accessable(uaddr, sizeof(int)))
+ {
+ rt_set_errno(EINVAL);
+ return -RT_EINVAL;
+ }
+
+ /**
+ * if (op & (FUTEX_WAKE|FUTEX_FD|FUTEX_WAKE_BITSET|FUTEX_TRYLOCK_PI|FUTEX_UNLOCK_PI)) was TRUE
+ * `timeout` should be ignored by implementation, according to POSIX futex(2) manual.
+ * since only FUTEX_WAKE is implemented in rt-smart, only FUTEX_WAKE was omitted currently
+ */
+ if (timeout && !(op & (FUTEX_WAKE)))
+ {
+ if (!lwp_user_accessable((void *)timeout, sizeof(struct timespec)))
+ {
+ rt_set_errno(EINVAL);
+ return -RT_EINVAL;
+ }
+ }
+ lock_ret = rt_mutex_take_interruptible(&_futex_lock, RT_WAITING_FOREVER);
+ if (lock_ret != RT_EOK)
+ {
+ rt_set_errno(EAGAIN);
+ return -RT_EINTR;
+ }
+
+ lwp = lwp_self();
+ futex = futex_get(uaddr, lwp);
+ if (futex == RT_NULL)
+ {
+ /* create a futex according to this uaddr */
+ futex = futex_create(uaddr, lwp);
+ if (futex == RT_NULL)
+ {
+ rt_mutex_release(&_futex_lock);
+ rt_set_errno(ENOMEM);
+ return -RT_ENOMEM;
+ }
+ if (lwp_user_object_add(lwp, futex->custom_obj) != 0)
+ {
+ rt_custom_object_destroy(futex->custom_obj);
+ rt_mutex_release(&_futex_lock);
+ rt_set_errno(ENOMEM);
+ return -RT_ENOMEM;
+ }
+ }
+
+ switch (op)
+ {
+ case FUTEX_WAIT:
+ ret = futex_wait(futex, val, timeout);
+ /* _futex_lock is released by futex_wait */
+ break;
+
+ case FUTEX_WAKE:
+ futex_wake(futex, val);
+ /* _futex_lock is released by futex_wake */
+ break;
+
+ default:
+ rt_mutex_release(&_futex_lock);
+ rt_set_errno(ENOSYS);
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
diff --git a/components/lwp/lwp_ipc.c b/components/lwp/lwp_ipc.c
new file mode 100644
index 0000000000..dc53310e82
--- /dev/null
+++ b/components/lwp/lwp_ipc.c
@@ -0,0 +1,1153 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-12 Jesven first version
+ */
+#include <rtthread.h>
+#include <rthw.h>
+#include <lwp.h>
+
+#include "lwp_ipc.h"
+#include "lwp_ipc_internal.h"
+
+#include <dfs_file.h>
+#include <poll.h>
+
+/**
+ * the IPC channel states
+ */
+enum
+{
+ RT_IPC_STAT_IDLE, /* no suspended threads */
+ RT_IPC_STAT_WAIT, /* suspended receivers exist */
+ RT_IPC_STAT_ACTIVE, /* suspended senders exist */
+};
+
+/**
+ * IPC message structure.
+ *
+ * They are allocated and released in the similar way like 'rt_chfd'.
+ */
+struct rt_ipc_msg
+{
+ struct rt_channel_msg msg; /**< the payload of msg */
+ rt_list_t mlist; /**< the msg list */
+ rt_uint8_t need_reply; /**< whether msg wait reply*/
+};
+typedef struct rt_ipc_msg *rt_ipc_msg_t;
+
+static rt_ipc_msg_t _ipc_msg_free_list = (rt_ipc_msg_t)RT_NULL; /* released chain */
+static int rt_ipc_msg_used = 0; /* first unallocated entry */
+static struct rt_ipc_msg ipc_msg_pool[RT_CH_MSG_MAX_NR]; /* initial message array */
+
+/**
+ * Allocate an IPC message from the statically-allocated array.
+ */
+static rt_ipc_msg_t _ipc_msg_alloc(void)
+{
+ rt_ipc_msg_t p = (rt_ipc_msg_t)RT_NULL;
+
+ if (_ipc_msg_free_list) /* use the released chain first */
+ {
+ p = _ipc_msg_free_list;
+ _ipc_msg_free_list = (rt_ipc_msg_t)p->msg.sender; /* emtry payload as a pointer */
+ }
+ else if (rt_ipc_msg_used < RT_CH_MSG_MAX_NR)
+ {
+ p = &ipc_msg_pool[rt_ipc_msg_used];
+ rt_ipc_msg_used++;
+ }
+ return p;
+}
+
+/**
+ * Put a released IPC message back to the released chain.
+ */
+static void _ipc_msg_free(rt_ipc_msg_t p_msg)
+{
+ p_msg->msg.sender = (void*)_ipc_msg_free_list;
+ _ipc_msg_free_list = p_msg;
+}
+
+/**
+ * Initialized the IPC message.
+ */
+static void rt_ipc_msg_init(rt_ipc_msg_t msg, struct rt_channel_msg *data, rt_uint8_t need_reply)
+{
+ RT_ASSERT(msg != RT_NULL);
+
+ msg->need_reply = need_reply;
+ msg->msg = *data;
+ msg->msg.sender = (void*)rt_thread_self();
+ rt_list_init(&msg->mlist);
+}
+
+/**
+ * Initialized the list of the waiting receivers on the IPC channel.
+ */
+rt_inline rt_err_t rt_channel_object_init(struct rt_ipc_object *ipc)
+{
+ rt_list_init(&(ipc->suspend_thread)); /* receiver list */
+
+ return RT_EOK;
+}
+
+/**
+ * Wakeup the first suspened thread in the list.
+ */
+rt_inline rt_err_t rt_channel_list_resume(rt_list_t *list)
+{
+ struct rt_thread *thread;
+
+ /* get the first thread entry waiting for sending */
+ thread = rt_list_entry(list->next, struct rt_thread, tlist);
+
+ rt_thread_resume(thread);
+
+ return RT_EOK;
+}
+
+/**
+ * Wakeup all the suspended threads in the list.
+ */
+rt_inline rt_err_t rt_channel_list_resume_all(rt_list_t *list)
+{
+ struct rt_thread *thread;
+ register rt_ubase_t temp;
+
+ /* wakeup all suspended threads for sending */
+ while (!rt_list_isempty(list))
+ {
+ temp = rt_hw_interrupt_disable();
+ thread = rt_list_entry(list->next, struct rt_thread, tlist);
+ thread->error = -RT_ERROR;
+ rt_thread_resume(thread);
+ rt_hw_interrupt_enable(temp);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * Suspend the thread and chain it into the end of the list.
+ */
+rt_inline rt_err_t rt_channel_list_suspend(rt_list_t *list, struct rt_thread *thread)
+{
+ /* suspend thread */
+ rt_err_t ret = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
+
+ if (ret == RT_EOK)
+ {
+ rt_list_insert_before(list, &(thread->tlist)); /* list end */
+ }
+
+ return ret;
+}
+
+
+static void _rt_channel_check_wq_wakup(rt_channel_t ch)
+{
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ if (rt_list_isempty(&ch->wait_msg))
+ {
+ rt_hw_interrupt_enable(level);
+ return;
+ }
+
+ rt_wqueue_wakeup(&ch->reader_queue, 0);
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * Create a new or open an existing IPC channel.
+ */
+rt_channel_t rt_raw_channel_open(const char *name, int flags)
+{
+ register rt_ubase_t temp = 0;
+ rt_channel_t ch = RT_NULL;
+
+ struct rt_object *object;
+ struct rt_list_node *node;
+ struct rt_object_information *information;
+
+ temp = rt_hw_interrupt_disable();
+ information = rt_object_get_information(RT_Object_Class_Channel);
+ RT_ASSERT(information != RT_NULL);
+
+ /* retrieve the existing IPC channels */
+ for (node = information->object_list.next;
+ node != &(information->object_list);
+ node = node->next)
+ {
+ object = rt_list_entry(node, struct rt_object, list);
+ if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
+ {
+ if ((flags & O_CREAT) && (flags & O_EXCL))
+ {
+ goto quit;
+ }
+ /* find the IPC channel with the specific name */
+ ch = (rt_channel_t)object;
+ ch->ref++; /* increase the reference count */
+ break;
+ }
+ }
+ if (!ch) /* create a new IPC channel */
+ {
+ if (flags & O_CREAT)
+ {
+ RT_DEBUG_NOT_IN_INTERRUPT;
+
+ /* allocate a real IPC channel structure */
+ ch = (rt_channel_t)rt_object_allocate(RT_Object_Class_Channel, name);
+ }
+
+ if (!ch)
+ {
+ goto quit;
+ }
+
+ rt_channel_object_init(&ch->parent); /* suspended receivers */
+ rt_list_init(&ch->wait_msg); /* unhandled messages */
+ rt_list_init(&ch->wait_thread); /* suspended senders */
+ rt_wqueue_init(&ch->reader_queue); /* reader poll queue */
+ ch->reply = RT_NULL;
+ ch->stat = RT_IPC_STAT_IDLE; /* no suspended threads */
+ ch->ref = 1;
+ }
+quit:
+ rt_hw_interrupt_enable(temp);
+ return ch;
+}
+
+/**
+ * Close an existiong IPC channel, release the resources.
+ */
+rt_err_t rt_raw_channel_close(rt_channel_t ch)
+{
+ register rt_ubase_t temp;
+
+ RT_DEBUG_NOT_IN_INTERRUPT;
+
+ if (ch == RT_NULL)
+ {
+ return -RT_EIO;
+ }
+
+ temp = rt_hw_interrupt_disable();
+ if (rt_object_get_type(&ch->parent.parent) != RT_Object_Class_Channel)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EIO;
+ }
+ if (rt_object_is_systemobject(&ch->parent.parent) != RT_FALSE)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EIO;
+ }
+
+ if (ch->ref == 0)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EIO;
+ }
+ ch->ref--;
+ if (ch->ref == 0)
+ {
+ /* wakeup all the suspended receivers and senders */
+ rt_channel_list_resume_all(&ch->parent.suspend_thread);
+ rt_channel_list_resume_all(&ch->wait_thread);
+
+ /* all ipc msg will lost */
+ rt_list_init(&ch->wait_msg);
+
+ rt_object_delete(&ch->parent.parent); /* release the IPC channel structure */
+ }
+ rt_hw_interrupt_enable(temp);
+ return RT_EOK;
+}
+
+static rt_err_t wakeup_sender_wait_recv(void *object, struct rt_thread *thread)
+{
+ rt_channel_t ch;
+
+ ch = (rt_channel_t)object;
+ if (ch->stat == RT_IPC_STAT_ACTIVE && ch->reply == thread)
+ {
+ ch->stat = RT_IPC_STAT_IDLE;
+ ch->reply = RT_NULL;
+ }
+ else
+ {
+ rt_ipc_msg_t msg;
+ rt_list_t *l;
+
+ l = ch->wait_msg.next;
+ while (l != &ch->wait_msg)
+ {
+ msg = rt_list_entry(l, struct rt_ipc_msg, mlist);
+ if (msg->need_reply && msg->msg.sender == thread)
+ {
+ rt_list_remove(&msg->mlist); /* remove the msg from the channel */
+ _ipc_msg_free(msg);
+ break;
+ }
+ l = l->next;
+ }
+ }
+ thread->error = -RT_EINTR;
+ return rt_thread_resume(thread); /* wake up the sender */
+}
+
+static rt_err_t wakeup_sender_wait_reply(void *object, struct rt_thread *thread)
+{
+ rt_channel_t ch;
+
+ ch = (rt_channel_t)object;
+ RT_ASSERT(ch->stat == RT_IPC_STAT_ACTIVE && ch->reply == thread);
+ ch->stat = RT_IPC_STAT_IDLE;
+ ch->reply = RT_NULL;
+ thread->error = -RT_EINTR;
+ return rt_thread_resume(thread); /* wake up the sender */
+}
+
+static void sender_timeout(void *parameter)
+{
+ struct rt_thread *thread = (struct rt_thread*)parameter;
+ rt_channel_t ch;
+
+ ch = (rt_channel_t)(thread->wakeup.user_data);
+ if (ch->stat == RT_IPC_STAT_ACTIVE && ch->reply == thread)
+ {
+ ch->stat = RT_IPC_STAT_IDLE;
+ ch->reply = RT_NULL;
+ }
+ else
+ {
+ rt_ipc_msg_t msg;
+ rt_list_t *l;
+
+ l = ch->wait_msg.next;
+ while (l != &ch->wait_msg)
+ {
+ msg = rt_list_entry(l, struct rt_ipc_msg, mlist);
+ if (msg->need_reply && msg->msg.sender == thread)
+ {
+ rt_list_remove(&msg->mlist); /* remove the msg from the channel */
+ _ipc_msg_free(msg);
+ break;
+ }
+ l = l->next;
+ }
+ }
+ thread->error = -RT_ETIMEOUT;
+ thread->wakeup.func = RT_NULL;
+
+ rt_list_remove(&(thread->tlist));
+ /* insert to schedule ready list */
+ rt_schedule_insert_thread(thread);
+ /* do schedule */
+ rt_schedule();
+}
+
+/**
+ * Send data through an IPC channel, wait for the reply or not.
+ */
+static rt_err_t _rt_raw_channel_send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, int need_reply, rt_channel_msg_t data_ret, rt_int32_t time)
+{
+ rt_ipc_msg_t msg;
+ struct rt_thread *thread_recv, *thread_send = 0;
+ register rt_base_t temp;
+ rt_err_t ret;
+ void (*old_timeout_func)(void *) = 0;
+
+ if (need_reply)
+ {
+ RT_DEBUG_NOT_IN_INTERRUPT;
+ }
+
+ if (ch == RT_NULL)
+ {
+ return -RT_EIO;
+ }
+
+ temp = rt_hw_interrupt_disable();
+
+ if (rt_object_get_type(&ch->parent.parent) != RT_Object_Class_Channel)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EIO;
+ }
+ if (need_reply && time == 0)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ETIMEOUT;
+ }
+
+ /* allocate an IPC message */
+ msg = _ipc_msg_alloc();
+ if (!msg)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ENOMEM;
+ }
+
+ rt_ipc_msg_init(msg, data, need_reply);
+
+ if (need_reply)
+ {
+ thread_send = rt_thread_self();
+ thread_send->error = RT_EOK;
+ }
+
+ switch (ch->stat)
+ {
+ case RT_IPC_STAT_IDLE:
+ case RT_IPC_STAT_ACTIVE:
+ if (need_reply)
+ {
+ ret = rt_channel_list_suspend(&ch->wait_thread, thread_send);
+ if (ret != RT_EOK)
+ {
+ _ipc_msg_free(msg);
+ rt_hw_interrupt_enable(temp);
+ return ret;
+ }
+ rt_thread_wakeup_set(thread_send, wakeup_sender_wait_recv, (void*)ch);
+ if (time > 0)
+ {
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_GET_FUNC,
+ &old_timeout_func);
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_SET_FUNC,
+ sender_timeout);
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_SET_TIME,
+ &time);
+ rt_timer_start(&(thread_send->thread_timer));
+ }
+ }
+ /*
+ * If there is no thread waiting for messages, chain the message
+ * into the list.
+ */
+ rt_list_insert_before(&ch->wait_msg, &msg->mlist);
+ break;
+ case RT_IPC_STAT_WAIT:
+ /*
+ * If there are suspended receivers on the IPC channel, transfer the
+ * pointer of the message to the first receiver directly and wake it
+ * up.
+ */
+ RT_ASSERT(ch->parent.suspend_thread.next != &ch->parent.suspend_thread);
+
+ if (need_reply)
+ {
+ ret = rt_channel_list_suspend(&ch->wait_thread, thread_send);
+ if (ret != RT_EOK)
+ {
+ _ipc_msg_free(msg);
+ rt_hw_interrupt_enable(temp);
+ return ret;
+ }
+ ch->reply = thread_send; /* record the current waiting sender */
+ ch->stat = RT_IPC_STAT_ACTIVE;
+ rt_thread_wakeup_set(thread_send, wakeup_sender_wait_reply, (void*)ch);
+ if (time > 0)
+ {
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_GET_FUNC,
+ &old_timeout_func);
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_SET_FUNC,
+ sender_timeout);
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_SET_TIME,
+ &time);
+ rt_timer_start(&(thread_send->thread_timer));
+ }
+ }
+ else
+ {
+ ch->stat = RT_IPC_STAT_IDLE;
+ }
+ thread_recv = rt_list_entry(ch->parent.suspend_thread.next, struct rt_thread, tlist);
+ thread_recv->msg_ret = msg; /* to the first suspended receiver */
+ thread_recv->error = RT_EOK;
+ rt_channel_list_resume(&ch->parent.suspend_thread);
+ break;
+ default:
+ break;
+ }
+
+ if ( ch->stat == RT_IPC_STAT_IDLE)
+ {
+ _rt_channel_check_wq_wakup(ch);
+ }
+ rt_hw_interrupt_enable(temp);
+
+ /* reschedule in order to let the potential receivers run */
+ rt_schedule();
+
+ if (need_reply)
+ {
+ temp = rt_hw_interrupt_disable();
+ if (old_timeout_func)
+ {
+ rt_timer_control(&(thread_send->thread_timer),
+ RT_TIMER_CTRL_SET_FUNC,
+ old_timeout_func);
+ }
+ ret = thread_send->error;
+ rt_hw_interrupt_enable(temp);
+
+ if (ret != RT_EOK)
+ {
+ return ret;
+ }
+
+ /* If the sender gets the chance to run, the requested reply must be valid. */
+ RT_ASSERT(data_ret != RT_NULL);
+ *data_ret = ((rt_ipc_msg_t)(thread_send->msg_ret))->msg; /* extract data */
+ temp = rt_hw_interrupt_disable();
+ _ipc_msg_free(thread_send->msg_ret); /* put back the message to kernel */
+ rt_hw_interrupt_enable(temp);
+ thread_send->msg_ret = RT_NULL;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * Send data through an IPC channel with no reply.
+ */
+rt_err_t rt_raw_channel_send(rt_channel_t ch, rt_channel_msg_t data)
+{
+ return _rt_raw_channel_send_recv_timeout(ch, data, 0, 0, RT_WAITING_FOREVER);
+}
+
+/**
+ * Send data through an IPC channel and wait for the relpy.
+ */
+rt_err_t rt_raw_channel_send_recv(rt_channel_t ch, rt_channel_msg_t data, rt_channel_msg_t data_ret)
+{
+ return _rt_raw_channel_send_recv_timeout(ch, data, 1, data_ret, RT_WAITING_FOREVER);
+}
+
+/**
+ * Send data through an IPC channel and wait for the relpy.
+ */
+rt_err_t rt_raw_channel_send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time)
+{
+ return _rt_raw_channel_send_recv_timeout(ch, data, 1, data_ret, time);
+}
+
+/**
+ * Reply to the waiting sender and wake it up.
+ */
+rt_err_t rt_raw_channel_reply(rt_channel_t ch, rt_channel_msg_t data)
+{
+ rt_ipc_msg_t msg;
+ struct rt_thread *thread;
+ register rt_base_t temp;
+
+ if (ch == RT_NULL)
+ {
+ return -RT_EIO;
+ }
+
+ temp = rt_hw_interrupt_disable();
+
+ if (rt_object_get_type(&ch->parent.parent) != RT_Object_Class_Channel)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EIO;
+ }
+
+ if (ch->stat != RT_IPC_STAT_ACTIVE)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ERROR;
+ }
+
+ if (ch->reply == RT_NULL)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ERROR;
+ }
+
+ /* allocate an IPC message */
+ msg = _ipc_msg_alloc();
+ if (!msg)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ENOMEM;
+ }
+
+ rt_ipc_msg_init(msg, data, 0);
+
+ thread = ch->reply;
+ thread->msg_ret = msg; /* transfer the reply to the sender */
+ rt_thread_resume(thread); /* wake up the sender */
+ ch->stat = RT_IPC_STAT_IDLE;
+ ch->reply = RT_NULL;
+
+ _rt_channel_check_wq_wakup(ch);
+ rt_hw_interrupt_enable(temp);
+ rt_schedule();
+
+ return RT_EOK;
+}
+
+static rt_err_t wakeup_receiver(void *object, struct rt_thread *thread)
+{
+ rt_channel_t ch;
+ rt_err_t ret;
+
+ ch = (rt_channel_t)object;
+ ch->stat = RT_IPC_STAT_IDLE;
+ thread->error = -RT_EINTR;
+ ret = rt_channel_list_resume(&ch->parent.suspend_thread);
+ _rt_channel_check_wq_wakup(ch);
+ return ret;
+}
+
+static void receiver_timeout(void *parameter)
+{
+ struct rt_thread *thread = (struct rt_thread*)parameter;
+ rt_channel_t ch;
+
+ ch = (rt_channel_t)(thread->wakeup.user_data);
+
+ ch->stat = RT_IPC_STAT_IDLE;
+ thread->error = -RT_ETIMEOUT;
+ thread->wakeup.func = RT_NULL;
+
+ rt_list_remove(&(thread->tlist));
+ /* insert to schedule ready list */
+ rt_schedule_insert_thread(thread);
+
+ _rt_channel_check_wq_wakup(ch);
+ /* do schedule */
+ rt_schedule();
+}
+
+/**
+ * Fetch a message from the specified IPC channel.
+ */
+static rt_err_t _rt_raw_channel_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, rt_int32_t time)
+{
+ struct rt_thread *thread;
+ rt_ipc_msg_t msg_ret;
+ register rt_base_t temp;
+ rt_err_t ret;
+ void (*old_timeout_func)(void *) = 0;
+
+ RT_DEBUG_NOT_IN_INTERRUPT;
+
+ if (ch == RT_NULL)
+ {
+ return -RT_EIO;
+ }
+
+ temp = rt_hw_interrupt_disable();
+
+ if (rt_object_get_type(&ch->parent.parent) != RT_Object_Class_Channel)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_EIO;
+ }
+ if (ch->stat != RT_IPC_STAT_IDLE)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ERROR;
+ }
+
+ if (ch->wait_msg.next != &ch->wait_msg) /* there exist unhandled messages */
+ {
+ msg_ret = rt_list_entry(ch->wait_msg.next, struct rt_ipc_msg, mlist);
+ rt_list_remove(ch->wait_msg.next); /* remove the message from the channel */
+ if (msg_ret->need_reply)
+ {
+ RT_ASSERT(ch->wait_thread.next != &ch->wait_thread);
+
+ thread = rt_list_entry(ch->wait_thread.next, struct rt_thread, tlist);
+ rt_list_remove(ch->wait_thread.next);
+ ch->reply = thread; /* record the waiting sender */
+ ch->stat = RT_IPC_STAT_ACTIVE; /* no valid suspened receivers */
+ }
+ *data = msg_ret->msg; /* extract the transferred data */
+ _ipc_msg_free(msg_ret); /* put back the message to kernel */
+ }
+ else
+ {
+ if (time == 0)
+ {
+ rt_hw_interrupt_enable(temp);
+ return -RT_ETIMEOUT;
+ }
+ /* no valid message, we must wait */
+ thread = rt_thread_self();
+
+ ret = rt_channel_list_suspend(&ch->parent.suspend_thread, thread);
+ if (ret != RT_EOK)
+ {
+ rt_hw_interrupt_enable(temp);
+ return ret;
+ }
+ rt_thread_wakeup_set(thread, wakeup_receiver, (void*)ch);
+ ch->stat = RT_IPC_STAT_WAIT;/* no valid suspended senders */
+ thread->error = RT_EOK;
+ if (time > 0)
+ {
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_GET_FUNC,
+ &old_timeout_func);
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_SET_FUNC,
+ receiver_timeout);
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_SET_TIME,
+ &time);
+ rt_timer_start(&(thread->thread_timer));
+ }
+ rt_hw_interrupt_enable(temp);
+
+ rt_schedule(); /* let the senders run */
+
+ temp = rt_hw_interrupt_disable();
+ if (old_timeout_func)
+ {
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_SET_FUNC,
+ old_timeout_func);
+ }
+ ret = thread->error;
+ if ( ret != RT_EOK)
+ {
+ rt_hw_interrupt_enable(temp);
+ return ret;
+ }
+ /* If waked up, the received message has been store into the thread. */
+ *data = ((rt_ipc_msg_t)(thread->msg_ret))->msg; /* extract data */
+ _ipc_msg_free(thread->msg_ret); /* put back the message to kernel */
+ thread->msg_ret = RT_NULL;
+ }
+
+ rt_hw_interrupt_enable(temp);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_raw_channel_recv(rt_channel_t ch, rt_channel_msg_t data)
+{
+ return _rt_raw_channel_recv_timeout(ch, data, RT_WAITING_FOREVER);
+}
+
+rt_err_t rt_raw_channel_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, rt_int32_t time)
+{
+ return _rt_raw_channel_recv_timeout(ch, data, time);
+}
+/**
+ * Peek a message from the specified IPC channel.
+ */
+rt_err_t rt_raw_channel_peek(rt_channel_t ch, rt_channel_msg_t data)
+{
+ return _rt_raw_channel_recv_timeout(ch, data, 0);
+}
+
+/* for API */
+
+static int lwp_fd_new(int fdt_type)
+{
+ struct dfs_fdtable *fdt;
+
+ if (fdt_type)
+ {
+ fdt = dfs_fdtable_get_global();
+ }
+ else
+ {
+ fdt = dfs_fdtable_get();
+ }
+ return fdt_fd_new(fdt);
+}
+
+static struct dfs_fd *lwp_fd_get(int fdt_type, int fd)
+{
+ struct dfs_fdtable *fdt;
+
+ if (fdt_type)
+ {
+ fdt = dfs_fdtable_get_global();
+ }
+ else
+ {
+ fdt = dfs_fdtable_get();
+ }
+ return fdt_fd_get(fdt, fd);
+}
+
+static void lwp_fd_release(int fdt_type, int fd)
+{
+ struct dfs_fdtable *fdt;
+
+ if (fdt_type)
+ {
+ fdt = dfs_fdtable_get_global();
+ }
+ else
+ {
+ fdt = dfs_fdtable_get();
+ }
+ fdt_fd_release(fdt, fd);
+}
+
+static int _chfd_alloc(int fdt_type)
+{
+ /* create a BSD socket */
+ int fd;
+
+ /* allocate a fd */
+ fd = lwp_fd_new(fdt_type);
+
+ if (fd < 0)
+ {
+ return -1;
+ }
+ return fd;
+}
+
+static void _chfd_free(int fd, int fdt_type)
+{
+ struct dfs_fd *d;
+
+ d = lwp_fd_get(fdt_type, fd);
+ if (d == RT_NULL)
+ {
+ return;
+ }
+ lwp_fd_release(fdt_type, fd);
+}
+
+/* for fops */
+static int channel_fops_poll(struct dfs_fd *file, struct rt_pollreq *req)
+{
+ int mask = POLLOUT;
+ rt_channel_t ch;
+
+ ch = (rt_channel_t)file->vnode->data;
+ rt_poll_add(&(ch->reader_queue), req);
+ if (ch->stat != RT_IPC_STAT_IDLE)
+ {
+ return mask;
+ }
+ if (!rt_list_isempty(&ch->wait_msg))
+ {
+ mask |= POLLIN;
+ }
+ return mask;
+}
+
+static int channel_fops_close(struct dfs_fd *file)
+{
+ rt_channel_t ch;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ ch = (rt_channel_t)file->vnode->data;
+ if (file->vnode->ref_count == 1)
+ {
+ ch->ref--;
+ if (ch->ref == 0)
+ {
+ /* wakeup all the suspended receivers and senders */
+ rt_channel_list_resume_all(&ch->parent.suspend_thread);
+ rt_channel_list_resume_all(&ch->wait_thread);
+
+ /* all ipc msg will lost */
+ rt_list_init(&ch->wait_msg);
+
+ rt_object_delete(&ch->parent.parent); /* release the IPC channel structure */
+ }
+ }
+ rt_hw_interrupt_enable(level);
+ return 0;
+}
+
+static const struct dfs_file_ops channel_fops =
+{
+ NULL, /* open */
+ channel_fops_close,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* lseek */
+ NULL, /* getdents */
+ channel_fops_poll,
+};
+
+int lwp_channel_open(int fdt_type, const char *name, int flags)
+{
+ int fd;
+ rt_channel_t ch = RT_NULL;
+ struct dfs_fd *d;
+
+ fd = _chfd_alloc(fdt_type); /* allocate an IPC channel descriptor */
+ if (fd == -1)
+ {
+ goto quit;
+ }
+ d = lwp_fd_get(fdt_type, fd);
+ d->vnode = (struct dfs_fnode *)rt_malloc(sizeof(struct dfs_fnode));
+ if (!d->vnode)
+ {
+ _chfd_free(fd, fdt_type);
+ fd = -1;
+ goto quit;
+ }
+
+ ch = rt_raw_channel_open(name, flags);
+ if (ch)
+ {
+ rt_memset(d->vnode, 0, sizeof(struct dfs_fnode));
+ rt_list_init(&d->vnode->list);
+ d->vnode->type = FT_USER;
+ d->vnode->path = NULL;
+ d->vnode->fullpath = NULL;
+
+ d->vnode->fops = &channel_fops;
+
+ d->flags = O_RDWR; /* set flags as read and write */
+ d->vnode->size = 0;
+ d->pos = 0;
+ d->vnode->ref_count = 1;
+
+ /* set socket to the data of dfs_fd */
+ d->vnode->data = (void *)ch;
+ }
+ else
+ {
+ rt_free(d->vnode);
+ _chfd_free(fd, fdt_type);
+ fd = -1;
+ }
+quit:
+ return fd;
+}
+
+static rt_channel_t fd_2_channel(int fdt_type, int fd)
+{
+ struct dfs_fd *d;
+
+ d = lwp_fd_get(fdt_type, fd);
+ if (d)
+ {
+ rt_channel_t ch;
+
+ ch = (rt_channel_t)d->vnode->data;
+ if (ch)
+ {
+ return ch;
+ }
+ }
+ return RT_NULL;
+}
+
+rt_err_t lwp_channel_close(int fdt_type, int fd)
+{
+ rt_channel_t ch;
+ struct dfs_fd *d;
+ struct dfs_fnode *vnode;
+
+ d = lwp_fd_get(fdt_type, fd);
+ if (!d)
+ {
+ return -RT_EIO;
+ }
+
+ vnode = d->vnode;
+ if (!vnode)
+ {
+ return -RT_EIO;
+ }
+
+ ch = fd_2_channel(fdt_type, fd);
+ if (!ch)
+ {
+ return -RT_EIO;
+ }
+ _chfd_free(fd, fdt_type);
+ if (vnode->ref_count == 1)
+ {
+ rt_free(vnode);
+ return rt_raw_channel_close(ch);
+ }
+
+ return 0;
+}
+
+rt_err_t lwp_channel_send(int fdt_type, int fd, rt_channel_msg_t data)
+{
+ rt_channel_t ch;
+ ch = fd_2_channel(fdt_type, fd);
+ if (ch)
+ {
+ return rt_raw_channel_send(ch, data);
+ }
+ return -RT_EIO;
+}
+
+rt_err_t lwp_channel_send_recv_timeout(int fdt_type, int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time)
+{
+ rt_channel_t ch;
+ ch = fd_2_channel(fdt_type, fd);
+ if (ch)
+ {
+ return rt_raw_channel_send_recv_timeout(ch, data, data_ret, time);
+ }
+ return -RT_EIO;
+}
+
+rt_err_t lwp_channel_reply(int fdt_type, int fd, rt_channel_msg_t data)
+{
+ rt_channel_t ch;
+ ch = fd_2_channel(fdt_type, fd);
+ if (ch)
+ {
+ return rt_raw_channel_reply(ch, data);
+ }
+ return -RT_EIO;
+}
+
+rt_err_t lwp_channel_recv_timeout(int fdt_type, int fd, rt_channel_msg_t data, rt_int32_t time)
+{
+ rt_channel_t ch;
+ ch = fd_2_channel(fdt_type, fd);
+ if (ch)
+ {
+ return rt_raw_channel_recv_timeout(ch, data, time);
+ }
+ return -RT_EIO;
+}
+
+int rt_channel_open(const char *name, int flags)
+{
+ return lwp_channel_open(FDT_TYPE_KERNEL, name, flags);
+}
+
+rt_err_t rt_channel_close(int fd)
+{
+ return lwp_channel_close(FDT_TYPE_KERNEL, fd);
+}
+
+rt_err_t rt_channel_send(int fd, rt_channel_msg_t data)
+{
+ return lwp_channel_send(FDT_TYPE_KERNEL, fd, data);
+}
+
+rt_err_t rt_channel_send_recv_timeout(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time)
+{
+ return lwp_channel_send_recv_timeout(FDT_TYPE_KERNEL, fd, data, data_ret, time);
+}
+
+rt_err_t rt_channel_send_recv(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret)
+{
+ return lwp_channel_send_recv_timeout(FDT_TYPE_KERNEL, fd, data, data_ret, RT_WAITING_FOREVER);
+}
+
+rt_err_t rt_channel_reply(int fd, rt_channel_msg_t data)
+{
+ return lwp_channel_reply(FDT_TYPE_KERNEL, fd, data);
+}
+
+rt_err_t rt_channel_recv_timeout(int fd, rt_channel_msg_t data, rt_int32_t time)
+{
+ return lwp_channel_recv_timeout(FDT_TYPE_KERNEL, fd, data, time);
+}
+
+rt_err_t rt_channel_recv(int fd, rt_channel_msg_t data)
+{
+ return lwp_channel_recv_timeout(FDT_TYPE_KERNEL, fd, data, RT_WAITING_FOREVER);
+}
+
+rt_err_t rt_channel_peek(int fd, rt_channel_msg_t data)
+{
+ return lwp_channel_recv_timeout(FDT_TYPE_KERNEL, fd, data, 0);
+}
+
+#ifdef RT_USING_FINSH
+static int list_channel(void)
+{
+ rt_base_t level;
+ rt_channel_t *channels;
+ rt_ubase_t index, count;
+ struct rt_object *object;
+ struct rt_list_node *node;
+ struct rt_object_information *information;
+
+ const char* stat_strs[] = {"idle", "wait", "active"};
+
+ information = rt_object_get_information(RT_Object_Class_Channel);
+ RT_ASSERT(information != RT_NULL);
+
+ count = 0;
+ level = rt_hw_interrupt_disable();
+ /* get the count of IPC channels */
+ for (node = information->object_list.next;
+ node != &(information->object_list);
+ node = node->next)
+ {
+ count ++;
+ }
+ rt_hw_interrupt_enable(level);
+
+ if (count == 0) return 0;
+
+ channels = (rt_channel_t *) rt_calloc(count, sizeof(rt_channel_t));
+ if (channels == RT_NULL) return 0; /* out of memory */
+
+ index = 0;
+ level = rt_hw_interrupt_disable();
+ /* retrieve pointer of IPC channels */
+ for (node = information->object_list.next;
+ node != &(information->object_list);
+ node = node->next)
+ {
+ object = rt_list_entry(node, struct rt_object, list);
+
+ channels[index] = (rt_channel_t)object;
+ index ++;
+ }
+ rt_hw_interrupt_enable(level);
+
+ rt_kprintf(" channel state\n");
+ rt_kprintf("-------- -------\n");
+ for (index = 0; index < count; index ++)
+ {
+ if (channels[index] != RT_NULL)
+ {
+ rt_kprintf("%-*.s", RT_NAME_MAX, channels[index]->parent.parent.name);
+ if (channels[index]->stat < 3)
+ rt_kprintf(" %s\n", stat_strs[channels[index]->stat]);
+ }
+ }
+
+ rt_free(channels);
+
+ return 0;
+}
+MSH_CMD_EXPORT(list_channel, list IPC channel information);
+#endif
+
diff --git a/components/lwp/lwp_ipc.h b/components/lwp/lwp_ipc.h
new file mode 100644
index 0000000000..adfe906914
--- /dev/null
+++ b/components/lwp/lwp_ipc.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-12 Jesven first version
+ */
+
+#ifndef LWP_IPC_H__
+#define LWP_IPC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+ RT_CHANNEL_RAW,
+ RT_CHANNEL_BUFFER
+};
+
+struct rt_channel_msg
+{
+ void *sender;
+ int type;
+ union
+ {
+ struct chbuf
+ {
+ void *buf;
+ size_t length;
+ } b;
+ void* d;
+ } u;
+};
+typedef struct rt_channel_msg *rt_channel_msg_t;
+
+int rt_channel_open(const char *name, int flags);
+rt_err_t rt_channel_close(int fd);
+rt_err_t rt_channel_send(int fd, rt_channel_msg_t data);
+rt_err_t rt_channel_send_recv(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret);
+rt_err_t rt_channel_send_recv_timeout(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time);
+rt_err_t rt_channel_reply(int fd, rt_channel_msg_t data);
+rt_err_t rt_channel_recv(int fd, rt_channel_msg_t data);
+rt_err_t rt_channel_recv_timeout(int fd, rt_channel_msg_t data, rt_int32_t time);
+rt_err_t rt_channel_peek(int fd, rt_channel_msg_t data);
+
+rt_channel_t rt_raw_channel_open(const char *name, int flags);
+rt_err_t rt_raw_channel_close(rt_channel_t ch);
+rt_err_t rt_raw_channel_send(rt_channel_t ch, rt_channel_msg_t data);
+rt_err_t rt_raw_channel_send_recv(rt_channel_t ch, rt_channel_msg_t data, rt_channel_msg_t data_ret);
+rt_err_t rt_raw_channel_send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time);
+rt_err_t rt_raw_channel_reply(rt_channel_t ch, rt_channel_msg_t data);
+rt_err_t rt_raw_channel_recv(rt_channel_t ch, rt_channel_msg_t data);
+rt_err_t rt_raw_channel_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, rt_int32_t time);
+rt_err_t rt_raw_channel_peek(rt_channel_t ch, rt_channel_msg_t data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/components/lwp/lwp_ipc_internal.h b/components/lwp/lwp_ipc_internal.h
new file mode 100644
index 0000000000..1efa7a1c02
--- /dev/null
+++ b/components/lwp/lwp_ipc_internal.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-16 Jesven first version
+ */
+#ifndef LWP_IPC_INTERNAL_H__
+#define LWP_IPC_INTERNAL_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <lwp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+ FDT_TYPE_LWP,
+ FDT_TYPE_KERNEL
+};
+
+int lwp_channel_open(int fdt_type, const char *name, int flags);
+rt_err_t lwp_channel_close(int fdt_type, int fd);
+rt_err_t lwp_channel_send(int fdt_type, int fd, rt_channel_msg_t data);
+rt_err_t lwp_channel_send_recv_timeout(int fdt_type, int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time);
+rt_err_t lwp_channel_reply(int fdt_type, int fd, rt_channel_msg_t data);
+rt_err_t lwp_channel_recv_timeout(int fdt_type, int fd, rt_channel_msg_t data, rt_int32_t time);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWP_IPC_INTERNAL_H__*/
diff --git a/components/lwp/lwp_mem.c b/components/lwp/lwp_mem.c
deleted file mode 100644
index fe9de9eb67..0000000000
--- a/components/lwp/lwp_mem.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-06-10 Bernard first version
- */
-
-#include <rtthread.h>
-#include <lwp.h>
-
-#define DBG_TAG "LWPMEM"
-#define DBG_LVL DBG_WARNING
-#include <rtdbg.h>
-
-// todo: remove repleat code
-#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_lwp_memheap_item), RT_ALIGN_SIZE)
-#define MEMITEM_SIZE(item) ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE)
-
-#ifndef LWP_MEM_PAGE_SIZE
- #define LWP_MEM_PAGE_SIZE (4 * 1024)
-#endif
-
-#ifndef LWP_MEM_MAX_PAGE_COUNT
- #define LWP_MEM_MAX_PAGE_COUNT (256 * 4)
-#endif
-
-static void *rt_lwp_malloc_page(struct rt_lwp *lwp, rt_size_t npages)
-{
- void *chunk;
- char name[6];
- struct rt_lwp_memheap *lwp_heap;
- rt_size_t page_cnt;
-
- RT_ASSERT(lwp != RT_NULL);
-
- page_cnt = lwp->heap_cnt + npages;
- if (page_cnt > LWP_MEM_MAX_PAGE_COUNT)
- {
- dbg_log(DBG_ERROR, "alloc new page failed, lwp memory size out of limited: %d\n", page_cnt);
- return RT_NULL;
- }
-
- lwp_heap = rt_malloc(sizeof(struct rt_lwp_memheap));
- if (lwp_heap == RT_NULL)
- {
- dbg_log(DBG_ERROR, "alloc new page head failed, out of memory : %d\n", page_cnt);
- return RT_NULL;
- }
-
- chunk = rt_malloc(npages * LWP_MEM_PAGE_SIZE);
- if (chunk == RT_NULL)
- {
- dbg_log(DBG_ERROR, "alloc new page buffer failed, out of memory : %d\n", page_cnt);
- rt_free(lwp_heap);
- return RT_NULL;
- }
-
- dbg_log(DBG_LOG, "lwp alloc page: %d\n", npages);
-
- rt_sprintf(name, "lwp%02x", lwp->heap_cnt);
- rt_lwp_memheap_init(lwp_heap, name, chunk, npages * LWP_MEM_PAGE_SIZE);
-
- rt_list_insert_before(&lwp->hlist, &lwp_heap->mlist);
-
- lwp->heap_cnt += npages;
-
- return chunk;
-}
-
-static void rt_lwp_free_page(struct rt_lwp *lwp, struct rt_lwp_memheap *lwp_heap)
-{
- rt_size_t npages;
-
- RT_ASSERT(lwp != RT_NULL);
- RT_ASSERT(lwp_heap != RT_NULL);
- RT_ASSERT(lwp_heap->start_addr != RT_NULL);
-
- npages = lwp_heap->pool_size / LWP_MEM_PAGE_SIZE;
- lwp->heap_cnt -= npages;
-
- dbg_log(DBG_LOG, "lwp free page: %d\n", npages);
-
- rt_list_remove(&lwp_heap->mlist);
-
- rt_free(lwp_heap->start_addr);
- rt_free(lwp_heap);
-}
-
-void rt_lwp_mem_init(struct rt_lwp *lwp)
-{
- RT_ASSERT(lwp != RT_NULL);
- rt_list_init(&lwp->hlist);
-}
-
-void rt_lwp_mem_deinit(struct rt_lwp *lwp)
-{
- struct rt_list_node *node;
-
- RT_ASSERT(lwp != RT_NULL);
-
- node = lwp->hlist.next;
-
- while (node != &(lwp->hlist))
- {
- struct rt_lwp_memheap *lwp_heap;
-
- lwp_heap = rt_list_entry(node, struct rt_lwp_memheap, mlist);
- RT_ASSERT(lwp_heap != RT_NULL);
-
- /* update note before free page*/
- node = node->next;
-
- rt_lwp_free_page(lwp, lwp_heap);
- }
-}
-
-void *rt_lwp_mem_malloc(rt_uint32_t size)
-{
- struct rt_lwp *lwp;
- struct rt_list_node *node;
- void *addr = RT_NULL;
- rt_uint32_t npages;
-
- if (size == 0)
- return RT_NULL;
-
- lwp = rt_lwp_self();
- RT_ASSERT(lwp != RT_NULL);
-
- for (node = lwp->hlist.next; node != &(lwp->hlist); node = node->next)
- {
- struct rt_lwp_memheap *lwp_heap;
- lwp_heap = rt_list_entry(node, struct rt_lwp_memheap, mlist);
-
- addr = rt_lwp_memheap_alloc(lwp_heap, size);
- if (addr != RT_NULL)
- {
- dbg_log(DBG_LOG, "lwp alloc 0x%x/%d\n", addr, size);
- return addr;
- }
- }
-
- npages = (size + rt_lwp_memheap_unavailable_size_get() + LWP_MEM_PAGE_SIZE) / LWP_MEM_PAGE_SIZE;
- if (RT_NULL != rt_lwp_malloc_page(lwp, npages))
- return rt_lwp_mem_malloc(size);
- else
- return RT_NULL;
-}
-
-void rt_lwp_mem_free(void *addr)
-{
- struct rt_lwp_memheap_item *header_ptr;
- struct rt_lwp_memheap *lwp_heap;
-
- if (addr == RT_NULL)
- return ;
-
- /* get memory item */
- header_ptr = (struct rt_lwp_memheap_item *)((rt_uint8_t *)addr - RT_MEMHEAP_SIZE);
- RT_ASSERT(header_ptr);
-
- lwp_heap = header_ptr->pool_ptr;
- RT_ASSERT(lwp_heap);
-
- dbg_log(DBG_LOG, "lwp free 0x%x\n", addr);
- rt_lwp_memheap_free((void *)addr);
-
- if (rt_lwp_memheap_is_empty(lwp_heap))
- {
- rt_lwp_free_page(rt_lwp_self(), lwp_heap);
- }
-}
-
-void *rt_lwp_mem_realloc(void *rmem, rt_size_t newsize)
-{
- void *new_ptr;
- struct rt_lwp_memheap_item *header_ptr;
-
- if (rmem == RT_NULL)
- return rt_lwp_mem_malloc(newsize);
-
- if (newsize == 0)
- {
- rt_lwp_mem_free(rmem);
- return RT_NULL;
- }
-
- /* get old memory item */
- header_ptr = (struct rt_lwp_memheap_item *)
- ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);
-
- new_ptr = rt_lwp_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
- if (new_ptr == RT_NULL)
- {
- /* allocate memory block from other memheap */
- new_ptr = rt_lwp_mem_malloc(newsize);
- if (new_ptr != RT_NULL && rmem != RT_NULL)
- {
- rt_size_t oldsize;
-
- /* get the size of old memory block */
- oldsize = MEMITEM_SIZE(header_ptr);
- if (newsize > oldsize)
- rt_memcpy(new_ptr, rmem, oldsize);
- else
- rt_memcpy(new_ptr, rmem, newsize);
-
- dbg_log(DBG_LOG, "lwp realloc with memcpy 0x%x -> 0x%x/%d\n", rmem, new_ptr, newsize);
- rt_lwp_mem_free(rmem);
-
- }
- }
-
- dbg_log(DBG_LOG, "lwp realloc in same address 0x%x/%d\n", rmem, newsize);
-
- return new_ptr;
-}
diff --git a/components/lwp/lwp_mem.h b/components/lwp/lwp_mem.h
deleted file mode 100644
index 7ef1c2293c..0000000000
--- a/components/lwp/lwp_mem.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-06-10 Bernard first version
- */
-
-#ifndef __LWP_MEM_H__
-#define __LWP_MEM_H__
-
-extern void rt_lwp_mem_init(struct rt_lwp *lwp);
-extern void rt_lwp_mem_deinit(struct rt_lwp *lwp);
-
-extern void *rt_lwp_mem_malloc(rt_uint32_t size);
-extern void rt_lwp_mem_free(void *addr);
-extern void *rt_lwp_mem_realloc(void *rmem, rt_size_t newsize);
-
-#endif
diff --git a/components/lwp/lwp_memheap.c b/components/lwp/lwp_memheap.c
deleted file mode 100644
index 9695aab282..0000000000
--- a/components/lwp/lwp_memheap.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2012-04-10 Bernard first implementation
- * 2012-10-16 Bernard add the mutex lock for heap object.
- * 2012-12-29 Bernard memheap can be used as system heap.
- * change mutex lock to semaphore lock.
- * 2013-04-10 Bernard add rt_lwp_memheap_realloc function.
- * 2013-05-24 Bernard fix the rt_lwp_memheap_realloc issue.
- * 2013-07-11 Grissiom fix the memory block splitting issue.
- * 2013-07-15 Grissiom optimize rt_lwp_memheap_realloc
- */
-
-#include <rthw.h>
-#include <rtthread.h>
-#include <lwp.h>
-
-/* dynamic pool magic and mask */
-#define RT_MEMHEAP_MAGIC 0x1ea01ea0
-#define RT_MEMHEAP_MASK 0xfffffffe
-#define RT_MEMHEAP_USED 0x01
-#define RT_MEMHEAP_FREED 0x00
-
-#define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED)
-#define RT_MEMHEAP_MINIALLOC 12
-
-#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_lwp_memheap_item), RT_ALIGN_SIZE)
-#define MEMITEM_SIZE(item) ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE)
-
-/*
- * The initialized memory pool will be:
- * +-----------------------------------+--------------------------+
- * | whole freed memory block | Used Memory Block Tailer |
- * +-----------------------------------+--------------------------+
- *
- * block_list --> whole freed memory block
- *
- * The length of Used Memory Block Tailer is 0,
- * which is prevents block merging across list
- */
-rt_err_t rt_lwp_memheap_init(struct rt_lwp_memheap *memheap,
- const char *name,
- void *start_addr,
- rt_uint32_t size)
-{
- struct rt_lwp_memheap_item *item;
-
- RT_ASSERT(memheap != RT_NULL);
-
- /* initialize pool object */
- memheap->start_addr = start_addr;
- memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
- memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
- memheap->max_used_size = memheap->pool_size - memheap->available_size;
-
- /* initialize the free list header */
- item = &(memheap->free_header);
- item->magic = RT_MEMHEAP_MAGIC;
- item->pool_ptr = memheap;
- item->next = RT_NULL;
- item->prev = RT_NULL;
- item->next_free = item;
- item->prev_free = item;
-
- /* set the free list to free list header */
- memheap->free_list = item;
-
- /* initialize the first big memory block */
- item = (struct rt_lwp_memheap_item *)start_addr;
- item->magic = RT_MEMHEAP_MAGIC;
- item->pool_ptr = memheap;
- item->next = RT_NULL;
- item->prev = RT_NULL;
- item->next_free = item;
- item->prev_free = item;
-
- item->next = (struct rt_lwp_memheap_item *)
- ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
- item->prev = item->next;
-
- /* block list header */
- memheap->block_list = item;
-
- /* place the big memory block to free list */
- item->next_free = memheap->free_list->next_free;
- item->prev_free = memheap->free_list;
- memheap->free_list->next_free->prev_free = item;
- memheap->free_list->next_free = item;
-
- /* move to the end of memory pool to build a small tailer block,
- * which prevents block merging
- */
- item = item->next;
- /* it's a used memory block */
- item->magic = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED;
- item->pool_ptr = memheap;
- item->next = (struct rt_lwp_memheap_item *)start_addr;
- item->prev = (struct rt_lwp_memheap_item *)start_addr;
- /* not in free list */
- item->next_free = item->prev_free = RT_NULL;
-
- /* initialize semaphore lock */
- rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO);
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n",
- start_addr, size, &(memheap->free_header)));
-
- return RT_EOK;
-}
-
-void *rt_lwp_memheap_alloc(struct rt_lwp_memheap *heap, rt_uint32_t size)
-{
- rt_err_t result;
- rt_uint32_t free_size;
- struct rt_lwp_memheap_item *header_ptr;
-
- RT_ASSERT(heap != RT_NULL);
-
- /* align allocated size */
- size = RT_ALIGN(size, RT_ALIGN_SIZE);
- if (size < RT_MEMHEAP_MINIALLOC)
- size = RT_MEMHEAP_MINIALLOC;
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
- size, RT_NAME_MAX, heap->parent.name));
-
- if (size < heap->available_size)
- {
- /* search on free list */
- free_size = 0;
-
- /* lock memheap */
- result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
- if (result != RT_EOK)
- {
- rt_set_errno(result);
-
- return RT_NULL;
- }
-
- /* get the first free memory block */
- header_ptr = heap->free_list->next_free;
- while (header_ptr != heap->free_list && free_size < size)
- {
- /* get current freed memory block size */
- free_size = MEMITEM_SIZE(header_ptr);
- if (free_size < size)
- {
- /* move to next free memory block */
- header_ptr = header_ptr->next_free;
- }
- }
-
- /* determine if the memory is available. */
- if (free_size >= size)
- {
- /* a block that satisfies the request has been found. */
-
- /* determine if the block needs to be split. */
- if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
- {
- struct rt_lwp_memheap_item *new_ptr;
-
- /* split the block. */
- new_ptr = (struct rt_lwp_memheap_item *)
- (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
- header_ptr,
- header_ptr->next,
- header_ptr->prev,
- new_ptr));
-
- /* mark the new block as a memory block and freed. */
- new_ptr->magic = RT_MEMHEAP_MAGIC;
-
- /* put the pool pointer into the new block. */
- new_ptr->pool_ptr = heap;
-
- /* break down the block list */
- new_ptr->prev = header_ptr;
- new_ptr->next = header_ptr->next;
- header_ptr->next->prev = new_ptr;
- header_ptr->next = new_ptr;
-
- /* remove header ptr from free list */
- header_ptr->next_free->prev_free = header_ptr->prev_free;
- header_ptr->prev_free->next_free = header_ptr->next_free;
- header_ptr->next_free = RT_NULL;
- header_ptr->prev_free = RT_NULL;
-
- /* insert new_ptr to free list */
- new_ptr->next_free = heap->free_list->next_free;
- new_ptr->prev_free = heap->free_list;
- heap->free_list->next_free->prev_free = new_ptr;
- heap->free_list->next_free = new_ptr;
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n",
- new_ptr->next_free,
- new_ptr->prev_free));
-
- /* decrement the available byte count. */
- heap->available_size = heap->available_size -
- size -
- RT_MEMHEAP_SIZE;
- if (heap->pool_size - heap->available_size > heap->max_used_size)
- heap->max_used_size = heap->pool_size - heap->available_size;
- }
- else
- {
- /* decrement the entire free size from the available bytes count. */
- heap->available_size = heap->available_size - free_size;
- if (heap->pool_size - heap->available_size > heap->max_used_size)
- heap->max_used_size = heap->pool_size - heap->available_size;
-
- /* remove header_ptr from free list */
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n",
- header_ptr,
- header_ptr->next_free,
- header_ptr->prev_free));
-
- header_ptr->next_free->prev_free = header_ptr->prev_free;
- header_ptr->prev_free->next_free = header_ptr->next_free;
- header_ptr->next_free = RT_NULL;
- header_ptr->prev_free = RT_NULL;
- }
-
- /* Mark the allocated block as not available. */
- header_ptr->magic |= RT_MEMHEAP_USED;
-
- /* release lock */
- rt_sem_release(&(heap->lock));
-
- /* Return a memory address to the caller. */
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n",
- (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
- header_ptr,
- size));
-
- return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
- }
-
- /* release lock */
- rt_sem_release(&(heap->lock));
- }
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
-
- /* Return the completion status. */
- return RT_NULL;
-}
-
-void *rt_lwp_memheap_realloc(struct rt_lwp_memheap *heap, void *ptr, rt_size_t newsize)
-{
- rt_err_t result;
- rt_size_t oldsize;
- struct rt_lwp_memheap_item *header_ptr;
- struct rt_lwp_memheap_item *new_ptr;
-
- if (newsize == 0)
- {
- rt_lwp_memheap_free(ptr);
-
- return RT_NULL;
- }
- /* align allocated size */
- newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
- if (newsize < RT_MEMHEAP_MINIALLOC)
- newsize = RT_MEMHEAP_MINIALLOC;
-
- if (ptr == RT_NULL)
- {
- return rt_lwp_memheap_alloc(heap, newsize);
- }
-
- /* get memory block header and get the size of memory block */
- header_ptr = (struct rt_lwp_memheap_item *)
- ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
- oldsize = MEMITEM_SIZE(header_ptr);
- /* re-allocate memory */
- if (newsize > oldsize)
- {
- void *new_ptr;
- struct rt_lwp_memheap_item *next_ptr;
-
- /* lock memheap */
- result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
- if (result != RT_EOK)
- {
- rt_set_errno(result);
- return RT_NULL;
- }
-
- next_ptr = header_ptr->next;
-
- /* header_ptr should not be the tail */
- RT_ASSERT(next_ptr > header_ptr);
-
- /* check whether the following free space is enough to expand */
- if (!RT_MEMHEAP_IS_USED(next_ptr))
- {
- rt_int32_t nextsize;
-
- nextsize = MEMITEM_SIZE(next_ptr);
- RT_ASSERT(next_ptr > 0);
-
- /* Here is the ASCII art of the situation that we can make use of
- * the next free node without alloc/memcpy, |*| is the control
- * block:
- *
- * oldsize free node
- * |*|-----------|*|----------------------|*|
- * newsize >= minialloc
- * |*|----------------|*|-----------------|*|
- */
- if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
- {
- /* decrement the entire free size from the available bytes count. */
- heap->available_size = heap->available_size - (newsize - oldsize);
- if (heap->pool_size - heap->available_size > heap->max_used_size)
- heap->max_used_size = heap->pool_size - heap->available_size;
-
- /* remove next_ptr from free list */
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
- next_ptr,
- next_ptr->next_free,
- next_ptr->prev_free));
-
- next_ptr->next_free->prev_free = next_ptr->prev_free;
- next_ptr->prev_free->next_free = next_ptr->next_free;
- next_ptr->next->prev = next_ptr->prev;
- next_ptr->prev->next = next_ptr->next;
-
- /* build a new one on the right place */
- next_ptr = (struct rt_lwp_memheap_item *)((char *)ptr + newsize);
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
- next_ptr,
- next_ptr->next,
- next_ptr->prev));
-
- /* mark the new block as a memory block and freed. */
- next_ptr->magic = RT_MEMHEAP_MAGIC;
-
- /* put the pool pointer into the new block. */
- next_ptr->pool_ptr = heap;
-
- next_ptr->prev = header_ptr;
- next_ptr->next = header_ptr->next;
- header_ptr->next->prev = next_ptr;
- header_ptr->next = next_ptr;
-
- /* insert next_ptr to free list */
- next_ptr->next_free = heap->free_list->next_free;
- next_ptr->prev_free = heap->free_list;
- heap->free_list->next_free->prev_free = next_ptr;
- heap->free_list->next_free = next_ptr;
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
- next_ptr->next_free,
- next_ptr->prev_free));
-
- /* release lock */
- rt_sem_release(&(heap->lock));
-
- return ptr;
- }
- }
-
- /* release lock */
- rt_sem_release(&(heap->lock));
-
- /* re-allocate a memory block */
- new_ptr = (void *)rt_lwp_memheap_alloc(heap, newsize);
- if (new_ptr != RT_NULL)
- {
- rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
- rt_lwp_memheap_free(ptr);
- }
-
- return new_ptr;
- }
-
- /* don't split when there is less than one node space left */
- if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
- return ptr;
-
- /* lock memheap */
- result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
- if (result != RT_EOK)
- {
- rt_set_errno(result);
-
- return RT_NULL;
- }
-
- /* split the block. */
- new_ptr = (struct rt_lwp_memheap_item *)
- (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
- header_ptr,
- header_ptr->next,
- header_ptr->prev,
- new_ptr));
-
- /* mark the new block as a memory block and freed. */
- new_ptr->magic = RT_MEMHEAP_MAGIC;
- /* put the pool pointer into the new block. */
- new_ptr->pool_ptr = heap;
-
- /* break down the block list */
- new_ptr->prev = header_ptr;
- new_ptr->next = header_ptr->next;
- header_ptr->next->prev = new_ptr;
- header_ptr->next = new_ptr;
-
- /* determine if the block can be merged with the next neighbor. */
- if (!RT_MEMHEAP_IS_USED(new_ptr->next))
- {
- struct rt_lwp_memheap_item *free_ptr;
-
- /* merge block with next neighbor. */
- free_ptr = new_ptr->next;
- heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
- header_ptr, header_ptr->next_free, header_ptr->prev_free));
-
- free_ptr->next->prev = new_ptr;
- new_ptr->next = free_ptr->next;
-
- /* remove free ptr from free list */
- free_ptr->next_free->prev_free = free_ptr->prev_free;
- free_ptr->prev_free->next_free = free_ptr->next_free;
- }
-
- /* insert the split block to free list */
- new_ptr->next_free = heap->free_list->next_free;
- new_ptr->prev_free = heap->free_list;
- heap->free_list->next_free->prev_free = new_ptr;
- heap->free_list->next_free = new_ptr;
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n",
- new_ptr->next_free,
- new_ptr->prev_free));
-
- /* increment the available byte count. */
- heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
-
- /* release lock */
- rt_sem_release(&(heap->lock));
-
- /* return the old memory block */
- return ptr;
-}
-
-void rt_lwp_memheap_free(void *ptr)
-{
- rt_err_t result;
- struct rt_lwp_memheap *heap;
- struct rt_lwp_memheap_item *header_ptr, *new_ptr;
- rt_uint32_t insert_header;
-
- /* NULL check */
- if (ptr == RT_NULL) return;
-
- /* set initial status as OK */
- insert_header = 1;
- new_ptr = RT_NULL;
- header_ptr = (struct rt_lwp_memheap_item *)
- ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n",
- ptr, header_ptr));
-
- /* check magic */
- RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
- RT_ASSERT(header_ptr->magic & RT_MEMHEAP_USED);
- /* check whether this block of memory has been over-written. */
- RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
-
- /* get pool ptr */
- heap = header_ptr->pool_ptr;
-
- /* lock memheap */
- result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
- if (result != RT_EOK)
- {
- rt_set_errno(result);
-
- return ;
- }
-
- /* Mark the memory as available. */
- header_ptr->magic &= ~RT_MEMHEAP_USED;
- /* Adjust the available number of bytes. */
- heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr);
-
- /* Determine if the block can be merged with the previous neighbor. */
- if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
- {
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n",
- header_ptr->prev));
-
- /* adjust the available number of bytes. */
- heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
-
- /* yes, merge block with previous neighbor. */
- (header_ptr->prev)->next = header_ptr->next;
- (header_ptr->next)->prev = header_ptr->prev;
-
- /* move header pointer to previous. */
- header_ptr = header_ptr->prev;
- /* don't insert header to free list */
- insert_header = 0;
- }
-
- /* determine if the block can be merged with the next neighbor. */
- if (!RT_MEMHEAP_IS_USED(header_ptr->next))
- {
- /* adjust the available number of bytes. */
- heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
-
- /* merge block with next neighbor. */
- new_ptr = header_ptr->next;
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
- new_ptr, new_ptr->next_free, new_ptr->prev_free));
-
- new_ptr->next->prev = header_ptr;
- header_ptr->next = new_ptr->next;
-
- /* remove new ptr from free list */
- new_ptr->next_free->prev_free = new_ptr->prev_free;
- new_ptr->prev_free->next_free = new_ptr->next_free;
- }
-
- if (insert_header)
- {
- /* no left merge, insert to free list */
- header_ptr->next_free = heap->free_list->next_free;
- header_ptr->prev_free = heap->free_list;
- heap->free_list->next_free->prev_free = header_ptr;
- heap->free_list->next_free = header_ptr;
-
- RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
- ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n",
- header_ptr->next_free, header_ptr->prev_free));
- }
-
- /* release lock */
- rt_sem_release(&(heap->lock));
-}
-
-rt_bool_t rt_lwp_memheap_is_empty(struct rt_lwp_memheap *memheap)
-{
- RT_ASSERT(memheap != RT_NULL);
-
- return (memheap->available_size + 2 * sizeof(struct rt_lwp_memheap_item)) == memheap->pool_size;
-}
-
-rt_bool_t rt_lwp_memheap_unavailable_size_get(void)
-{
- return 2 * RT_MEMHEAP_SIZE + 3;
-}
diff --git a/components/lwp/lwp_memheap.h b/components/lwp/lwp_memheap.h
deleted file mode 100644
index 845feb8594..0000000000
--- a/components/lwp/lwp_memheap.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-06-10 Bernard first version
- */
-
-#ifndef __LWP_MEMHEAP_H__
-#define __LWP_MEMHEAP_H__
-
-#include <stdint.h>
-#include <rtthread.h>
-
-/**
- * memory item on the heap
- */
-struct rt_lwp_memheap_item
-{
- rt_uint32_t magic; /**< magic number for memheap */
- struct rt_lwp_memheap *pool_ptr; /**< point of pool */
-
- struct rt_lwp_memheap_item *next; /**< next memheap item */
- struct rt_lwp_memheap_item *prev; /**< prev memheap item */
-
- struct rt_lwp_memheap_item *next_free; /**< next free memheap item */
- struct rt_lwp_memheap_item *prev_free; /**< prev free memheap item */
-};
-
-/**
- * Base structure of memory heap object
- */
-struct rt_lwp_memheap
-{
- struct rt_object parent; /**< inherit from rt_object */
-
- void *start_addr; /**< pool start address and size */
-
- rt_uint32_t pool_size; /**< pool size */
- rt_uint32_t available_size; /**< available size */
- rt_uint32_t max_used_size; /**< maximum allocated size */
-
- struct rt_lwp_memheap_item *block_list; /**< used block list */
- struct rt_lwp_memheap_item *free_list; /**< free block list */
- struct rt_lwp_memheap_item free_header; /**< free block list header */
-
- struct rt_semaphore lock; /**< semaphore lock */
-
- rt_list_t mlist;
-};
-
-extern rt_err_t rt_lwp_memheap_init(struct rt_lwp_memheap *memheap, const char *name, void *start_addr, rt_uint32_t size);
-extern void *rt_lwp_memheap_alloc(struct rt_lwp_memheap *heap, rt_uint32_t size);
-extern void rt_lwp_memheap_free(void *ptr);
-extern void *rt_lwp_memheap_realloc(struct rt_lwp_memheap *heap, void *ptr, rt_size_t newsize);
-extern rt_bool_t rt_lwp_memheap_is_empty(struct rt_lwp_memheap *memheap);
-extern rt_bool_t rt_lwp_memheap_unavailable_size_get(void);
-
-#endif
diff --git a/components/lwp/lwp_mm.c b/components/lwp/lwp_mm.c
new file mode 100644
index 0000000000..f8d051133c
--- /dev/null
+++ b/components/lwp/lwp_mm.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include "lwp_mm.h"
+
+static rt_mutex_t mm_lock;
+
+void rt_mm_lock(void)
+{
+ if (rt_thread_self())
+ {
+ if (!mm_lock)
+ {
+ mm_lock = rt_mutex_create("mm_lock", RT_IPC_FLAG_FIFO);
+ }
+ if (mm_lock)
+ {
+ rt_mutex_take(mm_lock, RT_WAITING_FOREVER);
+ }
+ }
+}
+
+void rt_mm_unlock(void)
+{
+ if (rt_thread_self())
+ {
+ if (mm_lock)
+ {
+ rt_mutex_release(mm_lock);
+ }
+ }
+}
diff --git a/components/lwp/lwp_mm.h b/components/lwp/lwp_mm.h
new file mode 100644
index 0000000000..57f9b78faf
--- /dev/null
+++ b/components/lwp/lwp_mm.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef __LWP_MM_H__
+#define __LWP_MM_H__
+
+void rt_mm_lock(void);
+void rt_mm_unlock(void);
+
+#endif /*__LWP_MM_H__*/
diff --git a/components/lwp/lwp_mm_area.c b/components/lwp/lwp_mm_area.c
new file mode 100644
index 0000000000..08ecf0684a
--- /dev/null
+++ b/components/lwp/lwp_mm_area.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-28 Jesven first version
+ */
+#include <rtthread.h>
+
+#ifdef RT_USING_USERSPACE
+#include <lwp_mm_area.h>
+
+int lwp_map_area_insert(struct lwp_avl_struct **avl_tree, size_t addr, size_t size, int ma_type)
+{
+ struct lwp_avl_struct *node = RT_NULL;
+ struct rt_mm_area_struct *ma = RT_NULL;
+
+ if (!size)
+ {
+ return -1;
+ }
+ ma = (struct rt_mm_area_struct *)rt_malloc(sizeof(struct rt_mm_area_struct));
+ if (!ma)
+ {
+ return -1;
+ }
+ ma->addr = addr;
+ ma->size = size;
+ ma->type = ma_type;
+
+ node = (struct lwp_avl_struct *)rt_malloc(sizeof(struct lwp_avl_struct));
+ if (!node)
+ {
+ rt_free(ma);
+ return -1;
+ }
+ memset(node, 0, sizeof(struct lwp_avl_struct));
+
+ node->avl_key = ma->addr;
+ node->data = (void *)ma;
+ lwp_avl_insert(node, avl_tree);
+ return 0;
+}
+
+void lwp_map_area_remove(struct lwp_avl_struct **avl_tree, size_t addr)
+{
+ struct lwp_avl_struct *node = RT_NULL;
+
+ node = lwp_avl_find(addr, *avl_tree);
+ if (!node)
+ {
+ return;
+ }
+ lwp_avl_remove(node, avl_tree);
+ rt_free(node->data);
+ rt_free(node);
+}
+
+struct lwp_avl_struct* lwp_map_find(struct lwp_avl_struct* ptree, size_t addr)
+{
+ struct lwp_avl_struct *node = ptree;
+
+ while (1)
+ {
+ if (!node)
+ {
+ return node;
+ }
+ if ((size_t)node->avl_key <= addr)
+ {
+ struct rt_mm_area_struct *ma = (struct rt_mm_area_struct *)node->data;
+ if ((ma->addr <= addr) && (addr < ma->addr + ma->size))
+ {
+ /* find area */
+ break;
+ }
+ node = node->avl_right;
+ }
+ else
+ {
+ node = node->avl_left;
+ }
+ }
+ return node;
+}
+
+struct lwp_avl_struct* lwp_map_find_first(struct lwp_avl_struct* ptree)
+{
+ if (ptree == AVL_EMPTY)
+ {
+ return (struct lwp_avl_struct *)0;
+ }
+ while (1)
+ {
+ if (!ptree->avl_left)
+ {
+ break;
+ }
+ ptree = ptree->avl_left;
+ }
+ return ptree;
+}
+
+int top_mem_fun(struct lwp_avl_struct* ptree, void *arg)
+{
+ size_t *vs = (size_t *)arg;
+ struct rt_mm_area_struct *ma;
+
+ ma = (struct rt_mm_area_struct *)ptree->data;
+ *vs += ma->size;
+ return 0;
+}
+
+size_t lwp_vmem_count(struct lwp_avl_struct *ptree)
+{
+ size_t vsize = 0;
+ lwp_avl_traversal(ptree, top_mem_fun, &vsize);
+ return vsize;
+}
+#endif
diff --git a/components/lwp/lwp_mm_area.h b/components/lwp/lwp_mm_area.h
new file mode 100644
index 0000000000..555a03ce48
--- /dev/null
+++ b/components/lwp/lwp_mm_area.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-28 Jesven first version
+ */
+#ifndef __LWP_MM_AREA_H__
+#define __LWP_MM_AREA_H__
+
+#include <string.h>
+#include <stdint.h>
+
+#include <lwp_avl.h>
+
+#ifdef RT_USING_USERSPACE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+ MM_AREA_TYPE_PHY = 0, /* mm_area physical address is IO register or reserved memory no cached*/
+ MM_AREA_TYPE_PHY_CACHED, /* mm_area physical address is IO register or reserved memory with cached */
+ MM_AREA_TYPE_SHM, /* mm_area physical address is shared memory */
+ MM_AREA_TYPE_DATA, /* mm_area physical address is alloced from page manager for data */
+ MM_AREA_TYPE_TEXT, /* mm_area physical address is alloced from page manager for text */
+ MM_AREA_TYPE_UNKNOW,
+};
+
+struct rt_mm_area_struct
+{
+ size_t addr;
+ size_t size;
+ int type;
+};
+
+int lwp_map_area_insert(struct lwp_avl_struct **avl_tree, size_t addr, size_t size, int ma_type);
+void lwp_map_area_remove(struct lwp_avl_struct **avl_tree, size_t addr);
+struct lwp_avl_struct* lwp_map_find(struct lwp_avl_struct* ptree, size_t addr);
+struct lwp_avl_struct* lwp_map_find_first(struct lwp_avl_struct* ptree);
+size_t lwp_vmem_count(struct lwp_avl_struct *ptree);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /*__LWP_MM_AREA_H__*/
diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c
new file mode 100644
index 0000000000..086a271e91
--- /dev/null
+++ b/components/lwp/lwp_pid.c
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-16 zhangjun first version
+ * 2021-02-20 lizhirui fix warning
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include <dfs_file.h>
+#include <unistd.h>
+#include <stdio.h> /* rename() */
+#include <sys/stat.h>
+#include <sys/statfs.h> /* statfs() */
+
+#include "lwp.h"
+#include "lwp_pid.h"
+#include "tty.h"
+
+#ifdef RT_USING_USERSPACE
+#include "lwp_user_mm.h"
+#endif
+
+#define DBG_TAG "LWP_PID"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define PID_MAX 10000
+
+#define PID_CT_ASSERT(name, x) \
+ struct assert_##name {char ary[2 * (x) - 1];}
+
+PID_CT_ASSERT(pid_min_nr, RT_LWP_MAX_NR > 1);
+PID_CT_ASSERT(pid_max_nr, RT_LWP_MAX_NR < PID_MAX);
+
+static struct lwp_avl_struct lwp_pid_ary[RT_LWP_MAX_NR];
+static struct lwp_avl_struct *lwp_pid_free_head = RT_NULL;
+static int lwp_pid_ary_alloced = 0;
+static struct lwp_avl_struct *lwp_pid_root = RT_NULL;
+static pid_t current_pid = 0;
+
+struct lwp_avl_struct *lwp_get_pid_ary(void)
+{
+ return lwp_pid_ary;
+}
+
+static pid_t lwp_pid_get(void)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+ pid_t pid = 0;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_pid_free_head;
+ if (p)
+ {
+ lwp_pid_free_head = (struct lwp_avl_struct *)p->avl_right;
+ }
+ else if (lwp_pid_ary_alloced < RT_LWP_MAX_NR)
+ {
+ p = lwp_pid_ary + lwp_pid_ary_alloced;
+ lwp_pid_ary_alloced++;
+ }
+ if (p)
+ {
+ int found_noused = 0;
+
+ RT_ASSERT(p->data == RT_NULL);
+ for (pid = current_pid + 1; pid < PID_MAX; pid++)
+ {
+ if (!lwp_avl_find(pid, lwp_pid_root))
+ {
+ found_noused = 1;
+ break;
+ }
+ }
+ if (!found_noused)
+ {
+ for (pid = 1; pid <= current_pid; pid++)
+ {
+ if (!lwp_avl_find(pid, lwp_pid_root))
+ {
+ found_noused = 1;
+ break;
+ }
+ }
+ }
+ p->avl_key = pid;
+ lwp_avl_insert(p, &lwp_pid_root);
+ current_pid = pid;
+ }
+ rt_hw_interrupt_enable(level);
+ return pid;
+}
+
+static void lwp_pid_put(pid_t pid)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_avl_find(pid, lwp_pid_root);
+ if (p)
+ {
+ p->data = RT_NULL;
+ lwp_avl_remove(p, &lwp_pid_root);
+ p->avl_right = lwp_pid_free_head;
+ lwp_pid_free_head = p;
+ }
+ rt_hw_interrupt_enable(level);
+}
+
+static void lwp_pid_set_lwp(pid_t pid, struct rt_lwp *lwp)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_avl_find(pid, lwp_pid_root);
+ if (p)
+ {
+ p->data = lwp;
+ }
+ rt_hw_interrupt_enable(level);
+}
+
+static void __exit_files(struct rt_lwp *lwp)
+{
+ int fd = lwp->fdt.maxfd - 1;
+
+ while (fd >= 0)
+ {
+ struct dfs_fd *d;
+
+ d = lwp->fdt.fds[fd];
+ if (d)
+ {
+ dfs_file_close(d);
+ fdt_fd_release(&lwp->fdt, fd);
+ }
+ fd--;
+ }
+}
+
+void lwp_user_object_lock_init(struct rt_lwp *lwp)
+{
+ rt_mutex_init(&lwp->object_mutex, "lwp_obj", RT_IPC_FLAG_PRIO);
+}
+
+void lwp_user_object_lock_destroy(struct rt_lwp *lwp)
+{
+ rt_mutex_detach(&lwp->object_mutex);
+}
+
+void lwp_user_object_lock(struct rt_lwp *lwp)
+{
+ if (lwp)
+ {
+ rt_mutex_take(&lwp->object_mutex, RT_WAITING_FOREVER);
+ }
+ else
+ {
+ RT_ASSERT(0);
+ }
+}
+
+void lwp_user_object_unlock(struct rt_lwp *lwp)
+{
+ if (lwp)
+ {
+ rt_mutex_release(&lwp->object_mutex);
+ }
+ else
+ {
+ RT_ASSERT(0);
+ }
+}
+
+int lwp_user_object_add(struct rt_lwp *lwp, rt_object_t object)
+{
+ int ret = -1;
+
+ if (lwp && object)
+ {
+ lwp_user_object_lock(lwp);
+ if (!lwp_avl_find((avl_key_t)object, lwp->object_root))
+ {
+ struct lwp_avl_struct *node;
+
+ node = (struct lwp_avl_struct *)rt_malloc(sizeof(struct lwp_avl_struct));
+ if (node)
+ {
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ object->lwp_ref_count++;
+ rt_hw_interrupt_enable(level);
+ node->avl_key = (avl_key_t)object;
+ lwp_avl_insert(node, &lwp->object_root);
+ ret = 0;
+ }
+ }
+ lwp_user_object_unlock(lwp);
+ }
+ return ret;
+}
+
+static rt_err_t _object_node_delete(struct rt_lwp *lwp, struct lwp_avl_struct *node)
+{
+ rt_err_t ret = -1;
+ rt_object_t object;
+
+ if (!lwp || !node)
+ {
+ return ret;
+ }
+ object = (rt_object_t)node->avl_key;
+ object->lwp_ref_count--;
+ if (object->lwp_ref_count == 0)
+ {
+ /* remove from kernel object list */
+ switch (object->type)
+ {
+ case RT_Object_Class_Semaphore:
+ ret = rt_sem_delete((rt_sem_t)object);
+ break;
+ case RT_Object_Class_Mutex:
+ ret = rt_mutex_delete((rt_mutex_t)object);
+ break;
+ case RT_Object_Class_Event:
+ ret = rt_event_delete((rt_event_t)object);
+ break;
+ case RT_Object_Class_MailBox:
+ ret = rt_mb_delete((rt_mailbox_t)object);
+ break;
+ case RT_Object_Class_MessageQueue:
+ ret = rt_mq_delete((rt_mq_t)object);
+ break;
+ case RT_Object_Class_Timer:
+ ret = rt_timer_delete((rt_timer_t)object);
+ break;
+ case RT_Object_Class_Custom:
+ ret = rt_custom_object_destroy(object);
+ break;
+ default:
+ LOG_E("input object type(%d) error", object->type);
+ break;
+ }
+ }
+ else
+ {
+ ret = 0;
+ }
+ lwp_avl_remove(node, &lwp->object_root);
+ rt_free(node);
+ return ret;
+}
+
+rt_err_t lwp_user_object_delete(struct rt_lwp *lwp, rt_object_t object)
+{
+ rt_err_t ret = -1;
+
+ if (lwp && object)
+ {
+ struct lwp_avl_struct *node;
+
+ lwp_user_object_lock(lwp);
+ node = lwp_avl_find((avl_key_t)object, lwp->object_root);
+ ret = _object_node_delete(lwp, node);
+ lwp_user_object_unlock(lwp);
+ }
+ return ret;
+}
+
+void lwp_user_object_clear(struct rt_lwp *lwp)
+{
+ struct lwp_avl_struct *node;
+
+ lwp_user_object_lock(lwp);
+ while ((node = lwp_map_find_first(lwp->object_root)) != RT_NULL)
+ {
+ _object_node_delete(lwp, node);
+ }
+ lwp_user_object_unlock(lwp);
+}
+
+static int _object_dup(struct lwp_avl_struct *node, void *arg)
+{
+ rt_object_t object;
+ struct rt_lwp *dst_lwp = (struct rt_lwp *)arg;
+
+ object = (rt_object_t)node->avl_key;
+ lwp_user_object_add(dst_lwp, object);
+ return 0;
+}
+
+void lwp_user_object_dup(struct rt_lwp *dst_lwp, struct rt_lwp *src_lwp)
+{
+ lwp_user_object_lock(src_lwp);
+ lwp_avl_traversal(src_lwp->object_root, _object_dup, dst_lwp);
+ lwp_user_object_unlock(src_lwp);
+}
+
+struct rt_lwp* lwp_new(void)
+{
+ pid_t pid;
+ rt_base_t level;
+ struct rt_lwp* lwp = RT_NULL;
+
+ lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
+ if (lwp == RT_NULL)
+ {
+ return lwp;
+ }
+ rt_memset(lwp, 0, sizeof(*lwp));
+ //lwp->tgroup_leader = RT_NULL;
+ rt_list_init(&lwp->wait_list);
+ lwp->leader = 0;
+ lwp->session = -1;
+ lwp->tty = RT_NULL;
+ rt_list_init(&lwp->t_grp);
+ lwp_user_object_lock_init(lwp);
+ lwp->address_search_head = RT_NULL;
+ rt_wqueue_init(&lwp->wait_queue);
+ lwp->ref = 1;
+
+ level = rt_hw_interrupt_disable();
+ pid = lwp_pid_get();
+ if (pid == 0)
+ {
+ lwp_user_object_lock_destroy(lwp);
+ rt_free(lwp);
+ lwp = RT_NULL;
+ LOG_E("pid slot fulled!\n");
+ goto out;
+ }
+ lwp->pid = pid;
+ lwp_pid_set_lwp(pid, lwp);
+
+#ifdef LWP_ENABLE_ASID
+ lwp->generation = 0;
+ lwp->asid = 0;
+#endif
+
+out:
+ rt_hw_interrupt_enable(level);
+ return lwp;
+}
+
+void lwp_free(struct rt_lwp* lwp)
+{
+ rt_base_t level;
+
+ if (lwp == RT_NULL)
+ {
+ return;
+ }
+
+ LOG_D("lwp free: %p\n", lwp);
+
+ level = rt_hw_interrupt_disable();
+ lwp->finish = 1;
+ rt_hw_interrupt_enable(level);
+
+ if (lwp->args != RT_NULL)
+ {
+#ifndef ARCH_MM_MMU
+ lwp->args_length = RT_NULL;
+#ifndef ARCH_MM_MPU
+ rt_free(lwp->args);
+#endif /* not defined ARCH_MM_MPU */
+#endif /* ARCH_MM_MMU */
+ lwp->args = RT_NULL;
+ }
+
+ if (lwp->fdt.fds != RT_NULL)
+ {
+ /* auto clean fds */
+ __exit_files(lwp);
+ rt_free(lwp->fdt.fds);
+ lwp->fdt.fds = RT_NULL;
+ }
+
+ lwp_user_object_clear(lwp);
+ lwp_user_object_lock_destroy(lwp);
+
+ /* free data section */
+ if (lwp->data_entry != RT_NULL)
+ {
+#ifdef ARCH_MM_MMU
+ rt_free_align(lwp->data_entry);
+#else
+#ifdef ARCH_MM_MPU
+ rt_lwp_umap_user(lwp, lwp->text_entry, 0);
+ rt_lwp_free_user(lwp, lwp->data_entry, lwp->data_size);
+#else
+ rt_free_align(lwp->data_entry);
+#endif /* ARCH_MM_MPU */
+#endif /* ARCH_MM_MMU */
+ lwp->data_entry = RT_NULL;
+ }
+
+ /* free text section */
+ if (lwp->lwp_type == LWP_TYPE_DYN_ADDR)
+ {
+ if (lwp->text_entry)
+ {
+ LOG_D("lwp text free: %p", lwp->text_entry);
+#ifndef ARCH_MM_MMU
+ rt_free((void*)lwp->text_entry);
+#endif /* not defined ARCH_MM_MMU */
+ lwp->text_entry = RT_NULL;
+ }
+ }
+
+#ifdef RT_USING_USERSPACE
+ lwp_unmap_user_space(lwp);
+#endif
+
+ level = rt_hw_interrupt_disable();
+ /* for children */
+ while (lwp->first_child)
+ {
+ struct rt_lwp *child;
+
+ child = lwp->first_child;
+ lwp->first_child = child->sibling;
+ if (child->finish)
+ {
+ lwp_pid_put(lwp_to_pid(child));
+ rt_hw_interrupt_enable(level);
+ rt_free(child);
+ level = rt_hw_interrupt_disable();
+ }
+ else
+ {
+ child->sibling = RT_NULL;
+ child->parent = RT_NULL;
+ }
+ }
+
+ rt_hw_interrupt_enable(level);
+ /* for parent */
+ {
+ struct termios *old_stdin_termios = get_old_termios();
+ struct rt_lwp *old_lwp = NULL;
+
+ if (lwp->session == -1)
+ {
+ tcsetattr(1, 0, old_stdin_termios);
+ }
+ level = rt_hw_interrupt_disable();
+ if (lwp->tty != RT_NULL)
+ {
+ rt_mutex_take(&lwp->tty->lock, RT_WAITING_FOREVER);
+ old_lwp = tty_pop(&lwp->tty->head, RT_NULL);
+ rt_mutex_release(&lwp->tty->lock);
+ if (lwp->tty->foreground == lwp)
+ {
+ lwp->tty->foreground = old_lwp;
+ lwp->tty = RT_NULL;
+ }
+ }
+
+ if (lwp->parent)
+ {
+ struct rt_thread *thread;
+ if (!rt_list_isempty(&lwp->wait_list))
+ {
+ thread = rt_list_entry(lwp->wait_list.next, struct rt_thread, tlist);
+ thread->error = RT_EOK;
+ thread->msg_ret = (void*)(rt_size_t)lwp->lwp_ret;
+ rt_thread_resume(thread);
+ rt_hw_interrupt_enable(level);
+ return;
+ }
+ else
+ {
+ struct rt_lwp **it = &lwp->parent->first_child;
+
+ while (*it != lwp)
+ {
+ it = &(*it)->sibling;
+ }
+ *it = lwp->sibling;
+ }
+ }
+ lwp_pid_put(lwp_to_pid(lwp));
+ rt_hw_interrupt_enable(level);
+ rt_free(lwp);
+ }
+}
+
+int lwp_ref_inc(struct rt_lwp *lwp)
+{
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ lwp->ref++;
+ rt_hw_interrupt_enable(level);
+
+ return 0;
+}
+
+int lwp_ref_dec(struct rt_lwp *lwp)
+{
+ rt_base_t level;
+ int ref = -1;
+
+ level = rt_hw_interrupt_disable();
+ if (lwp->ref)
+ {
+ lwp->ref--;
+ ref = lwp->ref;
+ }
+ rt_hw_interrupt_enable(level);
+ if (!ref)
+ {
+ struct rt_channel_msg msg;
+
+ if (lwp->debug)
+ {
+ memset(&msg, 0, sizeof msg);
+ rt_raw_channel_send(gdb_server_channel(), &msg);
+ }
+
+#ifndef ARCH_MM_MMU
+#ifdef RT_LWP_USING_SHM
+ lwp_shm_lwp_free(lwp);
+#endif /* RT_LWP_USING_SHM */
+#endif /* not defined ARCH_MM_MMU */
+ lwp_free(lwp);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+struct rt_lwp* lwp_from_pid(pid_t pid)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+ struct rt_lwp *lwp = RT_NULL;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_avl_find(pid, lwp_pid_root);
+ if (p)
+ {
+ lwp = (struct rt_lwp *)p->data;
+ }
+ rt_hw_interrupt_enable(level);
+ return lwp;
+}
+
+pid_t lwp_to_pid(struct rt_lwp* lwp)
+{
+ if (!lwp)
+ {
+ return 0;
+ }
+ return lwp->pid;
+}
+
+char* lwp_pid2name(int32_t pid)
+{
+ struct rt_lwp *lwp;
+ char* process_name = RT_NULL;
+
+ lwp = lwp_from_pid(pid);
+ if (lwp)
+ {
+ process_name = strrchr(lwp->cmd, '/');
+ process_name = process_name? process_name + 1: lwp->cmd;
+ }
+ return process_name;
+}
+
+pid_t lwp_name2pid(const char *name)
+{
+ int idx;
+ pid_t pid = 0;
+ rt_thread_t main_thread;
+ char* process_name = RT_NULL;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ for (idx = 0; idx < RT_LWP_MAX_NR; idx++)
+ {
+ /* 0 is reserved */
+ struct rt_lwp *lwp = (struct rt_lwp *)lwp_pid_ary[idx].data;
+
+ if (lwp)
+ {
+ process_name = strrchr(lwp->cmd, '/');
+ process_name = process_name? process_name + 1: lwp->cmd;
+ if (!rt_strncmp(name, process_name, RT_NAME_MAX))
+ {
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (!(main_thread->stat & RT_THREAD_CLOSE))
+ {
+ pid = lwp->pid;
+ }
+ }
+ }
+ }
+ rt_hw_interrupt_enable(level);
+ return pid;
+}
+
+int lwp_getpid(void)
+{
+ return ((struct rt_lwp *)rt_thread_self()->lwp)->pid;
+}
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+ pid_t ret = -1;
+ rt_base_t level;
+ struct rt_thread *thread;
+ struct rt_lwp *lwp;
+ struct rt_lwp *lwp_self;
+
+ level = rt_hw_interrupt_disable();
+ lwp = lwp_from_pid(pid);
+ if (!lwp)
+ {
+ goto quit;
+ }
+
+ lwp_self = (struct rt_lwp *)rt_thread_self()->lwp;
+ if (!lwp_self)
+ {
+ goto quit;
+ }
+ if (lwp->parent != lwp_self)
+ {
+ goto quit;
+ }
+
+ if (lwp->finish)
+ {
+ ret = pid;
+ }
+ else
+ {
+ if (!rt_list_isempty(&lwp->wait_list))
+ {
+ goto quit;
+ }
+ thread = rt_thread_self();
+ rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
+ rt_list_insert_before(&lwp->wait_list, &(thread->tlist));
+ rt_schedule();
+ if (thread->error == RT_EOK)
+ {
+ ret = pid;
+ }
+ }
+
+ if (ret != -1)
+ {
+ struct rt_lwp **lwp_node;
+
+ *status = lwp->lwp_ret;
+ lwp_node = &lwp_self->first_child;
+ while (*lwp_node != lwp)
+ {
+ RT_ASSERT(*lwp_node != RT_NULL);
+ lwp_node = &(*lwp_node)->sibling;
+ }
+ (*lwp_node) = lwp->sibling;
+
+ lwp_pid_put(pid);
+ rt_free(lwp);
+ }
+
+quit:
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+#ifdef RT_USING_FINSH
+/* copy from components/finsh/cmd.c */
+static void object_split(int len)
+{
+ while (len--)
+ {
+ rt_kprintf("-");
+ }
+}
+
+static void print_thread_info(struct rt_thread* thread, int maxlen)
+{
+ rt_uint8_t *ptr;
+ rt_uint8_t stat;
+
+#ifdef RT_USING_SMP
+ if (thread->oncpu != RT_CPU_DETACHED)
+ rt_kprintf("%-*.*s %3d %3d ", maxlen, RT_NAME_MAX, thread->name, thread->oncpu, thread->current_priority);
+ else
+ rt_kprintf("%-*.*s N/A %3d ", maxlen, RT_NAME_MAX, thread->name, thread->current_priority);
+#else
+ rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->name, thread->current_priority);
+#endif /*RT_USING_SMP*/
+
+ stat = (thread->stat & RT_THREAD_STAT_MASK);
+ if (stat == RT_THREAD_READY) rt_kprintf(" ready ");
+ else if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) rt_kprintf(" suspend");
+ else if (stat == RT_THREAD_INIT) rt_kprintf(" init ");
+ else if (stat == RT_THREAD_CLOSE) rt_kprintf(" close ");
+ else if (stat == RT_THREAD_RUNNING) rt_kprintf(" running");
+
+#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
+ ptr = (rt_uint8_t *)thread->stack_addr + thread->stack_size;
+ while (*ptr == '#')ptr--;
+
+ rt_kprintf(" 0x%08x 0x%08x %02d%% 0x%08x %03d\n",
+ ((rt_uint32_t)thread->sp - (rt_uint32_t)thread->stack_addr),
+ thread->stack_size,
+ ((rt_uint32_t)ptr - (rt_uint32_t)thread->stack_addr) * 100 / thread->stack_size,
+ thread->remaining_tick,
+ thread->error);
+#else
+ ptr = (rt_uint8_t *)thread->stack_addr;
+ while (*ptr == '#')ptr++;
+
+ rt_kprintf(" 0x%08x 0x%08x %02d%% 0x%08x %03d\n",
+ (thread->stack_size + (rt_uint32_t)(rt_size_t)thread->stack_addr - (rt_uint32_t)(rt_size_t)thread->sp),
+ thread->stack_size,
+ (thread->stack_size + (rt_uint32_t)(rt_size_t)thread->stack_addr - (rt_uint32_t)(rt_size_t)ptr) * 100
+ / thread->stack_size,
+ thread->remaining_tick,
+ thread->error);
+#endif
+}
+
+long list_process(void)
+{
+ int index;
+ int maxlen;
+ rt_ubase_t level;
+ struct rt_thread *thread;
+ struct rt_list_node *node, *list;
+ const char *item_title = "thread";
+
+ int count = 0;
+ struct rt_thread **threads;
+
+ maxlen = RT_NAME_MAX;
+#ifdef RT_USING_SMP
+ rt_kprintf("%-*.s %-*.s %-*.s cpu pri status sp stack size max used left tick error\n", 4, "PID", maxlen, "CMD", maxlen, item_title);
+ object_split(4);rt_kprintf(" ");object_split(maxlen);rt_kprintf(" ");object_split(maxlen);rt_kprintf(" ");
+ rt_kprintf( "--- --- ------- ---------- ---------- ------ ---------- ---\n");
+#else
+ rt_kprintf("%-*.s %-*.s %-*.s pri status sp stack size max used left tick error\n", 4, "PID", maxlen, "CMD", maxlen, item_title);
+ object_split(4);rt_kprintf(" ");object_split(maxlen);rt_kprintf(" ");object_split(maxlen);rt_kprintf(" ");
+ rt_kprintf( "--- ------- ---------- ---------- ------ ---------- ---\n");
+#endif /*RT_USING_SMP*/
+
+ count = rt_object_get_length(RT_Object_Class_Thread);
+ if (count > 0)
+ {
+ /* get thread pointers */
+ threads = (struct rt_thread **)rt_calloc(count, sizeof(struct rt_thread *));
+ if (threads)
+ {
+ index = rt_object_get_pointers(RT_Object_Class_Thread, (rt_object_t *)threads, count);
+
+ if (index > 0)
+ {
+ for (index = 0; index <count; index++)
+ {
+ struct rt_thread th;
+
+ thread = threads[index];
+ level = rt_hw_interrupt_disable();
+ if ((thread->type & ~RT_Object_Class_Static) != RT_Object_Class_Thread)
+ {
+ rt_hw_interrupt_enable(level);
+ continue;
+ }
+
+ rt_memcpy(&th, thread, sizeof(struct rt_thread));
+ rt_hw_interrupt_enable(level);
+
+ if (th.lwp == RT_NULL)
+ {
+ rt_kprintf(" %-*.*s ", maxlen, RT_NAME_MAX, "kernel");
+ print_thread_info(&th, maxlen);
+ }
+ }
+ }
+ rt_free(threads);
+ }
+ }
+
+ for (index = 0; index < RT_LWP_MAX_NR; index++)
+ {
+ struct rt_lwp *lwp = (struct rt_lwp *)lwp_pid_ary[index].data;
+
+ if (lwp)
+ {
+ list = &lwp->t_grp;
+ for (node = list->next; node != list; node = node->next)
+ {
+ thread = rt_list_entry(node, struct rt_thread, sibling);
+ rt_kprintf("%4d %-*.*s ", lwp_to_pid(lwp), maxlen, RT_NAME_MAX, lwp->cmd);
+ print_thread_info(thread, maxlen);
+ }
+ }
+ }
+ return 0;
+}
+MSH_CMD_EXPORT(list_process, list process);
+
+static void cmd_kill(int argc, char** argv)
+{
+ int pid;
+ int sig = 0;
+
+ if (argc < 2)
+ {
+ rt_kprintf("kill pid or kill pid -s signal\n");
+ return;
+ }
+
+ pid = atoi(argv[1]);
+ if (argc >= 4)
+ {
+ if (argv[2][0] == '-' && argv[2][1] == 's')
+ {
+ sig = atoi(argv[3]);
+ }
+ }
+ lwp_kill(pid, sig);
+}
+MSH_CMD_EXPORT_ALIAS(cmd_kill, kill, send a signal to a process);
+
+static void cmd_killall(int argc, char** argv)
+{
+ int pid;
+ if (argc < 2)
+ {
+ rt_kprintf("killall processes_name\n");
+ return;
+ }
+
+ while((pid = lwp_name2pid(argv[1])) > 0)
+ {
+ lwp_kill(pid, SIGKILL);
+ rt_thread_mdelay(100);
+ }
+}
+MSH_CMD_EXPORT_ALIAS(cmd_killall, killall, kill processes by name);
+
+#endif
+
+int lwp_check_exit_request(void)
+{
+ rt_thread_t thread = rt_thread_self();
+ if (!thread->lwp)
+ {
+ return 0;
+ }
+
+ if (thread->exit_request == LWP_EXIT_REQUEST_TRIGGERED)
+ {
+ thread->exit_request = LWP_EXIT_REQUEST_IN_PROCESS;
+ return 1;
+ }
+ return 0;
+}
+
+static int found_thread(struct rt_lwp* lwp, rt_thread_t thread)
+{
+ int found = 0;
+ rt_base_t level;
+ rt_list_t *list;
+
+ level = rt_hw_interrupt_disable();
+ list = lwp->t_grp.next;
+ while (list != &lwp->t_grp)
+ {
+ rt_thread_t iter_thread;
+
+ iter_thread = rt_list_entry(list, struct rt_thread, sibling);
+ if (thread == iter_thread)
+ {
+ found = 1;
+ break;
+ }
+ list = list->next;
+ }
+ rt_hw_interrupt_enable(level);
+ return found;
+}
+
+void lwp_request_thread_exit(rt_thread_t thread_to_exit)
+{
+ rt_thread_t main_thread;
+ rt_base_t level;
+ rt_list_t *list;
+ struct rt_lwp *lwp;
+
+ lwp = lwp_self();
+
+ if ((!thread_to_exit) || (!lwp))
+ {
+ return;
+ }
+
+ level = rt_hw_interrupt_disable();
+
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (thread_to_exit == main_thread)
+ {
+ goto finish;
+ }
+ if ((struct rt_lwp *)thread_to_exit->lwp != lwp)
+ {
+ goto finish;
+ }
+
+ for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
+ {
+ rt_thread_t thread;
+
+ thread = rt_list_entry(list, struct rt_thread, sibling);
+ if (thread != thread_to_exit)
+ {
+ continue;
+ }
+ if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
+ {
+ thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
+ }
+ if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
+ {
+ thread->error = -RT_EINTR;
+ rt_hw_dsb();
+ rt_thread_wakeup(thread);
+ }
+ break;
+ }
+
+ while (found_thread(lwp, thread_to_exit))
+ {
+ rt_thread_mdelay(10);
+ }
+
+finish:
+ rt_hw_interrupt_enable(level);
+ return;
+}
+
+void lwp_terminate(struct rt_lwp *lwp)
+{
+ rt_base_t level;
+ rt_list_t *list;
+
+ if (!lwp)
+ {
+ /* kernel thread not support */
+ return;
+ }
+
+ level = rt_hw_interrupt_disable();
+ for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
+ {
+ rt_thread_t thread;
+
+ thread = rt_list_entry(list, struct rt_thread, sibling);
+ if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
+ {
+ thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
+ }
+ if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
+ {
+ thread->error = RT_EINTR;
+ rt_hw_dsb();
+ rt_thread_wakeup(thread);
+ }
+ }
+ rt_hw_interrupt_enable(level);
+}
+
+void lwp_wait_subthread_exit(void)
+{
+ rt_base_t level;
+ struct rt_lwp *lwp;
+ rt_thread_t thread;
+ rt_thread_t main_thread;
+
+ lwp = lwp_self();
+ if (!lwp)
+ {
+ return;
+ }
+
+ thread = rt_thread_self();
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (thread != main_thread)
+ {
+ return;
+ }
+
+ while (1)
+ {
+ int subthread_is_terminated;
+
+ level = rt_hw_interrupt_disable();
+ subthread_is_terminated = (int)(thread->sibling.prev == &lwp->t_grp);
+ if (!subthread_is_terminated)
+ {
+ rt_thread_t sub_thread;
+ rt_list_t *list;
+ int all_subthread_in_init = 1;
+
+ /* check all subthread is in init state */
+ for (list = thread->sibling.prev; list != &lwp->t_grp; list = list->prev)
+ {
+
+ sub_thread = rt_list_entry(list, struct rt_thread, sibling);
+ if ((sub_thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
+ {
+ all_subthread_in_init = 0;
+ break;
+ }
+ }
+ if (all_subthread_in_init)
+ {
+ /* delete all subthread */
+ while ((list = thread->sibling.prev) != &lwp->t_grp)
+ {
+ sub_thread = rt_list_entry(list, struct rt_thread, sibling);
+ rt_list_remove(&sub_thread->sibling);
+ rt_thread_delete(sub_thread);
+ }
+ subthread_is_terminated = 1;
+ }
+ }
+ rt_hw_interrupt_enable(level);
+
+ if (subthread_is_terminated)
+ {
+ break;
+ }
+ rt_thread_mdelay(10);
+ }
+}
+
+static int _lwp_setaffinity(pid_t pid, int cpu)
+{
+ struct rt_lwp *lwp;
+ int ret = -1;
+
+ lwp = lwp_from_pid(pid);
+ if (lwp)
+ {
+#ifdef RT_USING_SMP
+ rt_list_t *list;
+
+ lwp->bind_cpu = cpu;
+ for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
+ {
+ rt_thread_t thread;
+
+ thread = rt_list_entry(list, struct rt_thread, sibling);
+ rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void *)(rt_size_t)cpu);
+ }
+#endif
+ ret = 0;
+ }
+ return ret;
+}
+
+int lwp_setaffinity(pid_t pid, int cpu)
+{
+ rt_base_t level;
+ int ret;
+
+#ifdef RT_USING_SMP
+ if (cpu < 0 || cpu > RT_CPUS_NR)
+ {
+ cpu = RT_CPUS_NR;
+ }
+#endif
+ level = rt_hw_interrupt_disable();
+ ret = _lwp_setaffinity(pid, cpu);
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+#ifdef RT_USING_SMP
+static void cmd_cpu_bind(int argc, char** argv)
+{
+ int pid;
+ int cpu;
+
+ if (argc < 3)
+ {
+ rt_kprintf("Useage: cpu_bind pid cpu\n");
+ return;
+ }
+
+ pid = atoi(argv[1]);
+ cpu = atoi(argv[2]);
+ lwp_setaffinity((pid_t)pid, cpu);
+}
+MSH_CMD_EXPORT_ALIAS(cmd_cpu_bind, cpu_bind, set a process bind to a cpu);
+#endif
diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h
new file mode 100644
index 0000000000..901c6f80b8
--- /dev/null
+++ b/components/lwp/lwp_pid.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-02-23 Jesven first version.
+ */
+
+#ifndef LWP_PID_H__
+#define LWP_PID_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rt_lwp;
+
+struct lwp_avl_struct *lwp_get_pid_ary(void);
+
+struct rt_lwp* lwp_new(void);
+void lwp_free(struct rt_lwp* lwp);
+
+int lwp_ref_inc(struct rt_lwp *lwp);
+int lwp_ref_dec(struct rt_lwp *lwp);
+
+struct rt_lwp* lwp_from_pid(pid_t pid);
+pid_t lwp_to_pid(struct rt_lwp* lwp);
+
+pid_t lwp_name2pid(const char* name);
+char* lwp_pid2name(int32_t pid);
+
+int lwp_getpid(void);
+
+pid_t waitpid(pid_t pid, int *status, int options);
+long list_process(void);
+
+void lwp_user_object_lock_init(struct rt_lwp *lwp);
+void lwp_user_object_lock_destroy(struct rt_lwp *lwp);
+void lwp_user_object_lock(struct rt_lwp *lwp);
+void lwp_user_object_unlock(struct rt_lwp *lwp);
+int lwp_user_object_add(struct rt_lwp *lwp, rt_object_t object);
+rt_err_t lwp_user_object_delete(struct rt_lwp *lwp, rt_object_t object);
+void lwp_user_object_clear(struct rt_lwp *lwp);
+void lwp_user_object_dup(struct rt_lwp *dst_lwp, struct rt_lwp *src_lwp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/components/lwp/lwp_pmutex.c b/components/lwp/lwp_pmutex.c
new file mode 100644
index 0000000000..bac99f2283
--- /dev/null
+++ b/components/lwp/lwp_pmutex.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021/01/02 bernard the first version
+ */
+
+#include <rtthread.h>
+#include <lwp.h>
+#ifdef RT_USING_USERSPACE
+#include <lwp_user_mm.h>
+#endif
+#include <sys/time.h>
+
+#define PMUTEX_NORMAL 0 /* Unable to recursion */
+#define PMUTEX_RECURSIVE 1 /* Can be recursion */
+#define PMUTEX_ERRORCHECK 2 /* This type of mutex provides error checking */
+
+struct rt_pmutex
+{
+ union
+ {
+ rt_mutex_t kmutex;
+ rt_sem_t ksem; /* use sem to emulate the mutex without recursive */
+ } lock;
+
+ struct lwp_avl_struct node;
+ struct rt_object *custom_obj;
+ rt_uint8_t type; /* pmutex type */
+};
+
+static struct rt_mutex _pmutex_lock;
+
+static int pmutex_system_init(void)
+{
+ rt_mutex_init(&_pmutex_lock, "pmtxLock", RT_IPC_FLAG_FIFO);
+ return 0;
+}
+INIT_PREV_EXPORT(pmutex_system_init);
+
+static rt_err_t pmutex_destory(void *data)
+{
+ rt_err_t ret = -1;
+ rt_base_t level = 0;
+ struct rt_pmutex *pmutex = (struct rt_pmutex *)data;
+
+ if (pmutex)
+ {
+ level = rt_hw_interrupt_disable();
+ /* remove pmutex from pmutext avl */
+ lwp_avl_remove(&pmutex->node, (struct lwp_avl_struct **)pmutex->node.data);
+ rt_hw_interrupt_enable(level);
+
+ if (pmutex->type == PMUTEX_NORMAL)
+ {
+ rt_sem_delete(pmutex->lock.ksem);
+ }
+ else
+ {
+ rt_mutex_delete(pmutex->lock.kmutex);
+ }
+
+ /* release object */
+ rt_free(pmutex);
+ ret = 0;
+ }
+ return ret;
+}
+
+static struct rt_pmutex* pmutex_create(void *umutex, struct rt_lwp *lwp)
+{
+ struct rt_pmutex *pmutex = RT_NULL;
+ struct rt_object *obj = RT_NULL;
+ rt_ubase_t type;
+
+ if (!lwp)
+ {
+ return RT_NULL;
+ }
+
+ long *p = (long *)umutex;
+ /* umutex[0] bit[0-1] saved mutex type */
+ type = *p & 3;
+ if (type != PMUTEX_NORMAL && type != PMUTEX_RECURSIVE && type != PMUTEX_ERRORCHECK)
+ {
+ return RT_NULL;
+ }
+
+ pmutex = (struct rt_pmutex *)rt_malloc(sizeof(struct rt_pmutex));
+ if (!pmutex)
+ {
+ return RT_NULL;
+ }
+
+ if (type == PMUTEX_NORMAL)
+ {
+ pmutex->lock.ksem = rt_sem_create("pmutex", 1, RT_IPC_FLAG_PRIO);
+ if (!pmutex->lock.ksem)
+ {
+ rt_free(pmutex);
+ return RT_NULL;
+ }
+ }
+ else
+ {
+ pmutex->lock.kmutex = rt_mutex_create("pmutex", RT_IPC_FLAG_PRIO);
+ if (!pmutex->lock.kmutex)
+ {
+ rt_free(pmutex);
+ return RT_NULL;
+ }
+ }
+
+ obj = rt_custom_object_create("pmutex", (void *)pmutex, pmutex_destory);
+ if (!obj)
+ {
+ if (pmutex->type == PMUTEX_NORMAL)
+ {
+ rt_sem_delete(pmutex->lock.ksem);
+ }
+ else
+ {
+ rt_mutex_delete(pmutex->lock.kmutex);
+ }
+ rt_free(pmutex);
+ return RT_NULL;
+ }
+ pmutex->node.avl_key = (avl_key_t)umutex;
+ pmutex->node.data = &lwp->address_search_head;
+ pmutex->custom_obj = obj;
+ pmutex->type = type;
+
+ /* insert into pmutex head */
+ lwp_avl_insert(&pmutex->node, &lwp->address_search_head);
+ return pmutex;
+}
+
+static struct rt_pmutex* pmutex_get(void *umutex, struct rt_lwp *lwp)
+{
+ struct rt_pmutex *pmutex = RT_NULL;
+ struct lwp_avl_struct *node = RT_NULL;
+
+ node = lwp_avl_find((avl_key_t)umutex, lwp->address_search_head);
+ if (!node)
+ {
+ return RT_NULL;
+ }
+ pmutex = rt_container_of(node, struct rt_pmutex, node);
+ return pmutex;
+}
+
+static int _pthread_mutex_init(void *umutex)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_pmutex *pmutex = RT_NULL;
+ rt_err_t lock_ret = 0;
+
+ /* umutex union is 6 x (void *) */
+ if (!lwp_user_accessable(umutex, sizeof(void *) * 6))
+ {
+ rt_set_errno(EINVAL);
+ return -EINVAL;
+ }
+
+ lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
+ if (lock_ret != RT_EOK)
+ {
+ rt_set_errno(EAGAIN);
+ return -EINTR;
+ }
+
+ lwp = lwp_self();
+ pmutex = pmutex_get(umutex, lwp);
+ if (pmutex == RT_NULL)
+ {
+ /* create a pmutex according to this umutex */
+ pmutex = pmutex_create(umutex, lwp);
+ if (pmutex == RT_NULL)
+ {
+ rt_mutex_release(&_pmutex_lock);
+ rt_set_errno(ENOMEM);
+ return -ENOMEM;
+ }
+ if (lwp_user_object_add(lwp, pmutex->custom_obj) != 0)
+ {
+ rt_custom_object_destroy(pmutex->custom_obj);
+ rt_set_errno(ENOMEM);
+ return -ENOMEM;
+ }
+ }
+ else
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+
+ if (pmutex->type == PMUTEX_NORMAL)
+ {
+ pmutex->lock.ksem->value = 1;
+ }
+ else
+ {
+ pmutex->lock.kmutex->owner = RT_NULL;
+ pmutex->lock.kmutex->priority = 0xFF;
+ pmutex->lock.kmutex->hold = 0;
+ pmutex->lock.kmutex->ceiling_priority = 0xFF;
+ }
+ rt_hw_interrupt_enable(level);
+ }
+
+ rt_mutex_release(&_pmutex_lock);
+
+ return 0;
+}
+
+static int _pthread_mutex_lock_timeout(void *umutex, struct timespec *timeout)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_pmutex *pmutex = RT_NULL;
+ rt_err_t lock_ret = 0;
+ rt_int32_t time = RT_WAITING_FOREVER;
+ register rt_base_t temp;
+
+ if (timeout)
+ {
+ if (!lwp_user_accessable((void *)timeout, sizeof(struct timespec)))
+ {
+ rt_set_errno(EINVAL);
+ return -EINVAL;
+ }
+ time = rt_timespec_to_tick(timeout);
+ }
+
+ lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
+ if (lock_ret != RT_EOK)
+ {
+ rt_set_errno(EAGAIN);
+ return -EINTR;
+ }
+
+ lwp = lwp_self();
+ pmutex = pmutex_get(umutex, lwp);
+ if (pmutex == RT_NULL)
+ {
+ rt_mutex_release(&_pmutex_lock);
+ rt_set_errno(EINVAL);
+ return -ENOMEM; /* umutex not recored in kernel */
+ }
+
+ rt_mutex_release(&_pmutex_lock);
+
+ switch (pmutex->type)
+ {
+ case PMUTEX_NORMAL:
+ lock_ret = rt_sem_take_interruptible(pmutex->lock.ksem, time);
+ break;
+ case PMUTEX_RECURSIVE:
+ lock_ret = rt_mutex_take_interruptible(pmutex->lock.kmutex, time);
+ break;
+ case PMUTEX_ERRORCHECK:
+ temp = rt_hw_interrupt_disable();
+ if (pmutex->lock.kmutex->owner == rt_thread_self())
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+ return -EDEADLK;
+ }
+ lock_ret = rt_mutex_take_interruptible(pmutex->lock.kmutex, time);
+ rt_hw_interrupt_enable(temp);
+ break;
+ default: /* unknown type */
+ return -EINVAL;
+ }
+
+ if (lock_ret != RT_EOK)
+ {
+ if (lock_ret == -RT_ETIMEOUT)
+ {
+ if (time == 0) /* timeout is 0, means try lock failed */
+ {
+ rt_set_errno(EBUSY);
+ return -EBUSY;
+ }
+ else
+ {
+ rt_set_errno(ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+ }
+ else
+ {
+ rt_set_errno(EAGAIN);
+ return -EAGAIN;
+ }
+ }
+ return 0;
+}
+
+static int _pthread_mutex_unlock(void *umutex)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_pmutex *pmutex = RT_NULL;
+ rt_err_t lock_ret = 0;
+
+ lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
+ if (lock_ret != RT_EOK)
+ {
+ rt_set_errno(EAGAIN);
+ return -EINTR;
+ }
+
+ lwp = lwp_self();
+ pmutex = pmutex_get(umutex, lwp);
+ if (pmutex == RT_NULL)
+ {
+ rt_mutex_release(&_pmutex_lock);
+ rt_set_errno(EPERM);
+ return -EPERM;//unlock static mutex of unlock state
+ }
+
+ rt_mutex_release(&_pmutex_lock);
+
+ switch (pmutex->type)
+ {
+ case PMUTEX_NORMAL:
+ if(pmutex->lock.ksem->value >=1)
+ {
+ rt_set_errno(EPERM);
+ return -EPERM;//unlock dynamic mutex of unlock state
+ }
+ else
+ {
+ lock_ret = rt_sem_release(pmutex->lock.ksem);
+ }
+ break;
+ case PMUTEX_RECURSIVE:
+ case PMUTEX_ERRORCHECK:
+ lock_ret = rt_mutex_release(pmutex->lock.kmutex);
+ break;
+ default: /* unknown type */
+ return -EINVAL;
+ }
+
+ if (lock_ret != RT_EOK)
+ {
+ rt_set_errno(EPERM);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int _pthread_mutex_destroy(void *umutex)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_pmutex *pmutex = RT_NULL;
+ rt_err_t lock_ret = 0;
+
+ lock_ret = rt_mutex_take_interruptible(&_pmutex_lock, RT_WAITING_FOREVER);
+ if (lock_ret != RT_EOK)
+ {
+ rt_set_errno(EAGAIN);
+ return -EINTR;
+ }
+
+ lwp = lwp_self();
+ pmutex = pmutex_get(umutex, lwp);
+ if (pmutex == RT_NULL)
+ {
+ rt_mutex_release(&_pmutex_lock);
+ rt_set_errno(EINVAL);
+ return -EINVAL;
+ }
+
+ lwp_user_object_delete(lwp, pmutex->custom_obj);
+ rt_mutex_release(&_pmutex_lock);
+
+ return 0;
+}
+
+int sys_pmutex(void *umutex, int op, void *arg)
+{
+ int ret = -EINVAL;
+
+ switch (op)
+ {
+ case PMUTEX_INIT:
+ ret = _pthread_mutex_init(umutex);
+ break;
+ case PMUTEX_LOCK:
+ ret = _pthread_mutex_lock_timeout(umutex, (struct timespec*)arg);
+ if (ret == -ENOMEM)
+ {
+ /* lock not init, try init it and lock again. */
+ ret = _pthread_mutex_init(umutex);
+ if (ret == 0)
+ {
+ ret = _pthread_mutex_lock_timeout(umutex, (struct timespec*)arg);
+ }
+ }
+ break;
+ case PMUTEX_UNLOCK:
+ ret = _pthread_mutex_unlock(umutex);
+ break;
+ case PMUTEX_DESTROY:
+ ret = _pthread_mutex_destroy(umutex);
+ break;
+ default:
+ rt_set_errno(EINVAL);
+ break;
+ }
+ return ret;
+}
diff --git a/components/lwp/lwp_setsid.c b/components/lwp/lwp_setsid.c
new file mode 100644
index 0000000000..d72363bde5
--- /dev/null
+++ b/components/lwp/lwp_setsid.c
@@ -0,0 +1,27 @@
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "lwp.h"
+//#include "lwp_tid.h"
+#include "lwp_pid.h"
+
+int setsid(void)
+{
+ int err = -EPERM;
+ struct rt_thread *current_thread = rt_thread_self();
+ struct rt_lwp *current_lwp = (struct rt_lwp *)rt_thread_self()->lwp;
+
+ if (current_lwp->session == current_thread->tid)
+ {
+ return err;
+ }
+
+ current_lwp->session = current_thread->tid;
+ current_lwp->__pgrp = current_thread->tid;
+ current_lwp->leader = 1;
+ current_lwp->tty = RT_NULL;
+ current_lwp->tty_old_pgrp = 0;
+
+ err = current_lwp->session;
+ return err;
+}
diff --git a/components/lwp/lwp_shm.c b/components/lwp/lwp_shm.c
new file mode 100644
index 0000000000..a28e3161a9
--- /dev/null
+++ b/components/lwp/lwp_shm.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-12 Jesven first version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+
+#ifdef RT_USING_USERSPACE
+#include <lwp.h>
+#include <lwp_shm.h>
+#include <lwp_mm.h>
+
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+
+/* the kernel structure to represent a share-memory */
+struct lwp_shm_struct
+{
+ size_t addr; /* point to the next item in the free list when not used */
+ size_t size;
+ int ref;
+ size_t key;
+};
+
+static struct lwp_avl_struct *shm_tree_key;
+static struct lwp_avl_struct *shm_tree_pa;
+
+static int shm_free_list = -1; /* the single-direct list of freed items */
+static int shm_id_used = 0; /* the latest allocated item in the array */
+static struct lwp_shm_struct _shm_ary[RT_LWP_SHM_MAX_NR];
+
+/*
+ * Try to allocate an structure 'lwp_shm_struct' from the freed list or the
+ * static array.
+ */
+static int _shm_id_alloc(void)
+{
+ int id = -1;
+
+ if (shm_free_list != -1) /* first try the freed list */
+ {
+ id = shm_free_list;
+ shm_free_list = (int)_shm_ary[shm_free_list].addr; /* single-direction */
+ }
+ else if (shm_id_used < RT_LWP_SHM_MAX_NR) /* then try the array */
+ {
+ id = shm_id_used;
+ shm_id_used++;
+ }
+ return id;
+}
+
+/* Release the item in the static array to the freed list. */
+static void shm_id_free(int id)
+{
+ /* link the freed itme to the single-direction list */
+ _shm_ary[id].addr = (size_t)shm_free_list;
+ shm_free_list = id;
+}
+
+/* Locate the shared memory through 'key' or create a new one. */
+static int _lwp_shmget(size_t key, size_t size, int create)
+{
+ int id = -1;
+ struct lwp_avl_struct *node_key = 0;
+ struct lwp_avl_struct *node_pa = 0;
+ void *page_addr = 0, *page_addr_p = RT_NULL;
+ uint32_t bit = 0;
+
+ /* try to locate the item with the key in the binary tree */
+ node_key = lwp_avl_find(key, shm_tree_key);
+ if (node_key)
+ {
+ return (struct lwp_shm_struct *)node_key->data - _shm_ary; /* the index */
+ }
+
+ /* If there doesn't exist such an item and we're allowed to create one ... */
+ if (create)
+ {
+ struct lwp_shm_struct* p;
+
+ if (!size)
+ {
+ goto err;
+ }
+
+ id = _shm_id_alloc();
+ if (id == -1)
+ {
+ goto err;
+ }
+
+ /* allocate pages up to 2's exponent to cover the required size */
+ bit = rt_page_bits(size);
+ page_addr = rt_pages_alloc(bit); /* virtual address */
+ if (!page_addr)
+ {
+ goto err;
+ }
+ page_addr_p = (void *)((char *)page_addr + PV_OFFSET); /* physical address */
+
+ /* initialize the shared memory structure */
+ p = _shm_ary + id;
+ p->addr = (size_t)page_addr_p;
+ p->size = (1UL << (bit + ARCH_PAGE_SHIFT));
+ p->ref = 0;
+ p->key = key;
+
+ /* then insert it into the balancing binary tree */
+ node_key = (struct lwp_avl_struct *)rt_malloc(sizeof(struct lwp_avl_struct) * 2);
+ if (!node_key)
+ {
+ goto err;
+ }
+ node_key->avl_key = p->key;
+ node_key->data = (void *)p;
+ lwp_avl_insert(node_key, &shm_tree_key);
+ node_pa = node_key + 1;
+ node_pa->avl_key = p->addr;
+ node_pa->data = (void *)p;
+ lwp_avl_insert(node_pa, &shm_tree_pa);
+ }
+ return id;
+
+err:
+ if (id != -1)
+ {
+ shm_id_free(id);
+ }
+ if (page_addr)
+ {
+ rt_pages_free(page_addr, bit);
+ }
+ if (node_key)
+ {
+ rt_free(node_key);
+ }
+ return -1;
+}
+
+/* A wrapping function, get the shared memory with interrupts disabled. */
+int lwp_shmget(size_t key, size_t size, int create)
+{
+ int ret = 0;
+
+ rt_mm_lock();
+ ret = _lwp_shmget(key, size, create);
+ rt_mm_unlock();
+ return ret;
+}
+
+/* Locate the binary tree node_key corresponding to the shared-memory id. */
+static struct lwp_avl_struct *shm_id_to_node(int id)
+{
+ struct lwp_avl_struct *node_key = 0;
+ struct lwp_shm_struct *p = RT_NULL;
+
+ /* check id */
+ if (id < 0 || id >= RT_LWP_SHM_MAX_NR)
+ {
+ return RT_NULL;
+ }
+
+ p = _shm_ary + id; /* the address of the shared-memory structure */
+ node_key = lwp_avl_find(p->key, shm_tree_key);
+ if (!node_key)
+ {
+ return RT_NULL;
+ }
+ if (node_key->data != (void *)p)
+ {
+ return RT_NULL;
+ }
+ return node_key;
+}
+
+/* Free the shared pages, the shared-memory structure and its binary tree node_key. */
+static int _lwp_shmrm(int id)
+{
+ struct lwp_avl_struct *node_key = RT_NULL;
+ struct lwp_avl_struct *node_pa = RT_NULL;
+ struct lwp_shm_struct* p = RT_NULL;
+ uint32_t bit = 0;
+
+ node_key = shm_id_to_node(id);
+ if (!node_key)
+ {
+ return -1;
+ }
+ p = (struct lwp_shm_struct *)node_key->data;
+ if (p->ref)
+ {
+ return 0;
+ }
+ bit = rt_page_bits(p->size);
+ rt_pages_free((void *)((char *)p->addr - PV_OFFSET), bit);
+ lwp_avl_remove(node_key, &shm_tree_key);
+ node_pa = node_key + 1;
+ lwp_avl_remove(node_pa, &shm_tree_pa);
+ rt_free(node_key);
+ shm_id_free(id);
+ return 0;
+}
+
+/* A wrapping function, free the shared memory with interrupt disabled. */
+int lwp_shmrm(int id)
+{
+ int ret = 0;
+
+ rt_mm_lock();
+ ret = _lwp_shmrm(id);
+ rt_mm_unlock();
+ return ret;
+}
+
+/* Map the shared memory specified by 'id' to the specified virtual address. */
+static void *_lwp_shmat(int id, void *shm_vaddr)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ struct lwp_avl_struct *node_key = RT_NULL;
+ struct lwp_shm_struct *p = RT_NULL;
+ void *va = RT_NULL;
+
+ /* The id is used to locate the node_key in the binary tree, and then get the
+ * shared-memory structure linked to the node_key. We don't use the id to refer
+ * to the shared-memory structure directly, because the binary tree is used
+ * to verify the structure is really in use.
+ */
+ node_key = shm_id_to_node(id);
+ if (!node_key)
+ {
+ return RT_NULL;
+ }
+ p = (struct lwp_shm_struct *)node_key->data; /* p = _shm_ary[id]; */
+
+ /* map the shared memory into the address space of the current thread */
+ lwp = lwp_self();
+ if (!lwp)
+ {
+ return RT_NULL;
+ }
+ va = lwp_map_user_type(lwp, shm_vaddr, (void *)p->addr, p->size, 1, MM_AREA_TYPE_SHM);
+ if (va)
+ {
+ p->ref++;
+ }
+ return va;
+}
+
+/* A wrapping function: attach the shared memory to the specified address. */
+void *lwp_shmat(int id, void *shm_vaddr)
+{
+ void *ret = RT_NULL;
+
+ if (((size_t)shm_vaddr & ARCH_PAGE_MASK) != 0)
+ {
+ return RT_NULL;
+ }
+ rt_mm_lock();
+ ret = _lwp_shmat(id, shm_vaddr);
+ rt_mm_unlock();
+ return ret;
+}
+
+static struct lwp_shm_struct *_lwp_shm_struct_get(struct rt_lwp *lwp, void *shm_vaddr)
+{
+ void *pa = RT_NULL;
+ struct lwp_avl_struct *node_pa = RT_NULL;
+
+ if (!lwp)
+ {
+ return RT_NULL;
+ }
+ pa = rt_hw_mmu_v2p(&lwp->mmu_info, shm_vaddr); /* physical memory */
+
+ node_pa = lwp_avl_find((size_t)pa, shm_tree_pa);
+ if (!node_pa)
+ {
+ return RT_NULL;
+ }
+ return (struct lwp_shm_struct *)node_pa->data;
+}
+
+static int _lwp_shm_ref_inc(struct rt_lwp *lwp, void *shm_vaddr)
+{
+ struct lwp_shm_struct* p = _lwp_shm_struct_get(lwp, shm_vaddr);
+
+ if (p)
+ {
+ p->ref++;
+ return p->ref;
+ }
+ return -1;
+}
+
+int lwp_shm_ref_inc(struct rt_lwp *lwp, void *shm_vaddr)
+{
+ int ret = 0;
+
+ rt_mm_lock();
+ ret = _lwp_shm_ref_inc(lwp, shm_vaddr);
+ rt_mm_unlock();
+
+ return ret;
+}
+
+static int _lwp_shm_ref_dec(struct rt_lwp *lwp, void *shm_vaddr)
+{
+ struct lwp_shm_struct* p = _lwp_shm_struct_get(lwp, shm_vaddr);
+
+ if (p && (p->ref > 0))
+ {
+ p->ref--;
+ return p->ref;
+ }
+ return -1;
+}
+
+int lwp_shm_ref_dec(struct rt_lwp *lwp, void *shm_vaddr)
+{
+ int ret = 0;
+
+ rt_mm_lock();
+ ret = _lwp_shm_ref_dec(lwp, shm_vaddr);
+ rt_mm_unlock();
+
+ return ret;
+}
+
+/* Unmap the shared memory from the address space of the current thread. */
+int _lwp_shmdt(void *shm_vaddr)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ int ret = 0;
+
+ lwp = lwp_self();
+ if (!lwp)
+ {
+ return -1;
+ }
+ ret = _lwp_shm_ref_dec(lwp, shm_vaddr);
+ if (ret >= 0)
+ {
+ lwp_unmap_user_phy(lwp, shm_vaddr);
+ return 0;
+ }
+ return -1;
+}
+/* A wrapping function: detach the mapped shared memory. */
+int lwp_shmdt(void *shm_vaddr)
+{
+ int ret = 0;
+
+ rt_mm_lock();
+ ret = _lwp_shmdt(shm_vaddr);
+ rt_mm_unlock();
+
+ return ret;
+}
+
+/* Get the virtual address of a shared memory in kernel. */
+void *_lwp_shminfo(int id)
+{
+ struct lwp_avl_struct *node_key = RT_NULL;
+ struct lwp_shm_struct *p = RT_NULL;
+
+ /* the share memory is in use only if it exsits in the binary tree */
+ node_key = shm_id_to_node(id);
+ if (!node_key)
+ {
+ return RT_NULL;
+ }
+ p = (struct lwp_shm_struct *)node_key->data; /* p = _shm_ary[id]; */
+
+ return (void *)((char *)p->addr - PV_OFFSET); /* get the virtual address */
+}
+
+/* A wrapping function: get the virtual address of a shared memory. */
+void *lwp_shminfo(int id)
+{
+ void *vaddr = RT_NULL;
+
+ rt_mm_lock();
+ vaddr = _lwp_shminfo(id);
+ rt_mm_unlock();
+ return vaddr;
+}
+
+#ifdef RT_USING_FINSH
+static int _shm_info(struct lwp_avl_struct* node_key, void *data)
+{
+ int id = 0;
+ struct lwp_shm_struct* p = (struct lwp_shm_struct *)node_key->data;
+
+ id = p - _shm_ary;
+ rt_kprintf("0x%08x 0x%08x 0x%08x %8d\n", p->key, p->addr, p->size, id);
+ return 0;
+}
+
+void list_shm(void)
+{
+ rt_kprintf(" key paddr size id\n");
+ rt_kprintf("---------- ---------- ---------- --------\n");
+ rt_mm_lock();
+ lwp_avl_traversal(shm_tree_key, _shm_info, NULL);
+ rt_mm_unlock();
+}
+MSH_CMD_EXPORT(list_shm, show share memory info);
+#endif
+
+#endif
diff --git a/components/lwp/lwp_shm.h b/components/lwp/lwp_shm.h
new file mode 100644
index 0000000000..db6b165614
--- /dev/null
+++ b/components/lwp/lwp_shm.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-12 Jesven first version
+ */
+#ifndef __LWP_SHM_H__
+#define __LWP_SHM_H__
+
+#include <lwp_avl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int lwp_shmget(size_t key, size_t size, int create);
+int lwp_shmrm(int id);
+void* lwp_shmat(int id, void* shm_vaddr);
+int lwp_shmdt(void* shm_vaddr);
+void *lwp_shminfo(int id);
+int lwp_shm_ref_inc(struct rt_lwp *lwp, void *shm_vaddr);
+int lwp_shm_ref_dec(struct rt_lwp *lwp, void *shm_vaddr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__LWP_SHM_H__*/
diff --git a/components/lwp/lwp_signal.c b/components/lwp/lwp_signal.c
new file mode 100644
index 0000000000..ccebec7d80
--- /dev/null
+++ b/components/lwp/lwp_signal.c
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-11-12 Jesven first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "lwp.h"
+#include "lwp_arch.h"
+#include "sys/signal.h"
+
+rt_inline void lwp_sigaddset(lwp_sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+
+ if (_LWP_NSIG_WORDS == 1)
+ {
+ set->sig[0] |= 1UL << sig;
+ }
+ else
+ {
+ set->sig[sig / _LWP_NSIG_BPW] |= 1UL << (sig % _LWP_NSIG_BPW);
+ }
+}
+
+rt_inline void lwp_sigdelset(lwp_sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+
+ if (_LWP_NSIG_WORDS == 1)
+ {
+ set->sig[0] &= ~(1UL << sig);
+ }
+ else
+ {
+ set->sig[sig / _LWP_NSIG_BPW] &= ~(1UL << (sig % _LWP_NSIG_BPW));
+ }
+}
+
+rt_inline int lwp_sigisemptyset(lwp_sigset_t *set)
+{
+ switch (_LWP_NSIG_WORDS)
+ {
+ case 4:
+ return (set->sig[3] | set->sig[2] |
+ set->sig[1] | set->sig[0]) == 0;
+ case 2:
+ return (set->sig[1] | set->sig[0]) == 0;
+ case 1:
+ return set->sig[0] == 0;
+ default:
+ return 1;
+ }
+}
+
+rt_inline int lwp_sigismember(lwp_sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+
+ if (_LWP_NSIG_WORDS == 1)
+ {
+ return 1 & (set->sig[0] >> sig);
+ }
+ else
+ {
+ return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
+ }
+}
+
+rt_inline int next_signal(lwp_sigset_t *pending, lwp_sigset_t *mask)
+{
+ unsigned long i, *s, *m, x;
+ int sig = 0;
+
+ s = pending->sig;
+ m = mask->sig;
+
+ x = *s & ~*m;
+ if (x)
+ {
+ sig = rt_hw_ffz(~x) + 1;
+ return sig;
+ }
+
+ switch (_LWP_NSIG_WORDS)
+ {
+ default:
+ for (i = 1; i < _LWP_NSIG_WORDS; ++i)
+ {
+ x = *++s &~ *++m;
+ if (!x)
+ continue;
+ sig = rt_hw_ffz(~x) + i*_LWP_NSIG_BPW + 1;
+ break;
+ }
+ break;
+
+ case 2:
+ x = s[1] &~ m[1];
+ if (!x)
+ break;
+ sig = rt_hw_ffz(~x) + _LWP_NSIG_BPW + 1;
+ break;
+
+ case 1:
+ /* Nothing to do */
+ break;
+ }
+
+ return sig;
+}
+
+int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag)
+{
+ struct rt_lwp *lwp = (struct rt_lwp*)thread->lwp;
+ int ret = 0;
+
+ switch (suspend_flag)
+ {
+ case RT_INTERRUPTIBLE:
+ if (!lwp_sigisemptyset(&thread->signal))
+ {
+ break;
+ }
+ if (thread->lwp && !lwp_sigisemptyset(&lwp->signal))
+ {
+ break;
+ }
+ ret = 1;
+ break;
+ case RT_KILLABLE:
+ if (lwp_sigismember(&thread->signal, SIGKILL))
+ {
+ break;
+ }
+ if (thread->lwp && lwp_sigismember(&lwp->signal, SIGKILL))
+ {
+ break;
+ }
+ ret = 1;
+ break;
+ case RT_UNINTERRUPTIBLE:
+ ret = 1;
+ break;
+ default:
+ RT_ASSERT(0);
+ break;
+ }
+ return ret;
+}
+
+int lwp_signal_check(void)
+{
+ rt_base_t level;
+ struct rt_thread *thread;
+ struct rt_lwp *lwp;
+ uint32_t have_signal = 0;
+
+ level = rt_hw_interrupt_disable();
+
+ thread = rt_thread_self();
+
+ if (thread->signal_in_process)
+ {
+ goto out;
+ }
+
+ lwp = (struct rt_lwp*)thread->lwp;
+
+ if (lwp->signal_in_process)
+ {
+ goto out;
+ }
+
+ have_signal = !lwp_sigisemptyset(&thread->signal);
+ if (have_signal)
+ {
+ thread->signal_in_process = 1;
+ goto out;
+ }
+ have_signal = !lwp_sigisemptyset(&lwp->signal);
+ if (have_signal)
+ {
+ lwp->signal_in_process = 1;
+ }
+out:
+ rt_hw_interrupt_enable(level);
+ return have_signal;
+}
+
+int lwp_signal_backup(void *user_sp, void *user_pc, void* user_flag)
+{
+ rt_base_t level;
+ struct rt_thread *thread;
+ struct rt_lwp *lwp;
+ int signal;
+
+ level = rt_hw_interrupt_disable();
+ thread = rt_thread_self();
+ if (thread->signal_in_process)
+ {
+ thread->user_ctx.sp = user_sp;
+ thread->user_ctx.pc = user_pc;
+ thread->user_ctx.flag = user_flag;
+
+ signal = next_signal(&thread->signal, &thread->signal_mask);
+ RT_ASSERT(signal != 0);
+ lwp_sigaddset(&thread->signal_mask, signal);
+ thread->signal_mask_bak = signal;
+ lwp_sigdelset(&thread->signal, signal);
+ }
+ else
+ {
+ lwp = (struct rt_lwp*)thread->lwp;
+ lwp->user_ctx.sp = user_sp;
+ lwp->user_ctx.pc = user_pc;
+ lwp->user_ctx.flag = user_flag;
+
+ signal = next_signal(&lwp->signal, &lwp->signal_mask);
+ RT_ASSERT(signal != 0);
+ lwp_sigaddset(&lwp->signal_mask, signal);
+ lwp->signal_mask_bak = signal;
+ lwp_sigdelset(&lwp->signal, signal);
+ }
+ rt_hw_interrupt_enable(level);
+ return signal;
+}
+
+struct rt_user_context *lwp_signal_restore(void)
+{
+ rt_base_t level;
+ struct rt_thread *thread;
+ struct rt_lwp *lwp;
+ struct rt_user_context *ctx;
+
+ level = rt_hw_interrupt_disable();
+ thread = rt_thread_self();
+ if (thread->signal_in_process)
+ {
+ ctx = &thread->user_ctx;
+ thread->signal_in_process = 0;
+
+ lwp_sigdelset(&thread->signal_mask, thread->signal_mask_bak);
+ thread->signal_mask_bak = 0;
+ }
+ else
+ {
+ lwp = (struct rt_lwp*)thread->lwp;
+ ctx = &lwp->user_ctx;
+ RT_ASSERT(lwp->signal_in_process != 0);
+ lwp->signal_in_process = 0;
+
+ lwp_sigdelset(&lwp->signal_mask, lwp->signal_mask_bak);
+ lwp->signal_mask_bak = 0;
+ }
+ rt_hw_interrupt_enable(level);
+ return ctx;
+}
+
+rt_inline int _lwp_check_ignore(int sig)
+{
+ if (sig == SIGCHLD || sig == SIGCONT)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+void sys_exit(int value);
+lwp_sighandler_t lwp_sighandler_get(int sig)
+{
+ lwp_sighandler_t func = RT_NULL;
+ struct rt_lwp *lwp;
+ rt_thread_t thread;
+ rt_base_t level;
+
+ if (sig == 0 || sig > _LWP_NSIG)
+ {
+ return func;
+ }
+ level = rt_hw_interrupt_disable();
+ thread = rt_thread_self();
+#ifndef ARCH_MM_MMU
+ if (thread->signal_in_process)
+ {
+ func = thread->signal_handler[sig - 1];
+ goto out;
+ }
+#endif
+ lwp = (struct rt_lwp*)thread->lwp;
+
+ func = lwp->signal_handler[sig - 1];
+ if (!func)
+ {
+ if (_lwp_check_ignore(sig))
+ {
+ goto out;
+ }
+ if (lwp->signal_in_process)
+ {
+ lwp_terminate(lwp);
+ }
+ sys_exit(0);
+ }
+out:
+ rt_hw_interrupt_enable(level);
+
+ if (func == (lwp_sighandler_t)SIG_IGN)
+ {
+ func = RT_NULL;
+ }
+ return func;
+}
+
+void lwp_sighandler_set(int sig, lwp_sighandler_t func)
+{
+ rt_base_t level;
+
+ if (sig == 0 || sig > _LWP_NSIG)
+ return;
+ if (sig == SIGKILL || sig == SIGSTOP)
+ return;
+ level = rt_hw_interrupt_disable();
+ ((struct rt_lwp*)rt_thread_self()->lwp)->signal_handler[sig - 1] = func;
+ rt_hw_interrupt_enable(level);
+}
+
+#ifndef ARCH_MM_MMU
+void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func)
+{
+ rt_base_t level;
+
+ if (sig == 0 || sig > _LWP_NSIG)
+ return;
+ level = rt_hw_interrupt_disable();
+ rt_thread_self()->signal_handler[sig - 1] = func;
+ rt_hw_interrupt_enable(level);
+}
+#endif
+
+int lwp_sigaction(int sig, const struct lwp_sigaction *act,
+ struct lwp_sigaction *oact, size_t sigsetsize)
+{
+ rt_base_t level;
+ struct rt_lwp *lwp;
+ int ret = -RT_EINVAL;
+ lwp_sigset_t newset;
+
+ level = rt_hw_interrupt_disable();
+ lwp = (struct rt_lwp*)rt_thread_self()->lwp;
+ if (!lwp)
+ {
+ goto out;
+ }
+ if (sigsetsize != sizeof(lwp_sigset_t))
+ {
+ goto out;
+ }
+ if (!act && !oact)
+ {
+ goto out;
+ }
+ if (oact)
+ {
+ oact->sa_flags = lwp->sa_flags;
+ oact->sa_mask = lwp->signal_mask;
+ oact->sa_restorer = RT_NULL;
+ oact->__sa_handler._sa_handler = lwp->signal_handler[sig - 1];
+ }
+ if (act)
+ {
+ lwp->sa_flags = act->sa_flags;
+ newset = act->sa_mask;
+ lwp_sigdelset(&newset, SIGKILL);
+ lwp_sigdelset(&newset, SIGSTOP);
+ lwp->signal_mask = newset;
+ lwp_sighandler_set(sig, act->__sa_handler._sa_handler);
+ }
+ ret = 0;
+out:
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+rt_inline void sigorsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1)
+{
+ switch (_LWP_NSIG_WORDS)
+ {
+ case 4:
+ dset->sig[3] = set0->sig[3] | set1->sig[3];
+ dset->sig[2] = set0->sig[2] | set1->sig[2];
+ case 2:
+ dset->sig[1] = set0->sig[1] | set1->sig[1];
+ case 1:
+ dset->sig[0] = set0->sig[0] | set1->sig[0];
+ default:
+ return;
+ }
+}
+
+rt_inline void sigandsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1)
+{
+ switch (_LWP_NSIG_WORDS)
+ {
+ case 4:
+ dset->sig[3] = set0->sig[3] & set1->sig[3];
+ dset->sig[2] = set0->sig[2] & set1->sig[2];
+ case 2:
+ dset->sig[1] = set0->sig[1] & set1->sig[1];
+ case 1:
+ dset->sig[0] = set0->sig[0] & set1->sig[0];
+ default:
+ return;
+ }
+}
+
+int lwp_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset)
+{
+ int ret = -1;
+ rt_base_t level;
+ struct rt_lwp *lwp;
+ struct rt_thread *thread;
+ lwp_sigset_t newset;
+
+ level = rt_hw_interrupt_disable();
+
+ thread = rt_thread_self();
+ lwp = (struct rt_lwp*)thread->lwp;
+ if (!lwp)
+ {
+ goto out;
+ }
+ if (oset)
+ {
+ rt_memcpy(oset, &lwp->signal_mask, sizeof(lwp_sigset_t));
+ }
+
+ if (sigset)
+ {
+ switch (how)
+ {
+ case SIG_BLOCK:
+ sigorsets(&newset, &lwp->signal_mask, sigset);
+ break;
+ case SIG_UNBLOCK:
+ sigandsets(&newset, &lwp->signal_mask, sigset);
+ break;
+ case SIG_SETMASK:
+ newset = *sigset;
+ break;
+ default:
+ ret = RT_EINVAL;
+ goto out;
+ }
+
+ lwp_sigdelset(&newset, SIGKILL);
+ lwp_sigdelset(&newset, SIGSTOP);
+
+ lwp->signal_mask = newset;
+ }
+ ret = 0;
+out:
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+int lwp_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset)
+{
+ rt_base_t level;
+ struct rt_thread *thread;
+ lwp_sigset_t newset;
+
+ level = rt_hw_interrupt_disable();
+ thread = rt_thread_self();
+
+ if (oset)
+ {
+ rt_memcpy(oset, &thread->signal_mask, sizeof(lwp_sigset_t));
+ }
+
+ if (sigset)
+ {
+ switch (how)
+ {
+ case SIG_BLOCK:
+ sigorsets(&newset, &thread->signal_mask, sigset);
+ break;
+ case SIG_UNBLOCK:
+ sigandsets(&newset, &thread->signal_mask, sigset);
+ break;
+ case SIG_SETMASK:
+ newset = *sigset;
+ break;
+ default:
+ goto out;
+ }
+
+ lwp_sigdelset(&newset, SIGKILL);
+ lwp_sigdelset(&newset, SIGSTOP);
+
+ thread->signal_mask = newset;
+ }
+out:
+ rt_hw_interrupt_enable(level);
+ return 0;
+}
+
+static void _do_signal_wakeup(rt_thread_t thread, int sig)
+{
+ if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
+ {
+ int need_schedule = 1;
+
+ if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK)
+ {
+ rt_thread_wakeup(thread);
+ }
+ else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK))
+ {
+ rt_thread_wakeup(thread);
+ }
+ else
+ {
+ need_schedule = 0;
+ }
+
+ /* do schedule */
+ if (need_schedule)
+ {
+ rt_schedule();
+ }
+ }
+}
+
+int lwp_kill(pid_t pid, int sig)
+{
+ rt_base_t level;
+ struct rt_lwp *lwp;
+ int ret = -1;
+ rt_thread_t thread;
+
+ if (sig < 0 || sig >= _LWP_NSIG)
+ {
+ rt_set_errno(EINVAL);
+ return ret;
+ }
+ level = rt_hw_interrupt_disable();
+ lwp = lwp_from_pid(pid);
+ if (!lwp || lwp->finish)
+ {
+ rt_set_errno(ESRCH);
+ goto out;
+ }
+ if (sig)
+ {
+ /* check main thread */
+ thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (!lwp_sigismember(&lwp->signal_mask, sig)) /* if signal masked */
+ {
+ lwp_sigaddset(&lwp->signal, sig);
+ _do_signal_wakeup(thread, sig);
+ }
+ }
+ ret = 0;
+out:
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+int lwp_thread_kill(rt_thread_t thread, int sig)
+{
+ rt_base_t level;
+ int ret = -RT_EINVAL;
+
+ if (!thread)
+ {
+ rt_set_errno(ESRCH);
+ return ret;
+ }
+ if (sig < 0 || sig >= _LWP_NSIG)
+ {
+ rt_set_errno(EINVAL);
+ return ret;
+ }
+ level = rt_hw_interrupt_disable();
+ if (!thread->lwp)
+ {
+ rt_set_errno(EPERM);
+ goto out;
+ }
+ if (!lwp_sigismember(&thread->signal_mask, sig)) /* if signal masked */
+ {
+ lwp_sigaddset(&thread->signal, sig);
+ _do_signal_wakeup(thread, sig);
+ }
+ ret = 0;
+out:
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
diff --git a/components/lwp/lwp_signal.h b/components/lwp/lwp_signal.h
new file mode 100644
index 0000000000..6d393f0098
--- /dev/null
+++ b/components/lwp/lwp_signal.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-02-23 Jesven first version.
+ */
+
+#ifndef LWP_SIGNAL_H__
+#define LWP_SIGNAL_H__
+
+#include <rtthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int lwp_signal_check(void);
+int lwp_signal_backup(void *user_sp, void *user_pc, void* user_flag);
+struct rt_user_context *lwp_signal_restore(void);
+lwp_sighandler_t lwp_sighandler_get(int sig);
+void lwp_sighandler_set(int sig, lwp_sighandler_t func);
+#ifndef ARCH_MM_MMU
+void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func);
+#endif
+int lwp_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset);
+int lwp_sigaction(int sig, const struct lwp_sigaction *act, struct lwp_sigaction * oact, size_t sigsetsize);
+int lwp_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset);
+
+int lwp_kill(pid_t pid, int sig);
+int lwp_thread_kill(rt_thread_t thread, int sig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index f2aec9303f..c241e1ef83 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -6,112 +6,997 @@
* Change Logs:
* Date Author Notes
* 2018-06-10 Bernard first version
+ * 2021-02-03 lizhirui add limit condition for network syscall and add 64-bit arch support
+ * 2021-02-06 lizhirui fix some bugs
+ * 2021-02-12 lizhirui add 64-bit support for sys_brk
+ * 2021-02-20 lizhirui fix some warnings
*/
-
+#define _GNU_SOURCE
/* RT-Thread System call */
+#include <rthw.h>
+#include <board.h>
+
#include <lwp.h>
-#include <lwp_mem.h>
-#include <lwp_syscall.h>
+#ifdef RT_USING_USERSPACE
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+#endif
+
+#include <fcntl.h>
+#ifdef RT_USING_DFS
#include <poll.h>
#include <sys/select.h>
+#include <dfs_file.h>
+#include <unistd.h>
+#include <stdio.h> /* rename() */
+#include <sys/stat.h>
+#include <sys/statfs.h> /* statfs() */
+#endif
+
+#include "syscall_data.h"
#if (defined(RT_USING_SAL) && defined(SAL_USING_POSIX))
#include <sys/socket.h>
-#define SYSCALL_NET(f) ((void*)(f))
+
+#define SYSCALL_NET(f) f
#else
-#define SYSCALL_NET(f) ((void*)sys_notimpl)
+#define SYSCALL_NET(f) SYSCALL_SIGN(sys_notimpl)
#endif
-#define DBG_TAG "LWP_CALL"
-#define DBG_LVL DBG_WARNING
+#if defined(RT_USING_DFS) && defined(RT_USING_USERSPACE)
+#define SYSCALL_USPACE(f) f
+#else
+#define SYSCALL_USPACE(f) SYSCALL_SIGN(sys_notimpl)
+#endif
+
+#define DBG_TAG "SYSCALL"
+#define DBG_LVL DBG_INFO
#include <rtdbg.h>
-static void __exit_files(rt_thread_t tid)
+#ifdef RT_USING_SAL
+#include <netdev_ipaddr.h>
+#include <netdev.h>
+
+#include <sal_netdb.h>
+#include <sal_socket.h>
+#include <sys/socket.h>
+#endif /* RT_USING_SAL */
+
+#include <tty.h>
+#include "lwp_ipc_internal.h"
+#include <sched.h>
+#ifndef GRND_NONBLOCK
+#define GRND_NONBLOCK 0x0001
+#endif /* GRND_NONBLOCK */
+
+#ifndef GRND_RANDOM
+#define GRND_RANDOM 0x0002
+#endif /*GRND_RANDOM */
+
+#define SET_ERRNO(no) rt_set_errno(-(no))
+#define GET_ERRNO() ((rt_get_errno() > 0) ? (-rt_get_errno()) : rt_get_errno())
+struct musl_sockaddr
{
- struct rt_lwp *lwp;
+ uint16_t sa_family;
+ char sa_data[14];
+};
- lwp = (struct rt_lwp *)tid->lwp;
- while (lwp->fdt.maxfd > 0)
+int sys_dup(int oldfd);
+int sys_dup2(int oldfd, int new);
+void lwp_cleanup(struct rt_thread *tid);
+
+#ifdef ARCH_MM_MMU
+#define ALLOC_KERNEL_STACK_SIZE 5120
+
+int sys_futex(int *uaddr, int op, int val, void *timeout, void *uaddr2, int val3);
+int sys_pmutex(void *umutex, int op, void *arg);
+int sys_cacheflush(void *addr, int len, int cache);
+static void *kmem_get(size_t size)
+{
+ return rt_malloc(size);
+}
+
+static void kmem_put(void *kptr)
+{
+ rt_free(kptr);
+}
+#else
+#define ALLOC_KERNEL_STACK_SIZE 1536
+#define ALLOC_KERNEL_STACK_SIZE_MIN 1024
+#define ALLOC_KERNEL_STACK_SIZE_MAX 4096
+
+extern void set_user_context(void *stack);
+#endif /* ARCH_MM_MMU */
+
+/* The same socket option is defined differently in the user interfaces and the
+ * implementation. The options should be converted in the kernel. */
+
+/* socket levels */
+#define INTF_SOL_SOCKET 1
+#define IMPL_SOL_SOCKET 0xFFF
+
+#define INTF_IPPROTO_IP 0
+#define IMPL_IPPROTO_IP 0
+
+#define INTF_IPPROTO_TCP 6
+#define IMPL_IPPROTO_TCP 6
+
+#define INTF_IPPROTO_IPV6 41
+#define IMPL_IPPROTO_IPV6 41
+
+/* SOL_SOCKET option names */
+#define INTF_SO_BROADCAST 6
+#define INTF_SO_KEEPALIVE 9
+#define INTF_SO_REUSEADDR 2
+#define INTF_SO_TYPE 3
+#define INTF_SO_ERROR 4
+#define INTF_SO_SNDTIMEO 21
+#define INTF_SO_RCVTIMEO 20
+#define INTF_SO_RCVBUF 8
+#define INTF_SO_LINGER 13
+#define INTF_SO_NO_CHECK 11
+#define INTF_SO_ACCEPTCONN 30
+#define INTF_SO_DONTROUTE 5
+#define INTF_SO_OOBINLINE 10
+#define INTF_SO_REUSEPORT 15
+#define INTF_SO_SNDBUF 7
+#define INTF_SO_SNDLOWAT 19
+#define INTF_SO_RCVLOWAT 18
+
+#define IMPL_SO_BROADCAST 0x0020
+#define IMPL_SO_KEEPALIVE 0x0008
+#define IMPL_SO_REUSEADDR 0x0004
+#define IMPL_SO_TYPE 0x1008
+#define IMPL_SO_ERROR 0x1007
+#define IMPL_SO_SNDTIMEO 0x1005
+#define IMPL_SO_RCVTIMEO 0x1006
+#define IMPL_SO_RCVBUF 0x1002
+#define IMPL_SO_LINGER 0x0080
+#define IMPL_SO_NO_CHECK 0x100a
+#define IMPL_SO_ACCEPTCONN 0x0002
+#define IMPL_SO_DONTROUTE 0x0010
+#define IMPL_SO_OOBINLINE 0x0100
+#define IMPL_SO_REUSEPORT 0x0200
+#define IMPL_SO_SNDBUF 0x1001
+#define IMPL_SO_SNDLOWAT 0x1003
+#define IMPL_SO_RCVLOWAT 0x1004
+
+/* IPPROTO_IP option names */
+#define INTF_IP_TTL 2
+#define INTF_IP_TOS 1
+#define INTF_IP_MULTICAST_TTL 33
+#define INTF_IP_MULTICAST_IF 32
+#define INTF_IP_MULTICAST_LOOP 34
+#define INTF_IP_ADD_MEMBERSHIP 35
+#define INTF_IP_DROP_MEMBERSHIP 36
+
+#define IMPL_IP_TTL 2
+#define IMPL_IP_TOS 1
+#define IMPL_IP_MULTICAST_TTL 5
+#define IMPL_IP_MULTICAST_IF 6
+#define IMPL_IP_MULTICAST_LOOP 7
+#define IMPL_IP_ADD_MEMBERSHIP 3
+#define IMPL_IP_DROP_MEMBERSHIP 4
+
+/* IPPROTO_TCP option names */
+#define INTF_TCP_NODELAY 1
+#define INTF_TCP_KEEPALIVE 9
+#define INTF_TCP_KEEPIDLE 4
+#define INTF_TCP_KEEPINTVL 5
+#define INTF_TCP_KEEPCNT 6
+
+#define IMPL_TCP_NODELAY 0x01
+#define IMPL_TCP_KEEPALIVE 0x02
+#define IMPL_TCP_KEEPIDLE 0x03
+#define IMPL_TCP_KEEPINTVL 0x04
+#define IMPL_TCP_KEEPCNT 0x05
+
+/* IPPROTO_IPV6 option names */
+#define INTF_IPV6_V6ONLY 26
+#define IMPL_IPV6_V6ONLY 27
+
+#ifdef RT_USING_SAL
+static void convert_sockopt(int *level, int *optname)
+{
+ if (*level == INTF_SOL_SOCKET)
{
- lwp->fdt.maxfd --;
- close(lwp->fdt.maxfd);
+ *level = IMPL_SOL_SOCKET;
+
+ switch (*optname)
+ {
+ case INTF_SO_REUSEADDR:
+ *optname = IMPL_SO_REUSEADDR;
+ break;
+ case INTF_SO_KEEPALIVE:
+ *optname = IMPL_SO_KEEPALIVE;
+ break;
+ case INTF_SO_BROADCAST:
+ *optname = IMPL_SO_BROADCAST;
+ break;
+ case INTF_SO_ACCEPTCONN:
+ *optname = IMPL_SO_ACCEPTCONN;
+ break;
+ case INTF_SO_DONTROUTE:
+ *optname = IMPL_SO_DONTROUTE;
+ break;
+ case INTF_SO_LINGER:
+ *optname = IMPL_SO_LINGER;
+ break;
+ case INTF_SO_OOBINLINE:
+ *optname = IMPL_SO_OOBINLINE;
+ break;
+ case INTF_SO_REUSEPORT:
+ *optname = IMPL_SO_REUSEPORT;
+ break;
+ case INTF_SO_SNDBUF:
+ *optname = IMPL_SO_SNDBUF;
+ break;
+ case INTF_SO_RCVBUF:
+ *optname = IMPL_SO_RCVBUF;
+ break;
+ case INTF_SO_SNDLOWAT:
+ *optname = IMPL_SO_SNDLOWAT;
+ break;
+ case INTF_SO_RCVLOWAT:
+ *optname = IMPL_SO_RCVLOWAT;
+ break;
+ case INTF_SO_SNDTIMEO:
+ *optname = IMPL_SO_SNDTIMEO;
+ break;
+ case INTF_SO_RCVTIMEO:
+ *optname = IMPL_SO_RCVTIMEO;
+ break;
+ case INTF_SO_ERROR:
+ *optname = IMPL_SO_ERROR;
+ break;
+ case INTF_SO_TYPE:
+ *optname = IMPL_SO_TYPE;
+ break;
+ case INTF_SO_NO_CHECK:
+ *optname = IMPL_SO_NO_CHECK;
+ break;
+
+ /*
+ * SO_DONTLINGER (*level = ((int)(~SO_LINGER))),
+ * SO_USELOOPBACK (*level = 0x0040) and
+ * SO_CONTIMEO (*level = 0x1009) are not supported for now.
+ */
+ default:
+ *optname = 0;
+ break;
+ }
+ return;
}
+
+ if (*level == INTF_IPPROTO_IP)
+ {
+ *level = IMPL_IPPROTO_IP;
+
+ switch (*optname)
+ {
+ case INTF_IP_TTL:
+ *optname = IMPL_IP_TTL;
+ break;
+ case INTF_IP_TOS:
+ *optname = IMPL_IP_TOS;
+ break;
+ case INTF_IP_MULTICAST_TTL:
+ *optname = IMPL_IP_MULTICAST_TTL;
+ break;
+ case INTF_IP_MULTICAST_IF:
+ *optname = IMPL_IP_MULTICAST_IF;
+ break;
+ case INTF_IP_MULTICAST_LOOP:
+ *optname = IMPL_IP_MULTICAST_LOOP;
+ break;
+ case INTF_IP_ADD_MEMBERSHIP:
+ *optname = IMPL_IP_ADD_MEMBERSHIP;
+ break;
+ case INTF_IP_DROP_MEMBERSHIP:
+ *optname = IMPL_IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (*level == INTF_IPPROTO_TCP)
+ {
+ *level = IMPL_IPPROTO_TCP;
+
+ switch (*optname)
+ {
+ case INTF_TCP_NODELAY:
+ *optname = IMPL_TCP_NODELAY;
+ break;
+ case INTF_TCP_KEEPALIVE:
+ *optname = IMPL_TCP_KEEPALIVE;
+ break;
+ case INTF_TCP_KEEPIDLE:
+ *optname = IMPL_TCP_KEEPIDLE;
+ break;
+ case INTF_TCP_KEEPINTVL:
+ *optname = IMPL_TCP_KEEPINTVL;
+ break;
+ case INTF_TCP_KEEPCNT:
+ *optname = IMPL_TCP_KEEPCNT;
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+ if (*level == INTF_IPPROTO_IPV6)
+ {
+ *level = IMPL_IPPROTO_IPV6;
+
+ switch (*optname)
+ {
+ case INTF_IPV6_V6ONLY:
+ *optname = IMPL_IPV6_V6ONLY;
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+}
+#endif /* RT_USING_SAL */
+
+#if defined(RT_USING_LWIP) || defined(SAL_USING_UNET)
+ static void sockaddr_tolwip(const struct musl_sockaddr *std, struct sockaddr *lwip)
+ {
+ if (std && lwip)
+ {
+ lwip->sa_len = sizeof(*lwip);
+ lwip->sa_family = (sa_family_t) std->sa_family;
+ memcpy(lwip->sa_data, std->sa_data, sizeof(lwip->sa_data));
+ }
+ }
+
+ static void sockaddr_tomusl(const struct sockaddr *lwip, struct musl_sockaddr *std)
+ {
+ if (std && lwip)
+ {
+ std->sa_family = (uint16_t) lwip->sa_family;
+ memcpy(std->sa_data, lwip->sa_data, sizeof(std->sa_data));
+ }
+ }
+#endif
+
+static void _crt_thread_entry(void *parameter)
+{
+ rt_thread_t tid;
+ rt_size_t user_stack;
+
+ tid = rt_thread_self();
+
+ user_stack = (rt_size_t)tid->user_stack + tid->user_stack_size;
+ user_stack &= ~7; //align 8
+
+#ifdef ARCH_MM_MMU
+ arch_crt_start_umode(parameter, tid->user_entry, (void *)user_stack, tid->stack_addr + tid->stack_size);
+#else
+ set_user_context((void*)user_stack);
+ arch_start_umode(parameter, tid->user_entry, ((struct rt_lwp *)tid->lwp)->data_entry, (void*)user_stack);
+#endif /* ARCH_MM_MMU */
}
/* thread/process */
void sys_exit(int value)
{
- rt_thread_t tid;
+ rt_base_t level;
+ rt_thread_t tid, main_thread;
+ struct rt_lwp *lwp;
+
+ LOG_D("thread/process exit.");
- /* TODO: handle the return_value */
- dbg_log(DBG_LOG, "enter sys_exit\n");
tid = rt_thread_self();
- __exit_files(tid);
- rt_thread_delete(tid);
+ lwp = (struct rt_lwp *)tid->lwp;
+
+ level = rt_hw_interrupt_disable();
+#ifdef ARCH_MM_MMU
+ if (tid->clear_child_tid)
+ {
+ int t = 0;
+ int *clear_child_tid = tid->clear_child_tid;
+ tid->clear_child_tid = RT_NULL;
+ lwp_put_to_user(clear_child_tid, &t, sizeof t);
+ sys_futex(clear_child_tid, FUTEX_WAKE, 1, RT_NULL, RT_NULL, 0);
+ }
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (main_thread == tid)
+ {
+ lwp_terminate(lwp);
+ lwp_wait_subthread_exit();
+ lwp->lwp_ret = value;
+ }
+#else
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ if (main_thread == tid)
+ {
+ rt_thread_t sub_thread;
+ rt_list_t *list;
+
+ lwp_terminate(lwp);
+
+ /* delete all subthread */
+ while ((list = tid->sibling.prev) != &lwp->t_grp)
+ {
+ sub_thread = rt_list_entry(list, struct rt_thread, sibling);
+ rt_list_remove(&sub_thread->sibling);
+ rt_thread_delete(sub_thread);
+ }
+ lwp->lwp_ret = value;
+ }
+#endif /* ARCH_MM_MMU */
+
+ rt_thread_delete(tid);
rt_schedule();
+ rt_hw_interrupt_enable(level);
return;
}
+/* exit group */
+void sys_exit_group(int status)
+{
+ return;
+}
+
/* syscall: "read" ret: "ssize_t" args: "int" "void *" "size_t" */
ssize_t sys_read(int fd, void *buf, size_t nbyte)
{
- return read(fd, buf, nbyte);
+#ifdef RT_USING_USERSPACE
+ void *kmem = RT_NULL;
+ ssize_t ret = -1;
+
+ if (!nbyte)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable((void *)buf, nbyte))
+ {
+ return -EFAULT;
+ }
+
+ kmem = kmem_get(nbyte);
+ if (!kmem)
+ {
+ return -ENOMEM;
+ }
+
+ ret = read(fd, kmem, nbyte);
+ if (ret > 0)
+ {
+ lwp_put_to_user(buf, kmem, ret);
+ }
+
+ kmem_put(kmem);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ if (!lwp_user_accessable((void *)buf, nbyte))
+ {
+ return -EFAULT;
+ }
+ ssize_t ret = read(fd, buf, nbyte);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
}
/* syscall: "write" ret: "ssize_t" args: "int" "const void *" "size_t" */
ssize_t sys_write(int fd, const void *buf, size_t nbyte)
{
- return write(fd, buf, nbyte);
+#ifdef RT_USING_USERSPACE
+ void *kmem = RT_NULL;
+ ssize_t ret = -1;
+
+ if (!nbyte)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable((void *)buf, nbyte))
+ {
+ return -EFAULT;
+ }
+
+ kmem = kmem_get(nbyte);
+ if (!kmem)
+ {
+ return -ENOMEM;
+ }
+
+ lwp_get_from_user(kmem, (void *)buf, nbyte);
+ ret = write(fd, kmem, nbyte);
+
+ kmem_put(kmem);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ if (!lwp_user_accessable((void *)buf, nbyte))
+ {
+ return -EFAULT;
+ }
+ ssize_t ret = write(fd, buf, nbyte);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
}
/* syscall: "lseek" ret: "off_t" args: "int" "off_t" "int" */
off_t sys_lseek(int fd, off_t offset, int whence)
{
- return lseek(fd, offset, whence);
+ off_t ret = lseek(fd, offset, whence);
+ return (ret < 0 ? GET_ERRNO() : ret);
}
/* syscall: "open" ret: "int" args: "const char *" "int" "..." */
-int sys_open(const char *name, int mode, ...)
+int sys_open(const char *name, int flag, ...)
{
- return open(name, mode, 0);
+#ifdef RT_USING_USERSPACE
+ int ret = -1;
+ rt_size_t len = 0;
+ char *kname = RT_NULL;
+
+ if (!lwp_user_accessable((void *)name, 1))
+ {
+ return -EFAULT;
+ }
+
+ len = rt_strlen(name);
+ if (!len)
+ {
+ return -EINVAL;
+ }
+
+ kname = (char *)kmem_get(len + 1);
+ if (!kname)
+ {
+ return -ENOMEM;
+ }
+
+ lwp_get_from_user(kname, (void *)name, len + 1);
+ ret = open(kname, flag, 0);
+
+ kmem_put(kname);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ if (!lwp_user_accessable((void *)name, 1))
+ {
+ return -EFAULT;
+ }
+ int ret = open(name, flag, 0);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
}
/* syscall: "close" ret: "int" args: "int" */
int sys_close(int fd)
{
- return close(fd);
+ int ret = close(fd);
+ return (ret < 0 ? GET_ERRNO() : ret);
}
/* syscall: "ioctl" ret: "int" args: "int" "u_long" "..." */
int sys_ioctl(int fd, unsigned long cmd, void* data)
{
- return ioctl(fd, cmd, data);
+ int ret = ioctl(fd, cmd, data);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_fstat(int file, struct stat *buf)
+{
+#ifdef RT_USING_USERSPACE
+ int ret = -1;
+ struct stat statbuff;
+
+ if (!lwp_user_accessable((void *)buf, sizeof(struct stat)))
+ {
+ return -EFAULT;
+ }
+ else
+ {
+ ret = fstat(file, &statbuff);
+
+ if (ret == 0)
+ {
+ lwp_put_to_user(buf, &statbuff, sizeof statbuff);
+ }
+ else
+ {
+ ret = GET_ERRNO();
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+ }
+#else
+ if (!lwp_user_accessable((void *)buf, sizeof(struct stat)))
+ {
+ return -EFAULT;
+ }
+ int ret = fstat(file, buf);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+/* DFS and lwip definitions */
+#define IMPL_POLLIN (0x01)
+
+#define IMPL_POLLOUT (0x02)
+
+#define IMPL_POLLERR (0x04)
+#define IMPL_POLLHUP (0x08)
+#define IMPL_POLLNVAL (0x10)
+
+/* musl definitions */
+#define INTF_POLLIN 0x001
+#define INTF_POLLPRI 0x002
+#define INTF_POLLOUT 0x004
+#define INTF_POLLERR 0x008
+#define INTF_POLLHUP 0x010
+#define INTF_POLLNVAL 0x020
+#define INTF_POLLRDNORM 0x040
+#define INTF_POLLRDBAND 0x080
+#define INTF_POLLWRNORM 0x100
+#define INTF_POLLWRBAND 0x200
+#define INTF_POLLMSG 0x400
+#define INTF_POLLRDHUP 0x2000
+
+#define INTF_POLLIN_MASK (INTF_POLLIN | INTF_POLLRDNORM | INTF_POLLRDBAND | INTF_POLLPRI)
+#define INTF_POLLOUT_MASK (INTF_POLLOUT | INTF_POLLWRNORM | INTF_POLLWRBAND)
+
+static void musl2dfs_events(short *events)
+{
+ short origin_e = *events;
+ short result_e = 0;
+
+ if (origin_e & INTF_POLLIN_MASK)
+ {
+ result_e |= IMPL_POLLIN;
+ }
+
+ if (origin_e & INTF_POLLOUT_MASK)
+ {
+ result_e |= IMPL_POLLOUT;
+ }
+
+ if (origin_e & INTF_POLLERR)
+ {
+ result_e |= IMPL_POLLERR;
+ }
+
+ if (origin_e & INTF_POLLHUP)
+ {
+ result_e |= IMPL_POLLHUP;
+ }
+
+ if (origin_e & INTF_POLLNVAL)
+ {
+ result_e |= IMPL_POLLNVAL;
+ }
+
+ *events = result_e;
+}
+
+static void dfs2musl_events(short *events)
+{
+ short origin_e = *events;
+ short result_e = 0;
+
+ if (origin_e & IMPL_POLLIN)
+ {
+ result_e |= INTF_POLLIN_MASK;
+ }
+
+ if (origin_e & IMPL_POLLOUT)
+ {
+ result_e |= INTF_POLLOUT_MASK;
+ }
+
+ if (origin_e & IMPL_POLLERR)
+ {
+ result_e |= INTF_POLLERR;
+ }
+
+ if (origin_e & IMPL_POLLHUP)
+ {
+ result_e |= INTF_POLLHUP;
+ }
+
+ if (origin_e & IMPL_POLLNVAL)
+ {
+ result_e |= INTF_POLLNVAL;
+ }
+
+ *events = result_e;
+}
+
+int sys_poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ int ret = -1;
+ int i = 0;
+#ifdef RT_USING_USERSPACE
+ struct pollfd *kfds = RT_NULL;
+
+ if (!lwp_user_accessable((void *)fds, nfds * sizeof *fds))
+ {
+ return -EFAULT;
+ }
+
+ kfds = (struct pollfd *)kmem_get(nfds * sizeof *kfds);
+ if (!kfds)
+ {
+ return -ENOMEM;
+ }
+
+ lwp_get_from_user(kfds, fds, nfds * sizeof *kfds);
+
+ for (i = 0; i < nfds; i++)
+ {
+ musl2dfs_events(&kfds[i].events);
+ }
+ ret = poll(kfds, nfds, timeout);
+ if (ret > 0)
+ {
+ for (i = 0; i < nfds; i++)
+ {
+ dfs2musl_events(&kfds->revents);
+ }
+ lwp_put_to_user(fds, kfds, nfds * sizeof *kfds);
+ }
+
+ kmem_put(kfds);
+ return ret;
+#else
+#ifdef RT_USING_MUSL
+ for (i = 0; i < nfds; i++)
+ {
+ musl2dfs_events(&fds->events);
+ }
+#endif /* RT_USING_MUSL */
+ if (!lwp_user_accessable((void *)fds, nfds * sizeof *fds))
+ {
+ return -EFAULT;
+ }
+ ret = poll(fds, nfds, timeout);
+#ifdef RT_USING_MUSL
+ if (ret > 0)
+ {
+ for (i = 0; i < nfds; i++)
+ {
+ dfs2musl_events(&fds->revents);
+ }
+ }
+#endif /* RT_USING_MUSL */
+ return ret;
+#endif /* RT_USING_USERSPACE */
+}
+
+int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+#ifdef RT_USING_USERSPACE
+ int ret = -1;
+ fd_set *kreadfds = RT_NULL, *kwritefds = RT_NULL, *kexceptfds = RT_NULL;
+
+ if (readfds)
+ {
+ if (!lwp_user_accessable((void *)readfds, sizeof *readfds))
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ kreadfds = (fd_set *)kmem_get(sizeof *kreadfds);
+ if (!kreadfds)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+ lwp_get_from_user(kreadfds, readfds, sizeof *kreadfds);
+ }
+ if (writefds)
+ {
+ if (!lwp_user_accessable((void *)writefds, sizeof *writefds))
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ kwritefds = (fd_set *)kmem_get(sizeof *kwritefds);
+ if (!kwritefds)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+ lwp_get_from_user(kwritefds, writefds, sizeof *kwritefds);
+ }
+ if (exceptfds)
+ {
+ if (!lwp_user_accessable((void *)exceptfds, sizeof *exceptfds))
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ kexceptfds = (fd_set *)kmem_get(sizeof *kexceptfds);
+ if (!kexceptfds)
+ {
+ SET_ERRNO(EINVAL);
+ goto quit;
+ }
+ lwp_get_from_user(kexceptfds, exceptfds, sizeof *kexceptfds);
+ }
+
+ ret = select(nfds, kreadfds, kwritefds, kexceptfds, timeout);
+ if (kreadfds)
+ {
+ lwp_put_to_user(readfds, kreadfds, sizeof *kreadfds);
+ }
+ if (kwritefds)
+ {
+ lwp_put_to_user(writefds, kwritefds, sizeof *kwritefds);
+ }
+ if (kexceptfds)
+ {
+ lwp_put_to_user(exceptfds, kexceptfds, sizeof *kexceptfds);
+ }
+quit:
+ if (kreadfds)
+ {
+ kmem_put(kreadfds);
+ }
+ if (kwritefds)
+ {
+ kmem_put(kwritefds);
+ }
+ if (kexceptfds)
+ {
+ kmem_put(kexceptfds);
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ int ret;
+
+ if (!lwp_user_accessable((void *)readfds, sizeof *readfds))
+ {
+ return -EFAULT;
+ }
+ if (!lwp_user_accessable((void *)writefds, sizeof *writefds))
+ {
+ return -EFAULT;
+ }
+ if (!lwp_user_accessable((void *)exceptfds, sizeof *exceptfds))
+ {
+ return -EFAULT;
+ }
+ ret = select(nfds, readfds, writefds, exceptfds, timeout);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+int sys_unlink(const char *pathname)
+{
+#ifdef RT_USING_USERSPACE
+ int ret = -1;
+ rt_size_t len = 0;
+ char *kname = RT_NULL;
+ int a_err = 0;
+
+ lwp_user_strlen(pathname, &a_err);
+ if (a_err)
+ {
+ return -EFAULT;
+ }
+
+ len = rt_strlen(pathname);
+ if (!len)
+ {
+ return -EINVAL;
+ }
+
+ kname = (char *)kmem_get(len + 1);
+ if (!kname)
+ {
+ return -ENOMEM;
+ }
+
+ lwp_get_from_user(kname, (void *)pathname, len + 1);
+ ret = unlink(kname);
+
+ kmem_put(kname);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ int ret = 0;
+ ret = unlink(pathname);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
}
/* syscall: "nanosleep" ret: "int" args: "const struct timespec *" "struct timespec *" */
int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
- rt_tick_t tick;
-
+ int ret = 0;
dbg_log(DBG_LOG, "sys_nanosleep\n");
+ if (!lwp_user_accessable((void *)rqtp, sizeof *rqtp))
+ return -EFAULT;
- tick = rqtp->tv_sec * RT_TICK_PER_SECOND + (rqtp->tv_nsec * RT_TICK_PER_SECOND)/ 1000000000;
- rt_thread_delay(tick);
-
+#ifdef RT_USING_USERSPACE
+ struct timespec rqtp_k;
+ struct timespec rmtp_k;
+
+ lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
+ ret = nanosleep(&rqtp_k, &rmtp_k);
+ if ((ret != -1 || rt_get_errno() == EINTR) && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
+ {
+ lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
+ return -EINTR;
+ }
+#else
if (rmtp)
{
- tick = rt_tick_get() - tick;
- /* get the passed time */
- rmtp->tv_sec = tick/RT_TICK_PER_SECOND;
- rmtp->tv_nsec = (tick%RT_TICK_PER_SECOND) * (1000000000/RT_TICK_PER_SECOND);
+ if (!lwp_user_accessable((void *)rmtp, sizeof *rmtp))
+ return -EFAULT;
+ ret = nanosleep(rqtp, rmtp);
+ }
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+/* syscall: "gettimeofday" ret: "int" args: "struct timeval *" "struct timezone *" */
+int sys_gettimeofday(struct timeval *tp, struct timezone *tzp)
+{
+#ifdef RT_USING_USERSPACE
+ struct timeval t_k;
+
+ if (tp)
+ {
+ if (!lwp_user_accessable((void *)tp, sizeof *tp))
+ {
+ return -EFAULT;
+ }
+
+ t_k.tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;
+ t_k.tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND);
+
+ lwp_put_to_user(tp, (void *)&t_k, sizeof t_k);
+ }
+#else
+ if (tp)
+ {
+ if (!lwp_user_accessable((void *)tp, sizeof *tp))
+ {
+ return -EFAULT;
+ }
+ tp->tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;
+ tp->tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND);
}
+#endif
+
+ return 0;
+}
+int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp)
+{
return 0;
}
+int sys_exec(char *filename, int argc, char **argv, char **envp)
+{
+ return lwp_execve(filename, 0, argc, argv, envp);
+}
+
+int sys_kill(int pid, int sig)
+{
+ int ret = 0;
+ ret = lwp_kill(pid, sig);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_getpid(void)
+{
+ return lwp_getpid();
+}
+
/* syscall: "getpriority" ret: "int" args: "int" "id_t" */
int sys_getpriority(int which, id_t who)
{
@@ -120,7 +1005,7 @@ int sys_getpriority(int which, id_t who)
rt_thread_t tid;
tid = rt_thread_self();
- if (who == (id_t)tid || who == 0xff)
+ if (who == (id_t)(rt_size_t)tid || who == 0xff)
{
return tid->current_priority;
}
@@ -137,7 +1022,7 @@ int sys_setpriority(int which, id_t who, int prio)
rt_thread_t tid;
tid = rt_thread_self();
- if ((who == (id_t)tid || who == 0xff) && (prio >= 0 && prio < RT_THREAD_PRIORITY_MAX))
+ if ((who == (id_t)(rt_size_t)tid || who == 0xff) && (prio >= 0 && prio < RT_THREAD_PRIORITY_MAX))
{
rt_thread_control(tid, RT_THREAD_CTRL_CHANGE_PRIORITY, &prio);
return 0;
@@ -147,122 +1032,3374 @@ int sys_setpriority(int which, id_t who, int prio)
return -1;
}
-/* syscall: "gettimeofday" ret: "int" args: "struct timeval *" "struct timezone *" */
-int sys_gettimeofday(struct timeval *tp, struct timezone *tzp)
+rt_sem_t sys_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
{
- if (tp)
+ rt_sem_t sem = rt_sem_create(name, value, flag);
+ if (lwp_user_object_add(lwp_self(), (rt_object_t)sem) != 0)
{
- tp->tv_sec = rt_tick_get() / RT_TICK_PER_SECOND;
- tp->tv_usec = (rt_tick_get() % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND);
+ rt_sem_delete(sem);
+ sem = NULL;
}
+ return sem;
+}
- return 0;
+rt_err_t sys_sem_delete(rt_sem_t sem)
+{
+ return lwp_user_object_delete(lwp_self(), (rt_object_t)sem);
}
-/* syscall: "settimeofday" ret: "int" args: "const struct timeval *" "const struct timezone *" */
-int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp)
+rt_err_t sys_sem_take(rt_sem_t sem, rt_int32_t time)
{
- return 0;
+ return rt_sem_take_interruptible(sem, time);
}
-/* syscall: "msgget" ret: "int" args: "key_t" "int" */
-int sys_msgget(key_t key, int msgflg)
+rt_err_t sys_sem_release(rt_sem_t sem)
{
- return -1;
+ return rt_sem_release(sem);
}
-/* syscall: "msgsnd" ret: "int" args: "int" "const void *" "size_t" "int" */
-int sys_msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg)
+rt_mutex_t sys_mutex_create(const char *name, rt_uint8_t flag)
{
- return -1;
+ rt_mutex_t mutex = rt_mutex_create(name, flag);
+ if (lwp_user_object_add(lwp_self(), (rt_object_t)mutex) != 0)
+ {
+ rt_mutex_delete(mutex);
+ mutex = NULL;
+ }
+ return mutex;
}
-/* syscall: "msgrcv" ret: "int" args: "int" "void *" "size_t" "long" "int" */
-int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
+rt_err_t sys_mutex_delete(rt_mutex_t mutex)
{
- return -1;
+ return lwp_user_object_delete(lwp_self(), (rt_object_t)mutex);
+}
+
+rt_err_t sys_mutex_take(rt_mutex_t mutex, rt_int32_t time)
+{
+ return rt_mutex_take_interruptible(mutex, time);
+}
+
+rt_err_t sys_mutex_release(rt_mutex_t mutex)
+{
+ return rt_mutex_release(mutex);
+}
+
+#ifdef RT_USING_USERSPACE
+/* memory allocation */
+rt_base_t sys_brk(void *addr)
+{
+ return lwp_brk(addr);
+}
+
+void *sys_mmap2(void *addr, size_t length, int prot,
+ int flags, int fd, off_t pgoffset)
+{
+ return lwp_mmap2(addr, length, prot, flags, fd, pgoffset);
+}
+
+int sys_munmap(void *addr, size_t length)
+{
+ return lwp_munmap(addr);
+}
+
+void *sys_mremap(void *old_address, size_t old_size,
+ size_t new_size, int flags, void *new_address)
+{
+ return (void *)-1;
+}
+
+int sys_madvise(void *addr, size_t len, int behav)
+{
+ return -ENOSYS;
+}
+#endif
+
+rt_event_t sys_event_create(const char *name, rt_uint8_t flag)
+{
+ rt_event_t event = rt_event_create(name, flag);
+ if (lwp_user_object_add(lwp_self(), (rt_object_t)event) != 0)
+ {
+ rt_event_delete(event);
+ event = NULL;
+ }
+ return event;
+}
+
+rt_err_t sys_event_delete(rt_event_t event)
+{
+ return lwp_user_object_delete(lwp_self(), (rt_object_t)event);
+}
+
+rt_err_t sys_event_send(rt_event_t event, rt_uint32_t set)
+{
+ return rt_event_send(event, set);
+}
+
+rt_err_t sys_event_recv(rt_event_t event,
+ rt_uint32_t set,
+ rt_uint8_t opt,
+ rt_int32_t timeout,
+ rt_uint32_t *recved)
+{
+ if ((recved != NULL) && !lwp_user_accessable((void *)recved, sizeof(rt_uint32_t *)))
+ {
+ return -EFAULT;
+ }
+ return rt_event_recv(event, set, opt, timeout, recved);
+}
+
+rt_mailbox_t sys_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
+{
+ rt_mailbox_t mb = rt_mb_create(name, size, flag);
+ if (lwp_user_object_add(lwp_self(), (rt_object_t)mb) != 0)
+ {
+ rt_mb_delete(mb);
+ mb = NULL;
+ }
+ return mb;
+}
+
+rt_err_t sys_mb_delete(rt_mailbox_t mb)
+{
+ return lwp_user_object_delete(lwp_self(), (rt_object_t)mb);
+}
+
+rt_err_t sys_mb_send(rt_mailbox_t mb, rt_ubase_t value)
+{
+ return rt_mb_send(mb, value);
+}
+
+rt_err_t sys_mb_send_wait(rt_mailbox_t mb,
+ rt_ubase_t value,
+ rt_int32_t timeout)
+{
+ return rt_mb_send_wait(mb, value, timeout);
+}
+
+rt_err_t sys_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
+{
+ if (!lwp_user_accessable((void *)value, sizeof(rt_ubase_t *)))
+ {
+ return -EFAULT;
+ }
+ return rt_mb_recv(mb, (rt_ubase_t *)value, timeout);
+}
+
+rt_mq_t sys_mq_create(const char *name,
+ rt_size_t msg_size,
+ rt_size_t max_msgs,
+ rt_uint8_t flag)
+{
+ rt_mq_t mq = rt_mq_create(name, msg_size, max_msgs, flag);
+ if (lwp_user_object_add(lwp_self(), (rt_object_t)mq) != 0)
+ {
+ rt_mq_delete(mq);
+ mq = NULL;
+ }
+ return mq;
+}
+
+rt_err_t sys_mq_delete(rt_mq_t mq)
+{
+ return lwp_user_object_delete(lwp_self(), (rt_object_t)mq);
+}
+
+rt_err_t sys_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
+{
+ if (!lwp_user_accessable((void *)buffer, size))
+ {
+ return -EFAULT;
+ }
+ return rt_mq_send(mq, buffer, size);
+}
+
+rt_err_t sys_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size)
+{
+ if (!lwp_user_accessable((void *)buffer, size))
+ {
+ return -EFAULT;
+ }
+ return rt_mq_urgent(mq, buffer, size);
+}
+
+rt_err_t sys_mq_recv(rt_mq_t mq,
+ void *buffer,
+ rt_size_t size,
+ rt_int32_t timeout)
+{
+ if (!lwp_user_accessable((void *)buffer, size))
+ {
+ return -EFAULT;
+ }
+ return rt_mq_recv(mq, buffer, size, timeout);
+}
+
+static void timer_timeout_callback(void *parameter)
+{
+ rt_sem_t sem = (rt_sem_t)parameter;
+ rt_sem_release(sem);
+}
+
+rt_timer_t sys_rt_timer_create(const char *name,
+ void *data,
+ rt_tick_t time,
+ rt_uint8_t flag)
+{
+ rt_timer_t timer = rt_timer_create(name, timer_timeout_callback, (void *)data, time, flag);
+ if (lwp_user_object_add(lwp_self(), (rt_object_t)timer) != 0)
+ {
+ rt_timer_delete(timer);
+ timer = NULL;
+ }
+ return timer;
+}
+
+rt_err_t sys_rt_timer_delete(rt_timer_t timer)
+{
+ return lwp_user_object_delete(lwp_self(), (rt_object_t)timer);
+}
+
+rt_err_t sys_rt_timer_start(rt_timer_t timer)
+{
+ return rt_timer_start(timer);
+}
+
+rt_err_t sys_rt_timer_stop(rt_timer_t timer)
+{
+ return rt_timer_stop(timer);
+}
+
+rt_err_t sys_rt_timer_control(rt_timer_t timer, int cmd, void *arg)
+{
+ return rt_timer_control(timer, cmd, arg);
+}
+
+rt_err_t sys_timer_create(clockid_t clockid, struct sigevent *restrict sevp, timer_t *restrict timerid)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+ struct sigevent sevp_k;
+ timer_t timerid_k;
+ struct sigevent evp_default;
+ if (sevp == NULL)
+ {
+ sevp_k.sigev_notify = SIGEV_SIGNAL;
+ sevp_k.sigev_signo = SIGALRM;
+ sevp = &sevp_k;
+ }
+ else
+ lwp_get_from_user(&sevp_k, (void *)sevp, sizeof sevp_k);
+ lwp_get_from_user(&timerid_k, (void *)timerid, sizeof timerid_k);
+ ret = timer_create(clockid, &sevp_k, &timerid_k);
+ if (ret != -RT_ERROR){
+ lwp_put_to_user(sevp, (void *)&sevp_k, sizeof sevp_k);
+ lwp_put_to_user(timerid, (void *)&timerid_k, sizeof timerid_k);
+ }
+#else
+ ret = timer_create(clockid, sevp, timerid);
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+rt_err_t sys_timer_delete(timer_t timerid)
+{
+ int ret = timer_delete(timerid);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+rt_err_t sys_timer_settime(timer_t timerid, int flags,
+ const struct itimerspec *restrict new_value,
+ struct itimerspec *restrict old_value)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+ struct itimerspec new_value_k;
+ struct itimerspec old_value_k;
+
+ lwp_get_from_user(&new_value_k, (void *)new_value, sizeof new_value_k);
+ lwp_get_from_user(&old_value_k, (void *)timerid, sizeof old_value_k);
+ ret = timer_settime(timerid, flags, &new_value_k, &old_value_k);
+ lwp_put_to_user(old_value, (void *)&old_value_k, sizeof old_value_k);
+
+#else
+ ret = timer_settime(timerid, flags, new_value, old_value);
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+rt_err_t sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+
+ struct itimerspec curr_value_k;
+ lwp_get_from_user(&curr_value_k, (void *)curr_value, sizeof curr_value_k);
+ ret = timer_gettime(timerid, &curr_value_k);
+ lwp_put_to_user(curr_value, (void *)&curr_value_k, sizeof curr_value_k);
+#else
+ ret = timer_gettime(timerid, curr_value);
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+rt_err_t sys_timer_getoverrun(timer_t timerid)
+{
+ int ret = 0;
+ ret = timer_getoverrun(timerid);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+rt_thread_t sys_thread_create(void *arg[])
+{
+ rt_base_t level = 0;
+ void *user_stack = 0;
+ struct rt_lwp *lwp = 0;
+ rt_thread_t thread = RT_NULL;
+ int tid = 0;
+
+ lwp = rt_thread_self()->lwp;
+ lwp_ref_inc(lwp);
+#ifdef RT_USING_USERSPACE
+ user_stack = lwp_map_user(lwp, 0, (size_t)arg[3], 0);
+ if (!user_stack)
+ {
+ goto fail;
+ }
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ goto fail;
+ }
+ thread = rt_thread_create((const char *)arg[0],
+ _crt_thread_entry,
+ (void *)arg[2],
+ ALLOC_KERNEL_STACK_SIZE,
+ (rt_uint8_t)(size_t)arg[4],
+ (rt_uint32_t)(rt_size_t)arg[5]);
+ if (!thread)
+ {
+ goto fail;
+ }
+
+#ifdef RT_USING_SMP
+ thread->bind_cpu = lwp->bind_cpu;
+#endif
+ thread->cleanup = lwp_cleanup;
+ thread->user_entry = (void (*)(void *))arg[1];
+ thread->user_stack = (void *)user_stack;
+ thread->user_stack_size = (rt_size_t)arg[3];
+#else
+ rt_uint32_t kstack_size = (rt_uint32_t)arg[7];
+ if (kstack_size < ALLOC_KERNEL_STACK_SIZE_MIN)
+ {
+ /* When kstack size is 0, the default size of the kernel stack is used */
+ kstack_size = kstack_size ? ALLOC_KERNEL_STACK_SIZE_MIN : ALLOC_KERNEL_STACK_SIZE;
+ }
+ else if (kstack_size > ALLOC_KERNEL_STACK_SIZE_MAX)
+ {
+ kstack_size = ALLOC_KERNEL_STACK_SIZE_MAX;
+ }
+
+ user_stack = (void *)arg[3];
+ if ((!user_stack) || ((rt_uint32_t)arg[6] == RT_NULL))
+ {
+ goto fail;
+ }
+
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ goto fail;
+ }
+
+ thread = rt_thread_create((const char *)arg[0], _crt_thread_entry, (void *)arg[2], kstack_size, (rt_uint8_t)(size_t)arg[5], (rt_uint32_t)arg[6]);
+ if (!thread)
+ {
+ goto fail;
+ }
+ thread->cleanup = lwp_cleanup;
+ thread->user_entry = (void (*)(void *))arg[1];
+ thread->user_stack = (void *)user_stack;
+ thread->user_stack_size = (uint32_t)arg[4];
+ rt_memset(thread->user_stack, '#', thread->user_stack_size);
+#endif /* RT_USING_USERSPACE */
+
+ thread->lwp = (void*)lwp;
+ thread->tid = tid;
+ lwp_tid_set_thread(tid, thread);
+
+ if (lwp->debug)
+ {
+ rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
+ }
+
+ level = rt_hw_interrupt_disable();
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+ rt_hw_interrupt_enable(level);
+
+ return thread;
+
+fail:
+ lwp_tid_put(tid);
+ if (lwp)
+ {
+ lwp_ref_dec(lwp);
+ }
+ return RT_NULL;
+}
+#ifdef ARCH_MM_MMU
+#define CLONE_VM 0x00000100
+#define CLONE_FS 0x00000200
+#define CLONE_FILES 0x00000400
+#define CLONE_SIGHAND 0x00000800
+#define CLONE_PTRACE 0x00002000
+#define CLONE_VFORK 0x00004000
+#define CLONE_PARENT 0x00008000
+#define CLONE_THREAD 0x00010000
+#define CLONE_NEWNS 0x00020000
+#define CLONE_SYSVSEM 0x00040000
+#define CLONE_SETTLS 0x00080000
+#define CLONE_PARENT_SETTID 0x00100000
+#define CLONE_CHILD_CLEARTID 0x00200000
+#define CLONE_DETACHED 0x00400000
+#define CLONE_UNTRACED 0x00800000
+#define CLONE_CHILD_SETTID 0x01000000
+#define CLONE_NEWCGROUP 0x02000000
+#define CLONE_NEWUTS 0x04000000
+#define CLONE_NEWIPC 0x08000000
+#define CLONE_NEWUSER 0x10000000
+#define CLONE_NEWPID 0x20000000
+#define CLONE_NEWNET 0x40000000
+#define CLONE_IO 0x80000000
+
+/* arg[] -> flags
+ * stack
+ * new_tid
+ * tls
+ * set_clear_tid_address
+ * quit_func
+ * start_args
+ * */
+#define SYS_CLONE_ARGS_NR 7
+
+long _sys_clone(void *arg[])
+{
+ rt_base_t level = 0;
+ struct rt_lwp *lwp = 0;
+ rt_thread_t thread = RT_NULL;
+ rt_thread_t self = RT_NULL;
+ int tid = 0;
+
+ unsigned long flags = 0;
+ void *user_stack = RT_NULL;
+ int *new_tid = RT_NULL;
+ void *tls = RT_NULL;
+ /*
+ musl call flags (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
+ | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
+ | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED);
+ */
+
+ /* check args */
+ if (!lwp_user_accessable(arg, sizeof(void *[SYS_CLONE_ARGS_NR])))
+ {
+ return -EFAULT;
+ }
+
+ flags = (unsigned long)(size_t)arg[0];
+ if ((flags & (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
+ != (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
+ {
+ return -EINVAL;
+ }
+
+ user_stack = arg[1];
+ new_tid = (int *)arg[2];
+ tls = (void *)arg[3];
+
+ if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
+ {
+ if (!lwp_user_accessable(new_tid, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ }
+
+ self = rt_thread_self();
+ lwp = self->lwp;
+ lwp_ref_inc(lwp);
+ if (!user_stack)
+ {
+ SET_ERRNO(EINVAL);
+ goto fail;
+ }
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ thread = rt_thread_create(self->name,
+ RT_NULL,
+ RT_NULL,
+ self->stack_size,
+ self->init_priority,
+ self->init_tick);
+ if (!thread)
+ {
+ goto fail;
+ }
+
+#ifdef RT_USING_SMP
+ thread->bind_cpu = lwp->bind_cpu;
+#endif
+ thread->cleanup = lwp_cleanup;
+ thread->user_entry = RT_NULL;
+ thread->user_stack = RT_NULL;
+ thread->user_stack_size = 0;
+ thread->lwp = (void *)lwp;
+ thread->tid = tid;
+
+ if ((flags & CLONE_SETTLS) == CLONE_SETTLS)
+ {
+ thread->thread_idr = tls;
+ }
+ if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
+ {
+ *new_tid = (int)(tid);
+ }
+ if ((flags & CLONE_CHILD_CLEARTID) == CLONE_CHILD_CLEARTID)
+ {
+ thread->clear_child_tid = (int *)arg[4];
+ }
+
+ if (lwp->debug)
+ {
+ rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
+ }
+
+ level = rt_hw_interrupt_disable();
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+ rt_hw_interrupt_enable(level);
+
+ /* copy origin stack */
+ rt_memcpy(thread->stack_addr, self->stack_addr, thread->stack_size);
+ lwp_tid_set_thread(tid, thread);
+ arch_set_thread_context(arch_clone_exit,
+ (void *)((char *)thread->stack_addr + thread->stack_size),
+ user_stack, &thread->sp);
+ /* new thread never reach there */
+ rt_thread_startup(thread);
+ return (long)tid;
+fail:
+ lwp_tid_put(tid);
+ if (lwp)
+ {
+ lwp_ref_dec(lwp);
+ }
+ return GET_ERRNO();
+}
+
+RT_WEAK long sys_clone(void *arg[])
+{
+ return _sys_clone(arg);
+}
+
+int lwp_dup_user(struct lwp_avl_struct* ptree, void *arg);
+
+static int _copy_process(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp)
+{
+ return lwp_avl_traversal(src_lwp->map_area, lwp_dup_user, dest_lwp);
+}
+
+static void lwp_struct_copy(struct rt_lwp *dst, struct rt_lwp *src)
+{
+#ifdef RT_USING_USERSPACE
+ dst->end_heap = src->end_heap;
+#endif
+ dst->lwp_type = src->lwp_type;
+ dst->text_entry = src->text_entry;
+ dst->text_size = src->text_size;
+ dst->data_entry = src->data_entry;
+ dst->data_size = src->data_size;
+ dst->args = src->args;
+ dst->leader = 0;
+ dst->session = src->session;
+ dst->tty_old_pgrp = 0;
+ dst->__pgrp = src->__pgrp;
+ dst->tty = src->tty;
+ rt_memcpy(dst->cmd, src->cmd, RT_NAME_MAX);
+
+ dst->sa_flags = src->sa_flags;
+ dst->signal_mask = src->signal_mask;
+ rt_memcpy(dst->signal_handler, src->signal_handler, sizeof dst->signal_handler);
+}
+
+static int lwp_copy_files(struct rt_lwp *dst, struct rt_lwp *src)
+{
+ struct dfs_fdtable *dst_fdt;
+ struct dfs_fdtable *src_fdt;
+
+ src_fdt = &src->fdt;
+ dst_fdt = &dst->fdt;
+ /* init fds */
+ dst_fdt->fds = rt_calloc(src_fdt->maxfd, sizeof(void *));
+ if (dst_fdt->fds)
+ {
+ struct dfs_fd *d_s;
+ int i;
+
+ dst_fdt->maxfd = src_fdt->maxfd;
+
+ dfs_fd_lock();
+ /* dup files */
+ for (i = 0; i < src_fdt->maxfd; i++)
+ {
+ d_s = fdt_fd_get(src_fdt, i);
+ if (d_s)
+ {
+ dst_fdt->fds[i] = d_s;
+ d_s->ref_count++;
+ }
+ }
+ dfs_fd_unlock();
+ return 0;
+ }
+ return -RT_ERROR;
+}
+
+int _sys_fork(void)
+{
+ rt_base_t level;
+ int tid = 0;
+ struct rt_lwp *lwp = RT_NULL;
+ struct rt_lwp *self_lwp = RT_NULL;
+ rt_thread_t thread = RT_NULL;
+ rt_thread_t self_thread = RT_NULL;
+ void *user_stack = RT_NULL;
+
+ /* new lwp */
+ lwp = lwp_new();
+ if (!lwp)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* new tid */
+ if ((tid = lwp_tid_get()) == 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* user space init */
+ if (lwp_user_space_init(lwp) != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ self_lwp = lwp_self();
+
+ /* copy process */
+ if (_copy_process(lwp, self_lwp) != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* copy lwp struct data */
+ lwp_struct_copy(lwp, self_lwp);
+
+ /* copy files */
+ if (lwp_copy_files(lwp, self_lwp) != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto fail;
+ }
+
+ /* create thread */
+ self_thread = rt_thread_self();
+
+ thread = rt_thread_create(self_thread->name,
+ RT_NULL,
+ RT_NULL,
+ self_thread->stack_size,
+ self_thread->init_priority,
+ self_thread->init_tick);
+ if (!thread)
+ {
+ goto fail;
+ }
+
+ thread->cleanup = self_thread->cleanup;
+ thread->user_entry = self_thread->user_entry;
+ thread->user_stack = self_thread->user_stack;
+ thread->user_stack_size = self_thread->user_stack_size;
+ thread->signal_mask = self_thread->signal_mask;
+ thread->thread_idr = self_thread->thread_idr;
+ thread->lwp = (void *)lwp;
+ thread->tid = tid;
+
+ level = rt_hw_interrupt_disable();
+
+ /* add thread to lwp process */
+ rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+
+ /* lwp add to children link */
+ lwp->sibling = self_lwp->first_child;
+ self_lwp->first_child = lwp;
+ lwp->parent = self_lwp;
+
+ rt_hw_interrupt_enable(level);
+
+ /* copy origin stack */
+ rt_memcpy(thread->stack_addr, self_thread->stack_addr, self_thread->stack_size);
+ lwp_tid_set_thread(tid, thread);
+
+ /* duplicate user objects */
+ lwp_user_object_dup(lwp, self_lwp);
+
+ level = rt_hw_interrupt_disable();
+ user_stack = arch_get_user_sp();
+ rt_hw_interrupt_enable(level);
+
+ arch_set_thread_context(arch_fork_exit,
+ (void *)((char *)thread->stack_addr + thread->stack_size),
+ user_stack, &thread->sp);
+ /* new thread never reach there */
+ level = rt_hw_interrupt_disable();
+ if (lwp->tty != RT_NULL)
+ {
+ int ret;
+ struct rt_lwp *old_lwp;
+
+ old_lwp = lwp->tty->foreground;
+ rt_mutex_take(&lwp->tty->lock, RT_WAITING_FOREVER);
+ ret = tty_push(&lwp->tty->head, old_lwp);
+ rt_mutex_release(&lwp->tty->lock);
+ if (ret < 0)
+ {
+ LOG_E("malloc fail!\n");
+ goto fail;
+ }
+
+ lwp->tty->foreground = lwp;
+ }
+ rt_hw_interrupt_enable(level);
+ rt_thread_startup(thread);
+ return lwp_to_pid(lwp);
+fail:
+ if (tid != 0)
+ {
+ lwp_tid_put(tid);
+ }
+ if (lwp)
+ {
+ lwp_ref_dec(lwp);
+ }
+ return GET_ERRNO();
+}
+
+size_t lwp_user_strlen(const char *s, int *err)
+{
+ size_t len = 0;
+
+ while (1)
+ {
+ if (!lwp_user_accessable((void *)(s + len), sizeof(char)))
+ {
+ if (err)
+ {
+ *err = 1;
+ }
+ return 0;
+ }
+ if (s[len] == '\0')
+ {
+ if (err)
+ {
+ *err = 0;
+ }
+ return len;
+ }
+ len++;
+ }
+}
+
+/* arm needs to wrap fork/clone call to preserved lr & caller saved regs */
+
+RT_WEAK int sys_fork(void)
+{
+ return _sys_fork();
+}
+
+RT_WEAK int sys_vfork(void)
+{
+ return sys_fork();
+}
+
+struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp);
+int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux);
+void lwp_user_obj_free(struct rt_lwp *lwp);
+
+#define _swap_lwp_data(lwp_used, lwp_new, type, member) \
+ do {\
+ type tmp;\
+ tmp = lwp_used->member;\
+ lwp_used->member = lwp_new->member;\
+ lwp_new->member = tmp;\
+ } while (0)
+
+static char *_insert_args(int new_argc, char *new_argv[], struct lwp_args_info *args)
+{
+ void *page = NULL;
+ int err = 0;
+ char **nargv;
+ char **nenvp;
+ char *p;
+ int i, len;
+ int nsize;
+
+ if (new_argc == 0)
+ {
+ goto quit;
+ }
+ page = rt_pages_alloc(0); /* 1 page */
+ if (!page)
+ {
+ goto quit;
+ }
+
+ nsize = new_argc * sizeof(char *);
+ for (i = 0; i < new_argc; i++)
+ {
+ nsize += rt_strlen(new_argv[i]) + 1;
+ }
+ if (nsize + args->size > ARCH_PAGE_SIZE)
+ {
+ err = 1;
+ goto quit;
+ }
+ nargv = (char **)page;
+ nenvp = nargv + args->argc + new_argc + 1;
+ p = (char *)(nenvp + args->envc + 1);
+ /* insert argv */
+ for (i = 0; i < new_argc; i++)
+ {
+ nargv[i] = p;
+ len = rt_strlen(new_argv[i]) + 1;
+ rt_memcpy(p, new_argv[i], len);
+ p += len;
+ }
+ /* copy argv */
+ nargv += new_argc;
+ for (i = 0; i < args->argc; i++)
+ {
+ nargv[i] = p;
+ len = rt_strlen(args->argv[i]) + 1;
+ rt_memcpy(p, args->argv[i], len);
+ p += len;
+ }
+ nargv[i] = NULL;
+ /* copy envp */
+ for (i = 0; i < args->envc; i++)
+ {
+ nenvp[i] = p;
+ len = rt_strlen(args->envp[i]) + 1;
+ rt_memcpy(p, args->envp[i], len);
+ p += len;
+ }
+ nenvp[i] = NULL;
+
+ /* update args */
+ args->argv = (char **)page;
+ args->argc = args->argc + new_argc;
+ args->envp = args->argv + args->argc + 1;
+ /* args->envc no change */
+ args->size = args->size + nsize;
+
+quit:
+ if (err && page)
+ {
+ rt_pages_free(page, 0);
+ page = NULL;
+ }
+ return page;
+}
+
+#define INTERP_BUF_SIZE 128
+static char *_load_script(const char *filename, struct lwp_args_info *args)
+{
+ void *page = NULL;
+ char *new_page;
+ int fd = -RT_ERROR;
+ int len;
+ char interp[INTERP_BUF_SIZE];
+ char *cp;
+ char *i_name;
+ char *i_arg;
+
+ fd = open(filename, O_BINARY | O_RDONLY, 0);
+ if (fd < 0)
+ {
+ goto quit;
+ }
+ len = read(fd, interp, INTERP_BUF_SIZE);
+ if (len < 2)
+ {
+ goto quit;
+ }
+
+ if ((interp[0] != '#') || (interp[1] != '!'))
+ {
+ goto quit;
+ }
+
+ if (len == INTERP_BUF_SIZE)
+ {
+ len--;
+ }
+ interp[len] = '\0';
+
+ if ((cp = strchr(interp, '\n')) == NULL)
+ {
+ cp = interp + INTERP_BUF_SIZE - 1;
+ }
+ *cp = '\0';
+ while (cp > interp)
+ {
+ cp--;
+ if ((*cp == ' ') || (*cp == '\t'))
+ {
+ *cp = '\0';
+ }
+ else
+ {
+ break;
+ }
+ }
+ for (cp = interp + 2; (*cp == ' ') || (*cp == '\t'); cp++)
+ {
+ /* nothing */
+ }
+ if (*cp == '\0')
+ {
+ goto quit; /* No interpreter name found */
+ }
+ i_name = cp;
+ i_arg = NULL;
+ for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
+ {
+ /* nothing */
+ }
+ while ((*cp == ' ') || (*cp == '\t'))
+ {
+ *cp++ = '\0';
+ }
+ if (*cp)
+ {
+ i_arg = cp;
+ }
+
+ if (i_arg)
+ {
+ new_page = _insert_args(1, &i_arg, args);
+ rt_pages_free(page, 0);
+ page = new_page;
+ if (!page)
+ {
+ goto quit;
+ }
+ }
+ new_page = _insert_args(1, &i_name, args);
+ rt_pages_free(page, 0);
+ page = new_page;
+
+quit:
+ if (fd >= 0)
+ {
+ close(fd);
+ }
+ return page;
+}
+
+int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[])
+{
+ int ret = -1;
+ int i;
+ void *page;
+ void *new_page;
+ int argc = 0;
+ int envc = 0;
+ int size;
+ char **kargv;
+ char **kenvp;
+ size_t len;
+ char *p;
+ char *i_arg;
+ struct lwp_args_info args_info;
+ struct process_aux *aux;
+
+ size = sizeof(char *);
+ if (argv)
+ {
+ while (1)
+ {
+ if (!argv[argc])
+ {
+ break;
+ }
+ len = rt_strlen((const char *)argv[argc]);
+ size += sizeof(char *) + len + 1;
+ argc++;
+ }
+ }
+ if (envp)
+ {
+ while (1)
+ {
+ if (!envp[envc])
+ {
+ break;
+ }
+ len = rt_strlen((const char *)envp[envc]);
+ size += sizeof(char *) + len + 1;
+ envc++;
+ }
+ }
+
+ page = rt_pages_alloc(0); /* 1 page */
+ if (!page)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+ kargv = (char **)page;
+ kenvp = kargv + argc + 1;
+ p = (char *)(kenvp + envc + 1);
+ /* copy argv */
+ if (argv)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ kargv[i] = p;
+ len = rt_strlen(argv[i]) + 1;
+ rt_memcpy(p, argv[i], len);
+ p += len;
+ }
+ kargv[i] = NULL;
+ }
+ /* copy envp */
+ if (envp)
+ {
+ for (i = 0; i < envc; i++)
+ {
+ kenvp[i] = p;
+ len = rt_strlen(envp[i]) + 1;
+ rt_memcpy(p, envp[i], len);
+ p += len;
+ }
+ kenvp[i] = NULL;
+ }
+
+ args_info.argc = argc;
+ args_info.argv = kargv;
+ args_info.envc = envc;
+ args_info.envp = kenvp;
+ args_info.size = size;
+
+ new_page = _insert_args(1, &exec_name, &args_info);
+ rt_pages_free(page, 0);
+ page = new_page;
+ if (!page)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+
+ i_arg = "-e";
+ new_page = _insert_args(1, &i_arg, &args_info);
+ rt_pages_free(page, 0);
+ page = new_page;
+ if (!page)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+
+ i_arg = "ld.so";
+ new_page = _insert_args(1, &i_arg, &args_info);
+ rt_pages_free(page, 0);
+ page = new_page;
+ if (!page)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+
+ if ((aux = lwp_argscopy(lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+
+ ret = lwp_load("/lib/ld.so", lwp, RT_NULL, 0, aux);
+
+ rt_strncpy(lwp->cmd, exec_name, RT_NAME_MAX);
+quit:
+ if (page)
+ {
+ rt_pages_free(page, 0);
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_execve(const char *path, char *const argv[], char *const envp[])
+{
+ int ret = -1;
+ int argc = 0;
+ int envc = 0;
+ void *page = NULL;
+ void *new_page;
+ int size = 0;
+ size_t len;
+ int access_err;
+ char **kargv;
+ char **kenvp;
+ char *p;
+ struct rt_lwp *new_lwp = NULL;
+ struct rt_lwp *lwp;
+ rt_base_t level;
+ int uni_thread;
+ rt_thread_t thread;
+ struct process_aux *aux;
+ int i;
+ struct lwp_args_info args_info;
+
+ lwp = lwp_self();
+ thread = rt_thread_self();
+ uni_thread = 1;
+ level = rt_hw_interrupt_disable();
+ if (lwp->t_grp.prev != &thread->sibling)
+ {
+ uni_thread = 0;
+ }
+ if (lwp->t_grp.next != &thread->sibling)
+ {
+ uni_thread = 0;
+ }
+ rt_hw_interrupt_enable(level);
+ if (!uni_thread)
+ {
+ SET_ERRNO(EINVAL);
+ goto quit;
+ }
+
+ len = lwp_user_strlen(path, &access_err);
+ if (access_err)
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+
+ size += sizeof(char *);
+ if (argv)
+ {
+ while (1)
+ {
+ if (!lwp_user_accessable((void *)(argv + argc), sizeof(char *)))
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ if (!argv[argc])
+ {
+ break;
+ }
+ len = lwp_user_strlen((const char *)argv[argc], &access_err);
+ if (access_err)
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ size += sizeof(char *) + len + 1;
+ argc++;
+ }
+ }
+ size += sizeof(char *);
+ if (envp)
+ {
+ while (1)
+ {
+ if (!lwp_user_accessable((void *)(envp + envc), sizeof(char *)))
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ if (!envp[envc])
+ {
+ break;
+ }
+ len = lwp_user_strlen((const char *)envp[envc], &access_err);
+ if (access_err)
+ {
+ SET_ERRNO(EFAULT);
+ goto quit;
+ }
+ size += sizeof(char *) + len + 1;
+ envc++;
+ }
+ }
+ if (size > ARCH_PAGE_SIZE)
+ {
+ SET_ERRNO(EINVAL);
+ goto quit;
+ }
+ page = rt_pages_alloc(0); /* 1 page */
+ if (!page)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+
+ kargv = (char **)page;
+ kenvp = kargv + argc + 1;
+ p = (char *)(kenvp + envc + 1);
+ /* copy argv */
+ if (argv)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ kargv[i] = p;
+ len = rt_strlen(argv[i]) + 1;
+ rt_memcpy(p, argv[i], len);
+ p += len;
+ }
+ kargv[i] = NULL;
+ }
+ /* copy envp */
+ if (envp)
+ {
+ for (i = 0; i < envc; i++)
+ {
+ kenvp[i] = p;
+ len = rt_strlen(envp[i]) + 1;
+ rt_memcpy(p, envp[i], len);
+ p += len;
+ }
+ kenvp[i] = NULL;
+ }
+
+ /* alloc new lwp to operation */
+ new_lwp = (struct rt_lwp *)rt_malloc(sizeof(struct rt_lwp));
+ if (!new_lwp)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+ rt_memset(new_lwp, 0, sizeof(struct rt_lwp));
+ new_lwp->ref = 1;
+ lwp_user_object_lock_init(new_lwp);
+ ret = arch_user_space_init(new_lwp);
+ if (ret != 0)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+ /* file is a script ? */
+ args_info.argc = argc;
+ args_info.argv = kargv;
+ args_info.envc = envc;
+ args_info.envp = kenvp;
+ args_info.size = size;
+ while (1)
+ {
+ new_page = _load_script(path, &args_info);
+ if (!new_page)
+ {
+ break;
+ }
+ rt_pages_free(page, 0);
+ page = new_page;
+ path = args_info.argv[0];
+ }
+
+ /* now load elf */
+ if ((aux = lwp_argscopy(new_lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL)
+ {
+ SET_ERRNO(ENOMEM);
+ goto quit;
+ }
+ ret = lwp_load(path, new_lwp, RT_NULL, 0, aux);
+ if (ret == 1)
+ {
+ /* dynamic */
+ lwp_unmap_user(new_lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE));
+ ret = load_ldso(new_lwp, (char *)path, args_info.argv, args_info.envp);
+ }
+ if (ret == RT_EOK)
+ {
+ int off = 0;
+ int last_backslash = 0;
+ char *run_name = args_info.argv[0];
+
+ /* clear all user objects */
+ lwp_user_object_clear(lwp);
+
+ /* find last \ or / */
+ while (1)
+ {
+ char c = run_name[off++];
+
+ if (c == '\0')
+ {
+ break;
+ }
+ if (c == '\\' || c == '/')
+ {
+ last_backslash = off;
+ }
+ }
+
+ /* load ok, now set thread name and swap the data of lwp and new_lwp */
+ level = rt_hw_interrupt_disable();
+
+ rt_strncpy(thread->name, run_name + last_backslash, RT_NAME_MAX);
+
+ rt_pages_free(page, 0);
+
+#ifdef RT_USING_USERSPACE
+ _swap_lwp_data(lwp, new_lwp, rt_mmu_info, mmu_info);
+ _swap_lwp_data(lwp, new_lwp, struct lwp_avl_struct *, map_area);
+ _swap_lwp_data(lwp, new_lwp, size_t, end_heap);
+#endif
+ _swap_lwp_data(lwp, new_lwp, uint8_t, lwp_type);
+ _swap_lwp_data(lwp, new_lwp, void *, text_entry);
+ _swap_lwp_data(lwp, new_lwp, uint32_t, text_size);
+ _swap_lwp_data(lwp, new_lwp, void *, data_entry);
+ _swap_lwp_data(lwp, new_lwp, uint32_t, data_size);
+
+ _swap_lwp_data(lwp, new_lwp, void *, args);
+
+ rt_memset(&thread->signal_mask, 0, sizeof(thread->signal_mask));
+ rt_memset(&thread->signal_mask_bak, 0, sizeof(thread->signal_mask_bak));
+ lwp->sa_flags = 0;
+ rt_memset(&lwp->signal_mask, 0, sizeof(lwp->signal_mask));
+ rt_memset(&lwp->signal_mask_bak, 0, sizeof(lwp->signal_mask_bak));
+ rt_memset(lwp->signal_handler, 0, sizeof(lwp->signal_handler));
+
+ /* to do: clsoe files with flag CLOEXEC */
+
+ lwp_mmu_switch(thread);
+
+ rt_hw_interrupt_enable(level);
+
+ lwp_ref_dec(new_lwp);
+ arch_start_umode(lwp->args,
+ lwp->text_entry,
+ (void*)USER_STACK_VEND,
+ thread->stack_addr + thread->stack_size);
+ /* never reach here */
+ }
+ return -EINVAL;
+quit:
+ if (page)
+ {
+ rt_pages_free(page, 0);
+ }
+ if (new_lwp)
+ {
+ lwp_ref_dec(new_lwp);
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+#endif /* ARCH_MM_MMU */
+
+rt_err_t sys_thread_delete(rt_thread_t thread)
+{
+#ifdef ARCH_MM_MMU
+ return rt_thread_delete(thread);
+#else
+ rt_err_t ret = 0;
+
+ if(thread->type != RT_Object_Class_Thread)
+ {
+ ret = -EINVAL;
+ goto __exit;
+ }
+
+ ret = rt_thread_delete(thread);
+
+ if (rt_thread_self() == thread)
+ {
+ rt_schedule();
+ }
+
+__exit:
+ return ret;
+#endif
+}
+
+rt_err_t sys_thread_startup(rt_thread_t thread)
+{
+ return rt_thread_startup(thread);
+}
+
+rt_thread_t sys_thread_self(void)
+{
+ return rt_thread_self();
+}
+
+/* sys channel */
+
+int sys_channel_open(const char *name, int flags)
+{
+ return lwp_channel_open(FDT_TYPE_LWP, name, flags);
+}
+
+rt_err_t sys_channel_close(int fd)
+{
+ return lwp_channel_close(FDT_TYPE_LWP, fd);
+}
+
+rt_err_t sys_channel_send(int fd, rt_channel_msg_t data)
+{
+ return lwp_channel_send(FDT_TYPE_LWP, fd, data);
+}
+
+rt_err_t sys_channel_send_recv_timeout(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret, rt_int32_t time)
+{
+ return lwp_channel_send_recv_timeout(FDT_TYPE_LWP, fd, data, data_ret, time);
+}
+
+rt_err_t sys_channel_reply(int fd, rt_channel_msg_t data)
+{
+ return lwp_channel_reply(FDT_TYPE_LWP, fd, data);
+}
+
+rt_err_t sys_channel_recv_timeout(int fd, rt_channel_msg_t data, rt_int32_t time)
+{
+ return lwp_channel_recv_timeout(FDT_TYPE_LWP, fd, data, time);
+}
+
+static struct rt_semaphore critical_lock;
+
+static int critical_init(void)
+{
+ rt_sem_init(&critical_lock, "ct_lock", 1, RT_IPC_FLAG_FIFO);
+ return 0;
+}
+INIT_DEVICE_EXPORT(critical_init);
+
+void sys_enter_critical(void)
+{
+ rt_sem_take(&critical_lock, RT_WAITING_FOREVER);
+}
+
+void sys_exit_critical(void)
+{
+ rt_sem_release(&critical_lock);
}
/* syscall: "sys_log" ret: "int" args: "const char*" "size" */
+static int __sys_log_enable = 0;
+static int sys_log_enable(int argc, char** argv)
+{
+ if (argc == 1)
+ {
+ rt_kprintf("sys_log = %d\n", __sys_log_enable);
+ return 0;
+ }
+ else
+ {
+ __sys_log_enable = atoi(argv[1]);
+ }
+
+ return 0;
+}
+MSH_CMD_EXPORT_ALIAS(sys_log_enable, sys_log, sys_log 1(enable)/0(disable));
+
int sys_log(const char* log, int size)
{
rt_device_t console = rt_console_get_device();
- if (console) rt_device_write(console, -1, log, size);
+ if (console && __sys_log_enable)
+ {
+ rt_device_write(console, -1, log, size);
+ }
return 0;
}
-void *sys_malloc(size_t size)
+int sys_stat(const char *file, struct stat *buf)
+{
+ int ret = 0;
+ ret = stat(file, buf);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_notimpl(void)
{
- return rt_lwp_mem_malloc(size);
+ return -ENOSYS;
}
-void sys_free(void *addr)
+uint32_t sys_hw_interrupt_disable(void)
{
- rt_lwp_mem_free(addr);
+ return rt_hw_interrupt_disable();
}
-void *sys_realloc(void *rmem, size_t newsize)
+void sys_hw_interrupt_enable(uint32_t level)
{
- return rt_lwp_mem_realloc(rmem, newsize);
+ rt_hw_interrupt_enable(level);
}
-int sys_fstat(int file, struct stat *buf)
+#ifdef RT_USING_USERSPACE
+int sys_shmget(size_t key, size_t size, int create)
{
- return fstat(file, buf);
+ return lwp_shmget(key, size, create);
}
-int sys_notimpl(void)
+int sys_shmrm(int id)
+{
+ return lwp_shmrm(id);
+}
+
+void* sys_shmat(int id, void* shm_vaddr)
+{
+ return lwp_shmat(id, shm_vaddr);
+}
+
+int sys_shmdt(void* shm_vaddr)
+{
+ return lwp_shmdt(shm_vaddr);
+}
+#elif defined RT_LWP_USING_SHM
+void *sys_shm_alloc(int size)
+{
+ if (size < 0)
+ {
+ return RT_NULL;
+ }
+ return lwp_shm_alloc((rt_size_t)size);
+}
+
+void *sys_shm_retain(void *mem)
+{
+ if (!lwp_user_accessable(mem, sizeof (void *)))
+ {
+ return RT_NULL;
+ }
+ return lwp_shm_retain(mem);
+}
+
+int sys_shm_free(void *mem)
+{
+ if (!lwp_user_accessable(mem, sizeof (void *)))
+ {
+ return -EFAULT;
+ }
+ lwp_shm_free(mem);
+ return 0;
+}
+#endif
+
+/* device interfaces */
+rt_err_t sys_device_init(rt_device_t dev)
+{
+ return rt_device_init(dev);
+}
+
+rt_err_t sys_device_register(rt_device_t dev, const char *name, rt_uint16_t flags)
+{
+ return rt_device_register(dev, name, flags);
+}
+
+rt_err_t sys_device_control(rt_device_t dev, int cmd, void *arg)
+{
+ return rt_device_control(dev, cmd, arg);
+}
+
+rt_device_t sys_device_find(const char* name)
+{
+ return rt_device_find(name);
+}
+
+rt_err_t sys_device_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ return rt_device_open(dev, oflag);
+}
+
+rt_err_t sys_device_close(rt_device_t dev)
+{
+ return rt_device_close(dev);
+}
+
+rt_size_t sys_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ return rt_device_read(dev, pos, buffer, size);
+}
+
+rt_size_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ return rt_device_write(dev, pos, buffer, size);
+}
+
+#ifdef RT_USING_SAL
+/* network interfaces */
+int sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
+{
+ int ret = -1;
+ struct sockaddr ksa;
+ struct musl_sockaddr kmusladdr;
+ socklen_t uaddrlen;
+ socklen_t kaddrlen;
+
+ if (addr)
+ {
+ if (!lwp_user_accessable(addrlen, sizeof (socklen_t)))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&uaddrlen, addrlen, sizeof (socklen_t));
+ if (!uaddrlen)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable(addr, uaddrlen))
+ {
+ return -EFAULT;
+ }
+ }
+
+ kaddrlen = sizeof(struct sockaddr);
+ ret = accept(socket, &ksa, &kaddrlen);
+ if (ret >= 0)
+ {
+ if (addr)
+ {
+ sockaddr_tomusl(&ksa, &kmusladdr);
+ if (uaddrlen > sizeof(struct musl_sockaddr))
+ {
+ uaddrlen = sizeof(struct musl_sockaddr);
+ }
+ lwp_put_to_user(addr, &kmusladdr, uaddrlen);
+ lwp_put_to_user(addrlen, &uaddrlen, sizeof (socklen_t));
+ }
+ }
+ return ret;
+}
+
+int sys_bind(int socket, const struct musl_sockaddr *name, socklen_t namelen)
+{
+ struct sockaddr sa;
+ struct musl_sockaddr kname;
+
+ if (!lwp_user_accessable((void *)name, namelen))
+ {
+ return -EFAULT;
+ }
+
+#ifdef SAL_USING_AF_UNIX
+ if (name->sa_family == AF_UNIX)
+ {
+ namelen = sizeof(struct sockaddr);
+ }
+#endif /* SAL_USING_AF_UNIX */
+
+ lwp_get_from_user(&kname, (void *)name, namelen);
+
+ sockaddr_tolwip(&kname, &sa);
+
+ return bind(socket, &sa, namelen);
+}
+
+int sys_shutdown(int socket, int how)
+{
+ return shutdown(socket, how);
+}
+
+int sys_getpeername (int socket, struct musl_sockaddr *name, socklen_t *namelen)
+{
+ int ret = -1;
+ struct sockaddr sa;
+ struct musl_sockaddr kname;
+ socklen_t unamelen;
+ socklen_t knamelen;
+
+ if (!lwp_user_accessable(namelen, sizeof (socklen_t *)))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t *));
+ if (!unamelen)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable(name, unamelen))
+ {
+ return -EFAULT;
+ }
+
+ knamelen = sizeof(struct sockaddr);
+ ret = getpeername(socket, &sa, &knamelen);
+
+ if (ret == 0)
+ {
+ sockaddr_tomusl(&sa, &kname);
+ if (unamelen > sizeof(struct musl_sockaddr))
+ {
+ unamelen = sizeof(struct musl_sockaddr);
+ }
+ lwp_put_to_user(name, &kname, unamelen);
+ lwp_put_to_user(namelen, &unamelen, sizeof (socklen_t *));
+ }
+ else
+ {
+ ret = GET_ERRNO();
+ }
+
+ return ret;
+}
+
+int sys_getsockname (int socket, struct musl_sockaddr *name, socklen_t *namelen)
+{
+ int ret = -1;
+ struct sockaddr sa;
+ struct musl_sockaddr kname;
+ socklen_t unamelen;
+ socklen_t knamelen;
+
+ if (!lwp_user_accessable(namelen, sizeof (socklen_t *)))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&unamelen, namelen, sizeof (socklen_t *));
+ if (!unamelen)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable(name, unamelen))
+ {
+ return -EFAULT;
+ }
+
+ knamelen = sizeof(struct sockaddr);
+ ret = getsockname(socket, &sa, &knamelen);
+ if (ret == 0)
+ {
+ sockaddr_tomusl(&sa, &kname);
+ if (unamelen > sizeof(struct musl_sockaddr))
+ {
+ unamelen = sizeof(struct musl_sockaddr);
+ }
+ lwp_put_to_user(name, &kname, unamelen);
+ lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t *));
+ }
+ else
+ {
+ ret = GET_ERRNO();
+ }
+ return ret;
+}
+
+int sys_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen)
+{
+ int ret;
+ convert_sockopt(&level, &optname);
+ ret = getsockopt(socket, level, optname, optval, optlen);
+
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
+{
+ int ret;
+ convert_sockopt(&level, &optname);
+ ret = setsockopt(socket, level, optname, optval, optlen);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_connect(int socket, const struct musl_sockaddr *name, socklen_t namelen)
+{
+ int ret;
+ struct sockaddr sa;
+ struct musl_sockaddr kname;
+
+ if (!lwp_user_accessable((void *)name, namelen))
+ {
+ return -EFAULT;
+ }
+
+#ifdef SAL_USING_AF_UNIX
+ if (name->sa_family == AF_UNIX)
+ {
+ namelen = sizeof(struct sockaddr);
+ }
+#endif /* SAL_USING_AF_UNIX */
+
+ lwp_get_from_user(&kname, (void *)name, namelen);
+
+ sockaddr_tolwip(&kname, &sa);
+
+ ret = connect(socket, &sa, namelen);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_listen(int socket, int backlog)
+{
+ return listen(socket, backlog);
+}
+
+#define MUSLC_MSG_OOB 0x0001
+#define MUSLC_MSG_PEEK 0x0002
+#define MUSLC_MSG_DONTWAIT 0x0040
+#define MUSLC_MSG_WAITALL 0x0100
+#define MUSLC_MSG_MORE 0x8000
+
+static int netflags_muslc_2_lwip(int flags)
+{
+ int flgs = 0;
+
+ if (flags & MUSLC_MSG_PEEK)
+ {
+ flgs |= MSG_PEEK;
+ }
+ if (flags & MUSLC_MSG_WAITALL)
+ {
+ flgs |= MSG_WAITALL;
+ }
+ if (flags & MUSLC_MSG_OOB)
+ {
+ flgs |= MSG_OOB;
+ }
+ if (flags & MUSLC_MSG_DONTWAIT)
+ {
+ flgs |= MSG_DONTWAIT;
+ }
+ if (flags & MUSLC_MSG_MORE)
+ {
+ flgs |= MSG_MORE;
+ }
+ return flgs;
+}
+
+int sys_recvfrom(int socket, void *mem, size_t len, int flags,
+ struct musl_sockaddr *from, socklen_t *fromlen)
+{
+ int flgs = 0;
+#ifdef RT_USING_USERSPACE
+ int ret = -1;
+ void *kmem = RT_NULL;
+#endif
+
+ flgs = netflags_muslc_2_lwip(flags);
+#ifdef RT_USING_USERSPACE
+ if (!len)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable((void *)mem, len))
+ {
+ return -EFAULT;
+ }
+
+ kmem = kmem_get(len);
+ if (!kmem)
+ {
+ return -ENOMEM;
+ }
+
+ if (flags == 0x2)
+ {
+ flags = 0x1;
+ }
+
+ if (from)
+ {
+ struct sockaddr sa;
+
+ ret = recvfrom(socket, kmem, len, flgs, &sa, fromlen);
+ sockaddr_tomusl(&sa, from);
+ }
+ else
+ {
+ ret = recvfrom(socket, kmem, len, flgs, NULL, NULL);
+ }
+
+ if (ret > 0)
+ {
+ lwp_put_to_user(mem, kmem, len);
+ }
+
+ kmem_put(kmem);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ int ret = -1;
+ if (from)
+ {
+ struct sockaddr sa = {0};
+
+ ret = recvfrom(socket, mem, len, flgs, &sa, fromlen);
+ sockaddr_tomusl(&sa, from);
+ }
+ else
+ {
+ ret = recvfrom(socket, mem, len, flags, NULL, NULL);
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+int sys_recv(int socket, void *mem, size_t len, int flags)
+{
+ int flgs = 0;
+ int ret;
+
+ flgs = netflags_muslc_2_lwip(flags);
+ ret = recvfrom(socket, mem, len, flgs, NULL, NULL);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_sendto(int socket, const void *dataptr, size_t size, int flags,
+ const struct musl_sockaddr *to, socklen_t tolen)
+{
+ int flgs = 0;
+#ifdef RT_USING_USERSPACE
+ int ret = -1;
+ void *kmem = RT_NULL;
+#endif
+
+ flgs = netflags_muslc_2_lwip(flags);
+#ifdef RT_USING_USERSPACE
+ if (!size)
+ {
+ return -EINVAL;
+ }
+
+ if (!lwp_user_accessable((void *)dataptr, size))
+ {
+ return -EFAULT;
+ }
+
+ kmem = kmem_get(size);
+ if (!kmem)
+ {
+ return -ENOMEM;
+ }
+
+ lwp_get_from_user(kmem, (void *)dataptr, size);
+
+ if (to)
+ {
+ struct sockaddr sa;
+ sockaddr_tolwip(to, &sa);
+
+ ret = sendto(socket, kmem, size, flgs, &sa, tolen);
+ }
+ else
+ {
+ ret = sendto(socket, kmem, size, flgs, NULL, tolen);
+ }
+
+ kmem_put(kmem);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#else
+ int ret;
+ if (to)
+ {
+ struct sockaddr sa;
+ sockaddr_tolwip(to, &sa);
+
+ ret = sendto(socket, dataptr, size, flgs, &sa, tolen);
+ }
+ else
+ {
+ ret = sendto(socket, dataptr, size, flgs, NULL, tolen);
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+int sys_send(int socket, const void *dataptr, size_t size, int flags)
+{
+ int ret;
+ int flgs = 0;
+
+ flgs = netflags_muslc_2_lwip(flags);
+ ret = sendto(socket, dataptr, size, flgs, NULL, 0);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_socket(int domain, int type, int protocol)
+{
+ int fd = -1;
+ int nonblock = 0;
+ /* not support SOCK_CLOEXEC type */
+ if (type & SOCK_CLOEXEC)
+ {
+ type &= ~SOCK_CLOEXEC;
+ }
+ if (type & SOCK_NONBLOCK)
+ {
+ nonblock = 1;
+ type &= ~SOCK_NONBLOCK;
+ }
+
+ fd = socket(domain, type, protocol);
+ if (fd < 0)
+ {
+ goto out;
+ }
+ if (nonblock)
+ {
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ }
+
+out:
+ return (fd < 0 ? GET_ERRNO() : fd);
+}
+
+int sys_closesocket(int socket)
+{
+ return closesocket(socket);
+}
+
+#endif
+
+rt_thread_t sys_thread_find(char *name)
+{
+ return rt_thread_find(name);
+}
+
+rt_tick_t sys_tick_get(void)
+{
+ return rt_tick_get();
+}
+
+rt_err_t sys_thread_mdelay(rt_int32_t ms)
+{
+ return rt_thread_mdelay(ms);
+}
+
+struct k_sigaction {
+ void (*handler)(int);
+ unsigned long flags;
+ void (*restorer)(void);
+ unsigned mask[2];
+};
+
+int sys_sigaction(int sig, const struct k_sigaction *act,
+ struct k_sigaction *oact, size_t sigsetsize)
+{
+ int ret = -RT_EINVAL;
+ struct lwp_sigaction kact, *pkact = RT_NULL;
+ struct lwp_sigaction koact, *pkoact = RT_NULL;
+
+ if (!sigsetsize)
+ {
+ SET_ERRNO(EINVAL);
+ goto out;
+ }
+ if (sigsetsize > sizeof(lwp_sigset_t))
+ {
+ sigsetsize = sizeof(lwp_sigset_t);
+ }
+ if (!act && !oact)
+ {
+ SET_ERRNO(EINVAL);
+ goto out;
+ }
+ if (oact)
+ {
+ if (!lwp_user_accessable((void *)oact, sizeof(*oact)))
+ {
+ SET_ERRNO(EFAULT);
+ goto out;
+ }
+ pkoact = &koact;
+ }
+ if (act)
+ {
+ if (!lwp_user_accessable((void *)act, sizeof(*act)))
+ {
+ SET_ERRNO(EFAULT);
+ goto out;
+ }
+ kact.sa_flags = act->flags;
+ kact.__sa_handler._sa_handler = act->handler;
+ memcpy(&kact.sa_mask, &act->mask, sigsetsize);
+ kact.sa_restorer = act->restorer;
+ pkact = &kact;
+ }
+
+ ret = lwp_sigaction(sig, pkact, pkoact, sigsetsize);
+#ifdef ARCH_MM_MMU
+ if (ret == 0 && oact)
+ {
+ lwp_put_to_user(&oact->handler, &pkoact->__sa_handler._sa_handler, sizeof(void (*)(int)));
+ lwp_put_to_user(&oact->mask, &pkoact->sa_mask, sigsetsize);
+ lwp_put_to_user(&oact->flags, &pkoact->sa_flags, sizeof(int));
+ lwp_put_to_user(&oact->restorer, &pkoact->sa_restorer, sizeof(void (*)(void)));
+ }
+#endif /* ARCH_MM_MMU */
+out:
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size)
+{
+ int ret = -1;
+ lwp_sigset_t *pnewset = RT_NULL, *poldset = RT_NULL;
+#ifdef ARCH_MM_MMU
+ lwp_sigset_t newset, oldset;
+#endif /* ARCH_MM_MMU*/
+
+ if (!size)
+ {
+ return -EINVAL;
+ }
+ if (!oset && !sigset)
+ {
+ return -EINVAL;
+ }
+ if (size > sizeof(lwp_sigset_t))
+ {
+ size = sizeof(lwp_sigset_t);
+ }
+ if (oset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = &oldset;
+#else
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = (lwp_sigset_t *)oset;
+#endif
+ }
+ if (sigset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&newset, (void *)sigset, size);
+ pnewset = &newset;
+#else
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ pnewset = (lwp_sigset_t *)sigset;
+#endif /* ARCH_MM_MMU */
+ }
+ ret = lwp_sigprocmask(how, pnewset, poldset);
+#ifdef ARCH_MM_MMU
+ if (ret < 0)
+ {
+ return ret;
+ }
+ if (oset)
+ {
+ lwp_put_to_user(oset, poldset, size);
+ }
+#endif /* ARCH_MM_MMU */
+ return (ret < 0 ? -EFAULT: ret);
+}
+
+int sys_tkill(int tid, int sig)
+{
+#ifdef ARCH_MM_MMU
+ rt_base_t level;
+ rt_thread_t thread;
+ int ret;
+
+ level = rt_hw_interrupt_disable();
+ thread = lwp_tid_get_thread(tid);
+ ret = lwp_thread_kill(thread, sig);
+ rt_hw_interrupt_enable(level);
+ return ret;
+#else
+ return lwp_thread_kill((rt_thread_t)tid, sig);
+#endif
+}
+
+int sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset, size_t size)
+{
+ int ret = -1;
+ lwp_sigset_t *pnewset = RT_NULL, *poldset = RT_NULL;
+#ifdef ARCH_MM_MMU
+ lwp_sigset_t newset, oldset;
+#endif /* ARCH_MM_MMU */
+
+ if (!size)
+ {
+ return -EINVAL;
+ }
+ if (!oset && !sigset)
+ {
+ return -EINVAL;
+ }
+ if (size != sizeof(lwp_sigset_t))
+ {
+ return -EINVAL;
+ }
+ if (oset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = &oldset;
+#else
+ if (!lwp_user_accessable((void *)oset, size))
+ {
+ return -EFAULT;
+ }
+ poldset = oset;
+#endif
+ }
+ if (sigset)
+ {
+#ifdef ARCH_MM_MMU
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&newset, (void *)sigset, sizeof(lwp_sigset_t));
+ pnewset = &newset;
+#else
+ if (!lwp_user_accessable((void *)sigset, size))
+ {
+ return -EFAULT;
+ }
+ pnewset = (lwp_sigset_t *)sigset;
+#endif
+ }
+ ret = lwp_thread_sigprocmask(how, pnewset, poldset);
+ if (ret < 0)
+ {
+ return ret;
+ }
+#ifdef ARCH_MM_MMU
+ if (oset)
+ {
+ lwp_put_to_user(oset, poldset, sizeof(lwp_sigset_t));
+ }
+#endif
+ return (ret < 0 ? -EFAULT: ret);
+}
+
+#ifndef ARCH_MM_MMU
+int sys_lwp_sighandler_set(int sig, lwp_sighandler_t func)
+{
+ if (!lwp_user_accessable((void *)func, sizeof(lwp_sighandler_t)))
+ {
+ return -EFAULT;
+ }
+
+ lwp_sighandler_set(sig, func);
+ return 0;
+}
+
+int sys_thread_sighandler_set(int sig, lwp_sighandler_t func)
+{
+ if (!lwp_user_accessable((void *)func, sizeof(lwp_sighandler_t)))
+ {
+ return -EFAULT;
+ }
+
+ lwp_thread_sighandler_set(sig, func);
+ return 0;
+}
+#endif /* not defined ARCH_MM_MMU */
+
+int32_t sys_waitpid(int32_t pid, int *status, int options)
+{
+ int ret = -1;
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)status, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ else
+ {
+ ret = waitpid(pid, status, options);
+ }
+#else
+ if (!lwp_user_accessable((void *)status, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ ret = waitpid(pid, status, options);
+#endif
+ return ret;
+}
+
+#if defined(RT_USING_SAL) && defined(SAL_USING_POSIX)
+struct musl_addrinfo
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ socklen_t ai_addrlen;
+
+ struct musl_sockaddr *ai_addr;
+ char *ai_canonname;
+
+ struct musl_addrinfo *ai_next;
+};
+
+int sys_getaddrinfo(const char *nodename,
+ const char *servname,
+ const struct musl_addrinfo *hints,
+ struct musl_addrinfo *res)
+{
+ int ret = -1;
+ struct addrinfo *k_res = NULL;
+ char *k_nodename = NULL;
+ char *k_servname = NULL;
+ struct addrinfo *k_hints = NULL;
+#ifdef RT_USING_USERSPACE
+ int err;
+#endif
+
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)res, sizeof(*res)))
+ {
+ SET_ERRNO(EFAULT);
+ goto exit;
+ }
+#endif
+ if (nodename)
+ {
+#ifdef RT_USING_USERSPACE
+ lwp_user_strlen(nodename, &err);
+ if (err)
+ {
+ SET_ERRNO(EFAULT);
+ goto exit;
+ }
+#endif
+ k_nodename = rt_strdup(nodename);
+ if (!k_nodename)
+ {
+ SET_ERRNO(ENOMEM);
+ goto exit;
+ }
+ }
+ if (servname)
+ {
+#ifdef RT_USING_USERSPACE
+ lwp_user_strlen(servname, &err);
+ if (err)
+ {
+ SET_ERRNO(EFAULT);
+ goto exit;
+ }
+#endif
+ k_servname = rt_strdup(servname);
+ if (!k_servname)
+ {
+ SET_ERRNO(ENOMEM);
+ goto exit;
+ }
+ }
+
+ if (hints)
+ {
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)hints, sizeof(*hints)))
+ {
+ SET_ERRNO(EFAULT);
+ goto exit;
+ }
+#endif
+ k_hints = (struct addrinfo *) rt_malloc(sizeof *hints);
+ if (!k_hints)
+ {
+ SET_ERRNO(ENOMEM);
+ goto exit;
+ }
+
+ rt_memset(k_hints, 0x0, sizeof(struct addrinfo));
+ k_hints->ai_flags = hints->ai_flags;
+ k_hints->ai_family = hints->ai_family;
+ k_hints->ai_socktype = hints->ai_socktype;
+ k_hints->ai_protocol = hints->ai_protocol;
+ k_hints->ai_addrlen = hints->ai_addrlen;
+ }
+
+ ret = sal_getaddrinfo(k_nodename, k_servname, k_hints, &k_res);
+ if (ret == 0)
+ {
+ /* set sockaddr */
+ sockaddr_tomusl(k_res->ai_addr, res->ai_addr);
+ res->ai_addrlen = k_res->ai_addrlen;
+
+ /* set up addrinfo */
+ res->ai_family = k_res->ai_family;
+ res->ai_flags = k_res->ai_flags;
+ res->ai_next = NULL;
+
+ if (hints != NULL)
+ {
+ /* copy socktype & protocol from hints if specified */
+ res->ai_socktype = hints->ai_socktype;
+ res->ai_protocol = hints->ai_protocol;
+ }
+
+ sal_freeaddrinfo(k_res);
+ k_res = NULL;
+ }
+
+exit:
+ if (k_nodename)
+ {
+ rt_free(k_nodename);
+ }
+ if (k_servname)
+ {
+ rt_free(k_servname);
+ }
+ if (k_hints)
+ {
+ rt_free(k_hints);
+ }
+
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+#define HOSTENT_BUFSZ 512
+int sys_gethostbyname2_r(const char *name, int af, struct hostent *ret,
+ char *buf, size_t buflen,
+ struct hostent **result, int *err)
+{
+ int ret_val = -1;
+ int sal_ret = -1 , sal_err = -1;
+ struct hostent sal_he;
+ struct hostent *sal_result = NULL;
+ char *sal_buf = NULL;
+ char *k_name = NULL;
+ int a_err = 0;
+
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)err, sizeof(*err)))
+ {
+ SET_ERRNO(EFAULT);
+ goto __exit;
+ }
+
+ if (!lwp_user_accessable((void *)result, sizeof(*result))
+ || !lwp_user_accessable((void *)ret, sizeof(*ret))
+ || !lwp_user_accessable((void *)buf, buflen))
+ {
+ /* not all arguments given */
+ *err = EFAULT;
+ SET_ERRNO(EFAULT);
+ goto __exit;
+ }
+
+ lwp_user_strlen(name, &a_err);
+ if (a_err)
+ {
+ *err = EFAULT;
+ SET_ERRNO(EFAULT);
+ goto __exit;
+ }
+#endif
+
+ *result = ret;
+ sal_buf = (char *)malloc(HOSTENT_BUFSZ);
+ if (sal_buf == NULL)
+ {
+ SET_ERRNO(ENOMEM);
+ goto __exit;
+ }
+
+ k_name = rt_strdup(name);
+ if (k_name == NULL)
+ {
+ SET_ERRNO(ENOMEM);
+ goto __exit;
+ }
+
+ /* get host by name in SAL */
+ sal_ret = sal_gethostbyname_r(k_name, &sal_he, sal_buf, HOSTENT_BUFSZ, &sal_result, &sal_err);
+ if (sal_ret == 0)
+ {
+ int index = 0, cnt = 0;
+ char *ptr = buf;
+
+ /* get counter */
+ index = 0;
+ while (sal_he.h_addr_list[index] != NULL)
+ {
+ index++;
+ }
+ cnt = index + 1;
+
+ /* update user space hostent */
+ ret->h_addrtype = sal_he.h_addrtype;
+ ret->h_length = sal_he.h_length;
+
+ rt_strncpy(ptr, k_name, buflen - (ptr - buf));
+ ret->h_name = ptr;
+ ptr += rt_strlen(k_name);
+
+ ret->h_addr_list = (char**)ptr;
+ ptr += cnt * sizeof(char *);
+
+ index = 0;
+ while (sal_he.h_addr_list[index] != NULL)
+ {
+ ret->h_addr_list[index] = ptr;
+ rt_memcpy(ptr, sal_he.h_addr_list[index], sal_he.h_length);
+
+ ptr += sal_he.h_length;
+ index++;
+ }
+ ret->h_addr_list[index] = NULL;
+ }
+
+ ret_val = 0;
+
+__exit:
+ /* release buffer */
+ if (sal_buf)
+ {
+ free(sal_buf);
+ }
+ if (k_name)
+ {
+ free(k_name);
+ }
+
+ return (ret_val < 0 ? GET_ERRNO() : ret_val);
+}
+#endif
+
+char *sys_getcwd(char *buf, size_t size)
+{
+ if (!lwp_user_accessable((void *)buf, size))
+ {
+ return RT_NULL;
+ }
+ getcwd(buf, size);
+
+ return (char *)strlen(buf);
+}
+
+int sys_chdir(const char *path)
+{
+#ifdef RT_USING_USERSPACE
+ int err = 0;
+
+ lwp_user_strlen(path, &err);
+ if (err)
+ {
+ return -EFAULT;
+ }
+ err = chdir(path);
+ return (err < 0 ? GET_ERRNO() : err);
+#else
+ int ret = chdir(path);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+int sys_mkdir(const char *path, mode_t mode)
+{
+#ifdef RT_USING_USERSPACE
+ int err = 0;
+
+ lwp_user_strlen(path, &err);
+ if (err)
+ {
+ return -EFAULT;
+ }
+ err = mkdir(path, mode);
+ return (err < 0 ? GET_ERRNO() : err);
+#else
+ int ret = mkdir(path, mode);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+int sys_rmdir(const char *path)
+{
+#ifdef RT_USING_USERSPACE
+ int err = 0;
+
+ lwp_user_strlen(path, &err);
+ if (err)
+ {
+ return -EFAULT;
+ }
+ err = unlink(path);
+ return (err < 0 ? GET_ERRNO() : err);
+#else
+ int ret = unlink(path);
+ return (ret < 0 ? GET_ERRNO() : ret);
+#endif
+}
+
+#ifdef RT_USING_MUSL
+typedef uint64_t ino_t;
+#endif
+struct libc_dirent {
+ ino_t d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+};
+int sys_getdents(int fd, struct libc_dirent *dirp, size_t nbytes)
+{
+ int ret = -1;
+ struct dfs_fd *dfs_fd;
+ size_t cnt = (nbytes / sizeof(struct libc_dirent));
+ size_t rtt_nbytes = 0;
+ struct dirent *rtt_dirp;
+
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)dirp, sizeof(struct libc_dirent)))
+ {
+ return -EFAULT;
+ }
+#endif
+
+ if (cnt == 0)
+ {
+ return -EINVAL;
+ }
+ rtt_nbytes = cnt * sizeof(struct dirent);
+ rtt_dirp = (struct dirent *)rt_malloc(rtt_nbytes);
+ if (!rtt_dirp)
+ {
+ return -ENOMEM;
+ }
+ dfs_fd = fd_get(fd);
+ ret = dfs_file_getdents(dfs_fd, rtt_dirp, rtt_nbytes);
+ if (ret > 0)
+ {
+ size_t i = 0;
+ cnt = ret / sizeof(struct dirent);
+ for (i = 0; i < cnt; i++)
+ {
+ dirp[i].d_ino = 0;
+ dirp[i].d_off = i*sizeof(struct libc_dirent);
+ dirp[i].d_type = rtt_dirp[i].d_type;
+ dirp[i].d_reclen = sizeof(struct libc_dirent);
+ strcpy(dirp[i].d_name, rtt_dirp[i].d_name);
+ }
+ ret = cnt * sizeof(struct libc_dirent);
+ }
+ rt_free(rtt_dirp);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+rt_err_t sys_get_errno(void)
+{
+ return rt_get_errno();
+}
+#ifdef ARCH_MM_MMU
+int sys_set_thread_area(void *p)
+{
+ rt_thread_t thread;
+
+ thread = rt_thread_self();
+ thread->thread_idr = p;
+ arch_set_thread_area(p);
+
+ return 0;
+}
+
+int sys_set_tid_address(int *tidptr)
+{
+ rt_thread_t thread;
+
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)tidptr, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+#endif
+ thread = rt_thread_self();
+ thread->clear_child_tid = tidptr;
+ return thread->tid;
+}
+#endif /* ARCH_MM_MMU */
+
+int sys_gettid(void)
+{
+ return rt_thread_self()->tid;
+}
+
+int sys_access(const char *filename, int mode)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+ rt_size_t len = 0;
+ char *kname = RT_NULL;
+ int a_err = 0;
+
+ lwp_user_strlen(filename, &a_err);
+ if (a_err)
+ {
+ return -EFAULT;
+ }
+
+ len = rt_strlen(filename);
+ if (!len)
+ {
+ return -EINVAL;
+ }
+
+ kname = (char *)kmem_get(len + 1);
+ if (!ret && !kname)
+ {
+ return -ENOMEM;
+ }
+
+ if (!ret)
+ {
+ lwp_get_from_user(kname, (void *)filename, len + 1);
+ ret = access(kname, mode);
+ kmem_put(kname);
+ }
+#else
+ ret = access(filename, mode);
+#endif
+
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_pipe(int fd[2])
+{
+ int ret;
+ if (!lwp_user_accessable((void *)fd, sizeof(int[2])))
+ {
+ return -EFAULT;
+ }
+ ret = pipe(fd);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_clock_settime(clockid_t clk, const struct timespec *ts)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+ size_t size = sizeof(struct timespec);
+ struct timespec *kts = NULL;
+
+ if (!lwp_user_accessable((void *)ts, size))
+ {
+ return -EFAULT;
+ }
+
+ kts = kmem_get(size);
+ if (!kts)
+ {
+ return -ENOMEM;
+ }
+
+ lwp_get_from_user(kts, (void *)ts, size);
+ ret = clock_settime(clk, kts);
+ kmem_put(kts);
+#else
+ if (!lwp_user_accessable((void *)ts, sizeof(struct timespec)))
+ {
+ return -EFAULT;
+ }
+ ret = clock_settime(clk, ts);
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_clock_gettime(clockid_t clk, struct timespec *ts)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+ size_t size = sizeof(struct timespec);
+ struct timespec *kts = NULL;
+
+ if (!lwp_user_accessable((void *)ts, size))
+ {
+ return -EFAULT;
+ }
+
+ kts = kmem_get(size);
+ if (!kts)
+ {
+ return -ENOMEM;
+ }
+
+ ret = clock_gettime(clk, kts);
+ if (ret != -1)
+ lwp_put_to_user(ts, kts, size);
+
+ kmem_put(kts);
+#else
+ if (!lwp_user_accessable((void *)ts, sizeof(struct timespec)))
+ {
+ return -EFAULT;
+ }
+ ret = clock_gettime(clk, ts);
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_clock_nanosleep(clockid_t clk, int flags, const struct timespec *rqtp, struct timespec *rmtp)
+{
+ int ret = 0;
+ dbg_log(DBG_LOG, "sys_nanosleep\n");
+ if (!lwp_user_accessable((void *)rqtp, sizeof *rqtp))
+ return -EFAULT;
+
+#ifdef RT_USING_USERSPACE
+ struct timespec rqtp_k;
+ struct timespec rmtp_k;
+
+ lwp_get_from_user(&rqtp_k, (void *)rqtp, sizeof rqtp_k);
+ ret = clock_nanosleep(clk, flags, &rqtp_k, &rmtp_k);
+ if ((ret != -1 || rt_get_errno() == EINTR) && rmtp && lwp_user_accessable((void *)rmtp, sizeof *rmtp))
+ {
+ lwp_put_to_user(rmtp, (void *)&rmtp_k, sizeof rmtp_k);
+ return -EINTR;
+ }
+#else
+ if (rmtp)
+ {
+ if (!lwp_user_accessable((void *)rmtp, sizeof *rmtp))
+ return -EFAULT;
+ ret = clock_nanosleep(clk, flags, rqtp, rmtp);
+ }
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_clock_getres(clockid_t clk, struct timespec *ts)
+{
+ int ret = 0;
+#ifdef RT_USING_USERSPACE
+ struct timespec kts;
+ size_t size = sizeof(struct timespec);
+
+ if (!lwp_user_accessable((void *)ts, size))
+ {
+ return -EFAULT;
+ }
+
+ ret = clock_getres(clk, &kts);
+
+ if (ret != -1)
+ lwp_put_to_user(ts, &kts, size);
+#else
+ if (!lwp_user_accessable((void *)ts, sizeof(struct timespec)))
+ {
+ return -EFAULT;
+ }
+ ret = clock_getres(clk, ts);
+#endif
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_rename(const char *oldpath, const char *newpath)
+{
+ int ret = -1;
+#ifdef RT_USING_USERSPACE
+ int err;
+
+ lwp_user_strlen(oldpath, &err);
+ if (err)
+ {
+ return -EFAULT;
+ }
+
+ lwp_user_strlen(newpath, &err);
+ if (err)
+ {
+ return -EFAULT;
+ }
+#endif
+ ret = rename(oldpath, newpath);
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+typedef unsigned long long rlim_t;
+
+struct rlimit {
+ rlim_t rlim_cur;
+ rlim_t rlim_max;
+};
+
+#define RLIMIT_CPU 0
+#define RLIMIT_FSIZE 1
+#define RLIMIT_DATA 2
+#define RLIMIT_STACK 3
+#define RLIMIT_CORE 4
+#define RLIMIT_RSS 5
+#define RLIMIT_NPROC 6
+#define RLIMIT_NOFILE 7
+#define RLIMIT_MEMLOCK 8
+#define RLIMIT_AS 9
+
+int sys_prlimit64(pid_t pid,
+ unsigned int resource,
+ const struct rlimit *new_rlim,
+ struct rlimit *old_rlim)
{
return -ENOSYS;
}
+int sys_getrlimit(unsigned int resource, unsigned long rlim[2])
+{
+ int ret = -1;
+
+ if (!lwp_user_accessable((void *)rlim, sizeof(unsigned long [2])))
+ {
+ return -EFAULT;
+ }
+ switch (resource)
+ {
+ case RLIMIT_NOFILE:
+ {
+ struct dfs_fdtable *fdt = dfs_fdtable_get();
+
+ dfs_fd_lock();
+ rlim[0] = fdt->maxfd;
+ dfs_fd_unlock();
+ rlim[1] = DFS_FD_MAX;
+ ret = 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
+{
+ return -ENOSYS;
+}
+
+int sys_setsid(void)
+{
+ int ret = 0;
+ ret = setsid();
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_getrandom(void *buf, size_t buflen, unsigned int flags)
+{
+ int ret = -1;
+ int count = 0;
+ void *kmem = RT_NULL;
+ rt_device_t rd_dev = RT_NULL;
+
+ if (flags & GRND_RANDOM)
+ rd_dev = rt_device_find("random");
+ else
+ rd_dev = rt_device_find("urandom");
+
+ if (rd_dev == RT_NULL)
+ {
+ return -EFAULT;
+ }
+
+ if (rt_device_open(rd_dev, RT_DEVICE_OFLAG_RDONLY) != RT_EOK)
+ {
+ return -EFAULT;
+ }
+
+ if (!lwp_user_accessable(buf, buflen))
+ {
+ rt_device_close(rd_dev);
+ return -EFAULT;
+ }
+
+#ifdef RT_USING_USERSPACE
+ kmem = kmem_get(buflen);
+ if (!kmem)
+ {
+ rt_device_close(rd_dev);
+ return -ENOMEM;
+ }
+
+ while (count < buflen)
+ {
+ ret = rt_device_read(rd_dev, count, (char *)kmem + count, buflen - count);
+ if (ret <= 0)
+ break;
+ count += ret;
+ }
+ rt_device_close(rd_dev);
+
+ ret = count;
+ if (count > 0)
+ {
+ ret = lwp_put_to_user(buf, kmem, count);
+ }
+ kmem_put(kmem);
+#else
+ while (count < buflen)
+ {
+ ret = rt_device_read(rd_dev, count, (char *)kmem + count, buflen - count);
+ if (ret <= 0)
+ break;
+ count += ret;
+ }
+ rt_device_close(rd_dev);
+
+ ret = count;
+#endif
+ return ret;
+}
+int sys_setaffinity(pid_t pid, size_t size, void *set)
+{
+ if (!lwp_user_accessable(set, sizeof(cpu_set_t)))
+ {
+ return -EFAULT;
+ }
+ for (int i = 0;i < size * 8; i++)
+ {
+ if (CPU_ISSET(i, (cpu_set_t *)set))
+ {
+ return lwp_setaffinity(pid, i);
+ }
+ }
+ return -1;
+}
+
+int sys_sched_setparam(pid_t pid, void *param)
+{
+ struct sched_param *sched_param = (struct sched_param *)param;
+ struct rt_lwp *lwp = NULL;
+ rt_thread_t main_thread;
+ int ret = -1;
+ if (!lwp_user_accessable(param, sizeof(struct sched_param)))
+ {
+ return -EFAULT;
+ }
+ if (pid > 0)
+ {
+ lwp = lwp_from_pid(pid);
+ }
+ else if (pid == 0)
+ {
+ lwp = lwp_self();
+ }
+ if (lwp)
+ {
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ return rt_thread_control(main_thread, RT_THREAD_CTRL_CHANGE_PRIORITY, (void *)&sched_param->sched_priority);
+ }
+ return ret;
+}
+
+int sys_sched_getparam(pid_t pid, void *param)
+{
+ struct sched_param *sched_param = (struct sched_param *)param;
+ struct rt_lwp *lwp = NULL;
+ rt_thread_t main_thread;
+ int ret = -1;
+ if (!lwp_user_accessable(param, sizeof(struct sched_param)))
+ {
+ return -EFAULT;
+ }
+ if (pid > 0)
+ {
+ lwp = lwp_from_pid(pid);
+ }
+ else if (pid == 0)
+ {
+ lwp = lwp_self();
+ }
+ if (lwp)
+ {
+ main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
+ sched_param->sched_priority = main_thread->current_priority;
+ ret = 0;
+ }
+ return ret;
+}
+
+int sys_sched_get_priority_max(int policy)
+{
+ if(policy < 0)
+ {
+ rt_set_errno(EINVAL);
+ return -rt_get_errno();
+ }
+ return RT_THREAD_PRIORITY_MAX;
+}
+
+int sys_sched_get_priority_min(int policy)
+{
+ if(policy < 0)
+ {
+ rt_set_errno(EINVAL);
+ return -rt_get_errno();
+ }
+ return 0;
+}
+
+int sys_sched_setscheduler(int tid, int policy, void *param)
+{
+ struct sched_param *sched_param = (struct sched_param *)param;
+ rt_thread_t thread = lwp_tid_get_thread(tid);
+
+ if (!lwp_user_accessable(param, sizeof(struct sched_param)))
+ {
+ return -EFAULT;
+ }
+ return rt_thread_control(thread, RT_THREAD_CTRL_CHANGE_PRIORITY, (void *)&sched_param->sched_priority);
+ return 0;
+}
+
+int sys_sched_getscheduler(int tid, int *policy, void *param)
+{
+ struct sched_param *sched_param = (struct sched_param *)param;
+ rt_thread_t thread = lwp_tid_get_thread(tid);
+ if (!lwp_user_accessable(sched_param, sizeof(struct sched_param)))
+ {
+ return -EFAULT;
+ }
+ sched_param->sched_priority = thread->current_priority;
+ *policy = 0;
+ return 0;
+}
+
+int sys_fsync(int fd)
+{
+ int res = fsync(fd);
+ if (res < 0)
+ res = rt_get_errno();
+ return res;
+}
+
const static void* func_table[] =
{
- (void *)sys_exit, // 0x01
- (void *)sys_read, // 0x02
- (void *)sys_write, // 0x03
- (void *)sys_lseek, // 0x04
- (void *)sys_open, // 0x05
- (void *)sys_close, // 0x06
- (void *)sys_ioctl, // 0x07
+ SYSCALL_SIGN(sys_exit), /* 01 */
+ SYSCALL_SIGN(sys_read),
+ SYSCALL_SIGN(sys_write),
+ SYSCALL_SIGN(sys_lseek),
+ SYSCALL_SIGN(sys_open), /* 05 */
+ SYSCALL_SIGN(sys_close),
+ SYSCALL_SIGN(sys_ioctl),
+ SYSCALL_SIGN(sys_fstat),
+ SYSCALL_SIGN(sys_poll),
+ SYSCALL_SIGN(sys_nanosleep), /* 10 */
+ SYSCALL_SIGN(sys_gettimeofday),
+ SYSCALL_SIGN(sys_settimeofday),
+ SYSCALL_SIGN(sys_exec),
+ SYSCALL_SIGN(sys_kill),
+ SYSCALL_SIGN(sys_getpid), /* 15 */
+ SYSCALL_SIGN(sys_getpriority),
+ SYSCALL_SIGN(sys_setpriority),
+ SYSCALL_SIGN(sys_sem_create),
+ SYSCALL_SIGN(sys_sem_delete),
+ SYSCALL_SIGN(sys_sem_take), /* 20 */
+ SYSCALL_SIGN(sys_sem_release),
+ SYSCALL_SIGN(sys_mutex_create),
+ SYSCALL_SIGN(sys_mutex_delete),
+ SYSCALL_SIGN(sys_mutex_take),
+ SYSCALL_SIGN(sys_mutex_release), /* 25 */
+ SYSCALL_SIGN(sys_event_create),
+ SYSCALL_SIGN(sys_event_delete),
+ SYSCALL_SIGN(sys_event_send),
+ SYSCALL_SIGN(sys_event_recv),
+ SYSCALL_SIGN(sys_mb_create), /* 30 */
+ SYSCALL_SIGN(sys_mb_delete),
+ SYSCALL_SIGN(sys_mb_send),
+ SYSCALL_SIGN(sys_mb_send_wait),
+ SYSCALL_SIGN(sys_mb_recv),
+ SYSCALL_SIGN(sys_mq_create), /* 35 */
+ SYSCALL_SIGN(sys_mq_delete),
+ SYSCALL_SIGN(sys_mq_send),
+ SYSCALL_SIGN(sys_mq_urgent),
+ SYSCALL_SIGN(sys_mq_recv),
+ SYSCALL_SIGN(sys_thread_create), /* 40 */
+ SYSCALL_SIGN(sys_thread_delete),
+ SYSCALL_SIGN(sys_thread_startup),
+ SYSCALL_SIGN(sys_thread_self),
+ SYSCALL_SIGN(sys_channel_open),
+ SYSCALL_SIGN(sys_channel_close), /* 45 */
+ SYSCALL_SIGN(sys_channel_send),
+ SYSCALL_SIGN(sys_channel_send_recv_timeout),
+ SYSCALL_SIGN(sys_channel_reply),
+ SYSCALL_SIGN(sys_channel_recv_timeout),
+ SYSCALL_SIGN(sys_enter_critical), /* 50 */
+ SYSCALL_SIGN(sys_exit_critical),
- (void *)sys_nanosleep, // 0x08
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_brk)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_mmap2)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_munmap)),
+#ifdef ARCH_MM_MMU
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_shmget)), /* 55 */
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_shmrm)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_shmat)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_shmdt)),
+#else
+#ifdef RT_LWP_USING_SHM
+ SYSCALL_SIGN(sys_shm_alloc), /* 55 */
+ SYSCALL_SIGN(sys_shm_free),
+ SYSCALL_SIGN(sys_shm_retain),
+ SYSCALL_SIGN(sys_notimpl),
+#else
+ SYSCALL_SIGN(sys_notimpl), /* 55 */
+ SYSCALL_SIGN(sys_notimpl),
+ SYSCALL_SIGN(sys_notimpl),
+ SYSCALL_SIGN(sys_notimpl),
+#endif /* RT_LWP_USING_SHM */
+#endif /* ARCH_MM_MMU */
+ SYSCALL_SIGN(sys_device_init),
+ SYSCALL_SIGN(sys_device_register), /* 60 */
+ SYSCALL_SIGN(sys_device_control),
+ SYSCALL_SIGN(sys_device_find),
+ SYSCALL_SIGN(sys_device_open),
+ SYSCALL_SIGN(sys_device_close),
+ SYSCALL_SIGN(sys_device_read), /* 65 */
+ SYSCALL_SIGN(sys_device_write),
+
+ SYSCALL_SIGN(sys_stat),
+ SYSCALL_SIGN(sys_thread_find),
- (void *)sys_getpriority, // 0x09
- (void *)sys_setpriority, // 0x0a
+ SYSCALL_NET(SYSCALL_SIGN(sys_accept)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_bind)), /* 70 */
+ SYSCALL_NET(SYSCALL_SIGN(sys_shutdown)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_getpeername)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_getsockname)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_getsockopt)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_setsockopt)), /* 75 */
+ SYSCALL_NET(SYSCALL_SIGN(sys_connect)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_listen)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_recv)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_recvfrom)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_send)), /* 80 */
+ SYSCALL_NET(SYSCALL_SIGN(sys_sendto)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_socket)),
- (void *)sys_gettimeofday, // 0x0b
- (void *)sys_settimeofday, // 0x0c
+ SYSCALL_NET(SYSCALL_SIGN(sys_closesocket)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_getaddrinfo)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_gethostbyname2_r)), /* 85 */
- (void *)sys_malloc, // 0x0d
- (void *)sys_free, // 0x0e
- (void *)sys_realloc, //0x0f
- (void *)sys_fstat, // 0x10
- (void *)poll, // 0x11
+ SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_SIGN(sys_notimpl), //network, /* 90 */
+ SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_SIGN(sys_notimpl), //network,
- SYSCALL_NET(accept), // 0x12
- SYSCALL_NET(bind), // 0x13
- SYSCALL_NET(shutdown), // 0x14
- SYSCALL_NET(getpeername),// 0x15
- SYSCALL_NET(getsockname),// 0x16
- SYSCALL_NET(getsockopt), // 0x17
- SYSCALL_NET(setsockopt), // 0x18
- SYSCALL_NET(connect), // 0x19
- SYSCALL_NET(listen), // 0x1a
- SYSCALL_NET(recv), // 0x1b
- SYSCALL_NET(recvfrom), // 0x1c
- SYSCALL_NET(send), // 0x1d
- SYSCALL_NET(sendto), // 0x1e
- SYSCALL_NET(socket), // 0x1f
+#ifdef RT_USING_DFS
+ SYSCALL_SIGN(sys_select),
+#else
+ SYSCALL_SIGN(sys_notimpl),
+#endif
- (void *)select, // 0x20
+ SYSCALL_SIGN(sys_notimpl), //SYSCALL_SIGN(sys_hw_interrupt_disable), /* 95 */
+ SYSCALL_SIGN(sys_notimpl), //SYSCALL_SIGN(sys_hw_interrupt_enable),
+
+ SYSCALL_SIGN(sys_tick_get),
+ SYSCALL_SIGN(sys_exit_group),
+
+ SYSCALL_SIGN(sys_notimpl), //rt_delayed_work_init,
+ SYSCALL_SIGN(sys_notimpl), //rt_work_submit, /* 100 */
+ SYSCALL_SIGN(sys_notimpl), //rt_wqueue_wakeup,
+ SYSCALL_SIGN(sys_thread_mdelay),
+ SYSCALL_SIGN(sys_sigaction),
+ SYSCALL_SIGN(sys_sigprocmask),
+ SYSCALL_SIGN(sys_tkill), /* 105 */
+ SYSCALL_SIGN(sys_thread_sigprocmask),
+#ifdef ARCH_MM_MMU
+ SYSCALL_SIGN(sys_cacheflush),
+ SYSCALL_SIGN(sys_notimpl),
+ SYSCALL_SIGN(sys_notimpl),
+#else
+ SYSCALL_SIGN(sys_notimpl),
+ SYSCALL_SIGN(sys_lwp_sighandler_set),
+ SYSCALL_SIGN(sys_thread_sighandler_set),
+#endif
+ SYSCALL_SIGN(sys_waitpid), /* 110 */
+
+ SYSCALL_SIGN(sys_rt_timer_create),
+ SYSCALL_SIGN(sys_rt_timer_delete),
+ SYSCALL_SIGN(sys_rt_timer_start),
+ SYSCALL_SIGN(sys_rt_timer_stop),
+ SYSCALL_SIGN(sys_rt_timer_control), /* 115 */
+ SYSCALL_SIGN(sys_getcwd),
+ SYSCALL_SIGN(sys_chdir),
+ SYSCALL_SIGN(sys_unlink),
+ SYSCALL_SIGN(sys_mkdir),
+ SYSCALL_SIGN(sys_rmdir), /* 120 */
+ SYSCALL_SIGN(sys_getdents),
+ SYSCALL_SIGN(sys_get_errno),
+#ifdef ARCH_MM_MMU
+ SYSCALL_SIGN(sys_set_thread_area),
+ SYSCALL_SIGN(sys_set_tid_address),
+#else
+ SYSCALL_SIGN(sys_notimpl),
+ SYSCALL_SIGN(sys_notimpl),
+#endif
+ SYSCALL_SIGN(sys_access), /* 125 */
+ SYSCALL_SIGN(sys_pipe),
+ SYSCALL_SIGN(sys_clock_settime),
+ SYSCALL_SIGN(sys_clock_gettime),
+ SYSCALL_SIGN(sys_clock_getres),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_clone)), /* 130 */
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_futex)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_pmutex)),
+ SYSCALL_SIGN(sys_dup),
+ SYSCALL_SIGN(sys_dup2),
+ SYSCALL_SIGN(sys_rename), /* 135 */
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_fork)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_execve)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_vfork)),
+ SYSCALL_SIGN(sys_gettid),
+ SYSCALL_SIGN(sys_prlimit64), /* 140 */
+ SYSCALL_SIGN(sys_getrlimit),
+ SYSCALL_SIGN(sys_setrlimit),
+ SYSCALL_SIGN(sys_setsid),
+ SYSCALL_SIGN(sys_getrandom),
+ SYSCALL_SIGN(sys_notimpl), // SYSCALL_SIGN(sys_readlink) /* 145 */
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_mremap)),
+ SYSCALL_USPACE(SYSCALL_SIGN(sys_madvise)),
+ SYSCALL_SIGN(sys_sched_setparam),
+ SYSCALL_SIGN(sys_sched_getparam),
+ SYSCALL_SIGN(sys_sched_get_priority_max),
+ SYSCALL_SIGN(sys_sched_get_priority_min),
+ SYSCALL_SIGN(sys_sched_setscheduler),
+ SYSCALL_SIGN(sys_sched_getscheduler),
+ SYSCALL_SIGN(sys_setaffinity),
+ SYSCALL_SIGN(sys_fsync),
+ SYSCALL_SIGN(sys_clock_nanosleep),
+ SYSCALL_SIGN(sys_timer_create),
+ SYSCALL_SIGN(sys_timer_delete),
+ SYSCALL_SIGN(sys_timer_settime),
+ SYSCALL_SIGN(sys_timer_gettime),
+ SYSCALL_SIGN(sys_timer_getoverrun),
};
const void *lwp_get_sys_api(rt_uint32_t number)
{
- const void *func = (const void*)sys_notimpl;
+ const void *func = (const void *)sys_notimpl;
if (number == 0xff)
{
@@ -271,11 +4408,32 @@ const void *lwp_get_sys_api(rt_uint32_t number)
else
{
number -= 1;
- if (number < sizeof(func_table)/sizeof(func_table[0]))
+ if (number < sizeof(func_table) / sizeof(func_table[0]) / 2)
{
- func = func_table[number];
+ func = func_table[number << 1];
}
}
return func;
}
+
+const char *lwp_get_syscall_name(rt_uint32_t number)
+{
+ const char *name = "sys_notimpl";
+
+ if (number == 0xff)
+ {
+ name = "sys_log";
+ }
+ else
+ {
+ number -= 1;
+ if (number < sizeof(func_table) / sizeof(func_table[0]) / 2)
+ {
+ name = (char*)func_table[(number << 1) + 1];
+ }
+ }
+
+ // skip sys_
+ return name + 4;
+}
diff --git a/components/lwp/lwp_syscall.h b/components/lwp/lwp_syscall.h
index 749406c1ca..3b4e0f7ac1 100644
--- a/components/lwp/lwp_syscall.h
+++ b/components/lwp/lwp_syscall.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
+ * Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
- * 2018-12-10 Jesven fix complie error in iar and keil
+ * 2019-11-12 Jesven the first version
*/
#ifndef __LWP_SYSCALL_H__
@@ -15,11 +15,16 @@
#include <rtthread.h>
#include <dfs_file.h>
#include <unistd.h>
+#include <stdio.h> /* rename() */
#include <sys/stat.h>
-#include <sys/statfs.h>
+#include <sys/statfs.h> /* statfs() */
+#include <poll.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
typedef long suseconds_t; /* microseconds (signed) */
typedef uint32_t id_t; /* may contain pid, uid or gid */
@@ -27,26 +32,15 @@ typedef uint32_t id_t; /* may contain pid, uid or gid */
/*
* Process priority specifications to get/setpriority.
*/
-#define PRIO_MIN (-20)
-#define PRIO_MAX 20
+#define PRIO_MIN (-20)
+#define PRIO_MAX 20
-#define PRIO_PROCESS 0 /* only support lwp process */
-#define PRIO_PGRP 1
-#define PRIO_USER 2
+#define PRIO_PROCESS 0 /* only support lwp process */
+#define PRIO_PGRP 1
+#define PRIO_USER 2
-#ifndef TIMEVAL_TO_TIMESPEC
-#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
- (ts)->tv_sec = (tv)->tv_sec; \
- (ts)->tv_nsec = (tv)->tv_usec * 1000; \
-}
-#endif
-
-#ifndef TIMESPEC_TO_TIMEVAL
-#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
- (tv)->tv_sec = (ts)->tv_sec; \
- (tv)->tv_usec = (ts)->tv_nsec / 1000; \
-}
-#endif
+const char *lwp_get_syscall_name(rt_uint32_t number);
+const void *lwp_get_sys_api(rt_uint32_t number);
void sys_exit(int value);
ssize_t sys_read(int fd, void *buf, size_t nbyte);
@@ -54,15 +48,56 @@ ssize_t sys_write(int fd, const void *buf, size_t nbyte);
off_t sys_lseek(int fd, off_t offset, int whence);
int sys_open(const char *name, int mode, ...);
int sys_close(int fd);
+int sys_ioctl(int fd, unsigned long cmd, void* data);
+int sys_fstat(int file, struct stat *buf);
+int sys_poll(struct pollfd *fds, nfds_t nfds, int timeout);
int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
-int sys_getpriority(int which, id_t who);
-int sys_setpriority(int which, id_t who, int prio);
int sys_gettimeofday(struct timeval *tp, struct timezone *tzp);
int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp);
-int sys_msgget(key_t key, int msgflg);
-int sys_msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg);
-int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
+int sys_exec(char *filename, int argc, char **argv, char **envp);
+int sys_kill(int pid, int sig);
+int sys_getpid(void);
+int sys_getpriority(int which, id_t who);
+int sys_setpriority(int which, id_t who, int prio);
+rt_sem_t sys_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag);
+rt_err_t sys_sem_delete(rt_sem_t sem);
+rt_err_t sys_sem_take(rt_sem_t sem, rt_int32_t time);
+rt_err_t sys_sem_release(rt_sem_t sem);
+rt_mutex_t sys_mutex_create(const char *name, rt_uint8_t flag);
+rt_err_t sys_mutex_delete(rt_mutex_t mutex);
+rt_err_t sys_mutex_take(rt_mutex_t mutex, rt_int32_t time);
+rt_err_t sys_mutex_release(rt_mutex_t mutex);
+rt_event_t sys_event_create(const char *name, rt_uint8_t flag);
+rt_err_t sys_event_delete(rt_event_t event);
+rt_err_t sys_event_send(rt_event_t event, rt_uint32_t set);
+rt_err_t sys_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t opt, rt_int32_t timeout, rt_uint32_t *recved);
+rt_mailbox_t sys_mb_create(const char *name, rt_size_t size, rt_uint8_t flag);
+rt_err_t sys_mb_delete(rt_mailbox_t mb);
+rt_err_t sys_mb_send(rt_mailbox_t mb, rt_ubase_t value);
+rt_err_t sys_mb_send_wait(rt_mailbox_t mb, rt_ubase_t value, rt_int32_t timeout);
+rt_err_t sys_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout);
+rt_mq_t sys_mq_create(const char *name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag);
+rt_err_t sys_mq_delete(rt_mq_t mq);
+rt_err_t sys_mq_send(rt_mq_t mq, void *buffer, rt_size_t size);
+rt_err_t sys_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size);
+rt_err_t sys_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, rt_int32_t timeout);
+rt_thread_t sys_thread_create(void *arg[]);
+rt_err_t sys_thread_delete(rt_thread_t thread);
+rt_err_t sys_thread_startup(rt_thread_t thread);
+rt_thread_t sys_thread_self(void);
+int sys_channel_open(const char *name, int flags);
+rt_err_t sys_channel_close(int fd);
+rt_err_t sys_channel_send(int fd, rt_channel_msg_t data);
+rt_err_t sys_channel_send_recv(int fd, rt_channel_msg_t data, rt_channel_msg_t data_ret);
+rt_err_t sys_channel_reply(int fd, rt_channel_msg_t data);
+rt_err_t sys_channel_recv(int fd, rt_channel_msg_t data);
+void sys_enter_critical(void);
+void sys_exit_critical(void);
int sys_log(const char* log, int size);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/components/lwp/lwp_tid.c b/components/lwp/lwp_tid.c
new file mode 100644
index 0000000000..0a77c5308c
--- /dev/null
+++ b/components/lwp/lwp_tid.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-15 shaojinchun first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "lwp.h"
+
+#ifdef RT_USING_USERSPACE
+#include "lwp_user_mm.h"
+#endif
+
+#define DBG_TAG "LWP_TID"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define TID_MAX 10000
+
+#define TID_CT_ASSERT(name, x) \
+ struct assert_##name {char ary[2 * (x) - 1];}
+
+TID_CT_ASSERT(tid_min_nr, LWP_TID_MAX_NR > 1);
+TID_CT_ASSERT(tid_max_nr, LWP_TID_MAX_NR < TID_MAX);
+
+static struct lwp_avl_struct lwp_tid_ary[LWP_TID_MAX_NR];
+static struct lwp_avl_struct *lwp_tid_free_head = RT_NULL;
+static int lwp_tid_ary_alloced = 0;
+static struct lwp_avl_struct *lwp_tid_root = RT_NULL;
+static int current_tid = 0;
+
+int lwp_tid_get(void)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+ int tid = 0;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_tid_free_head;
+ if (p)
+ {
+ lwp_tid_free_head = (struct lwp_avl_struct *)p->avl_right;
+ }
+ else if (lwp_tid_ary_alloced < LWP_TID_MAX_NR)
+ {
+ p = lwp_tid_ary + lwp_tid_ary_alloced;
+ lwp_tid_ary_alloced++;
+ }
+ if (p)
+ {
+ int found_noused = 0;
+
+ RT_ASSERT(p->data == RT_NULL);
+ for (tid = current_tid + 1; tid < TID_MAX; tid++)
+ {
+ if (!lwp_avl_find(tid, lwp_tid_root))
+ {
+ found_noused = 1;
+ break;
+ }
+ }
+ if (!found_noused)
+ {
+ for (tid = 1; tid <= current_tid; tid++)
+ {
+ if (!lwp_avl_find(tid, lwp_tid_root))
+ {
+ found_noused = 1;
+ break;
+ }
+ }
+ }
+ p->avl_key = tid;
+ lwp_avl_insert(p, &lwp_tid_root);
+ current_tid = tid;
+ }
+ rt_hw_interrupt_enable(level);
+ return tid;
+}
+
+void lwp_tid_put(int tid)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_avl_find(tid, lwp_tid_root);
+ if (p)
+ {
+ p->data = RT_NULL;
+ lwp_avl_remove(p, &lwp_tid_root);
+ p->avl_right = lwp_tid_free_head;
+ lwp_tid_free_head = p;
+ }
+ rt_hw_interrupt_enable(level);
+}
+
+rt_thread_t lwp_tid_get_thread(int tid)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+ rt_thread_t thread = RT_NULL;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_avl_find(tid, lwp_tid_root);
+ if (p)
+ {
+ thread = (rt_thread_t)p->data;
+ }
+ rt_hw_interrupt_enable(level);
+ return thread;
+}
+
+void lwp_tid_set_thread(int tid, rt_thread_t thread)
+{
+ rt_base_t level;
+ struct lwp_avl_struct *p;
+
+ level = rt_hw_interrupt_disable();
+ p = lwp_avl_find(tid, lwp_tid_root);
+ if (p)
+ {
+ p->data = thread;
+ }
+ rt_hw_interrupt_enable(level);
+}
diff --git a/components/lwp/lwp_user_mm.c b/components/lwp/lwp_user_mm.c
new file mode 100644
index 0000000000..44e2a3a96a
--- /dev/null
+++ b/components/lwp/lwp_user_mm.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-28 Jesven first version
+ * 2021-02-06 lizhirui fixed fixed vtable size problem
+ * 2021-02-12 lizhirui add 64-bit support for lwp_brk
+ * 2021-02-19 lizhirui add riscv64 support for lwp_user_accessable and lwp_get_from_user
+ * 2021-06-07 lizhirui modify user space bound check
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+#include <lwp_mm.h>
+
+int lwp_user_space_init(struct rt_lwp *lwp)
+{
+ return arch_user_space_init(lwp);
+}
+
+#ifdef LWP_ENABLE_ASID
+void rt_hw_mmu_switch(void *mtable, unsigned int pid, unsigned int asid);
+#else
+void rt_hw_mmu_switch(void *mtable);
+#endif
+void *rt_hw_mmu_tbl_get(void);
+void lwp_mmu_switch(struct rt_thread *thread)
+{
+ struct rt_lwp *l = RT_NULL;
+ void *pre_mmu_table = RT_NULL, *new_mmu_table = RT_NULL;
+
+ if (thread->lwp)
+ {
+ l = (struct rt_lwp *)thread->lwp;
+ new_mmu_table = (void *)((char *)l->mmu_info.vtable + l->mmu_info.pv_off);
+ }
+ else
+ {
+ new_mmu_table = arch_kernel_mmu_table_get();
+ }
+
+ pre_mmu_table = rt_hw_mmu_tbl_get();
+ if (pre_mmu_table != new_mmu_table)
+ {
+#ifdef LWP_ENABLE_ASID
+ rt_hw_mmu_switch(new_mmu_table, l ? l->pid : 0, arch_get_asid(l));
+#else
+ rt_hw_mmu_switch(new_mmu_table);
+#endif
+ }
+}
+
+static void unmap_range(struct rt_lwp *lwp, void *addr, size_t size, int pa_need_free)
+{
+ void *va = RT_NULL, *pa = RT_NULL;
+ int i = 0;
+
+ for (va = addr, i = 0; i < size; va = (void *)((char *)va + ARCH_PAGE_SIZE), i += ARCH_PAGE_SIZE)
+ {
+ pa = rt_hw_mmu_v2p(&lwp->mmu_info, va);
+ if (pa)
+ {
+ rt_hw_mmu_unmap(&lwp->mmu_info, va, ARCH_PAGE_SIZE);
+ if (pa_need_free)
+ {
+ rt_pages_free((void *)((char *)pa - PV_OFFSET), 0);
+ }
+ }
+ }
+}
+
+void lwp_unmap_user_space(struct rt_lwp *lwp)
+{
+ struct lwp_avl_struct *node = RT_NULL;
+
+ while ((node = lwp_map_find_first(lwp->map_area)) != 0)
+ {
+ struct rt_mm_area_struct *ma = (struct rt_mm_area_struct *)node->data;
+ int pa_need_free = 0;
+
+ RT_ASSERT(ma->type < MM_AREA_TYPE_UNKNOW);
+
+ switch (ma->type)
+ {
+ case MM_AREA_TYPE_DATA:
+ case MM_AREA_TYPE_TEXT:
+ pa_need_free = 1;
+ break;
+ case MM_AREA_TYPE_SHM:
+ lwp_shm_ref_dec(lwp, (void *)ma->addr);
+ break;
+ }
+ unmap_range(lwp, (void *)ma->addr, ma->size, pa_need_free);
+ lwp_map_area_remove(&lwp->map_area, ma->addr);
+ }
+
+ arch_user_space_vtable_free(lwp);
+}
+
+static void *_lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, int text)
+{
+ void *va = RT_NULL;
+ int ret = 0;
+ rt_mmu_info *m_info = &lwp->mmu_info;
+ int area_type;
+
+ va = rt_hw_mmu_map_auto(m_info, map_va, map_size, MMU_MAP_U_RWCB);
+ if (!va)
+ {
+ return 0;
+ }
+
+ area_type = text ? MM_AREA_TYPE_TEXT : MM_AREA_TYPE_DATA;
+ ret = lwp_map_area_insert(&lwp->map_area, (size_t)va, map_size, area_type);
+ if (ret != 0)
+ {
+ unmap_range(lwp, va, map_size, 1);
+ return 0;
+ }
+ return va;
+}
+
+int lwp_unmap_user(struct rt_lwp *lwp, void *va)
+{
+ struct lwp_avl_struct *ma_avl_node = RT_NULL;
+ struct rt_mm_area_struct *ma = RT_NULL;
+ int pa_need_free = 0;
+
+ rt_mm_lock();
+ va = (void *)((size_t)va & ~ARCH_PAGE_MASK);
+ ma_avl_node = lwp_map_find(lwp->map_area, (size_t)va);
+ if (!ma_avl_node)
+ {
+ rt_mm_unlock();
+ return -1;
+ }
+ ma = (struct rt_mm_area_struct *)ma_avl_node->data;
+
+ RT_ASSERT(ma->type < MM_AREA_TYPE_UNKNOW);
+ if ((ma->type == MM_AREA_TYPE_DATA) || (ma->type == MM_AREA_TYPE_TEXT))
+ {
+ pa_need_free = 1;
+ }
+ unmap_range(lwp, (void *)ma->addr, ma->size, pa_need_free);
+ lwp_map_area_remove(&lwp->map_area, (size_t)va);
+ rt_mm_unlock();
+ return 0;
+}
+
+int lwp_dup_user(struct lwp_avl_struct *ptree, void *arg)
+{
+ struct rt_lwp *self_lwp = lwp_self();
+ struct rt_lwp *new_lwp = (struct rt_lwp *)arg;
+ struct rt_mm_area_struct *ma = (struct rt_mm_area_struct *)ptree->data;
+ void *pa = RT_NULL;
+ void *va = RT_NULL;
+
+ switch (ma->type)
+ {
+ case MM_AREA_TYPE_PHY:
+ pa = rt_hw_mmu_v2p(&self_lwp->mmu_info, (void *)ma->addr);
+ va = lwp_map_user_type(new_lwp, (void *)ma->addr, pa, ma->size, 0, MM_AREA_TYPE_PHY);
+ break;
+ case MM_AREA_TYPE_PHY_CACHED:
+ pa = rt_hw_mmu_v2p(&self_lwp->mmu_info, (void *)ma->addr);
+ va = lwp_map_user_type(new_lwp, (void *)ma->addr, pa, ma->size, 0, MM_AREA_TYPE_PHY_CACHED);
+ break;
+ case MM_AREA_TYPE_SHM:
+ va = (void *)ma->addr;
+ if (lwp_shm_ref_inc(self_lwp, va) > 0)
+ {
+ pa = rt_hw_mmu_v2p(&self_lwp->mmu_info, va);
+ va = lwp_map_user_type(new_lwp, va, pa, ma->size, 1, MM_AREA_TYPE_SHM);
+ }
+ break;
+ case MM_AREA_TYPE_DATA:
+ va = lwp_map_user(new_lwp, (void *)ma->addr, ma->size, 0);
+ if (va == (void *)ma->addr)
+ {
+ lwp_data_put(&new_lwp->mmu_info, va, va, ma->size);
+ }
+ break;
+ case MM_AREA_TYPE_TEXT:
+ {
+ char *addr = (char *)ma->addr;
+ size_t size = ma->size;
+
+ while (size)
+ {
+ pa = rt_hw_mmu_v2p(&self_lwp->mmu_info, (void *)addr);
+ rt_page_ref_inc((char *)pa - self_lwp->mmu_info.pv_off, 0);
+ va = lwp_map_user_type(new_lwp, addr, pa, ARCH_PAGE_SIZE, 1, MM_AREA_TYPE_TEXT);
+ if (va != addr)
+ {
+ return -1;
+ }
+ addr += ARCH_PAGE_SIZE;
+ size -= ARCH_PAGE_SIZE;
+ }
+ va = (void *)ma->addr;
+ }
+ break;
+ default:
+ RT_ASSERT(0);
+ break;
+ }
+ if (va != (void *)ma->addr)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int lwp_unmap_user_phy(struct rt_lwp *lwp, void *va)
+{
+ return lwp_unmap_user(lwp, va);
+}
+
+int lwp_unmap_user_type(struct rt_lwp *lwp, void *va)
+{
+ return lwp_unmap_user(lwp, va);
+}
+
+void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, int text)
+{
+ void *ret = RT_NULL;
+ size_t offset = 0;
+
+ if (!map_size)
+ {
+ return 0;
+ }
+ offset = (size_t)map_va & ARCH_PAGE_MASK;
+ map_size += (offset + ARCH_PAGE_SIZE - 1);
+ map_size &= ~ARCH_PAGE_MASK;
+ map_va = (void *)((size_t)map_va & ~ARCH_PAGE_MASK);
+
+ rt_mm_lock();
+ ret = _lwp_map_user(lwp, map_va, map_size, text);
+ rt_mm_unlock();
+ if (ret)
+ {
+ ret = (void *)((char *)ret + offset);
+ }
+ return ret;
+}
+
+static void *_lwp_map_user_type(struct rt_lwp *lwp, void *map_va, void *map_pa, size_t map_size, int cached, int type)
+{
+ void *va = RT_NULL;
+ rt_mmu_info *m_info = &lwp->mmu_info;
+ size_t attr = 0;
+ int ret = 0;
+
+ if (cached)
+ {
+ attr = MMU_MAP_U_RWCB;
+ if (type == MM_AREA_TYPE_PHY)
+ {
+ type = MM_AREA_TYPE_PHY_CACHED;
+ }
+ }
+ else
+ {
+ attr = MMU_MAP_U_RW;
+ }
+
+ va = rt_hw_mmu_map(m_info, map_va, map_pa, map_size, attr);
+ if (va)
+ {
+ ret = lwp_map_area_insert(&lwp->map_area, (size_t)va, map_size, type);
+ if (ret != 0)
+ {
+ unmap_range(lwp, va, map_size, 0);
+ return 0;
+ }
+ }
+ return va;
+}
+
+void *lwp_map_user_type(struct rt_lwp *lwp, void *map_va, void *map_pa, size_t map_size, int cached, int type)
+{
+ void *ret = RT_NULL;
+ size_t offset = 0;
+
+ if (!map_size)
+ {
+ return 0;
+ }
+ if (map_va)
+ {
+ if (((size_t)map_va & ARCH_PAGE_MASK) != ((size_t)map_pa & ARCH_PAGE_MASK))
+ {
+ return 0;
+ }
+ }
+ offset = (size_t)map_pa & ARCH_PAGE_MASK;
+ map_size += (offset + ARCH_PAGE_SIZE - 1);
+ map_size &= ~ARCH_PAGE_MASK;
+ map_pa = (void *)((size_t)map_pa & ~ARCH_PAGE_MASK);
+
+ rt_mm_lock();
+ ret = _lwp_map_user_type(lwp, map_va, map_pa, map_size, cached, type);
+ rt_mm_unlock();
+ if (ret)
+ {
+ ret = (void *)((char *)ret + offset);
+ }
+ return ret;
+}
+
+void *lwp_map_user_phy(struct rt_lwp *lwp, void *map_va, void *map_pa, size_t map_size, int cached)
+{
+ return lwp_map_user_type(lwp, map_va, map_pa, map_size, cached, MM_AREA_TYPE_PHY);
+}
+
+rt_base_t lwp_brk(void *addr)
+{
+ rt_base_t ret = -1;
+ struct rt_lwp *lwp = RT_NULL;
+
+ rt_mm_lock();
+ lwp = rt_thread_self()->lwp;
+
+ if ((size_t)addr <= lwp->end_heap)
+ {
+ ret = (rt_base_t)lwp->end_heap;
+ }
+ else
+ {
+ size_t size = 0;
+ void *va = RT_NULL;
+
+ if ((size_t)addr <= USER_HEAP_VEND)
+ {
+ size = (((size_t)addr - lwp->end_heap) + ARCH_PAGE_SIZE - 1) & ~ARCH_PAGE_MASK;
+ va = lwp_map_user(lwp, (void *)lwp->end_heap, size, 0);
+ }
+ if (va)
+ {
+ lwp->end_heap += size;
+ ret = lwp->end_heap;
+ }
+ }
+ rt_mm_unlock();
+ return ret;
+}
+
+#define MAP_ANONYMOUS 0x20
+
+void* lwp_mmap2(void *addr, size_t length, int prot,
+ int flags, int fd, off_t pgoffset)
+{
+ void *ret = (void *)-1;
+
+ if (fd == -1)
+ {
+ rt_mm_lock();
+ ret = lwp_map_user(lwp_self(), addr, length, 0);
+ rt_mm_unlock();
+
+ if (ret)
+ {
+ if ((flags & MAP_ANONYMOUS) != 0)
+ {
+ rt_memset(ret, 0, length);
+ }
+ }
+ else
+ {
+ ret = (void *)-1;
+ }
+ }
+ else
+ {
+ struct dfs_fd *d;
+
+ d = fd_get(fd);
+ if (d && d->vnode->type == FT_DEVICE)
+ {
+ struct dfs_mmap2_args mmap2;
+
+ mmap2.addr = addr;
+ mmap2.length = length;
+ mmap2.prot = prot;
+ mmap2.flags = flags;
+ mmap2.pgoffset = pgoffset;
+ mmap2.ret = (void*) -1;
+
+ if (dfs_file_mmap2(d, &mmap2) == 0)
+ {
+ ret = mmap2.ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int lwp_munmap(void *addr)
+{
+ int ret = 0;
+
+ rt_mm_lock();
+ ret = lwp_unmap_user(lwp_self(), addr);
+ rt_mm_unlock();
+
+ return ret;
+}
+
+size_t lwp_get_from_user(void *dst, void *src, size_t size)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ rt_mmu_info *m_info = RT_NULL;
+
+ /* check src */
+
+ if (src < (void *)USER_VADDR_START)
+ {
+ return 0;
+ }
+ if (src >= (void *)USER_VADDR_TOP)
+ {
+ return 0;
+ }
+ if ((void *)((char *)src + size) > (void *)USER_VADDR_TOP)
+ {
+ return 0;
+ }
+
+ lwp = lwp_self();
+ if (!lwp)
+ {
+ return 0;
+ }
+ m_info = &lwp->mmu_info;
+
+ return lwp_data_get(m_info, dst, src, size);
+}
+
+size_t lwp_put_to_user(void *dst, void *src, size_t size)
+{
+ struct rt_lwp *lwp = RT_NULL;
+ rt_mmu_info *m_info = RT_NULL;
+
+ /* check dst */
+ if (dst < (void *)USER_VADDR_START)
+ {
+ return 0;
+ }
+ if (dst >= (void *)USER_VADDR_TOP)
+ {
+ return 0;
+ }
+ if ((void *)((char *)dst + size) > (void *)USER_VADDR_TOP)
+ {
+ return 0;
+ }
+
+ lwp = lwp_self();
+ if (!lwp)
+ {
+ return 0;
+ }
+ m_info = &lwp->mmu_info;
+ return lwp_data_put(m_info, dst, src, size);
+}
+
+int lwp_user_accessable(void *addr, size_t size)
+{
+ void *addr_start = RT_NULL, *addr_end = RT_NULL, *next_page = RT_NULL;
+ void *tmp_addr = RT_NULL;
+ struct rt_lwp *lwp = lwp_self();
+ rt_mmu_info *mmu_info = RT_NULL;
+
+ if (!lwp)
+ {
+ return 0;
+ }
+ if (!size || !addr)
+ {
+ return 0;
+ }
+ addr_start = addr;
+ addr_end = (void *)((char *)addr + size);
+
+#ifdef ARCH_RISCV64
+ if(addr_start < (void *)USER_VADDR_START)
+ {
+ return 0;
+ }
+#else
+ if (addr_start >= (void *)USER_VADDR_TOP)
+ {
+ return 0;
+ }
+ if (addr_end > (void *)USER_VADDR_TOP)
+ {
+ return 0;
+ }
+#endif
+
+ mmu_info = &lwp->mmu_info;
+ next_page = (void *)(((size_t)addr_start + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
+ do
+ {
+ size_t len = (char *)next_page - (char *)addr_start;
+
+ if (size < len)
+ {
+ len = size;
+ }
+ tmp_addr = rt_hw_mmu_v2p(mmu_info, addr_start);
+ if (!tmp_addr)
+ {
+ return 0;
+ }
+ addr_start = (void *)((char *)addr_start + len);
+ size -= len;
+ next_page = (void *)((char *)next_page + ARCH_PAGE_SIZE);
+ } while (addr_start < addr_end);
+ return 1;
+}
+
+/* src is in mmu_info space, dst is in current thread space */
+size_t lwp_data_get(rt_mmu_info *mmu_info, void *dst, void *src, size_t size)
+{
+ size_t copy_len = 0;
+ void *addr_start = RT_NULL, *addr_end = RT_NULL, *next_page = RT_NULL;
+ void *tmp_dst = RT_NULL, *tmp_src = RT_NULL;
+
+ if (!size || !dst)
+ {
+ return 0;
+ }
+ tmp_dst = dst;
+ addr_start = src;
+ addr_end = (void *)((char *)src + size);
+ next_page = (void *)(((size_t)addr_start + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
+ do
+ {
+ size_t len = (char *)next_page - (char *)addr_start;
+
+ if (size < len)
+ {
+ len = size;
+ }
+ tmp_src = rt_hw_mmu_v2p(mmu_info, addr_start);
+ if (!tmp_src)
+ {
+ break;
+ }
+ tmp_src = (void *)((char *)tmp_src - PV_OFFSET);
+ rt_memcpy(tmp_dst, tmp_src, len);
+ tmp_dst = (void *)((char *)tmp_dst + len);
+ addr_start = (void *)((char *)addr_start + len);
+ size -= len;
+ next_page = (void *)((char *)next_page + ARCH_PAGE_SIZE);
+ copy_len += len;
+ } while (addr_start < addr_end);
+ return copy_len;
+}
+
+/* dst is in mmu_info space, src is in current thread space */
+size_t lwp_data_put(rt_mmu_info *mmu_info, void *dst, void *src, size_t size)
+{
+ size_t copy_len = 0;
+ void *addr_start = RT_NULL, *addr_end = RT_NULL, *next_page = RT_NULL;
+ void *tmp_dst = RT_NULL, *tmp_src = RT_NULL;
+
+ if (!size || !dst)
+ {
+ return 0;
+ }
+ tmp_src = src;
+ addr_start = dst;
+ addr_end = (void *)((char *)dst + size);
+ next_page = (void *)(((size_t)addr_start + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
+ do
+ {
+ size_t len = (char *)next_page - (char *)addr_start;
+
+ if (size < len)
+ {
+ len = size;
+ }
+ tmp_dst = rt_hw_mmu_v2p(mmu_info, addr_start);
+ if (!tmp_dst)
+ {
+ break;
+ }
+ tmp_dst = (void *)((char *)tmp_dst - PV_OFFSET);
+ rt_memcpy(tmp_dst, tmp_src, len);
+ tmp_src = (void *)((char *)tmp_src + len);
+ addr_start = (void *)((char *)addr_start + len);
+ size -= len;
+ next_page = (void *)((char *)next_page + ARCH_PAGE_SIZE);
+ copy_len += len;
+ } while (addr_start < addr_end);
+ return copy_len;
+}
+
+void lwp_data_cache_flush(rt_mmu_info *mmu_info, void *vaddr, size_t size)
+{
+ void *paddr = RT_NULL;
+
+ paddr = rt_hw_mmu_v2p(mmu_info, vaddr);
+ paddr = (void *)((char *)paddr - PV_OFFSET);
+
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, paddr, size);
+}
+#endif
diff --git a/components/lwp/lwp_user_mm.h b/components/lwp/lwp_user_mm.h
new file mode 100644
index 0000000000..07cb27e722
--- /dev/null
+++ b/components/lwp/lwp_user_mm.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-10-28 Jesven first version
+ * 2021-02-12 lizhirui add 64-bit support for lwp_brk
+ */
+#ifndef __LWP_USER_MM_H__
+#define __LWP_USER_MM_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#ifdef RT_USING_USERSPACE
+#include <lwp.h>
+#include <lwp_mm_area.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int lwp_user_space_init(struct rt_lwp *lwp);
+void lwp_unmap_user_space(struct rt_lwp *lwp);
+
+int lwp_unmap_user(struct rt_lwp *lwp, void *va);
+void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, int text);
+
+void *lwp_map_user_phy(struct rt_lwp *lwp, void *map_va, void *map_pa, size_t map_size, int cached);
+int lwp_unmap_user_phy(struct rt_lwp *lwp, void *va);
+
+void *lwp_map_user_type(struct rt_lwp *lwp, void *map_va, void *map_pa, size_t map_size, int cached, int type);
+int lwp_unmap_user_type(struct rt_lwp *lwp, void *va);
+
+rt_base_t lwp_brk(void *addr);
+void* lwp_mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
+int lwp_munmap(void *addr);
+
+size_t lwp_get_from_user(void *dst, void *src, size_t size);
+size_t lwp_put_to_user(void *dst, void *src, size_t size);
+int lwp_user_accessable(void *addr, size_t size);
+
+size_t lwp_data_get(rt_mmu_info *mmu_info, void *dst, void *src, size_t size);
+size_t lwp_data_put(rt_mmu_info *mmu_info, void *dst, void *src, size_t size);
+void lwp_data_cache_flush(rt_mmu_info *mmu_info, void *vaddr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /*__LWP_USER_MM_H__*/
diff --git a/components/lwp/page.c b/components/lwp/page.c
new file mode 100644
index 0000000000..5cf63be5e0
--- /dev/null
+++ b/components/lwp/page.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-11-01 Jesven The first version
+ */
+#include <stdint.h>
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <page.h>
+#include <mmu.h>
+
+#define ARCH_PAGE_LIST_SIZE (ARCH_ADDRESS_WIDTH_BITS - ARCH_PAGE_SHIFT)
+
+#define DBG_TAG "PAGE"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+struct page
+{
+ struct page *next; /* same level next */
+ struct page *pre; /* same level pre */
+ uint32_t size_bits; /* if is ARCH_ADDRESS_WIDTH_BITS, means not free */
+ int ref_cnt; /* page group ref count */
+};
+
+static struct page* page_start;
+static void* page_addr;
+static size_t page_nr;
+
+static struct page *page_list[ARCH_PAGE_LIST_SIZE];
+
+RT_WEAK int rt_hw_clz(size_t n)
+{
+ int bits = sizeof(size_t) * 8;
+
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ n |= (n >> 16);
+
+#ifdef ARCH_CPU_64BIT
+ n |= (n >> 32);
+
+ n = (n & 0x5555555555555555UL) + ((n >> 1) & 0x5555555555555555UL);
+ n = (n & 0x3333333333333333UL) + ((n >> 2) & 0x3333333333333333UL);
+ n = (n & 0x0707070707070707UL) + ((n >> 4) & 0x0707070707070707UL);
+ n = (n & 0x000f000f000f000fUL) + ((n >> 8) & 0x000f000f000f000fUL);
+ n = (n & 0x0000001f0000001fUL) + ((n >> 16) & 0x0000001f0000001fUL);
+ n = (n & 0x000000000000003fUL) + ((n >> 32) & 0x000000000000003fUL);
+#else
+ n = (n & 0x55555555UL) + ((n >> 1) & 0x55555555UL);
+ n = (n & 0x33333333UL) + ((n >> 2) & 0x33333333UL);
+ n = (n & 0x07070707UL) + ((n >> 4) & 0x07070707UL);
+ n = (n & 0x000f000fUL) + ((n >> 8) & 0x000f000fUL);
+ n = (n & 0x0000001fUL) + ((n >> 16) & 0x0000001fUL);
+#endif
+ return bits - n;
+}
+
+RT_WEAK int rt_hw_ctz(size_t n)
+{
+ int ret = sizeof(size_t) * 8;
+
+ if (n)
+ {
+ ret -= (rt_hw_clz(n ^ (n - 1)) + 1);
+ }
+ return ret;
+}
+
+size_t rt_page_bits(size_t size)
+{
+ int bit = sizeof(size_t) * 8 - rt_hw_clz(size) - 1;
+
+ if ((size ^ (1UL << bit)) != 0)
+ {
+ bit++;
+ }
+ bit -= ARCH_PAGE_SHIFT;
+ if (bit < 0)
+ {
+ bit = 0;
+ }
+ return bit;
+}
+
+static struct page * addr_to_page(void *addr)
+{
+ size_t off;
+
+ if (addr < page_addr)
+ {
+ return 0;
+ }
+ off = (size_t)((char*)addr - (char*)page_addr);
+ off >>= ARCH_PAGE_SHIFT;
+ if (off >= page_nr)
+ {
+ return 0;
+ }
+ return &page_start[off];
+}
+
+static void* page_to_addr(struct page* p)
+{
+ if (!p)
+ {
+ return 0;
+ }
+ return (void*)((char*)page_addr + ((p - page_start) << ARCH_PAGE_SHIFT));
+}
+
+static inline struct page *buddy_get(struct page *p, uint32_t size_bits)
+{
+ size_t addr;
+
+ addr = (size_t)page_to_addr(p);
+ addr ^= (1UL << (size_bits + ARCH_PAGE_SHIFT));
+ return addr_to_page((void*)addr);
+}
+
+static void page_remove(struct page *p, uint32_t size_bits)
+{
+ if (p->pre)
+ {
+ p->pre->next = p->next;
+ }
+ else
+ {
+ page_list[size_bits] = p->next;
+ }
+
+ if (p->next)
+ {
+ p->next->pre = p->pre;
+ }
+
+ p->size_bits = ARCH_ADDRESS_WIDTH_BITS;
+}
+
+static void page_insert(struct page *p, uint32_t size_bits)
+{
+ p->next = page_list[size_bits];
+ if (p->next)
+ {
+ p->next->pre = p;
+ }
+ p->pre = 0;
+ page_list[size_bits] = p;
+ p->size_bits = size_bits;
+}
+
+static void _pages_ref_inc(struct page *p, uint32_t size_bits)
+{
+ struct page *page_head;
+ int idx;
+
+ /* find page group head */
+ idx = p - page_start;
+ if (idx < 0 || idx >= page_nr)
+ {
+ return;
+ }
+ idx = idx & ~((1UL << size_bits) - 1);
+
+ page_head = page_start + idx;
+ page_head->ref_cnt++;
+}
+
+static int _pages_ref_get(struct page *p, uint32_t size_bits)
+{
+ struct page *page_head;
+ int idx;
+
+ /* find page group head */
+ idx = p - page_start;
+ if (idx < 0 || idx >= page_nr)
+ {
+ return 0;
+ }
+ idx = idx & ~((1UL << size_bits) - 1);
+
+ page_head = page_start + idx;
+ return page_head->ref_cnt;
+}
+
+static int _pages_free(struct page *p, uint32_t size_bits)
+{
+ uint32_t level = size_bits;
+ struct page *buddy;
+
+ RT_ASSERT(p->ref_cnt > 0);
+ RT_ASSERT(p->size_bits == ARCH_ADDRESS_WIDTH_BITS);
+
+ p->ref_cnt--;
+ if (p->ref_cnt != 0)
+ {
+ return 0;
+ }
+
+ while (level < ARCH_PAGE_LIST_SIZE)
+ {
+ buddy = buddy_get(p, level);
+ if (buddy && buddy->size_bits == level)
+ {
+ page_remove(buddy, level);
+ p = (p < buddy) ? p : buddy;
+ level++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ page_insert(p, level);
+ return 1;
+}
+
+static struct page *_pages_alloc(uint32_t size_bits)
+{
+ struct page *p;
+
+ if (page_list[size_bits])
+ {
+ p = page_list[size_bits];
+ page_remove(p, size_bits);
+ }
+ else
+ {
+ uint32_t level;
+
+ for (level = size_bits + 1; level < ARCH_PAGE_LIST_SIZE; level++)
+ {
+ if (page_list[level])
+ {
+ break;
+ }
+ }
+ if (level == ARCH_PAGE_LIST_SIZE)
+ {
+ return 0;
+ }
+
+ p = page_list[level];
+ page_remove(p, level);
+ while (level > size_bits)
+ {
+ page_insert(p, level - 1);
+ p = buddy_get(p, level - 1);
+ level--;
+ }
+ }
+ p->size_bits = ARCH_ADDRESS_WIDTH_BITS;
+ p->ref_cnt = 1;
+ return p;
+}
+
+int rt_page_ref_get(void *addr, uint32_t size_bits)
+{
+ struct page *p;
+ rt_base_t level;
+ int ref;
+
+ p = addr_to_page(addr);
+ level = rt_hw_interrupt_disable();
+ ref = _pages_ref_get(p, size_bits);
+ rt_hw_interrupt_enable(level);
+ return ref;
+}
+
+void rt_page_ref_inc(void *addr, uint32_t size_bits)
+{
+ struct page *p;
+ rt_base_t level;
+
+ p = addr_to_page(addr);
+ level = rt_hw_interrupt_disable();
+ _pages_ref_inc(p, size_bits);
+ rt_hw_interrupt_enable(level);
+}
+
+void *rt_pages_alloc(uint32_t size_bits)
+{
+ struct page *p;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ p = _pages_alloc(size_bits);
+ rt_hw_interrupt_enable(level);
+ return page_to_addr(p);
+}
+
+int rt_pages_free(void *addr, uint32_t size_bits)
+{
+ struct page *p;
+ int real_free = 0;
+
+ p = addr_to_page(addr);
+ if (p)
+ {
+ rt_base_t level;
+ level = rt_hw_interrupt_disable();
+ real_free = _pages_free(p, size_bits);
+ rt_hw_interrupt_enable(level);
+ }
+ return real_free;
+}
+
+void list_page(void)
+{
+ int i;
+ size_t total = 0;
+
+ rt_base_t level;
+ level = rt_hw_interrupt_disable();
+
+ for (i = 0; i < ARCH_PAGE_LIST_SIZE; i++)
+ {
+ struct page *p = page_list[i];
+
+ rt_kprintf("level %d ", i);
+
+ while (p)
+ {
+ total += (1UL << i);
+ rt_kprintf("[0x%08p]", page_to_addr(p));
+ p = p->next;
+ }
+ rt_kprintf("\n");
+ }
+ rt_hw_interrupt_enable(level);
+ rt_kprintf("free pages is %08x\n", total);
+ rt_kprintf("-------------------------------\n");
+}
+MSH_CMD_EXPORT(list_page, show page info);
+
+void rt_page_get_info(size_t *total_nr, size_t *free_nr)
+{
+ int i;
+ size_t total_free = 0;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ for (i = 0; i < ARCH_PAGE_LIST_SIZE; i++)
+ {
+ struct page *p = page_list[i];
+
+ while (p)
+ {
+ total_free += (1UL << i);
+ p = p->next;
+ }
+ }
+ rt_hw_interrupt_enable(level);
+ *total_nr = page_nr;
+ *free_nr = total_free;
+}
+
+void rt_page_init(rt_region_t reg)
+{
+ int i;
+
+ LOG_D("split 0x%08x 0x%08x\n", reg.start, reg.end);
+
+ reg.start += ARCH_PAGE_MASK;
+ reg.start &= ~ARCH_PAGE_MASK;
+
+ reg.end &= ~ARCH_PAGE_MASK;
+
+ {
+ int nr = ARCH_PAGE_SIZE / sizeof(struct page);
+ int total = (reg.end - reg.start) >> ARCH_PAGE_SHIFT;
+ int mnr = (total + nr) / (nr + 1);
+
+ LOG_D("nr = 0x%08x\n", nr);
+ LOG_D("total = 0x%08x\n", total);
+ LOG_D("mnr = 0x%08x\n", mnr);
+
+ RT_ASSERT(mnr < total);
+
+ page_start = (struct page*)reg.start;
+ reg.start += (mnr << ARCH_PAGE_SHIFT);
+ page_addr = (void*)reg.start;
+ page_nr = (reg.end - reg.start) >> ARCH_PAGE_SHIFT;
+ }
+
+ LOG_D("align 0x%08x 0x%08x\n", reg.start, reg.end);
+
+ /* init free list */
+ for (i = 0; i < ARCH_PAGE_LIST_SIZE; i++)
+ {
+ page_list[i] = 0;
+ }
+
+ /* add pages to free list */
+ while (reg.start != reg.end)
+ {
+ struct page *p;
+ int align_bits;
+ int size_bits;
+
+ size_bits = ARCH_ADDRESS_WIDTH_BITS - 1 - rt_hw_clz(reg.end - reg.start);
+ align_bits = rt_hw_ctz(reg.start);
+ if (align_bits < size_bits)
+ {
+ size_bits = align_bits;
+ }
+ p = addr_to_page((void*)reg.start);
+ p->size_bits = ARCH_ADDRESS_WIDTH_BITS;
+ p->ref_cnt = 1;
+ _pages_free(p, size_bits - ARCH_PAGE_SHIFT);
+ reg.start += (1UL << size_bits);
+ }
+}
+#endif
diff --git a/components/lwp/page.h b/components/lwp/page.h
new file mode 100644
index 0000000000..8b65299d91
--- /dev/null
+++ b/components/lwp/page.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-11-01 Jesven The first version
+ */
+
+#ifndef __PAGE_H__
+#define __PAGE_H__
+
+#ifdef RT_USING_USERSPACE
+
+typedef struct tag_region
+{
+ size_t start;
+ size_t end;
+} rt_region_t;
+
+void rt_page_init(rt_region_t reg);
+
+void *rt_pages_alloc(uint32_t size_bits);
+
+void rt_page_ref_inc(void *addr, uint32_t size_bits);
+
+int rt_page_ref_get(void *addr, uint32_t size_bits);
+
+int rt_pages_free(void *addr, uint32_t size_bits);
+
+void rt_pageinfo_dump(void);
+
+size_t rt_page_bits(size_t size);
+
+void rt_page_get_info(size_t *total_nr, size_t *free_nr);
+
+#endif
+
+#endif /*__PAGE_H__*/
diff --git a/components/lwp/syscall_data.h b/components/lwp/syscall_data.h
new file mode 100644
index 0000000000..7c700e0dd0
--- /dev/null
+++ b/components/lwp/syscall_data.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-10 RT-Thread The first version
+ */
+#ifndef __SYSCALL_DATA_H__
+#define __SYSCALL_DATA_H__
+
+#include <rtthread.h>
+
+/**
+ * @brief signature for syscall, used to locate syscall metadata.
+ *
+ * We don't allocate an exclusive section in ELF like Linux do
+ * to avoid initializing necessary data by iterating that section,
+ * which increases system booting time. We signature a pointer
+ * just below each syscall entry in syscall table to make it
+ * easy to locate every syscall's metadata by using syscall id.
+ *
+ * TODO Currently this adds a dummy pointer to syscall name.
+ * After adding metadata of every syscalls in front of their definition,
+ * this should be replaced by a pointer to that structure
+ */
+#define SYSCALL_SIGN(func) \
+ (void *)func, \
+ RT_STRINGIFY(func)
+
+#endif /* __SYSCALL_DATA_H__ */ \ No newline at end of file
diff --git a/components/net/netdev/src/netdev.c b/components/net/netdev/src/netdev.c
index aa06f51fdf..09f6c37d9a 100644
--- a/components/net/netdev/src/netdev.c
+++ b/components/net/netdev/src/netdev.c
@@ -741,6 +741,14 @@ static void netdev_auto_change_default(struct netdev *netdev)
{
struct netdev *new_netdev = RT_NULL;
+ if (netdev->flags & NETDEV_FLAG_LINK_UP)
+ {
+ if (!(netdev_default->flags & NETDEV_FLAG_LINK_UP))
+ {
+ netdev_set_default(netdev);
+ }
+ return;
+ }
if (rt_memcmp(netdev, netdev_default, sizeof(struct netdev)) == 0)
{
new_netdev = netdev_get_first_by_flags(NETDEV_FLAG_LINK_UP);
@@ -996,6 +1004,35 @@ static void netdev_list_if(void)
}
}
+#ifdef RT_LWIP_DHCP
+int netdev_dhcp_open(char* netdev_name)
+{
+ struct netdev *netdev = RT_NULL;
+ netdev = netdev_get_by_name(netdev_name);
+ if (netdev == RT_NULL)
+ {
+ rt_kprintf("bad network interface device name(%s).\n", netdev_name);
+ return -1;
+ }
+ netdev_dhcp_enabled(netdev,RT_TRUE);
+ return 0;
+}
+
+int netdev_dhcp_close(char* netdev_name)
+{
+ struct netdev *netdev = RT_NULL;
+
+ netdev = netdev_get_by_name(netdev_name);
+ if (netdev == RT_NULL)
+ {
+ rt_kprintf("bad network interface device name(%s).\n", netdev_name);
+ return -1;
+ }
+ netdev_dhcp_enabled(netdev,RT_FALSE);
+ return 0;
+}
+#endif
+
static void netdev_set_if(char* netdev_name, char* ip_addr, char* gw_addr, char* nm_addr)
{
struct netdev *netdev = RT_NULL;
@@ -1008,6 +1045,10 @@ static void netdev_set_if(char* netdev_name, char* ip_addr, char* gw_addr, char*
return;
}
+#ifdef RT_LWIP_DHCP
+ netdev_dhcp_close(netdev_name);
+#endif
+
/* set IP address */
if ((ip_addr != RT_NULL) && inet_aton(ip_addr, &addr))
{
@@ -1033,6 +1074,15 @@ int netdev_ifconfig(int argc, char **argv)
{
netdev_list_if();
}
+#ifdef RT_LWIP_DHCP
+ else if(argc == 3)
+ {
+ if (!strcmp(argv[2], "dhcp"))
+ {
+ netdev_dhcp_open(argv[1]);
+ }
+ }
+#endif
else if (argc == 5)
{
rt_kprintf("config : %s\n", argv[1]);
@@ -1044,6 +1094,9 @@ int netdev_ifconfig(int argc, char **argv)
else
{
rt_kprintf("bad parameter! e.g: ifconfig e0 192.168.1.30 192.168.1.1 255.255.255.0\n");
+#ifdef RT_LWIP_DHCP
+ rt_kprintf("bad parameter! e.g: ifconfig e0 dhcp\n");
+#endif
}
return 0;
diff --git a/components/net/sal/dfs_net/dfs_net.c b/components/net/sal/dfs_net/dfs_net.c
index 67b652c320..2aded9fcd8 100644
--- a/components/net/sal/dfs_net/dfs_net.c
+++ b/components/net/sal/dfs_net/dfs_net.c
@@ -26,39 +26,64 @@ int dfs_net_getsocket(int fd)
_dfs_fd = fd_get(fd);
if (_dfs_fd == NULL) return -1;
- if (_dfs_fd->type != FT_SOCKET) socket = -1;
- else socket = (int)_dfs_fd->data;
+ if (_dfs_fd->vnode->type != FT_SOCKET) socket = -1;
+ else socket = (int)(size_t)_dfs_fd->vnode->data;
- fd_put(_dfs_fd); /* put this dfs fd */
return socket;
}
static int dfs_net_ioctl(struct dfs_fd* file, int cmd, void* args)
{
- int socket = (int) file->data;
+ int ret;
+ int socket = (int)(size_t)file->vnode->data;
- return sal_ioctlsocket(socket, cmd, args);
+ ret = sal_ioctlsocket(socket, cmd, args);
+ if (ret < 0)
+ {
+ ret = rt_get_errno();
+ return (ret > 0) ? (-ret) : ret;
+ }
+ return ret;
}
static int dfs_net_read(struct dfs_fd* file, void *buf, size_t count)
{
- int socket = (int) file->data;
+ int ret;
+ int socket = (int)(size_t)file->vnode->data;
- return sal_recvfrom(socket, buf, count, 0, NULL, NULL);
+ ret = sal_recvfrom(socket, buf, count, 0, NULL, NULL);
+ if (ret < 0)
+ {
+ ret = rt_get_errno();
+ return (ret > 0) ? (-ret) : ret;
+ }
+ return ret;
}
static int dfs_net_write(struct dfs_fd *file, const void *buf, size_t count)
{
- int socket = (int) file->data;
-
- return sal_sendto(socket, buf, count, 0, NULL, 0);
+ int ret;
+ int socket = (int)(size_t)file->vnode->data;
+
+ ret = sal_sendto(socket, buf, count, 0, NULL, 0);
+ if (ret < 0)
+ {
+ ret = rt_get_errno();
+ return (ret > 0) ? (-ret) : ret;
+ }
+ return ret;
}
-
static int dfs_net_close(struct dfs_fd* file)
{
- int socket = (int) file->data;
+ int socket;
+ int ret = 0;
- return sal_closesocket(socket);
+ if (file->vnode->ref_count == 1)
+ {
+ socket = (int)(size_t)file->vnode->data;
+ ret = sal_closesocket(socket);
+ }
+ return ret;
}
static int dfs_net_poll(struct dfs_fd *file, struct rt_pollreq *req)
diff --git a/components/net/sal/impl/af_inet_lwip.c b/components/net/sal/impl/af_inet_lwip.c
index e99da3117a..401b9001e4 100644
--- a/components/net/sal/impl/af_inet_lwip.c
+++ b/components/net/sal/impl/af_inet_lwip.c
@@ -165,7 +165,7 @@ static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len
if (event)
{
- rt_wqueue_wakeup(&sock->wait_head, (void*) event);
+ rt_wqueue_wakeup(&sock->wait_head, (void*)(size_t)event);
}
}
#endif /* SAL_USING_POSIX */
@@ -229,7 +229,7 @@ int inet_ioctlsocket(int socket, long cmd, void *arg)
{
case F_GETFL:
case F_SETFL:
- return lwip_fcntl(socket, cmd, (int) arg);
+ return lwip_fcntl(socket, cmd, (int)(size_t)arg);
default:
return lwip_ioctl(socket, cmd, arg);
@@ -243,13 +243,13 @@ static int inet_poll(struct dfs_fd *file, struct rt_pollreq *req)
struct lwip_sock *sock;
struct sal_socket *sal_sock;
- sal_sock = sal_get_socket((int) file->data);
+ sal_sock = sal_get_socket((int)(size_t)file->vnode->data);
if(!sal_sock)
{
return -1;
}
- sock = lwip_tryget_socket((int)sal_sock->user_data);
+ sock = lwip_tryget_socket((int)(size_t)sal_sock->user_data);
if (sock != NULL)
{
rt_base_t level;
diff --git a/components/net/sal/include/sal_socket.h b/components/net/sal/include/sal_socket.h
index c479d21c62..b77487516f 100644
--- a/components/net/sal/include/sal_socket.h
+++ b/components/net/sal/include/sal_socket.h
@@ -36,8 +36,12 @@ typedef uint16_t in_port_t;
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
+#define SOCK_PACKET 10
-#define SOCK_MAX (SOCK_RAW + 1)
+#define SOCK_NONBLOCK 04000
+#define SOCK_CLOEXEC 02000000
+
+#define SOCK_MAX (SOCK_CLOEXEC + 1)
/* Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) */
#define SO_REUSEADDR 0x0004 /* Allow local address reuse */
@@ -68,11 +72,13 @@ typedef uint16_t in_port_t;
#define SOL_SOCKET 0xfff /* options for socket level */
#define AF_UNSPEC 0
+#define AF_UNIX 1
#define AF_INET 2
#define AF_INET6 10
#define AF_CAN 29 /* Controller Area Network */
#define AF_AT 45 /* AT socket */
#define AF_WIZ 46 /* WIZnet socket */
+#define PF_UNIX AF_UNIX
#define PF_INET AF_INET
#define PF_INET6 AF_INET6
#define PF_UNSPEC AF_UNSPEC
@@ -158,6 +164,15 @@ struct sockaddr
char sa_data[14];
};
+/* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket. */
+struct sockaddr_un
+{
+ uint8_t sa_len;
+ sa_family_t sa_family;
+ char sun_path[108]; /* Path name. */
+};
+
+
#if NETDEV_IPV4
/* members are in network byte order */
struct sockaddr_in
@@ -194,6 +209,40 @@ struct sockaddr_storage
#endif /* NETDEV_IPV6 */
};
+#define IFNAMSIZ 16
+struct sal_ifmap
+{
+ unsigned long int mem_start;
+ unsigned long int mem_end;
+ unsigned short int base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+};
+
+struct sal_ifreq
+{
+ union
+ {
+ char ifrn_name[IFNAMSIZ];
+ } ifr_ifrn;
+ union
+ {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short int ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct sal_ifmap ifru_map;
+ char ifru_slave[IFNAMSIZ];
+ char ifru_newname[IFNAMSIZ];
+ char *ifru_data;
+ } ifr_ifru;
+};
+
int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen);
int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen);
int sal_shutdown(int socket, int how);
diff --git a/components/net/sal/socket/net_sockets.c b/components/net/sal/socket/net_sockets.c
index 1b6db50e6d..e10ffef9b0 100644
--- a/components/net/sal/socket/net_sockets.c
+++ b/components/net/sal/socket/net_sockets.c
@@ -41,20 +41,28 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
if(d)
{
/* this is a socket fd */
- d->type = FT_SOCKET;
- d->path = NULL;
-
- d->fops = dfs_net_get_fops();
+ d->vnode = (struct dfs_fnode *)rt_malloc(sizeof(struct dfs_fnode));
+ if (!d->vnode)
+ {
+ /* release fd */
+ fd_release(fd);
+ rt_set_errno(-ENOMEM);
+ return -1;
+ }
+ rt_memset(d->vnode, 0, sizeof(struct dfs_fnode));
+ rt_list_init(&d->vnode->list);
+ d->vnode->type = FT_SOCKET;
+ d->vnode->path = NULL;
+ d->vnode->fullpath = NULL;
+ d->vnode->ref_count = 1;
+ d->vnode->fops = dfs_net_get_fops();
d->flags = O_RDWR; /* set flags as read and write */
- d->size = 0;
+ d->vnode->size = 0;
d->pos = 0;
/* set socket to the data of dfs_fd */
- d->data = (void *) new_socket;
-
- /* release the ref-count of fd */
- fd_put(d);
+ d->vnode->data = (void *)(size_t)new_socket;
return fd;
}
@@ -72,6 +80,17 @@ int bind(int s, const struct sockaddr *name, socklen_t namelen)
{
int socket = dfs_net_getsocket(s);
+#ifdef SAL_USING_AF_UNIX
+ struct sockaddr_in server_addr = {0};
+ if (name->sa_family == AF_UNIX)
+ {
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(514);
+ server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ return sal_bind(socket, (struct sockaddr *)&server_addr, namelen);
+ }
+#endif /* SAL_USING_AF_UNIX */
+
return sal_bind(socket, name, namelen);
}
RTM_EXPORT(bind);
@@ -106,8 +125,6 @@ int shutdown(int s, int how)
error = -1;
}
- fd_put(d);
-
return error;
}
RTM_EXPORT(shutdown);
@@ -148,6 +165,17 @@ int connect(int s, const struct sockaddr *name, socklen_t namelen)
{
int socket = dfs_net_getsocket(s);
+#ifdef SAL_USING_AF_UNIX
+ struct sockaddr_in server_addr = {0};
+ if (name->sa_family == AF_UNIX)
+ {
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(514);
+ server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ return sal_connect(socket, (struct sockaddr *)&server_addr, namelen);
+ }
+#endif /* SAL_USING_AF_UNIX */
+
return sal_connect(socket, name, namelen);
}
RTM_EXPORT(connect);
@@ -210,38 +238,51 @@ int socket(int domain, int type, int protocol)
return -1;
}
d = fd_get(fd);
+ d->vnode = (struct dfs_fnode *)rt_malloc(sizeof(struct dfs_fnode));
+ if (!d->vnode)
+ {
+ /* release fd */
+ fd_release(fd);
+ rt_set_errno(-ENOMEM);
+ return -1;
+ }
+
+#ifdef SAL_USING_AF_UNIX
+ if (domain == AF_UNIX)
+ {
+ domain = AF_INET;
+ }
+#endif /* SAL_USING_AF_UNIX */
/* create socket and then put it to the dfs_fd */
socket = sal_socket(domain, type, protocol);
if (socket >= 0)
{
+ rt_memset(d->vnode, 0, sizeof(struct dfs_fnode));
+ rt_list_init(&d->vnode->list);
/* this is a socket fd */
- d->type = FT_SOCKET;
- d->path = NULL;
-
- d->fops = dfs_net_get_fops();
+ d->vnode->type = FT_SOCKET;
+ d->vnode->path = NULL;
+ d->vnode->fullpath = NULL;
+ d->vnode->ref_count = 1;
+ d->vnode->fops = dfs_net_get_fops();
d->flags = O_RDWR; /* set flags as read and write */
- d->size = 0;
+ d->vnode->size = 0;
d->pos = 0;
/* set socket to the data of dfs_fd */
- d->data = (void *) socket;
+ d->vnode->data = (void *)(size_t)socket;
}
else
{
+ rt_free(d->vnode);
/* release fd */
- fd_put(d);
- fd_put(d);
-
+ fd_release(fd);
rt_set_errno(-ENOMEM);
-
return -1;
}
- /* release the ref-count of fd */
- fd_put(d);
-
return fd;
}
RTM_EXPORT(socket);
@@ -266,6 +307,12 @@ int closesocket(int s)
return -1;
}
+ if (!d->vnode)
+ {
+ rt_set_errno(-EBADF);
+ return -1;
+ }
+
if (sal_closesocket(socket) == 0)
{
error = 0;
@@ -276,9 +323,9 @@ int closesocket(int s)
error = -1;
}
+ rt_free(d->vnode);
/* socket has been closed, delete it from file system fd */
- fd_put(d);
- fd_put(d);
+ fd_release(s);
return error;
}
diff --git a/components/net/sal/src/sal_socket.c b/components/net/sal/src/sal_socket.c
index e3dafd0cc8..d1f9f645e6 100644
--- a/components/net/sal/src/sal_socket.c
+++ b/components/net/sal/src/sal_socket.c
@@ -12,6 +12,7 @@
#include <rtthread.h>
#include <rthw.h>
#include <sys/time.h>
+#include <sys/ioctl.h>
#include <sal_socket.h>
#include <sal_netdb.h>
@@ -594,7 +595,7 @@ int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
/* check the network interface socket operations */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, accept);
- new_socket = pf->skt_ops->accept((int) sock->user_data, addr, addrlen);
+ new_socket = pf->skt_ops->accept((int)(size_t)sock->user_data, addr, addrlen);
if (new_socket != -1)
{
int retval;
@@ -624,7 +625,7 @@ int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
/* new socket create by accept should have the same netdev with server*/
new_sock->netdev = sock->netdev;
/* socket structure user_data used to store the acquired new socket */
- new_sock->user_data = (void *) new_socket;
+ new_sock->user_data = (void *)(size_t)new_socket;
return new_sal_socket;
}
@@ -690,13 +691,13 @@ int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen)
return -1;
}
sock->netdev = new_netdev;
- sock->user_data = (void *) new_socket;
+ sock->user_data = (void *)(size_t)new_socket;
}
}
/* check and get protocol families by the network interface device */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, bind);
- return pf->skt_ops->bind((int) sock->user_data, name, namelen);
+ return pf->skt_ops->bind((int)(size_t)sock->user_data, name, namelen);
}
int sal_shutdown(int socket, int how)
@@ -712,7 +713,7 @@ int sal_shutdown(int socket, int how)
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, shutdown);
- if (pf->skt_ops->shutdown((int) sock->user_data, how) == 0)
+ if (pf->skt_ops->shutdown((int)(size_t)sock->user_data, how) == 0)
{
#ifdef SAL_USING_TLS
if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket))
@@ -745,7 +746,7 @@ int sal_getpeername(int socket, struct sockaddr *name, socklen_t *namelen)
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, getpeername);
- return pf->skt_ops->getpeername((int) sock->user_data, name, namelen);
+ return pf->skt_ops->getpeername((int)(size_t)sock->user_data, name, namelen);
}
int sal_getsockname(int socket, struct sockaddr *name, socklen_t *namelen)
@@ -759,7 +760,7 @@ int sal_getsockname(int socket, struct sockaddr *name, socklen_t *namelen)
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, getsockname);
- return pf->skt_ops->getsockname((int) sock->user_data, name, namelen);
+ return pf->skt_ops->getsockname((int)(size_t)sock->user_data, name, namelen);
}
int sal_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen)
@@ -773,7 +774,7 @@ int sal_getsockopt(int socket, int level, int optname, void *optval, socklen_t *
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, getsockopt);
- return pf->skt_ops->getsockopt((int) sock->user_data, level, optname, optval, optlen);
+ return pf->skt_ops->getsockopt((int)(size_t)sock->user_data, level, optname, optval, optlen);
}
int sal_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
@@ -819,7 +820,7 @@ int sal_setsockopt(int socket, int level, int optname, const void *optval, sockl
return pf->skt_ops->setsockopt((int) sock->user_data, level, optname, optval, optlen);
}
#else
- return pf->skt_ops->setsockopt((int) sock->user_data, level, optname, optval, optlen);
+ return pf->skt_ops->setsockopt((int)(size_t)sock->user_data, level, optname, optval, optlen);
#endif /* SAL_USING_TLS */
}
@@ -837,7 +838,7 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, connect);
- ret = pf->skt_ops->connect((int) sock->user_data, name, namelen);
+ ret = pf->skt_ops->connect((int)(size_t)sock->user_data, name, namelen);
#ifdef SAL_USING_TLS
if (ret >= 0 && SAL_SOCKOPS_PROTO_TLS_VALID(sock, connect))
{
@@ -864,7 +865,7 @@ int sal_listen(int socket, int backlog)
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, listen);
- return pf->skt_ops->listen((int) sock->user_data, backlog);
+ return pf->skt_ops->listen((int)(size_t)sock->user_data, backlog);
}
int sal_recvfrom(int socket, void *mem, size_t len, int flags,
@@ -894,10 +895,10 @@ int sal_recvfrom(int socket, void *mem, size_t len, int flags,
}
else
{
- return pf->skt_ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen);
+ return pf->skt_ops->recvfrom((int)(size_t)sock->user_data, mem, len, flags, from, fromlen);
}
#else
- return pf->skt_ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen);
+ return pf->skt_ops->recvfrom((int)(size_t)sock->user_data, mem, len, flags, from, fromlen);
#endif
}
@@ -931,7 +932,7 @@ int sal_sendto(int socket, const void *dataptr, size_t size, int flags,
return pf->skt_ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
}
#else
- return pf->skt_ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
+ return pf->skt_ops->sendto((int)(size_t)sock->user_data, dataptr, size, flags, to, tolen);
#endif
}
@@ -983,7 +984,7 @@ int sal_socket(int domain, int type, int protocol)
}
}
#endif
- sock->user_data = (void *) proto_socket;
+ sock->user_data = (void *)(size_t)proto_socket;
return sock->socket;
}
socket_delete(socket);
@@ -1003,7 +1004,7 @@ int sal_closesocket(int socket)
/* valid the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, closesocket);
- if (pf->skt_ops->closesocket((int) sock->user_data) == 0)
+ if (pf->skt_ops->closesocket((int)(size_t)sock->user_data) == 0)
{
#ifdef SAL_USING_TLS
if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket))
@@ -1031,14 +1032,69 @@ int sal_ioctlsocket(int socket, long cmd, void *arg)
{
struct sal_socket *sock;
struct sal_proto_family *pf;
-
+ struct sockaddr_in *addr_in = RT_NULL;
+ struct sockaddr *addr = RT_NULL;
+ ip_addr_t input_ipaddr;
/* get the socket object by socket descriptor */
SAL_SOCKET_OBJ_GET(sock, socket);
/* check the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, ioctlsocket);
- return pf->skt_ops->ioctlsocket((int) sock->user_data, cmd, arg);
+ struct sal_ifreq *ifr = (struct sal_ifreq *)arg;
+
+ if((sock->domain == AF_INET)&&(sock->netdev)&&(ifr != RT_NULL))
+ {
+ switch (cmd)
+ {
+ case SIOCGIFADDR:
+ addr_in = (struct sockaddr_in *)&(ifr->ifr_ifru.ifru_addr);
+#if NETDEV_IPV4 && NETDEV_IPV6
+ addr_in->sin_addr.s_addr = sock->netdev->ip_addr.u_addr.ip4.addr;
+#elif NETDEV_IPV4
+ addr_in->sin_addr.s_addr = sock->netdev->ip_addr.addr;
+#elif NETDEV_IPV6
+#error "not only support IPV6"
+#endif /* NETDEV_IPV4 && NETDEV_IPV6*/
+ return 0;
+
+ case SIOCSIFADDR:
+ addr = (struct sockaddr *)&(ifr->ifr_ifru.ifru_addr);
+ sal_sockaddr_to_ipaddr(addr,&input_ipaddr);
+ netdev_set_ipaddr(sock->netdev,&input_ipaddr);
+ return 0;
+
+ case SIOCGIFNETMASK:
+ addr_in = (struct sockaddr_in *)&(ifr->ifr_ifru.ifru_netmask);
+#if NETDEV_IPV4 && NETDEV_IPV6
+ addr_in->sin_addr.s_addr = sock->netdev->netmask.u_addr.ip4.addr;
+#elif NETDEV_IPV4
+ addr_in->sin_addr.s_addr = sock->netdev->netmask.addr;
+#elif NETDEV_IPV6
+#error "not only support IPV6"
+#endif /* NETDEV_IPV4 && NETDEV_IPV6*/
+ return 0;
+
+ case SIOCSIFNETMASK:
+ addr = (struct sockaddr *)&(ifr->ifr_ifru.ifru_netmask);
+ sal_sockaddr_to_ipaddr(addr,&input_ipaddr);
+ netdev_set_netmask(sock->netdev,&input_ipaddr);
+ return 0;
+
+ case SIOCGIFHWADDR:
+ addr = (struct sockaddr *)&(ifr->ifr_ifru.ifru_hwaddr);
+ rt_memcpy(addr->sa_data,sock->netdev->hwaddr,sock->netdev->hwaddr_len);
+ return 0;
+
+ case SIOCGIFMTU:
+ ifr->ifr_ifru.ifru_mtu = sock->netdev->mtu;
+ return 0;
+
+ default:
+ break;
+ }
+ }
+ return pf->skt_ops->ioctlsocket((int)(size_t)sock->user_data, cmd, arg);
}
#ifdef SAL_USING_POSIX
@@ -1046,7 +1102,7 @@ int sal_poll(struct dfs_fd *file, struct rt_pollreq *req)
{
struct sal_socket *sock;
struct sal_proto_family *pf;
- int socket = (int) file->data;
+ int socket = (int)(size_t)file->vnode->data;
/* get the socket object by socket descriptor */
SAL_SOCKET_OBJ_GET(sock, socket);
diff --git a/components/utilities/resource/SConscript b/components/utilities/resource/SConscript
new file mode 100644
index 0000000000..3f33b790c5
--- /dev/null
+++ b/components/utilities/resource/SConscript
@@ -0,0 +1,8 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+group = DefineGroup('resource', src, depend = ['RT_USING_POSIX_PIPE'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/utilities/resource/resource_id.c b/components/utilities/resource/resource_id.c
new file mode 100644
index 0000000000..43f64e7b03
--- /dev/null
+++ b/components/utilities/resource/resource_id.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-08-25 RT-Thread First version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+#include <resource_id.h>
+
+void resource_id_init(resource_id_t *mgr, int size, void **res)
+{
+ if (mgr)
+ {
+ mgr->size = size;
+ mgr->_res = res;
+ mgr->noused = 0;
+ mgr->_free = RT_NULL;
+ }
+}
+
+int resource_id_get(resource_id_t *mgr)
+{
+ rt_base_t level;
+ void **cur;
+
+ level = rt_hw_interrupt_disable();
+ if (mgr->_free)
+ {
+ cur = mgr->_free;
+ mgr->_free = (void **)*mgr->_free;
+ rt_hw_interrupt_enable(level);
+ return cur - mgr->_res;
+ }
+ else if (mgr->noused < mgr->size)
+ {
+ cur = &mgr->_res[mgr->noused++];
+ rt_hw_interrupt_enable(level);
+ return cur - mgr->_res;
+ }
+ rt_hw_interrupt_enable(level);
+ return -1;
+}
+
+void resource_id_put(resource_id_t *mgr, int no)
+{
+ rt_base_t level;
+ void **cur;
+
+ if (no >= 0 && no < mgr->size)
+ {
+ level = rt_hw_interrupt_disable();
+ cur = &mgr->_res[no];
+ *cur = (void *)mgr->_free;
+ mgr->_free = cur;
+ rt_hw_interrupt_enable(level);
+ }
+}
+
diff --git a/components/utilities/resource/resource_id.h b/components/utilities/resource/resource_id.h
new file mode 100644
index 0000000000..9706a3cbaf
--- /dev/null
+++ b/components/utilities/resource/resource_id.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-08-25 RT-Thread First version
+ */
+
+#ifndef RESOURCE_ID_H__
+#define RESOURCE_ID_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#define RESOURCE_ID_INIT(size, pool) {size, pool, 0, RT_NULL}
+
+typedef struct
+{
+ int size;
+ void **_res;
+ int noused;
+ void **_free;
+} resource_id_t;
+
+void resource_id_init(resource_id_t *mgr, int size, void **res);
+int resource_id_get(resource_id_t *mgr);
+void resource_id_put(resource_id_t *mgr, int no);
+
+#endif /*RESOURCE_ID_H__*/
diff --git a/components/utilities/rt-link/src/rtlink_dev.c b/components/utilities/rt-link/src/rtlink_dev.c
index 702aed32da..f15294fc4d 100644
--- a/components/utilities/rt-link/src/rtlink_dev.c
+++ b/components/utilities/rt-link/src/rtlink_dev.c
@@ -49,7 +49,7 @@ int rtlink_fops_open(struct dfs_fd *fd)
break;
}
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
if (fd->flags & O_NONBLOCK)
{
rt_device_control(device, RT_LINK_TX_NONBLOCKING | RT_LINK_RX_NONBLOCKING, RT_NULL);
@@ -61,7 +61,7 @@ int rtlink_fops_open(struct dfs_fd *fd)
int rtlink_fops_close(struct dfs_fd *fd)
{
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
rt_device_set_rx_indicate(device, RT_NULL);
return rt_device_close(device);
@@ -70,7 +70,7 @@ int rtlink_fops_close(struct dfs_fd *fd)
int rtlink_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
{
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
if (cmd == O_NONBLOCK)
{
@@ -86,7 +86,7 @@ int rtlink_fops_read(struct dfs_fd *fd, void *buf, size_t count)
{
int size = 0;
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
size = rt_device_read(device, -1, buf, count);
if (size <= 0)
@@ -100,7 +100,7 @@ int rtlink_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
{
int size = 0;
rt_device_t device;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
size = rt_device_write(device, -1, buf, count);
if (size <= 0)
@@ -117,7 +117,7 @@ int rtlink_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
rt_device_t device;
struct rt_link_device *rtlink_dev;
- device = (rt_device_t)fd->data;
+ device = (rt_device_t)fd->vnode->data;
RT_ASSERT(device != RT_NULL);
rtlink_dev = (struct rt_link_device *)device;