Skip to content

Add initial support for LessOS#107

Merged
nchapman merged 9 commits into
developfrom
feature/lessos
Dec 31, 2025
Merged

Add initial support for LessOS#107
nchapman merged 9 commits into
developfrom
feature/lessos

Conversation

@nchapman

Copy link
Copy Markdown
Collaborator

No description provided.

Implements generic LessOS bootstrap that routes to platform-specific
launchers based on LESSOS_PLATFORM environment variable.

Changes:
- Add workspace/rk3566/ platform (RK3566 SoC devices for LessOS)
- Add workspace/all/paks/LessUI/lessos/init.sh (generic bootstrap)
- Add rk3566 to platforms.json with lessos flag
- Add lessos target to Makefile
- Add skeleton/SYSTEM/rk3566/ structure
- Add LESSOS_PLATFORM env var check to updater (falls back to cpuinfo)
- Update lessos/init.sh to copy .tmp_update and run updater
- Create rk3566/install/boot.sh platform boot script
- Add rk3566 to PLATFORMS list and Makefile.copy for boot assets
- Bundle .tmp_update into lessos/ directory in Makefile special target
- Fix tg5040 boot.sh for consistency (while loop, fallback reboot)
- Add HAS_OPENGLES flag for Mali-G52 GPU
- Use GLVideo for effects instead of SDL2
- Remove hardcoded SDL_VIDEODRIVER (let SDL2 auto-detect)
Adds paths.h/paths.c to read LESSOS_STORAGE environment variable at
startup, falling back to compile-time SDCARD_PATH for other platforms.
Enables dynamic storage paths for LessOS (internal vs external SD).

- Created paths.h with runtime path globals (g_sdcard_path, etc.)
- Created paths.c with Paths_init() implementation
- Added paths.c to common build sources
- Updated launch.sh template to export LESSOS_STORAGE
Replace compile-time path macros with runtime g_* globals throughout
launcher, player, and tool paks. All code now calls Paths_init() at
startup and uses dynamic paths.

- Updated launcher, player, Clock, and shui to call Paths_init()
- Replaced SDCARD_PATH, ROMS_PATH, etc. with g_* runtime globals
- Added debug logging for ROM discovery and emulator detection
Fixes display issues and boot flow for rk3566 running on LessOS.

- show.c: Remove SDL_WINDOW_FULLSCREEN_DESKTOP (requires window manager)
- show.c: Add error handling and diagnostic logging
- boot.sh: Add boot logging to /lessui-boot.log
- boot.sh: Fix working directory after atomic update deletes .tmp_update
- Enable OpenGL ES rendering for rk3566 platform
Add paths_stub.c for unit tests and update all test builds to link
against it. All 1508 tests pass.

- Created paths_stub.c with pre-initialized test paths
- Updated Makefile.qa to include PATHS_STUB in test builds
- Added rk3566 platform to System Report pak
Copilot AI review requested due to automatic review settings December 31, 2025 19:31
@nchapman nchapman changed the title Add support for LessOS Add initial support for LessOS Dec 31, 2025

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds support for LessOS, a new operating system for retro gaming handhelds, along with the RK3566 platform (Rockchip SoC) that runs on it. The changes enable LessUI to run on devices like the PowKiddy RGB30 and Anbernic RG353 series through LessOS.

Key changes:

  • Added complete RK3566 platform implementation with hardware-specific drivers, settings library, and boot utilities
  • Modified boot scripts to support both stock OS and LessOS environments with conditional path detection
  • Integrated LessOS bootstrap into the build system with platform detection and updater modifications

Reviewed changes

