Implement several previously-stubbed service commands and refine the
system version reporting from the prior hardware-info work:
- ptm:sysm ConfigureNew3DSCPU (0x0818): accept the clock/L2 config
bitfield. Azahar always runs as New 3DS, so no switching is needed.
- fs:USER GetSdmcCid (0x0819) / GetNandCid (0x081A): return all-zero
CIDs, consistent with the all-zero ID0/ID1 used in the SDMC path.
- cfg:i ClearParentalControls (0x040F): clear the parental restriction
email block (0x000C0002) and persist. The PIN and secret answer in
0x00100001 are intentionally preserved, matching hardware behaviour.
Synthesize the virtual TWL /sys/log/product.log dynamically from the
installed CVer/NVer titles' RomFS version.bin instead of a hardcoded
string, so the reported system version reflects the actual installed
firmware. If those titles are absent, the file is reported as not
found rather than returning misleading data.
Drop the dummy all-zero TwlParentalRestrictions config block default,
which caused a fake parental PIN to be reported when the block was
never set up.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously the game list rescanned game directories on every launch and
after any event that might have changed game files. This commit replaces
that with a persistent JSON cache so subsequent launches populate the
list instantly from disk.
Key changes:
- game_list_cache.h/cpp: new JSON cache at ConfigDir/game_list_cache.json.
Keyed by a DirsSignature fingerprint (path + deep_scan for every dir);
invalidated automatically when the directory list changes.
- GameListWorker: emits CacheEntryReady in parallel with EntryReady,
carrying raw metadata so entries can be rebuilt without touching ROMs.
- GameList::PopulateAsync: checks cache first. On a hit it rebuilds the
model synchronously from cached data (PopulateFromCache) with no worker
thread. On a miss it runs the full scan and saves the new cache in
DonePopulating.
- GameList::ForceRescan: invalidates the cache then calls PopulateAsync.
- GameList::RefreshPlayTimes: updates only the play-time column in-place;
called after a game session ends instead of a full rescan.
- QFileSystemWatcher is kept for CIA-install plumbing but is no longer
connected to any automatic rescan.
- File menu: new "Refresh Game List" action (F5) triggers ForceRescan.
- OnCIAInstallFinished: uses ForceRescan (new title needs a fresh scan).
- OnStopGame: uses RefreshPlayTimes (only play time changed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ptm: GetAdapterState/GetBatteryChargeState model plugged-in fully-charged
state; SetBatteryEmptyLEDPattern and IsShutdownByBatteryEmpty return nominal
values; shared_page battery fields updated to match
- mcu::HWC: GetBatteryVoltage (0xD7), GetBatteryLevel (100),
GetBatteryTemperature (28°C), GetMcuFwVerHigh/Low (3.65 raw 0x13/0x65),
ReadRegister for reg 0x7F (PMIC/battery-vendor system-state bytes) and
reg 0x0A (temperature), GetInfoRegisters with same system-state payload
- mcu::NWM: add new service module with wireless LED stubs
(SetWirelessLedState, GetWirelessLedState)
- gsp::Lcd: GetVendor returns 0xCC (TN/TN screens)
- gsp::GPU: GetDisplayCaptureInfo stubbed to not spam log
- ac: LoadNetworkSetting stubs for slots 1-3 returning a placeholder open
AP; SetClientVersion stubbed; ac:i CloseAsync stubbed
- cfg: WiFi slot 1 default block (0x100001) pre-populated with an open
network so the slot is not blank
- fs: GetSdmcCid/GetNandCid return fixed dummy CIDs; NAND TWL archive
intercepts /sys/log/product.log via in-memory VirtualFile backend
(no host filesystem involvement); ArchiveFactory_NAND::Initialize
returns true immediately for TWL type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Return the next PlayHistory ring index from GetPlayHistory instead of the number of entries written, matching libctru's ptm:plays API expectations. Treat incoming reads as physical ring indices, keep PlayHistory cached in memory, and make CalcPlayHistoryStart perform signed ring-index arithmetic. Also keeps NotifyPlayEvent appends consistent when the saved ring start is nonzero.
Validation: git diff --check -- src/core/hle/service/ptm/ptm.cpp src/core/hle/service/ptm/ptm.h
Add PTM PlayHistory.dat support backed by system savedata 00010022, including read/write helpers, play-history IPC handlers, NotifyPlayEvent, ClearPlayHistory, CalcPlayHistoryStart, and zero-filled empty-state repair.
Record play events from APT application, HOME Menu, library applet, and system applet lifecycle transitions so Activity Log can aggregate valid sessions from regenerated saves.
Add fs:USER handlers for ListSeeds, GetNumTitleTags, and ListTitleTags used by Activity Log library scans, and wire remaining PTM common handlers needed by the app.
Validation: git diff --check; user confirmed regenerated PTM and Activity Log saves display correctly.
Async IPC continuations can finish while System::Shutdown is tearing down service, kernel, and timing state. The dump showed an HTTP ReceiveData RunAsync task calling Thread::WakeAfterDelay after shutdown had begun, which reached Core::Timing::ScheduleEvent with invalid timing state and crashed.
Mark KernelSystem as shutting down at the start of System::Shutdown and in the kernel destructor. Route RunAsync and RunOnThreadWorker completions through HLERequestContext::WakeAfterAsync, which skips scheduling guest-thread wakes once shutdown starts and balances the pending async counter instead.
Validation: git diff --check
The previous NullWaitObject fix only covered WaitSynchronizationN (0x25).
WaitSynchronization1 (0x24) had the same issue: handle=0 returned
ResultInvalidHandle immediately, crashing any process whose wait handle
had not been populated yet.
Apply the same fix: handle=0 is substituted with a NullWaitObject so the
thread sleeps until the timeout expires and receives ResultTimeout, matching
real hardware behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
svc.cpp / kernel:
- Add NullWaitObject: handle=0 in svcWaitSynchronizationN is treated as a
permanently-unavailable slot (never fires) instead of returning
ResultInvalidHandle. Official Nintendo APT library builds pass aptSleepSync=0
when sleeping for HOME Menu; real hardware silently ignores null slots and lets
the other handles (APT:Parameter) drive the wakeup.
- Process now inherits WaitObject so svcWaitSynchronizationN on process handles
works correctly. LLE HOME Menu waits on a process handle during startup;
previously Azahar returned ResultInvalidHandle because Process only extended
Object, not WaitObject. Process becomes available (ShouldWait=false) when it
exits; TerminateProcess calls WakeupAllWaitingThreads.
applet_manager.cpp / apt.cpp:
- RequestForSysApplet auto-Response now attaches a pre-signaled event so the
application can svcWaitSynchronizationN on the received handle without hanging.
- Wakeup parameters with no object now get a pre-signaled event (same fix).
- RegisterApplet initial Wakeup now sends a pre-signaled event.
- LeaveHomeMenu: supply a pre-signaled event when HOME Menu passes handle=0, so
the application does not crash when it calls svcSignalEvent on the result.
- Removed the old logic that force-nulled objects on system→application sends
(this was masking the real issue and breaking Wakeup handle delivery).
cfg.cpp:
- GetRegion defaults from_secure_info=true so CFGU_SecureInfoGetRegion reads
SecureInfo_A (contains the hardware region) instead of falling back to
auto-detect which returned JPN(0) for 3DSX homebrew with no preferred regions.
fs_user.cpp/h:
- Implement GetSdmcCtrRootPath (0x0848): returns /Nintendo 3DS/<ID0>/<ID1> as a
UTF-16LE wide string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Tools > Create Shortcuts for All Games > Add to Desktop /
Add to Applications Menu. Asks for fullscreen preference once, then
iterates every unique game in the list with a progress dialog and
shows a summary on completion. Hidden on macOS where single-game
shortcut creation is also unsupported.
GameList gains GetAllGames() to enumerate unique (program_id, path)
pairs from the model, deduplicating entries that appear in both a
directory and the Favorites section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ReceiveData now streams body data in chunks via content_receiver + stream_cv
instead of blocking until the full response body is downloaded; fixes downloads
of large files that would time out before the body completed
- GetDownloadSizeState returns Content-Length from response headers immediately
(via response_headers_future) rather than waiting for the progress callback,
matching real hardware behavior
- GetResponseStatusCode and GetResponseHeader resolve from response_headers_future
so they return as soon as headers arrive, not after full body download
- CancelConnection implemented: cancel_mutex + cancel_stop_fn set/cleared around
client->send(); calling stop() aborts any in-flight request
- Cert chain stubs: CreateRootCertChain, DestroyRootCertChain, RootCertChainAddCert,
RootCertChainAddDefaultCert, RootCertChainRemoveCert, SelectRootCertChain
- Shutdown fix: HTTP_C destructor sets async_shutdown and spin-waits for
async_pending==0; async lambdas bail early on shutdown to prevent
use-after-free of freed KernelSystem
- AM: remove redundant encrypted CIA check that blocked legitimate installs
- build-azahar.ps1: deploy now copies per-file with error counting instead of
Move-Item so locked files (emulator open) produce warnings rather than silent failure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: Add sbom and attestation
* tools: Add verify-release.sh
* verify-release.sh: Set executable permission
* verify-release.sh: Put downloads into a gitignored directory
* tools: Make verify-release also download sbom
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
* ci: Add sbom and attestation
* tools: Add verify-release.sh
* verify-release.sh: Set executable permission
* verify-release.sh: Put downloads into a gitignored directory
* tools: Make verify-release also download sbom
---------
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>