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 d3bee955a..ccc61a5f4 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -74,10 +74,12 @@ static uint32_t pid_current = 1; static pcb_t *root_process = NULL; /* root process */ /* only the following sections are supported */ -#define SUPPORTED_SECTION_COUNT 8 -static const char *supported_section_names[SUPPORTED_SECTION_COUNT] = { - ".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", +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. 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/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") 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} 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() + diff --git a/usr/src/tests/CMakeLists.txt b/usr/src/tests/CMakeLists.txt new file mode 100644 index 000000000..7ae48e239 --- /dev/null +++ b/usr/src/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.16) + +add_executable(hello-world.elf hello_world.cpp) +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/allocation_test.cpp b/usr/src/tests/allocation_test.cpp new file mode 100644 index 000000000..dca56f86a --- /dev/null +++ b/usr/src/tests/allocation_test.cpp @@ -0,0 +1,35 @@ +/* + * 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 new file mode 100644 index 000000000..eef30af66 --- /dev/null +++ b/usr/src/tests/class_test.cpp @@ -0,0 +1,53 @@ +/* + * 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: + Person(const std::string &name, int 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; + } +}; + +int main() +{ + Person p("Jean-Pierre", 30); + p.hello(); + + return 0; +} diff --git a/usr/src/tests/exception_test.cpp b/usr/src/tests/exception_test.cpp new file mode 100644 index 000000000..6026dea25 --- /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/files_test.cpp b/usr/src/tests/files_test.cpp new file mode 100644 index 000000000..731ed9686 --- /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 + return 0; +} diff --git a/usr/src/tests/hello_world.cpp b/usr/src/tests/hello_world.cpp new file mode 100644 index 000000000..4ef192cd0 --- /dev/null +++ b/usr/src/tests/hello_world.cpp @@ -0,0 +1,26 @@ +/* + * 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() +{ + std::cout << "Hello World!" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/usr/src/tests/stdlib_test.cpp b/usr/src/tests/stdlib_test.cpp new file mode 100644 index 000000000..a450971be --- /dev/null +++ b/usr/src/tests/stdlib_test.cpp @@ -0,0 +1,63 @@ +/* + * 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 + +void vector_test() +{ + // 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 + 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 diff --git a/usr/src/tests/threads_test.cpp b/usr/src/tests/threads_test.cpp new file mode 100644 index 000000000..bb2d77a4f --- /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; +}