From 4e58c243ac4dd6f59eab3ca4e6d4bad163a57593 Mon Sep 17 00:00:00 2001 From: mlund Date: Thu, 20 Aug 2026 09:46:53 +0200 Subject: [PATCH] Take the freeze slot number in the byte order the code actually uses syspart_locate_freezeslot documents X as the low byte, but it pushes X then Y and pops plx before ply, so the multiply reads the low byte from Y. freeze_to_slot already asks for "Slot in XXYY", and callers follow the code rather than the comment, so correct the comment and the bounds check rather than the pops. That check rejected nothing: it fell through to the low byte whichever way the high byte compared. Fixing it exposed error paths that returned without pulling the pushed slot number. Also say why syspart_unfreeze_from_slot_trap restores only X: the trap dispatch clobbers it with tax, while Y reaches the handler untouched. Under Xemu: slot 2145 of 2045 was accepted, now refused; 0 and 1 unchanged. --- src/hyppo/syspart.asm | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/hyppo/syspart.asm b/src/hyppo/syspart.asm index 2cad8125b..592ef76db 100644 --- a/src/hyppo/syspart.asm +++ b/src/hyppo/syspart.asm @@ -237,6 +237,8 @@ syspart_configsector_apply_trap: sta hypervisor_enterexit_trigger syspart_unfreeze_from_slot_trap: + ;; Only X needs restoring: the dispatch above clobbers it with tax, + ;; while Y arrives from the caller untouched. ldx hypervisor_x jsr syspart_locate_freezeslot jsr unfreeze_load_from_sdcard_immediate @@ -278,8 +280,13 @@ syspart_locate_freezeslot_trap: syspart_locate_freezeslot: ;; Get the first sector of a given freeze slot - ;; X = low byte of slot # - ;; Y = high byte of slot # + ;; X = high byte of slot # + ;; Y = low byte of slot # + ;; + ;; The slot number is pushed here and popped back below in the same + ;; order, which swaps the pair: plx takes what phy pushed. So the + ;; multiply reads its low byte from Y, and freeze_to_slot in freeze.asm + ;; documents the same order ("Slot in XXYY"). phx phy @@ -288,21 +295,25 @@ syspart_locate_freezeslot: lda syspart_present bne splf1 lda #syspart_error_nosyspart - sta syspart_error_code - clc - rts + bra slotfail splf1: - ;; Check that freeze slot number is not invalid - cpy syspart_freeze_slot_count+1 - beq sc1 + ;; Check that freeze slot number is not invalid. + ;; High byte first; only when it matches does the low byte decide. + cpx syspart_freeze_slot_count+1 bcc slotnumok -sc1: cpx syspart_freeze_slot_count+0 - beq slotbad + bne slotbad + cpy syspart_freeze_slot_count+0 bcc slotnumok slotbad: ;; Report error status for out of bounds slot number lda #syspart_error_badslotnum +slotfail: + ;; Both error paths leave through here, because the slot number is + ;; still on the stack from the phx/phy above and returning without it + ;; would take the caller's return address with it. sta syspart_error_code + plx + plx clc rts