Copilot reviewed 19 out of 24 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
workspace/tg5040/install/boot.sh Removed sync call and reboot logic, switched to while loop for launcher
workspace/rk3566/install/boot.sh New RK3566 boot script with LessOS storage path support
workspace/rk3566/show/show.c SDL2-based boot splash display utility (has null pointer issues)
workspace/rk3566/show/Makefile Build configuration for show utility
workspace/rk3566/platform/platform.h Hardware definitions and button mappings for RK3566 devices
workspace/rk3566/platform/platform.c Platform-specific implementation using SDL2 render backend
workspace/rk3566/platform/Makefile.env Compiler flags for ARM Cortex-A55 architecture
workspace/rk3566/platform/Makefile.copy File copy rules for platform binaries
workspace/rk3566/libmsettings/* Shared memory settings library for volume/brightness control
workspace/rk3566/Makefile Platform build configuration
workspace/rk3566/README.md Comprehensive documentation for RK3566 platform (contains RGB30-specific references)
workspace/all/paks/config/platforms.json Added rk3566 platform configuration with LessOS flag
workspace/all/paks/LessUI/platforms/rk3566/init.sh Platform initialization script for LessOS
skeleton/SYSTEM/rk3566/* Platform skeleton files (system.cfg, bin/shutdown, empty directories)
skeleton/BOOT/lessos/init.sh LessOS bootstrap entry point
skeleton/BOOT/common/updater Modified to detect LessOS platform and use appropriate storage paths
Makefile Added rk3566 to platform list and LessOS-specific packaging targets

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread workspace/rk3566/platform/platform.h Outdated
Comment thread workspace/rk3566/platform/platform.c Outdated
Comment thread workspace/rk3566/platform/platform.c Outdated
Comment thread workspace/rk3566/Makefile Outdated
Comment thread workspace/rk3566/Makefile Outdated
Comment thread workspace/rk3566/show/show.c Outdated
Comment thread workspace/rk3566/show/show.c Outdated
Comment thread workspace/rk3566/show/show.c Outdated
Comment thread workspace/rk3566/README.md
Comment thread workspace/rk3566/Makefile Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 39 out of 44 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +63 to +66
if (shm_fd==-1 && errno==EEXIST) { // already exists
puts("Settings client");
shm_fd = shm_open(SHM_KEY, O_RDWR, 0644);
settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If shm_open() fails for the client path (line 65), the code doesn't check if shm_fd is valid before calling mmap(). This could lead to undefined behavior. Add error checking: if (shm_fd == -1) { perror("shm_open failed"); exit(1); }

Copilot uses AI. Check for mistakes.


void InitSettings(void) {
sprintf(SettingsPath, "%s/msettings.bin", getenv("USERDATA_PATH"));

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sprintf function is used without bounds checking. If USERDATA_PATH environment variable contains a very long string, this could overflow the 256-byte SettingsPath buffer. Consider using snprintf instead to prevent buffer overflow.

Copilot uses AI. Check for mistakes.
void SetRawVolume(int val) { // 0 - 100
// printf("SetRawVolume(%i)\n", val); fflush(stdout);
char cmd[256];
sprintf(cmd, "amixer sset -M 'Master' %i%% &> /dev/null", val);

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sprintf calls with user-controlled val parameter could lead to buffer overflow. Although val is expected to be numeric, using snprintf with explicit buffer size would be safer. Consider replacing with snprintf(cmd, sizeof(cmd), ...).

Copilot uses AI. Check for mistakes.
// printf("SetJack(%i)\n", value); fflush(stdout);

char cmd[256];
sprintf(cmd, "amixer cset name='Playback Path' '%s' &> /dev/null", value?"HP":"SPK");

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sprintf call could overflow the 256-byte buffer if the string value ("HP" or "SPK") is somehow modified. Use snprintf(cmd, sizeof(cmd), ...) instead for bounds checking.

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +135
void SetBrightness(int value) {
if (settings->hdmi) return;

int raw;
switch (value) {
// TODO: redo, range is 0-255
case 0: raw=4; break; // 0
case 1: raw=6; break; // 2
case 2: raw=10; break; // 4
case 3: raw=16; break; // 6
case 4: raw=32; break; // 16
case 5: raw=48; break; // 16
case 6: raw=64; break; // 16
case 7: raw=96; break; // 32
case 8: raw=128; break; // 32
case 9: raw=192; break; // 64
case 10: raw=255; break; // 64
}

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SetBrightness function doesn't handle invalid input values. If value is outside the range 0-10, the raw variable will be uninitialized, leading to undefined behavior. Add a default case or bounds check to handle invalid inputs.

Copilot uses AI. Check for mistakes.
Comment on lines 58 to 59
run_platform_install "$SYSTEM_PATH/$PLATFORM/bin/install.sh" "$LOG_FILE"

if [ "$ACTION" = "installing" ]; then
log_info "Rebooting..."
reboot
fi
fi

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The automatic reboot after installation has been removed. Previously, if ACTION was "installing", the script would reboot immediately after installation. Now the script continues to the launch loop instead. This is a behavioral change that should be intentional - verify that this is the desired behavior for new installations on tg5040.

Copilot uses AI. Check for mistakes.

// Build all derived paths
(void)snprintf(g_roms_path, PATHS_MAX_LEN, "%s/Roms", g_sdcard_path);
(void)snprintf(g_root_system_path, PATHS_MAX_LEN, "%s/.system/", g_sdcard_path);

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The g_root_system_path includes a trailing slash in line 52 ("%s/.system/"), but other paths don't consistently use trailing slashes. This inconsistency could lead to malformed paths if code elsewhere doesn't expect the trailing slash. Consider removing it for consistency, or document why it's needed here.

Suggested change
(void)snprintf(g_root_system_path, PATHS_MAX_LEN, "%s/.system/", g_sdcard_path);
(void)snprintf(g_root_system_path, PATHS_MAX_LEN, "%s/.system", g_sdcard_path);

Copilot uses AI. Check for mistakes.


void InitSettings(void) {
sprintf(SettingsPath, "%s/msettings.bin", getenv("USERDATA_PATH"));

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If getenv("USERDATA_PATH") returns NULL, this will cause undefined behavior (dereferencing a NULL pointer). Add a NULL check before using the environment variable, or provide a default fallback path.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +19
char path[256];
snprintf(path, sizeof(path), "%s", argv[1]);

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The snprintf call is redundant here - it simply copies argv[1] to path without any formatting. This can be replaced with a simpler bounds-checked string copy or just use argv[1] directly in subsequent calls.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +73
shm_fd = shm_open(SHM_KEY, O_RDWR | O_CREAT | O_EXCL, 0644); // see if it exists
if (shm_fd==-1 && errno==EEXIST) { // already exists
puts("Settings client");
shm_fd = shm_open(SHM_KEY, O_RDWR, 0644);
settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
}
else { // host
puts("Settings host"); // should always be keymon
is_host = 1;
// we created it so set initial size and populate
ftruncate(shm_fd, shm_size);
settings = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

Copilot AI Dec 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If mmap() fails (returns MAP_FAILED), the code doesn't check for this condition. Subsequently accessing the settings pointer would cause a segmentation fault. Add error checking after both mmap() calls: if (settings == MAP_FAILED) { perror("mmap failed"); exit(1); }

Copilot uses AI. Check for mistakes.
@nchapman nchapman merged commit 2ad1e0d into develop Dec 31, 2025
4 checks passed
@nchapman nchapman deleted the feature/lessos branch December 31, 2025 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants