From 84a6c487e494a9408bc4d6a34145ee2f22292808 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 3 Dec 2025 14:28:19 +0100 Subject: [PATCH 01/17] fixes to correct bug introduced by the MUSL support --- so3/arch/arm64/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/arch/arm64/traps.c b/so3/arch/arm64/traps.c index d154731e8..a4cd707af 100644 --- a/so3/arch/arm64/traps.c +++ b/so3/arch/arm64/traps.c @@ -252,7 +252,7 @@ void trap_handle(cpu_regs_t *regs) default: __err: lprintk("### On CPU %d: ESR_Elx_EC(esr): 0x%lx\n", smp_processor_id(), ESR_ELx_EC(esr)); - trap_handle_error(regs->lr); + trap_handle_error(regs->pc); kernel_panic(); } } From 4e6e2172ad72881d9e9314c962970b5457ae3abf Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Wed, 17 Dec 2025 15:30:45 +0100 Subject: [PATCH 02/17] fix for userspace threads --- so3/arch/arm64/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/arch/arm64/traps.c b/so3/arch/arm64/traps.c index a4cd707af..d154731e8 100644 --- a/so3/arch/arm64/traps.c +++ b/so3/arch/arm64/traps.c @@ -252,7 +252,7 @@ void trap_handle(cpu_regs_t *regs) default: __err: lprintk("### On CPU %d: ESR_Elx_EC(esr): 0x%lx\n", smp_processor_id(), ESR_ELx_EC(esr)); - trap_handle_error(regs->pc); + trap_handle_error(regs->lr); kernel_panic(); } } From bec7bbdd880923ddfb959b843186e9eb8df4f47e Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Wed, 10 Dec 2025 18:03:52 +0100 Subject: [PATCH 03/17] [c++] Add basic C++ apps The apps are: hello-world, simple class & use of std::vector Signed-off-by: Jean-Pierre Miceli --- usr/CMakeLists.txt | 2 +- usr/src/tests/CMakeLists.txt | 5 ++++ usr/src/tests/class_test.cpp | 48 +++++++++++++++++++++++++++++++++++ usr/src/tests/hello_world.cpp | 27 ++++++++++++++++++++ usr/src/tests/vector_test.cpp | 36 ++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 usr/src/tests/CMakeLists.txt create mode 100644 usr/src/tests/class_test.cpp create mode 100644 usr/src/tests/hello_world.cpp create mode 100644 usr/src/tests/vector_test.cpp diff --git a/usr/CMakeLists.txt b/usr/CMakeLists.txt index 387abe07c..f30cd284f 100644 --- a/usr/CMakeLists.txt +++ b/usr/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16) -project(so3-usr LANGUAGES C ASM) +project(so3-usr LANGUAGES C CXX ASM) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/usr/src/tests/CMakeLists.txt b/usr/src/tests/CMakeLists.txt new file mode 100644 index 000000000..63e4efad7 --- /dev/null +++ b/usr/src/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.16) + +add_executable(hello-world.elf hello_world.cpp) +add_executable(class-test.elf class_test.cpp) +add_executable(vector-test.elf vector_test.cpp) diff --git a/usr/src/tests/class_test.cpp b/usr/src/tests/class_test.cpp new file mode 100644 index 000000000..b01eb3864 --- /dev/null +++ b/usr/src/tests/class_test.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +class Person { +private: + std::string _name; + int _age; + +public: + // Constructor + Person(const std::string& name, int age) + : _name(name), _age(age) {} + + // Method to print info + void hello() const { + // std::cout << "Hi, I'm " << _name + // << " and I'm " << _age + // << " years old." << std::endl; + + printf("Hi, I'm %s and I'm %d years old.\n"); + } +}; + +int main() +{ + Person p("Jean-Pierre", 30); + p.hello(); + + return 0; +} diff --git a/usr/src/tests/hello_world.cpp b/usr/src/tests/hello_world.cpp new file mode 100644 index 000000000..b4a87e6c8 --- /dev/null +++ b/usr/src/tests/hello_world.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +int main() +{ + // printf("JMI\n"); + std::cout << "Hello World!" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/usr/src/tests/vector_test.cpp b/usr/src/tests/vector_test.cpp new file mode 100644 index 000000000..0f429b362 --- /dev/null +++ b/usr/src/tests/vector_test.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +int main() { + // Create and initialize a vector with 3 integer values + std::vector numbers = {10, 20, 30}; + + // Compute the sum + int sum = 0; + for (int value : numbers) { + sum += value; + } + + // Output the result + printf("Sum of vector entries: %d\n", sum); + + return 0; +} \ No newline at end of file From 52c77e109e00cb7db1db42420ff543d0e197e378 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Wed, 10 Dec 2025 18:05:23 +0100 Subject: [PATCH 04/17] [c++] udpate of CMakeList of usr/scr to compile test c++ apps Signed-off-by: Jean-Pierre Miceli --- usr/src/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/usr/src/CMakeLists.txt b/usr/src/CMakeLists.txt index 8da5d119b..35ebfcf6a 100644 --- a/usr/src/CMakeLists.txt +++ b/usr/src/CMakeLists.txt @@ -22,3 +22,8 @@ if (MICROPYTHON AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")) add_subdirectory(micropython) endif() +option(WITH_TESTS "Build the test/example apps" ON) +if (WITH_TESTS) + add_subdirectory(tests) +endif() + From a01803186492a3ff6863cfa9d846ae83b7ae0ce6 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Wed, 10 Dec 2025 18:06:33 +0100 Subject: [PATCH 05/17] [c++] Add section used by C++ apps to so3 Signed-off-by: Jean-Pierre Miceli --- so3/kernel/main.c | 2 +- so3/kernel/process.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/so3/kernel/main.c b/so3/kernel/main.c index 8858c2447..1bf429d99 100644 --- a/so3/kernel/main.c +++ b/so3/kernel/main.c @@ -98,7 +98,7 @@ void kernel_start(void) { lprintk("%s", SO3_BANNER); - LOG_INFO("Now bootstraping the kernel ..."); + LOG_INFO("Now bootstraping the kernel ...\n"); /* Memory manager subsystem initialization */ memory_init(); diff --git a/so3/kernel/process.c b/so3/kernel/process.c index 4c9f0ac05..e7c5e21e4 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -74,10 +74,11 @@ static uint32_t pid_current = 1; static pcb_t *root_process = NULL; /* root process */ /* only the following sections are supported */ -#define SUPPORTED_SECTION_COUNT 10 -static const char *supported_section_names[SUPPORTED_SECTION_COUNT] = { - ".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", ".init_array", ".fini_array", +static const char *supported_section_names[] = { + ".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", + ".eh_frame", ".gcc_except_table", ".init_array", ".fini_array", ".data.rel.ro", ".got", ".got.plt", }; +#define SUPPORTED_SECTION_COUNT (sizeof(supported_section_names) / sizeof(supported_section_names[0])) /* * Find a process (pcb_t) from its pid. From 7e001eaf5345aca9e21532cc4da47f8996a6bb68 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Thu, 11 Dec 2025 15:47:27 +0100 Subject: [PATCH 06/17] [c++] Add 'no-rtti' flag in the musl toolchains Signed-off-by: Jean-Pierre Miceli --- usr/aarch64-linux-musl.cmake | 2 +- usr/arm-linux-musl.cmake | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/usr/aarch64-linux-musl.cmake b/usr/aarch64-linux-musl.cmake index a36f89037..f7c353062 100644 --- a/usr/aarch64-linux-musl.cmake +++ b/usr/aarch64-linux-musl.cmake @@ -26,4 +26,4 @@ set(CMAKE_ASM_FLAGS "-D__ARM64__ -D__ASSEMBLY__") set(CMAKE_LINKER "aarch64-linux-musl-ld") -set(CMAKE_EXE_LINKER_FLAGS "-Os -static" CACHE STRING "SO3 usr LDFLAGS for executables") +set(CMAKE_EXE_LINKER_FLAGS "-Os -static -fno-rtti" CACHE STRING "SO3 usr LDFLAGS for executables") diff --git a/usr/arm-linux-musl.cmake b/usr/arm-linux-musl.cmake index 4d38558df..f148c3542 100644 --- a/usr/arm-linux-musl.cmake +++ b/usr/arm-linux-musl.cmake @@ -26,5 +26,4 @@ set(CMAKE_ASM_FLAGS "-D__ARM__ -D__ASSEMBLY__") set(CMAKE_LINKER "arm-linux-musleabihf-ld") - -set(CMAKE_EXE_LINKER_FLAGS "-Os -static" CACHE STRING "SO3 usr LDFLAGS for executables") +set(CMAKE_EXE_LINKER_FLAGS "-Os -static -fno-rtti" CACHE STRING "SO3 usr LDFLAGS for executables") From 7582d0f0ff3d55fe2be582e6644e9f85ee158326 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Thu, 11 Dec 2025 15:48:23 +0100 Subject: [PATCH 07/17] [usr] Move the '.debug_*' sections in a separated file The '.debug_*' sections of the usr apps are move in a seperated file ('app.elf.debug'). The apps is then much lighter. For example, C++ hello-world shrink form 8.2MB to 884K. For debug, the app.elf.debug is linked with the app.elf. Signed-off-by: Jean-Pierre Miceli --- usr/build.sh | 30 ++++++++++++++++++++++++++++++ usr/deploy.sh | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/usr/build.sh b/usr/build.sh index 747697471..d596d04dc 100755 --- a/usr/build.sh +++ b/usr/build.sh @@ -11,6 +11,33 @@ usage() { echo " -h Print this help" } +# Place the debug info of the applications in a separate file +strip_debug_info() +{ + # retrieve the correct objcop tool + # if [ "$1" == "virt32" -o "$1" == "rpi4" ]; then + if [ "$1" = "virt32" ] || [ "$1" = "rpi4" ]; then + OBJCOPY="arm-linux-musleabihf-objcopy" + else + OBJCOPY="aarch64-linux-musl-objcopy" + fi + + for app in build/deploy/*.elf; do + [ -e "$app" ] || continue + + # 1. Create a file with only '.debug_*' sections + $OBJCOPY --only-keep-debug $app $app.debug + + # 2. remove/strip debug info + $OBJCOPY --strip-all $app + + # 3. Connect the two files + $OBJCOPY --add-gnu-debuglink=$app.debug $app + + done +} + + install_file_elf() { if [ -f $1 ] ; then for subfolder_app in $(find build/src -type f -iname "*.elf"); do @@ -120,4 +147,7 @@ install_directory_root out install_file_elf +strip_debug_info "$PLATFORM" + + exit 0 diff --git a/usr/deploy.sh b/usr/deploy.sh index 8ab92c9b5..c3c2bffd0 100755 --- a/usr/deploy.sh +++ b/usr/deploy.sh @@ -18,6 +18,6 @@ echo Deploying user apps into the ramfs partition cd ../rootfs ./mount.sh ${PLATFORM} sudo cp -r ../usr/out/* fs -sudo cp -r ../usr/build/deploy/* fs +sudo cp -r ../usr/build/deploy/*.elf fs ./umount.sh ${PLATFORM} From 98b39a20187986b015e4e5e15266f479adf5a3e2 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Tue, 16 Dec 2025 10:56:34 +0100 Subject: [PATCH 08/17] [c++] Add some more basic tests Signed-off-by: Jean-Pierre Miceli --- usr/src/tests/CMakeLists.txt | 4 ++- usr/src/tests/allocation_test.cpp | 34 +++++++++++++++++++ usr/src/tests/class_test.cpp | 15 ++++---- usr/src/tests/exception_test.cpp | 28 +++++++++++++++ usr/src/tests/hello_world.cpp | 1 - .../{vector_test.cpp => stdlib_test.cpp} | 33 ++++++++++++++++-- 6 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 usr/src/tests/allocation_test.cpp create mode 100644 usr/src/tests/exception_test.cpp rename usr/src/tests/{vector_test.cpp => stdlib_test.cpp} (72%) diff --git a/usr/src/tests/CMakeLists.txt b/usr/src/tests/CMakeLists.txt index 63e4efad7..95e4e692f 100644 --- a/usr/src/tests/CMakeLists.txt +++ b/usr/src/tests/CMakeLists.txt @@ -2,4 +2,6 @@ cmake_minimum_required(VERSION 3.16) add_executable(hello-world.elf hello_world.cpp) add_executable(class-test.elf class_test.cpp) -add_executable(vector-test.elf vector_test.cpp) +add_executable(stdlib-test.elf stdlib_test.cpp) +add_executable(exception-test.elf exception_test.cpp) +add_executable(allocation-test.elf allocation_test.cpp) diff --git a/usr/src/tests/allocation_test.cpp b/usr/src/tests/allocation_test.cpp new file mode 100644 index 000000000..9113b0c56 --- /dev/null +++ b/usr/src/tests/allocation_test.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +struct Aligned { alignas(64) int x; }; + +int main() +{ + void* p = ::operator new(1024); + ::operator delete(p); + + Aligned* a = new Aligned; + delete a; + + std::cout << "Test OK" << std::endl; +} + diff --git a/usr/src/tests/class_test.cpp b/usr/src/tests/class_test.cpp index b01eb3864..af1d43ec9 100644 --- a/usr/src/tests/class_test.cpp +++ b/usr/src/tests/class_test.cpp @@ -25,17 +25,18 @@ class Person { int _age; public: - // Constructor Person(const std::string& name, int age) - : _name(name), _age(age) {} + : _name(name), _age(age) { + std::cout << "Person constructor" << std::endl; + } + + ~Person() { + std::cout << "Person Destructor" << std::endl; + } // Method to print info void hello() const { - // std::cout << "Hi, I'm " << _name - // << " and I'm " << _age - // << " years old." << std::endl; - - printf("Hi, I'm %s and I'm %d years old.\n"); + std::cout << "Hi, I'm " << _name << " and I'm " << _age << " years old." << std::endl; } }; diff --git a/usr/src/tests/exception_test.cpp b/usr/src/tests/exception_test.cpp new file mode 100644 index 000000000..8945b01c2 --- /dev/null +++ b/usr/src/tests/exception_test.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +int main() +{ + try { + throw 42; + } catch (int x) { + std::cout << "caught: " << x << std::endl; + } +} diff --git a/usr/src/tests/hello_world.cpp b/usr/src/tests/hello_world.cpp index b4a87e6c8..c37c206be 100644 --- a/usr/src/tests/hello_world.cpp +++ b/usr/src/tests/hello_world.cpp @@ -20,7 +20,6 @@ int main() { - // printf("JMI\n"); std::cout << "Hello World!" << std::endl; return 0; diff --git a/usr/src/tests/vector_test.cpp b/usr/src/tests/stdlib_test.cpp similarity index 72% rename from usr/src/tests/vector_test.cpp rename to usr/src/tests/stdlib_test.cpp index 0f429b362..1926217ec 100644 --- a/usr/src/tests/vector_test.cpp +++ b/usr/src/tests/stdlib_test.cpp @@ -18,8 +18,10 @@ #include #include +#include -int main() { +void vector_test() +{ // Create and initialize a vector with 3 integer values std::vector numbers = {10, 20, 30}; @@ -30,7 +32,34 @@ int main() { } // Output the result - printf("Sum of vector entries: %d\n", sum); + std::cout << "Sum of vector entries: " << sum << std::endl; +} + + +void string_test() +{ + std::string s = "abc"; + s += "def"; + std::cout << "String: " << s << std::endl; +} + +void map_test() +{ + std::map m; + + m[1] = 2; + + std::cout << "Map m[1]: " << m[1] << std::endl; +} + + +int main() { + + vector_test(); + + string_test(); + + map_test(); return 0; } \ No newline at end of file From 3ead3c4bab5b1ded88cb9da9d382a5545bdfcbe9 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Tue, 16 Dec 2025 11:13:09 +0100 Subject: [PATCH 09/17] [c++] Fix clang-format Signed-off-by: Jean-Pierre Miceli --- usr/src/tests/allocation_test.cpp | 15 ++++++----- usr/src/tests/class_test.cpp | 40 +++++++++++++++------------- usr/src/tests/exception_test.cpp | 6 ++--- usr/src/tests/hello_world.cpp | 4 +-- usr/src/tests/stdlib_test.cpp | 44 +++++++++++++++---------------- 5 files changed, 56 insertions(+), 53 deletions(-) diff --git a/usr/src/tests/allocation_test.cpp b/usr/src/tests/allocation_test.cpp index 9113b0c56..dca56f86a 100644 --- a/usr/src/tests/allocation_test.cpp +++ b/usr/src/tests/allocation_test.cpp @@ -19,16 +19,17 @@ #include #include -struct Aligned { alignas(64) int x; }; +struct Aligned { + alignas(64) int x; +}; int main() { - void* p = ::operator new(1024); - ::operator delete(p); + void *p = ::operator new(1024); + ::operator delete(p); - Aligned* a = new Aligned; - delete a; + Aligned *a = new Aligned; + delete a; - std::cout << "Test OK" << std::endl; + std::cout << "Test OK" << std::endl; } - diff --git a/usr/src/tests/class_test.cpp b/usr/src/tests/class_test.cpp index af1d43ec9..eef30af66 100644 --- a/usr/src/tests/class_test.cpp +++ b/usr/src/tests/class_test.cpp @@ -20,30 +20,34 @@ #include class Person { -private: - std::string _name; - int _age; + private: + std::string _name; + int _age; -public: - Person(const std::string& name, int age) - : _name(name), _age(age) { - std::cout << "Person constructor" << std::endl; - } + public: + Person(const std::string &name, int age) + : _name(name) + , _age(age) + { + std::cout << "Person constructor" << std::endl; + } - ~Person() { - std::cout << "Person Destructor" << std::endl; - } + ~Person() + { + std::cout << "Person Destructor" << std::endl; + } - // Method to print info - void hello() const { - std::cout << "Hi, I'm " << _name << " and I'm " << _age << " years old." << std::endl; - } + // Method to print info + void hello() const + { + std::cout << "Hi, I'm " << _name << " and I'm " << _age << " years old." << std::endl; + } }; int main() { - Person p("Jean-Pierre", 30); - p.hello(); + Person p("Jean-Pierre", 30); + p.hello(); - return 0; + return 0; } diff --git a/usr/src/tests/exception_test.cpp b/usr/src/tests/exception_test.cpp index 8945b01c2..6026dea25 100644 --- a/usr/src/tests/exception_test.cpp +++ b/usr/src/tests/exception_test.cpp @@ -22,7 +22,7 @@ int main() { try { throw 42; - } catch (int x) { - std::cout << "caught: " << x << std::endl; - } + } catch (int x) { + std::cout << "caught: " << x << std::endl; + } } diff --git a/usr/src/tests/hello_world.cpp b/usr/src/tests/hello_world.cpp index c37c206be..4ef192cd0 100644 --- a/usr/src/tests/hello_world.cpp +++ b/usr/src/tests/hello_world.cpp @@ -20,7 +20,7 @@ int main() { - std::cout << "Hello World!" << std::endl; + std::cout << "Hello World!" << std::endl; - return 0; + return 0; } \ No newline at end of file diff --git a/usr/src/tests/stdlib_test.cpp b/usr/src/tests/stdlib_test.cpp index 1926217ec..a450971be 100644 --- a/usr/src/tests/stdlib_test.cpp +++ b/usr/src/tests/stdlib_test.cpp @@ -22,44 +22,42 @@ void vector_test() { - // Create and initialize a vector with 3 integer values - std::vector numbers = {10, 20, 30}; + // Create and initialize a vector with 3 integer values + std::vector numbers = { 10, 20, 30 }; - // Compute the sum - int sum = 0; - for (int value : numbers) { - sum += value; - } + // Compute the sum + int sum = 0; + for (int value : numbers) { + sum += value; + } - // Output the result - std::cout << "Sum of vector entries: " << sum << std::endl; + // Output the result + std::cout << "Sum of vector entries: " << sum << std::endl; } - void string_test() { - std::string s = "abc"; - s += "def"; - std::cout << "String: " << s << std::endl; + std::string s = "abc"; + s += "def"; + std::cout << "String: " << s << std::endl; } void map_test() { - std::map m; + std::map m; - m[1] = 2; + m[1] = 2; - std::cout << "Map m[1]: " << m[1] << std::endl; + std::cout << "Map m[1]: " << m[1] << std::endl; } +int main() +{ + vector_test(); -int main() { - - vector_test(); - - string_test(); + string_test(); - map_test(); + map_test(); - return 0; + return 0; } \ No newline at end of file From 049c5f197586adc71ed3b124825ec6a42e495d4e Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Tue, 16 Dec 2025 11:18:58 +0100 Subject: [PATCH 10/17] [c++] clang-format / again Signed-off-by: Jean-Pierre Miceli --- so3/kernel/process.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/so3/kernel/process.c b/so3/kernel/process.c index e7c5e21e4..ccc61a5f4 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -75,8 +75,9 @@ static pcb_t *root_process = NULL; /* root process */ /* only the following sections are supported */ static const char *supported_section_names[] = { - ".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", - ".eh_frame", ".gcc_except_table", ".init_array", ".fini_array", ".data.rel.ro", ".got", ".got.plt", + ".init", ".text", ".rodata", ".data", ".sbss", + ".bss", ".scommon", ".fini", ".eh_frame", ".gcc_except_table", + ".init_array", ".fini_array", ".data.rel.ro", ".got", ".got.plt", }; #define SUPPORTED_SECTION_COUNT (sizeof(supported_section_names) / sizeof(supported_section_names[0])) From 92c056efc59eb09e8233ea31fac8c191c74c5110 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 5 Jan 2026 14:37:07 +0100 Subject: [PATCH 11/17] [C++] Add std::thread & std::ofstream (files) tests Signed-off-by: Jean-Pierre Miceli --- usr/src/tests/CMakeLists.txt | 4 ++ usr/src/tests/files_test.cpp | 17 +++++++ usr/src/tests/threads_test.cpp | 88 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 usr/src/tests/files_test.cpp create mode 100644 usr/src/tests/threads_test.cpp diff --git a/usr/src/tests/CMakeLists.txt b/usr/src/tests/CMakeLists.txt index 95e4e692f..7ae48e239 100644 --- a/usr/src/tests/CMakeLists.txt +++ b/usr/src/tests/CMakeLists.txt @@ -5,3 +5,7 @@ add_executable(class-test.elf class_test.cpp) add_executable(stdlib-test.elf stdlib_test.cpp) add_executable(exception-test.elf exception_test.cpp) add_executable(allocation-test.elf allocation_test.cpp) +add_executable(threads-test.elf threads_test.cpp) +add_executable(files-test.elf files_test.cpp) + + diff --git a/usr/src/tests/files_test.cpp b/usr/src/tests/files_test.cpp new file mode 100644 index 000000000..f5316b2db --- /dev/null +++ b/usr/src/tests/files_test.cpp @@ -0,0 +1,17 @@ + + + +#include +#include + +int main() { + std::ofstream file("example.txt"); + if (!file) { + std::cerr << "Failed to open file\n"; + return 1; + } + + file << "Hello from C++\n"; + // file closes automatically (RAII) + return 0; +} \ No newline at end of file diff --git a/usr/src/tests/threads_test.cpp b/usr/src/tests/threads_test.cpp new file mode 100644 index 000000000..5503c1e0e --- /dev/null +++ b/usr/src/tests/threads_test.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include + +struct ThreadArgs { + long thread_id; + std::mutex* mtx; +}; + +// Thread function +long simple_thread(ThreadArgs args) +{ + std::cout << "Thread " << args.thread_id << ": Executing" << std::endl; + + // Lock the mutex + args.mtx->lock(); + std::cout << "Thread " << args.thread_id << ": Locked mutex" << std::endl; + + std::this_thread::sleep_for(std::chrono::seconds(3)); + + std::cout << "Thread " << args.thread_id << ": Unlocking mutex" << std::endl; + args.mtx->unlock(); + + std::cout << "Thread " << args.thread_id << ": Thread finished" << std::endl; + + return args.thread_id; +} + +int main() +{ + std::mutex mtx; + + printf("== C++ threads tests ==\n"); + + // Create thread arguments + ThreadArgs args1{1, &mtx}; + ThreadArgs args2{2, &mtx}; + + // Store threads and their return values + std::vector threads; + long ret1, ret2; + + // Launch threads + std::thread t1([&]() { ret1 = simple_thread(args1); }); + std::thread t2([&]() { ret2 = simple_thread(args2); }); + + threads.push_back(std::move(t1)); + threads.push_back(std::move(t2)); + + // Wait for threads to finish + for (auto& t : threads) { + if (t.joinable()) { + t.join(); + } + } + + // Check return values + if (ret1 != 1) { + std::cout << "Unexpected return value for thread 1" << std::endl; + } + if (ret2 != 2) { + std::cout << "Unexpected return value for thread 2" << std::endl; + } + + std::cout << "All threads finished" << std::endl; + return 0; +} From 753bdb818648fe1aaf378615517841ef32805af5 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 5 Jan 2026 14:44:02 +0100 Subject: [PATCH 12/17] [C++] fix src format Signed-off-by: Jean-Pierre Miceli --- so3/arch/arm32/thread.c | 2 +- so3/arch/arm64/thread.c | 2 +- so3/kernel/process.c | 2 +- usr/src/tests/files_test.cpp | 22 ++++---- usr/src/tests/threads_test.cpp | 94 +++++++++++++++++----------------- 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/so3/arch/arm32/thread.c b/so3/arch/arm32/thread.c index dc92101a4..9ec16090c 100644 --- a/so3/arch/arm32/thread.c +++ b/so3/arch/arm32/thread.c @@ -83,7 +83,7 @@ void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top) /* Reset all user's registers to zero except for PC, PSTATE and SP * which needs to be set to the properly start the thread. */ - *user_regs = (cpu_regs_t) { + *user_regs = (cpu_regs_t){ .pc = (u32) fn_entry, .psr = PSR_USR_MODE | PSR_I_BIT, .sp_usr = stack_top, diff --git a/so3/arch/arm64/thread.c b/so3/arch/arm64/thread.c index 9ad64bae3..ca4ce1da4 100644 --- a/so3/arch/arm64/thread.c +++ b/so3/arch/arm64/thread.c @@ -79,7 +79,7 @@ void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top) /* Reset all user's registers to zero except for PC, PSTATE and SP * which needs to be set to the properly start the program */ - *user_regs = (cpu_regs_t) { + *user_regs = (cpu_regs_t){ .pc = (u64) fn_entry, .pstate = PSR_MODE_EL0t, .sp_usr = stack_top, diff --git a/so3/kernel/process.c b/so3/kernel/process.c index ccc61a5f4..fe922f5cd 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -346,7 +346,7 @@ void create_root_process(void) (void *) __root_proc_end - (void *) __root_proc_start, false); /* Start main user thread. */ - thread_args = (clone_args_t) { + thread_args = (clone_args_t){ .name = "root_proc", .pcb = pcb, .stack = pcb->stack_top, diff --git a/usr/src/tests/files_test.cpp b/usr/src/tests/files_test.cpp index f5316b2db..731ed9686 100644 --- a/usr/src/tests/files_test.cpp +++ b/usr/src/tests/files_test.cpp @@ -1,17 +1,17 @@ - #include #include -int main() { - std::ofstream file("example.txt"); - if (!file) { - std::cerr << "Failed to open file\n"; - return 1; - } +int main() +{ + std::ofstream file("example.txt"); + if (!file) { + std::cerr << "Failed to open file\n"; + return 1; + } - file << "Hello from C++\n"; - // file closes automatically (RAII) - return 0; -} \ No newline at end of file + file << "Hello from C++\n"; + // file closes automatically + return 0; +} diff --git a/usr/src/tests/threads_test.cpp b/usr/src/tests/threads_test.cpp index 5503c1e0e..bb2d77a4f 100644 --- a/usr/src/tests/threads_test.cpp +++ b/usr/src/tests/threads_test.cpp @@ -24,65 +24,65 @@ #include struct ThreadArgs { - long thread_id; - std::mutex* mtx; + long thread_id; + std::mutex *mtx; }; // Thread function long simple_thread(ThreadArgs args) { - std::cout << "Thread " << args.thread_id << ": Executing" << std::endl; + std::cout << "Thread " << args.thread_id << ": Executing" << std::endl; - // Lock the mutex - args.mtx->lock(); - std::cout << "Thread " << args.thread_id << ": Locked mutex" << std::endl; + // Lock the mutex + args.mtx->lock(); + std::cout << "Thread " << args.thread_id << ": Locked mutex" << std::endl; - std::this_thread::sleep_for(std::chrono::seconds(3)); + std::this_thread::sleep_for(std::chrono::seconds(3)); - std::cout << "Thread " << args.thread_id << ": Unlocking mutex" << std::endl; - args.mtx->unlock(); + std::cout << "Thread " << args.thread_id << ": Unlocking mutex" << std::endl; + args.mtx->unlock(); - std::cout << "Thread " << args.thread_id << ": Thread finished" << std::endl; + std::cout << "Thread " << args.thread_id << ": Thread finished" << std::endl; - return args.thread_id; + return args.thread_id; } int main() { - std::mutex mtx; - - printf("== C++ threads tests ==\n"); - - // Create thread arguments - ThreadArgs args1{1, &mtx}; - ThreadArgs args2{2, &mtx}; - - // Store threads and their return values - std::vector threads; - long ret1, ret2; - - // Launch threads - std::thread t1([&]() { ret1 = simple_thread(args1); }); - std::thread t2([&]() { ret2 = simple_thread(args2); }); - - threads.push_back(std::move(t1)); - threads.push_back(std::move(t2)); - - // Wait for threads to finish - for (auto& t : threads) { - if (t.joinable()) { - t.join(); - } - } - - // Check return values - if (ret1 != 1) { - std::cout << "Unexpected return value for thread 1" << std::endl; - } - if (ret2 != 2) { - std::cout << "Unexpected return value for thread 2" << std::endl; - } - - std::cout << "All threads finished" << std::endl; - return 0; + std::mutex mtx; + + printf("== C++ threads tests ==\n"); + + // Create thread arguments + ThreadArgs args1{ 1, &mtx }; + ThreadArgs args2{ 2, &mtx }; + + // Store threads and their return values + std::vector threads; + long ret1, ret2; + + // Launch threads + std::thread t1([&]() { ret1 = simple_thread(args1); }); + std::thread t2([&]() { ret2 = simple_thread(args2); }); + + threads.push_back(std::move(t1)); + threads.push_back(std::move(t2)); + + // Wait for threads to finish + for (auto &t : threads) { + if (t.joinable()) { + t.join(); + } + } + + // Check return values + if (ret1 != 1) { + std::cout << "Unexpected return value for thread 1" << std::endl; + } + if (ret2 != 2) { + std::cout << "Unexpected return value for thread 2" << std::endl; + } + + std::cout << "All threads finished" << std::endl; + return 0; } From ae9e0ff2b514695441fea1507e05ce88245641b6 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 5 Jan 2026 14:49:31 +0100 Subject: [PATCH 13/17] Fix clang format Signed-off-by: Jean-Pierre Miceli --- so3/arch/arm32/thread.c | 2 +- so3/arch/arm64/thread.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/so3/arch/arm32/thread.c b/so3/arch/arm32/thread.c index 9ec16090c..dc92101a4 100644 --- a/so3/arch/arm32/thread.c +++ b/so3/arch/arm32/thread.c @@ -83,7 +83,7 @@ void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top) /* Reset all user's registers to zero except for PC, PSTATE and SP * which needs to be set to the properly start the thread. */ - *user_regs = (cpu_regs_t){ + *user_regs = (cpu_regs_t) { .pc = (u32) fn_entry, .psr = PSR_USR_MODE | PSR_I_BIT, .sp_usr = stack_top, diff --git a/so3/arch/arm64/thread.c b/so3/arch/arm64/thread.c index ca4ce1da4..9ad64bae3 100644 --- a/so3/arch/arm64/thread.c +++ b/so3/arch/arm64/thread.c @@ -79,7 +79,7 @@ void arch_restart_user_thread(tcb_t *tcb, th_fn_t fn_entry, addr_t stack_top) /* Reset all user's registers to zero except for PC, PSTATE and SP * which needs to be set to the properly start the program */ - *user_regs = (cpu_regs_t){ + *user_regs = (cpu_regs_t) { .pc = (u64) fn_entry, .pstate = PSR_MODE_EL0t, .sp_usr = stack_top, From 5a220ca3651e8618bb163fa6a16e65e9f22a5058 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 5 Jan 2026 14:53:38 +0100 Subject: [PATCH 14/17] clang format again Signed-off-by: Jean-Pierre Miceli --- so3/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/kernel/process.c b/so3/kernel/process.c index fe922f5cd..ccc61a5f4 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -346,7 +346,7 @@ void create_root_process(void) (void *) __root_proc_end - (void *) __root_proc_start, false); /* Start main user thread. */ - thread_args = (clone_args_t){ + thread_args = (clone_args_t) { .name = "root_proc", .pcb = pcb, .stack = pcb->stack_top, From 1f1cad5eddf99ba26ac132840bc7bf5ac33dfa84 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Fri, 16 Jan 2026 11:30:05 +0100 Subject: [PATCH 15/17] [C++] Add Copyright in src file + clean-up Signed-off-by: Jean-Pierre Miceli --- usr/build.sh | 1 - usr/src/tests/files_test.cpp | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/usr/build.sh b/usr/build.sh index d596d04dc..3b089289a 100755 --- a/usr/build.sh +++ b/usr/build.sh @@ -15,7 +15,6 @@ usage() { strip_debug_info() { # retrieve the correct objcop tool - # if [ "$1" == "virt32" -o "$1" == "rpi4" ]; then if [ "$1" = "virt32" ] || [ "$1" = "rpi4" ]; then OBJCOPY="arm-linux-musleabihf-objcopy" else diff --git a/usr/src/tests/files_test.cpp b/usr/src/tests/files_test.cpp index 731ed9686..e5ac0c9c3 100644 --- a/usr/src/tests/files_test.cpp +++ b/usr/src/tests/files_test.cpp @@ -1,4 +1,20 @@ - +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ #include #include From cff6f12fc36285b19a035c9d7f6dc2e60ad34d22 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Fri, 16 Jan 2026 18:51:11 +0100 Subject: [PATCH 16/17] rework elf loading to ensure all section are loaded and added kuser helpers --- so3/arch/arm32/Makefile | 1 + so3/arch/arm32/kuser_helper.S | 99 +++++++++++++++++++++++++++++++++++ so3/fs/elf.c | 21 +++++--- so3/include/elf.h | 6 ++- so3/kernel/process.c | 98 ++++++++-------------------------- so3/mm/memory.c | 8 +++ usr/aarch64-linux-musl.cmake | 1 + usr/arm-linux-musl.cmake | 3 +- 8 files changed, 152 insertions(+), 85 deletions(-) create mode 100644 so3/arch/arm32/kuser_helper.S diff --git a/so3/arch/arm32/Makefile b/so3/arch/arm32/Makefile index 1b03fb8e0..1dd060edd 100644 --- a/so3/arch/arm32/Makefile +++ b/so3/arch/arm32/Makefile @@ -7,6 +7,7 @@ obj-y += vfp.o obj-y += backtrace.o backtrace_asm.o obj-y += smccc-call.o obj-y += syscalls.o +obj-y += kuser_helper.o obj-y += lib/ diff --git a/so3/arch/arm32/kuser_helper.S b/so3/arch/arm32/kuser_helper.S new file mode 100644 index 000000000..0a3265694 --- /dev/null +++ b/so3/arch/arm32/kuser_helper.S @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2025 Clément Dieperink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file is copied from the Linux kernel with some small adaptation for SO3. + * Original file from Linux 6.18 : linux/arch/arm/kernel/entry-armv.S:652-842 + */ + + +/* + * User helpers. + * + * Each segment is 32-byte aligned and will be moved to the top of the high + * vector page. New segments (if ever needed) must be added in front of + * existing ones. This mechanism should be used only for things that are + * really small and justified, and not be abused freely. + * + * See Documentation/arch/arm/kernel_user_helpers.rst for formal definitions. + */ + .macro usr_ret, reg + ret \reg + .endm + + .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: + +/* + * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular + * kuser "slots", therefore 0xffff0f80 is not used as a valid entry point. + */ + + @ Not implemented as eorseq doesn't compile +__kuser_cmpxchg64: @ 0xffff0f60 + + kuser_pad __kuser_cmpxchg64, 64 + +__kuser_memory_barrier: @ 0xffff0fa0 + dmb ish + mov pc, lr + + kuser_pad __kuser_memory_barrier, 32 + +__kuser_cmpxchg: @ 0xffff0fc0 + + dmb ish +1: ldrex r3, [r2] + subs r3, r3, r0 + strexeq r3, r1, [r2] + teqeq r3, #1 + beq 1b + rsbs r0, r3, #0 + /* beware -- each __kuser slot must be 8 instructions max */ + b __kuser_memory_barrier + + kuser_pad __kuser_cmpxchg, 32 + + @ Not implemented here as syscall already exist +__kuser_get_tls: @ 0xffff0fe0 + mov r0, #0 + mov pc, lr + 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/so3/fs/elf.c b/so3/fs/elf.c index 5899debd2..24d20e702 100644 --- a/so3/fs/elf.c +++ b/so3/fs/elf.c @@ -166,7 +166,7 @@ void elf_load_segments(elf_img_info_t *elf_img_info) { size_t i; size_t segment_start, segment_end; - size_t page_start, page_end; + size_t min_segment_start, max_segment_end; /* Segments */ #ifdef CONFIG_ARCH_ARM32 @@ -189,7 +189,8 @@ void elf_load_segments(elf_img_info_t *elf_img_info) LOG_DEBUG("sizeof(struct elf64_phdr): %d bytes\n", sizeof(struct elf64_phdr)); #endif - elf_img_info->segment_page_count = 0; + min_segment_start = -1; + max_segment_end = 0; for (i = 0; i < elf_img_info->header->e_phnum; i++) { #ifdef CONFIG_ARCH_ARM32 memcpy(elf_img_info->segments + i, @@ -202,16 +203,22 @@ void elf_load_segments(elf_img_info_t *elf_img_info) #endif if (elf_img_info->segments[i].p_type == PT_LOAD) { - /* Don't use only p_memsz to get page count as p_vaddr can be unaligned and additionnal page will be needed. */ segment_start = elf_img_info->segments[i].p_vaddr; segment_end = segment_start + elf_img_info->segments[i].p_memsz; - page_start = segment_start >> PAGE_SHIFT; - page_end = (segment_end + PAGE_SIZE) >> PAGE_SHIFT; - - elf_img_info->segment_page_count += page_end - page_start; + min_segment_start = min(min_segment_start, (segment_start & PAGE_MASK)); + max_segment_end = max(max_segment_end, segment_end); } } + + if (max_segment_end != -1) { + elf_img_info->segment_start_vaddr = min_segment_start; + elf_img_info->segment_end_vaddr = max_segment_end; + } else { + elf_img_info->segment_start_vaddr = 0; + elf_img_info->segment_end_vaddr = 0; + } + LOG_DEBUG("segments use %d virtual pages\n", elf_img_info->segment_page_count); for (i = 0; i < elf_img_info->header->e_phnum; i++) { diff --git a/so3/include/elf.h b/so3/include/elf.h index 688bbb678..61b6d8472 100644 --- a/so3/include/elf.h +++ b/so3/include/elf.h @@ -33,7 +33,8 @@ struct elf_img_info { Elf32_Phdr *segments; /* program header */ char **section_names; void *file_buffer; - uint32_t segment_page_count; + addr_t segment_start_vaddr; + addr_t segment_end_vaddr; }; typedef Elf32_Off elf_addr_t; @@ -46,7 +47,8 @@ struct elf_img_info { Elf64_Phdr *segments; /* program header */ char **section_names; void *file_buffer; - uint64_t segment_page_count; + addr_t segment_start_vaddr; + addr_t segment_end_vaddr; }; typedef Elf64_Off elf_addr_t; diff --git a/so3/kernel/process.c b/so3/kernel/process.c index ccc61a5f4..2646e5113 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -73,14 +73,6 @@ char *proc_state_str(proc_state_t state) static uint32_t pid_current = 1; static pcb_t *root_process = NULL; /* root process */ -/* only the following sections are supported */ -static const char *supported_section_names[] = { - ".init", ".text", ".rodata", ".data", ".sbss", - ".bss", ".scommon", ".fini", ".eh_frame", ".gcc_except_table", - ".init_array", ".fini_array", ".data.rel.ro", ".got", ".got.plt", -}; -#define SUPPORTED_SECTION_COUNT (sizeof(supported_section_names) / sizeof(supported_section_names[0])) - /* * Find a process (pcb_t) from its pid. * Return NULL if no process has been found. @@ -511,16 +503,13 @@ void post_setup_image(args_env_t *args_env, elf_img_info_t *elf_img_info) /* This should contains a bitmask of hardware capabilities */ NEW_AUX_ENT(AT_HWCAP, HWCAP_ELF); - /* Those value should come from elf_img_info->header, but as user application - * are compiled with linker option -N, the program header (PHDR) isn't in a PT_LOAD - * segment meaning it will not be copied in userspace. - * The main effect of this is that variable in thread local storage will not be possible. - * Those variable are *flaged* with __thread (i.e `__thread int n;`) and aren't used for now. - * This header is also used for dynamically linking, which isn't supported by SO3 anyway. + /* Set PHDR information, so userspace can retrieve TLS information. + * Due to how userspace application are built the PHDR segments is missing and so + * we need to manually compute its address. */ - NEW_AUX_ENT(AT_PHDR, 0); - NEW_AUX_ENT(AT_PHENT, 0); - NEW_AUX_ENT(AT_PHNUM, 0); + NEW_AUX_ENT(AT_PHDR, elf_img_info->header->e_phoff + (elf_img_info->segment_start_vaddr & PAGE_MASK)); + NEW_AUX_ENT(AT_PHENT, sizeof(*elf_img_info->segments)); + NEW_AUX_ENT(AT_PHNUM, elf_img_info->header->e_phnum); /* NULL termination */ NEW_AUX_ENT(AT_NULL, 0); @@ -611,17 +600,18 @@ int setup_proc_image_replace(elf_img_info_t *elf_img_info, pcb_t *pcb, int argc, * application must start at 0x1000 (at the lowest). */ - pcb->page_count += elf_img_info->segment_page_count; + page_count = ((elf_img_info->segment_end_vaddr - elf_img_info->segment_start_vaddr) >> PAGE_SHIFT) + 1; + pcb->page_count += page_count; /* Map the elementary sections (text, data, bss) */ - allocate_page(pcb, (uint32_t) (elf_img_info->header->e_entry & PAGE_MASK), elf_img_info->segment_page_count, true); + allocate_page(pcb, elf_img_info->segment_start_vaddr, page_count, true); LOG_DEBUG("entry point: 0x%08x\n", elf_img_info->header->e_entry); LOG_DEBUG("page count: 0x%08x\n", pcb->page_count); /* Maximum heap size */ page_count = ALIGN_UP(HEAP_SIZE, PAGE_SIZE) >> PAGE_SHIFT; - pcb->heap_base = (elf_img_info->header->e_entry & PAGE_MASK) + (pcb->page_count + 1) * PAGE_SIZE; + pcb->heap_base = (elf_img_info->segment_end_vaddr & PAGE_MASK) + PAGE_SIZE; pcb->heap_pointer = pcb->heap_base; pcb->page_count += page_count; @@ -645,12 +635,12 @@ int setup_proc_image_replace(elf_img_info_t *elf_img_info, pcb_t *pcb, int argc, /* load sections from each loadable segment into the process' virtual pages */ void load_process(elf_img_info_t *elf_img_info) { - unsigned long section_start, section_end; - unsigned long segment_start, segment_end; - int i, j, k, l; - bool section_supported; - char section_base_name[16]; - int section_name_dots; + int i; + + /* Manually copy the PHDR as no segement/section contains it. */ + memcpy((void *) (elf_img_info->header->e_phoff + (elf_img_info->segment_start_vaddr & PAGE_MASK)), + elf_img_info->file_buffer + elf_img_info->header->e_phoff, + elf_img_info->header->e_phnum * elf_img_info->header->e_phentsize); /* Loading the different segments */ for (i = 0; i < elf_img_info->header->e_phnum; i++) { @@ -658,56 +648,14 @@ void load_process(elf_img_info_t *elf_img_info) /* Skip unloadable segments */ continue; - segment_start = elf_img_info->segments[i].p_offset; - segment_end = segment_start + elf_img_info->segments[i].p_memsz; - - /* Sections */ - for (j = 0; j < elf_img_info->header->e_shnum; j++) { - section_start = elf_img_info->sections[j].sh_offset; - section_end = section_start + elf_img_info->sections[j].sh_size; - - /* Verify if the section is part of this segment */ - if ((section_start < segment_start) || (section_end > segment_end)) - continue; - - /* Copy only base name of the section */ - l = 0; - section_name_dots = 0; - do { - section_base_name[l] = elf_img_info->section_names[j][l]; - if (section_base_name[l] == '.' && section_name_dots++) - break; // Base name stops at second '.' - } while (section_base_name[l++] != '\0'); - - /* Terminate string correctly (replace second '.' if stopped by it) */ - section_base_name[l] = '\0'; - - /* Not all sections are supported */ - section_supported = false; - for (k = 0; k < SUPPORTED_SECTION_COUNT; k++) { - if (!strcmp(section_base_name, supported_section_names[k])) { - section_supported = true; - break; - } - } - - if (!section_supported) { - LOG_DEBUG("Section %s not loaded: unsupported name\n", elf_img_info->section_names[j]); - continue; - } + /* Copy all required data. */ + memcpy((void *) elf_img_info->segments[i].p_vaddr, + (void *) (elf_img_info->file_buffer + elf_img_info->segments[i].p_offset), + elf_img_info->segments[i].p_filesz); - /* Load this section into the process' virtual memory */ - if (elf_img_info->sections[j].sh_type == SHT_NOBITS) - /* unless it were not stored in the file (.bss) - */ - continue; - - /* Real load of contents in the user space memory of the - * process */ - memcpy((void *) elf_img_info->sections[j].sh_addr, - (void *) (elf_img_info->file_buffer + elf_img_info->sections[j].sh_offset), - elf_img_info->sections[j].sh_size); - } + /* Set remaining byte (bss) to zero. */ + memset((void *) (elf_img_info->segments[i].p_vaddr + elf_img_info->segments[i].p_filesz), 0, + elf_img_info->segments[i].p_memsz - elf_img_info->segments[i].p_filesz); } /* Make sure all data are flushed for future context switch. */ diff --git a/so3/mm/memory.c b/so3/mm/memory.c index 8e9181b1b..98df46f52 100644 --- a/so3/mm/memory.c +++ b/so3/mm/memory.c @@ -434,6 +434,11 @@ void memory_init(void) #if defined(CONFIG_ARCH_ARM32) addr_t vectors_paddr; + + /* kuser helper are special function provided to userspace by the kernel. */ + addr_t kuser_sz; + extern char __kuser_helper_start[]; + extern char __kuser_helper_end[]; #endif void *new_sys_root_pgtable; @@ -496,6 +501,9 @@ void memory_init(void) create_mapping(NULL, VECTOR_VADDR, vectors_paddr, PAGE_SIZE, true); memcpy((void *) VECTOR_VADDR, (void *) &__vectors_start, (void *) &__vectors_end - (void *) &__vectors_start); + + kuser_sz = __kuser_helper_end - __kuser_helper_start; + memcpy((void *) (VECTOR_VADDR + PAGE_SIZE - kuser_sz), __kuser_helper_start, kuser_sz); #endif set_pgtable(__sys_root_pgtable); diff --git a/usr/aarch64-linux-musl.cmake b/usr/aarch64-linux-musl.cmake index f7c353062..34f5499a7 100644 --- a/usr/aarch64-linux-musl.cmake +++ b/usr/aarch64-linux-musl.cmake @@ -21,6 +21,7 @@ set(CMAKE_CXX_COMPILER "aarch64-linux-musl-g++") set(CMAKE_ASM_COMPILER "aarch64-linux-musl-gcc") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99 -D_GNU_SOURCE -D__ARM64__ -fno-common") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -D_GNU_SOURCE -D__ARM64__ -fno-common") set(CMAKE_ASM_FLAGS "-D__ARM64__ -D__ASSEMBLY__") diff --git a/usr/arm-linux-musl.cmake b/usr/arm-linux-musl.cmake index f148c3542..768c06320 100644 --- a/usr/arm-linux-musl.cmake +++ b/usr/arm-linux-musl.cmake @@ -21,7 +21,8 @@ set(CMAKE_CXX_COMPILER "arm-linux-musleabihf-g++") set(CMAKE_ASM_COMPILER "arm-linux-musleabihf-gcc") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99 -D_GNU_SOURCE -D__ARM__ -marm -mno-thumb-interwork -ffreestanding -fno-common") - +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -D_GNU_SOURCE -D__ARM__ -marm -mno-thumb-interwork -ffreestanding -fno-common") + set(CMAKE_ASM_FLAGS "-D__ARM__ -D__ASSEMBLY__") set(CMAKE_LINKER "arm-linux-musleabihf-ld") From 0d70faf795a383fab46f8e467e7a1cf72490a730 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Fri, 16 Jan 2026 18:51:52 +0100 Subject: [PATCH 17/17] fix copyright --- so3/arch/arm32/kuser_helper.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/arch/arm32/kuser_helper.S b/so3/arch/arm32/kuser_helper.S index 0a3265694..765a3976f 100644 --- a/so3/arch/arm32/kuser_helper.S +++ b/so3/arch/arm32/kuser_helper.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2025 Clément Dieperink + * Copyright (C) 2026 Clément Dieperink * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as