From 4ce652e4b2ebfbb9be73e650defe655c192af186 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Fri, 22 Feb 2019 16:08:44 -0800 Subject: [PATCH] userspace: remove APP_SHARED_MEM Kconfig This is an integral part of userspace and cannot be used on its own. Fold into the main userspace configuration. Signed-off-by: Andrew Boie --- CMakeLists.txt | 6 ++--- arch/arc/core/mpu/arc_mpu.c | 4 ++-- arch/arm/core/cortex_m/mpu/arm_core_mpu.c | 4 ++-- arch/x86/core/crt0.S | 4 ++-- arch/x86/core/x86_mmu.c | 2 +- .../kernel/usermode/kernelobjects.rst | 1 - .../kernel/usermode/usermode_sharedmem.rst | 3 +-- include/app_memory/app_memdomain.h | 4 ++-- include/arch/arc/v2/linker.ld | 4 ++-- include/arch/arm/cortex_m/scripts/linker.ld | 4 ++-- include/arch/x86/linker.ld | 6 ++--- include/misc/libc-hooks.h | 2 +- kernel/compiler_stack_protect.c | 2 +- kernel/init.c | 4 ++-- kernel/userspace.c | 23 ++++++++++++++++++ lib/libc/minimal/source/stdlib/malloc.c | 6 ++--- lib/libc/newlib/libc-hooks.c | 2 +- samples/userspace/shared_mem/prj.conf | 1 - scripts/gen_app_partitions.py | 2 +- subsys/CMakeLists.txt | 1 - subsys/Kconfig | 2 -- subsys/app_memory/CMakeLists.txt | 2 -- subsys/app_memory/Kconfig | 8 ------- subsys/app_memory/app_memdomain.c | 24 ------------------- subsys/testsuite/Kconfig | 1 - subsys/testsuite/ztest/include/ztest_test.h | 2 +- subsys/testsuite/ztest/src/ztest.c | 8 +++---- tests/kernel/threads/thread_init/src/main.c | 2 +- 28 files changed, 57 insertions(+), 77 deletions(-) delete mode 100644 subsys/app_memory/CMakeLists.txt delete mode 100644 subsys/app_memory/Kconfig delete mode 100644 subsys/app_memory/app_memdomain.c diff --git a/CMakeLists.txt b/CMakeLists.txt index da0fccb015..d556688e1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -362,9 +362,7 @@ zephyr_cc_option(-Wpointer-arith) # Declare MPU userspace dependencies before the linker scripts to make # sure the order of dependencies are met if(CONFIG_USERSPACE) - if(CONFIG_APP_SHARED_MEM) - set(APP_SMEM_DEP app_smem_linker) - endif() + set(APP_SMEM_DEP app_smem_linker) if(CONFIG_ARM) set(PRIV_STACK_DEP priv_stacks_prebuilt) endif() @@ -1152,7 +1150,7 @@ configure_file( $ENV{ZEPHYR_BASE}/include/arch/arm/cortex_m/scripts/app_smem.ld ${PROJECT_BINARY_DIR}/include/generated/app_smem.ld) -if(CONFIG_APP_SHARED_MEM AND CONFIG_USERSPACE) +if(CONFIG_USERSPACE) set(APP_SMEM_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem.ld") set(OBJ_FILE_DIR "${PROJECT_BINARY_DIR}/../") diff --git a/arch/arc/core/mpu/arc_mpu.c b/arch/arc/core/mpu/arc_mpu.c index be712d798e..53321d7eac 100644 --- a/arch/arc/core/mpu/arc_mpu.c +++ b/arch/arc/core/mpu/arc_mpu.c @@ -446,8 +446,8 @@ void arc_core_mpu_configure_user_context(struct k_thread *thread) /* for kernel threads, no need to configure user context */ if (!(thread->base.user_options & K_USER)) { -#if defined(CONFIG_APP_SHARED_MEM) && CONFIG_ARC_MPU_VER == 3 - /* APP_SHARED_MEM is handled here, all privileged threads have +#if defined(CONFIG_USERSPACE) && CONFIG_ARC_MPU_VER == 3 + /* USERSPACE is handled here, all privileged threads have * the right to access it. */ base = (u32_t)&_app_smem_start; diff --git a/arch/arm/core/cortex_m/mpu/arm_core_mpu.c b/arch/arm/core/cortex_m/mpu/arm_core_mpu.c index 0b53d9e891..fb081ae5b4 100644 --- a/arch/arm/core/cortex_m/mpu/arm_core_mpu.c +++ b/arch/arm/core/cortex_m/mpu/arm_core_mpu.c @@ -37,11 +37,11 @@ LOG_MODULE_REGISTER(mpu); /* Convenience macros to denote the start address and the size of the system * memory area, where dynamic memory regions may be programmed at run-time. */ -#if defined(CONFIG_APP_SHARED_MEM) +#if defined(CONFIG_USERSPACE) #define _MPU_DYNAMIC_REGIONS_AREA_START ((u32_t)&_app_smem_start) #else #define _MPU_DYNAMIC_REGIONS_AREA_START ((u32_t)&__kernel_ram_start) -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ #define _MPU_DYNAMIC_REGIONS_AREA_SIZE ((u32_t)&__kernel_ram_end - \ _MPU_DYNAMIC_REGIONS_AREA_START) diff --git a/arch/x86/core/crt0.S b/arch/x86/core/crt0.S index 165a2b49c6..1e93955e35 100644 --- a/arch/x86/core/crt0.S +++ b/arch/x86/core/crt0.S @@ -314,13 +314,13 @@ __csSet: call _x86_data_copy -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE movl $_app_smem_start, %edi /* DATA in RAM (dest) */ movl $_app_smem_rom_start, %esi /* DATA in ROM (src) */ movl $_app_smem_num_words, %ecx /* Size of DATA in quad bytes */ call _x86_data_copy -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_XIP */ diff --git a/arch/x86/core/x86_mmu.c b/arch/x86/core/x86_mmu.c index 416d8e5bd5..a9e1d27144 100644 --- a/arch/x86/core/x86_mmu.c +++ b/arch/x86/core/x86_mmu.c @@ -24,7 +24,7 @@ MMU_BOOT_REGION((u32_t)&_image_rodata_start, (u32_t)&_image_rodata_size, MMU_ENTRY_READ | MMU_ENTRY_USER | MMU_ENTRY_EXECUTE_DISABLE); -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE MMU_BOOT_REGION((u32_t)&_app_smem_start, (u32_t)&_app_smem_size, MMU_ENTRY_WRITE | MMU_ENTRY_RUNTIME_USER | MMU_ENTRY_EXECUTE_DISABLE); diff --git a/doc/reference/kernel/usermode/kernelobjects.rst b/doc/reference/kernel/usermode/kernelobjects.rst index 85eef344eb..55cfb1d163 100644 --- a/doc/reference/kernel/usermode/kernelobjects.rst +++ b/doc/reference/kernel/usermode/kernelobjects.rst @@ -265,7 +265,6 @@ Configuration Options Related configuration options: * :option:`CONFIG_USERSPACE` -* :option:`CONFIG_APP_SHARED_MEM` * :option:`CONFIG_MAX_THREAD_BYTES` API Reference diff --git a/doc/reference/kernel/usermode/usermode_sharedmem.rst b/doc/reference/kernel/usermode/usermode_sharedmem.rst index b4d6356485..75dbfa7f6e 100644 --- a/doc/reference/kernel/usermode/usermode_sharedmem.rst +++ b/doc/reference/kernel/usermode/usermode_sharedmem.rst @@ -33,8 +33,7 @@ the proper alignment for processors requiring power of two boundaries. Without the wrapper, a developer is required to implement custom linker scripts for each processor in the project. -The general usage is as follows. Define CONFIG_APP_SHARED_MEM=y in the -proj.conf file in the project folder. Include app_memory/app_memdomain.h +The general usage is as follows. Include app_memory/app_memdomain.h in the userspace source file. Mark the variable to be placed in a memory partition. The two markers are for data and bss respectively: K_APP_DMEM(id) and K_APP_BMEM(id). The id is used as the partition name. diff --git a/include/app_memory/app_memdomain.h b/include/app_memory/app_memdomain.h index f72fd14796..acbd02e955 100644 --- a/include/app_memory/app_memdomain.h +++ b/include/app_memory/app_memdomain.h @@ -5,7 +5,7 @@ #include #include -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE #if defined(CONFIG_X86) #define MEM_DOMAIN_ALIGN_SIZE _STACK_BASE_ALIGN @@ -104,5 +104,5 @@ struct z_app_region { #define K_APP_BMEM_SECTION(ptn) .bss #define K_APPMEM_PARTITION_DEFINE(name) -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ #endif /* ZEPHYR_INCLUDE_APP_MEMORY_APP_MEMDOMAIN_H_ */ diff --git a/include/arch/arc/v2/linker.ld b/include/arch/arc/v2/linker.ld index 6502347daf..a40ba7a565 100644 --- a/include/arch/arc/v2/linker.ld +++ b/include/arch/arc/v2/linker.ld @@ -138,7 +138,7 @@ SECTIONS { #include -#if defined(CONFIG_APP_SHARED_MEM) +#if defined(CONFIG_USERSPACE) #define APP_SHARED_ALIGN MPU_MIN_SIZE_ALIGN #define SMEM_PARTITION_ALIGN MPU_ALIGN @@ -147,7 +147,7 @@ SECTIONS { _image_ram_start = _app_smem_start; _app_smem_size = _app_smem_end - _app_smem_start; _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) { MPU_MIN_SIZE_ALIGN diff --git a/include/arch/arm/cortex_m/scripts/linker.ld b/include/arch/arm/cortex_m/scripts/linker.ld index 4bbf65f445..0b3180e3df 100644 --- a/include/arch/arm/cortex_m/scripts/linker.ld +++ b/include/arch/arm/cortex_m/scripts/linker.ld @@ -382,7 +382,7 @@ SECTIONS _ramfunc_rom_start = LOADADDR(.ramfunc); #endif /* CONFIG_ARCH_HAS_RAMFUNC_SUPPORT */ -#if defined(CONFIG_APP_SHARED_MEM) +#if defined(CONFIG_USERSPACE) #define APP_SHARED_ALIGN . = ALIGN(_region_min_align); #define SMEM_PARTITION_ALIGN MPU_ALIGN @@ -390,7 +390,7 @@ SECTIONS _app_smem_size = _app_smem_end - _app_smem_start; _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) { diff --git a/include/arch/x86/linker.ld b/include/arch/x86/linker.ld index c553201633..d6c9bf6a8b 100644 --- a/include/arch/x86/linker.ld +++ b/include/arch/x86/linker.ld @@ -207,7 +207,7 @@ SECTIONS __gcov_bss_size = __gcov_bss_end - __gcov_bss_start; #endif /* CONFIG_COVERAGE_GCOV */ -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE /* APP SHARED MEMORY REGION */ #define SMEM_PARTITION_ALIGN(size) MMU_PAGE_ALIGN #define APP_SHARED_ALIGN MMU_PAGE_ALIGN @@ -219,12 +219,12 @@ SECTIONS _app_smem_num_words = _app_smem_size >> 2; _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); _app_smem_num_words = _app_smem_size >> 2; -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD OPTIONAL),) { MMU_PAGE_ALIGN -#if !defined(CONFIG_APP_SHARED_MEM) +#if !defined(CONFIG_USERSPACE) _image_ram_start = .; #endif /* diff --git a/include/misc/libc-hooks.h b/include/misc/libc-hooks.h index 476c519f03..3c6d6536be 100644 --- a/include/misc/libc-hooks.h +++ b/include/misc/libc-hooks.h @@ -36,7 +36,7 @@ __syscall size_t _zephyr_fwrite(const void *_MLIBC_RESTRICT ptr, size_t size, size_t nitems, FILE *_MLIBC_RESTRICT stream); #endif /* CONFIG_NEWLIB_LIBC */ -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE /* Memory partition containing the libc malloc arena */ extern struct k_mem_partition z_malloc_partition; diff --git a/kernel/compiler_stack_protect.c b/kernel/compiler_stack_protect.c index 5f20ad2081..c2869b531a 100644 --- a/kernel/compiler_stack_protect.c +++ b/kernel/compiler_stack_protect.c @@ -46,7 +46,7 @@ void FUNC_NORETURN _StackCheckHandler(void) * Symbol referenced by GCC compiler generated code for canary value. * The canary value gets initialized in _Cstart(). */ -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE K_APP_DMEM(z_libc_partition) uintptr_t __stack_chk_guard; #else __noinit uintptr_t __stack_chk_guard; diff --git a/kernel/init.c b/kernel/init.c index 8d725fb584..0895b81e33 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -190,7 +190,7 @@ void _data_copy(void) data_copy_xip_relocation(); #endif /* CONFIG_CODE_DATA_RELOCATION */ -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE #ifdef CONFIG_STACK_CANARIES /* stack canary checking is active for all C functions. * __stack_chk_guard is some uninitialized value living in the @@ -213,7 +213,7 @@ void _data_copy(void) (void)memcpy(&_app_smem_start, &_app_smem_rom_start, ((u32_t) &_app_smem_end - (u32_t) &_app_smem_start)); #endif /* CONFIG_STACK_CANARIES */ -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ } #endif diff --git a/kernel/userspace.c b/kernel/userspace.c index 1925ee3704..990d60e0b9 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -727,6 +727,29 @@ out: return ret; } +/* + * Application memory region initialization + */ + +extern char __app_shmem_regions_start[]; +extern char __app_shmem_regions_end[]; + +static int app_shmem_bss_zero(struct device *unused) +{ + struct z_app_region *region, *end; + + end = (struct z_app_region *)&__app_shmem_regions_end; + region = (struct z_app_region *)&__app_shmem_regions_start; + + for ( ; region < end; region++) { + (void)memset(region->bss_start, 0, region->bss_size); + } + + return 0; +} + +SYS_INIT(app_shmem_bss_zero, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + /* * Default handlers if otherwise unimplemented */ diff --git a/lib/libc/minimal/source/stdlib/malloc.c b/lib/libc/minimal/source/stdlib/malloc.c index 696ae2dd6b..4b69f5b7d9 100644 --- a/lib/libc/minimal/source/stdlib/malloc.c +++ b/lib/libc/minimal/source/stdlib/malloc.c @@ -16,16 +16,16 @@ #include LOG_MODULE_DECLARE(os); -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE K_APPMEM_PARTITION_DEFINE(z_malloc_partition); #endif #if (CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0) -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE #define POOL_SECTION K_APP_DMEM_SECTION(z_malloc_partition) #else #define POOL_SECTION .data -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ K_MUTEX_DEFINE(malloc_mutex); SYS_MEM_POOL_DEFINE(z_malloc_mem_pool, &malloc_mutex, 16, diff --git a/lib/libc/newlib/libc-hooks.c b/lib/libc/newlib/libc-hooks.c index bc7b7c5daa..c430eb8137 100644 --- a/lib/libc/newlib/libc-hooks.c +++ b/lib/libc/newlib/libc-hooks.c @@ -59,7 +59,7 @@ extern void *_heap_sentry; static unsigned char *heap_base = UINT_TO_POINTER(USED_RAM_END_ADDR); -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE struct k_mem_partition z_malloc_partition; static int malloc_prepare(struct device *unused) diff --git a/samples/userspace/shared_mem/prj.conf b/samples/userspace/shared_mem/prj.conf index 346901edc7..90b88349b6 100644 --- a/samples/userspace/shared_mem/prj.conf +++ b/samples/userspace/shared_mem/prj.conf @@ -1,2 +1 @@ CONFIG_USERSPACE=y -CONFIG_APP_SHARED_MEM=y diff --git a/scripts/gen_app_partitions.py b/scripts/gen_app_partitions.py index 66c5795c57..1433c179be 100644 --- a/scripts/gen_app_partitions.py +++ b/scripts/gen_app_partitions.py @@ -16,7 +16,7 @@ from elftools.elf.elffile import ELFFile # This script will create sections and linker variables to place the # application shared memory partitions. # these are later read by the macros defined in app_memdomain.h for -# initialization purpose when APP_SHARED_MEM is enabled. +# initialization purpose when USERSPACE is enabled. data_template = """ /* Auto generated code do not modify */ SMEM_PARTITION_ALIGN(data_smem_{0}_bss_end - data_smem_{0}_start); diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 9977a523fe..47188c0163 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory_ifdef(CONFIG_APP_SHARED_MEM app_memory) add_subdirectory(debug) add_subdirectory(logging) add_subdirectory_ifdef(CONFIG_BT bluetooth) diff --git a/subsys/Kconfig b/subsys/Kconfig index 22b0b55e50..f0338d925d 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -37,8 +37,6 @@ source "subsys/settings/Kconfig" source "subsys/testsuite/Kconfig" -source "subsys/app_memory/Kconfig" - source "subsys/fb/Kconfig" source "subsys/jwt/Kconfig" diff --git a/subsys/app_memory/CMakeLists.txt b/subsys/app_memory/CMakeLists.txt deleted file mode 100644 index c974bbd7cb..0000000000 --- a/subsys/app_memory/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -zephyr_library() -zephyr_library_sources(app_memdomain.c) diff --git a/subsys/app_memory/Kconfig b/subsys/app_memory/Kconfig deleted file mode 100644 index 9d2f862357..0000000000 --- a/subsys/app_memory/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -menu "General Kernel Options" - -config APP_SHARED_MEM - bool "Application shared memory with app_memory" - help - This is a wrapper around app_memory to simplify usage. - -endmenu diff --git a/subsys/app_memory/app_memdomain.c b/subsys/app_memory/app_memdomain.c deleted file mode 100644 index 53a9c71398..0000000000 --- a/subsys/app_memory/app_memdomain.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include -#include - -extern char __app_shmem_regions_start[]; -extern char __app_shmem_regions_end[]; - -static int app_shmem_bss_zero(struct device *unused) -{ - struct z_app_region *region, *end; - - end = (struct z_app_region *)&__app_shmem_regions_end; - region = (struct z_app_region *)&__app_shmem_regions_start; - - for ( ; region < end; region++) { - (void)memset(region->bss_start, 0, region->bss_size); - } - - return 0; -} - -SYS_INIT(app_shmem_bss_zero, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/subsys/testsuite/Kconfig b/subsys/testsuite/Kconfig index fab933e3b7..fd77588c1e 100644 --- a/subsys/testsuite/Kconfig +++ b/subsys/testsuite/Kconfig @@ -63,7 +63,6 @@ config TEST_USERSPACE depends on ARCH_HAS_USERSPACE depends on TEST select USERSPACE - select APP_SHARED_MEM select DYNAMIC_OBJECTS default y help diff --git a/subsys/testsuite/ztest/include/ztest_test.h b/subsys/testsuite/ztest/include/ztest_test.h index edcd4e9243..c3fbb4a97c 100644 --- a/subsys/testsuite/ztest/include/ztest_test.h +++ b/subsys/testsuite/ztest/include/ztest_test.h @@ -143,7 +143,7 @@ static inline void unit_test_noop(void) */ /* definitions for use with testing application shared memory */ -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE #define ZTEST_DMEM K_APP_DMEM(ztest_mem_partition) #define ZTEST_BMEM K_APP_BMEM(ztest_mem_partition) #define ZTEST_SECTION K_APP_DMEM_SECTION(ztest_mem_partition) diff --git a/subsys/testsuite/ztest/src/ztest.c b/subsys/testsuite/ztest/src/ztest.c index bc5ca961f4..6036a719f5 100644 --- a/subsys/testsuite/ztest/src/ztest.c +++ b/subsys/testsuite/ztest/src/ztest.c @@ -7,7 +7,7 @@ #include #include #include -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE #include #endif @@ -282,7 +282,7 @@ void end_report(void) } } -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE struct k_mem_domain ztest_mem_domain; K_APPMEM_PARTITION_DEFINE(ztest_mem_partition); #endif @@ -299,7 +299,7 @@ int main(void) #else void main(void) { -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE struct k_mem_partition *parts[] = { &ztest_mem_partition, /* C library globals, stack canary storage, etc */ @@ -314,7 +314,7 @@ void main(void) */ k_mem_domain_init(&ztest_mem_domain, ARRAY_SIZE(parts), parts); k_mem_domain_add_thread(&ztest_mem_domain, k_current_get()); -#endif /* CONFIG_APP_SHARED_MEM */ +#endif /* CONFIG_USERSPACE */ _init_mock(); test_main(); diff --git a/tests/kernel/threads/thread_init/src/main.c b/tests/kernel/threads/thread_init/src/main.c index 08c33f623a..157746aaf8 100644 --- a/tests/kernel/threads/thread_init/src/main.c +++ b/tests/kernel/threads/thread_init/src/main.c @@ -207,7 +207,7 @@ void test_main(void) { k_thread_access_grant(k_current_get(), &thread_preempt, &stack_preempt, &start_sema, &end_sema); -#ifdef CONFIG_APP_SHARED_MEM +#ifdef CONFIG_USERSPACE k_mem_domain_add_thread(&ztest_mem_domain, T_KDEFINE_COOP_THREAD); k_mem_domain_add_thread(&ztest_mem_domain, T_KDEFINE_PREEMPT_THREAD); #endif