|
| 1 | +/* |
| 2 | + * PROJECT: FreeLoader |
| 3 | + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) |
| 4 | + * PURPOSE: Real mode helper code for Original Xbox |
| 5 | + * COPYRIGHT: Copyright 2011 Timo Kreuzer <timo.kreuzer@reactos.org> |
| 6 | + * Copyright 2012-2019 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> |
| 7 | + * Copyright 2026 Daniel Victor <ilauncherdeveloper@gmail.com> |
| 8 | + */ |
| 9 | + |
| 10 | +Empty8042: |
| 11 | + .word HEX(00eb), HEX(00eb) /* jmp $+2, jmp $+2 */ |
| 12 | + in al, HEX(64) |
| 13 | + cmp al, HEX(0ff) /* legacy-free machine without keyboard */ |
| 14 | + jz Empty8042_ret /* controllers on Intel Macs read back 0xFF */ |
| 15 | + test al, 2 |
| 16 | + jnz Empty8042 |
| 17 | +Empty8042_ret: |
| 18 | + ret |
| 19 | + |
| 20 | +EnableA20: |
| 21 | + pusha |
| 22 | + call Empty8042 |
| 23 | + mov al, HEX(0D1) /* command write */ |
| 24 | + out HEX(064), al |
| 25 | + call Empty8042 |
| 26 | + mov al, HEX(0DF) /* A20 on */ |
| 27 | + out HEX(060), al |
| 28 | + call Empty8042 |
| 29 | + mov al, HEX(0FF) /* pulse output port */ |
| 30 | + out HEX(064), al |
| 31 | + call Empty8042 |
| 32 | + popa |
| 33 | + ret |
| 34 | + |
| 35 | +DisableA20: |
| 36 | + pusha |
| 37 | + call Empty8042 |
| 38 | + mov al, HEX(0D1) /* command write */ |
| 39 | + out HEX(064), al |
| 40 | + call Empty8042 |
| 41 | + mov al, HEX(0DD) /* A20 off */ |
| 42 | + out HEX(060), al |
| 43 | + call Empty8042 |
| 44 | + mov al, HEX(0FF) /* pulse output port */ |
| 45 | + out HEX(064), al |
| 46 | + call Empty8042 |
| 47 | + popa |
| 48 | + ret |
| 49 | + |
| 50 | +/* |
| 51 | + * writestr |
| 52 | + * si = pointer to zero terminated string |
| 53 | + */ |
| 54 | +writestr: |
| 55 | + pushfd |
| 56 | + pushad |
| 57 | +writestr_top: |
| 58 | + lodsb |
| 59 | + and al, al |
| 60 | + jz writestr_end |
| 61 | + call writechr |
| 62 | + jmp short writestr_top |
| 63 | +writestr_end: |
| 64 | + popad |
| 65 | + popfd |
| 66 | + ret |
| 67 | + |
| 68 | +/* |
| 69 | + * writechr |
| 70 | + * al = character to output |
| 71 | + */ |
| 72 | +writechr: |
| 73 | + /* no-op on Xbox, as it doesn't have INT 10h / VGA BIOS |
| 74 | + * FIXME: This could be made to output to the serial port */ |
| 75 | + ret |
| 76 | + |
| 77 | +/* |
| 78 | + * writehex[248]: Write a hex number in (AL, AX, EAX) to the console |
| 79 | + */ |
| 80 | +writehex2: |
| 81 | + pushfd |
| 82 | + pushad |
| 83 | + shl eax, 24 |
| 84 | + mov cx, 2 |
| 85 | + jmp short writehex_common |
| 86 | +writehex4: |
| 87 | + pushfd |
| 88 | + pushad |
| 89 | + shl eax, 16 |
| 90 | + mov cx, 4 |
| 91 | + jmp short writehex_common |
| 92 | +writehex8: |
| 93 | + pushfd |
| 94 | + pushad |
| 95 | + mov cx, 8 |
| 96 | +writehex_common: |
| 97 | +.loop: |
| 98 | + rol eax, 4 |
| 99 | + push eax |
| 100 | + and al, HEX(0F) |
| 101 | + cmp al, 10 |
| 102 | + jae .high |
| 103 | +.low: |
| 104 | + add al, '0' |
| 105 | + jmp short .ischar |
| 106 | +.high: |
| 107 | + add al, 'A'-10 |
| 108 | +.ischar: |
| 109 | + call writechr |
| 110 | + pop eax |
| 111 | + loop .loop |
| 112 | + popad |
| 113 | + popfd |
| 114 | + ret |
| 115 | + |
| 116 | + |
| 117 | +Reboot: |
| 118 | + /* FIXME: perform reboot via SMC on I2C bus */ |
| 119 | + cli |
| 120 | + |
| 121 | + /* Disable A20 address line */ |
| 122 | + call DisableA20 |
| 123 | + |
| 124 | + /* and jump to the Reset Vector in the ROM */ |
| 125 | + ljmp16 HEX(0F000), HEX(0FFF0) |
| 126 | + |
| 127 | + |
| 128 | +Relocator16Boot: |
| 129 | + cli |
| 130 | + |
| 131 | + /* Disable A20 address line */ |
| 132 | + call DisableA20 |
| 133 | + |
| 134 | + /* Get current EFLAGS and mask CF, ZF and SF */ |
| 135 | + pushf |
| 136 | + pop cx |
| 137 | + and cx, not (EFLAGS_CF or EFLAGS_ZF or EFLAGS_SF) |
| 138 | + |
| 139 | + /* Get flags CF, ZF and SF from the REGS structure */ |
| 140 | + mov ax, word ptr cs:[BSS_RegisterSet + REGS_EFLAGS] |
| 141 | + and ax, (EFLAGS_CF or EFLAGS_ZF or EFLAGS_SF) |
| 142 | + |
| 143 | + /* Combine flags and set them */ |
| 144 | + or ax, cx |
| 145 | + push ax |
| 146 | + popf |
| 147 | + |
| 148 | + /* Setup the segment registers */ |
| 149 | + mov ax, word ptr cs:[BSS_RegisterSet + REGS_DS] |
| 150 | + mov ds, ax |
| 151 | + mov ax, word ptr cs:[BSS_RegisterSet + REGS_ES] |
| 152 | + mov es, ax |
| 153 | + mov ax, word ptr cs:[BSS_RegisterSet + REGS_FS] |
| 154 | + mov fs, ax |
| 155 | + mov ax, word ptr cs:[BSS_RegisterSet + REGS_GS] |
| 156 | + mov gs, ax |
| 157 | + |
| 158 | + /* Patch the jump address (segment:offset) */ |
| 159 | + mov eax, dword ptr cs:[BSS_RealModeEntry] |
| 160 | + mov dword ptr cs:[Relocator16Address], eax |
| 161 | + |
| 162 | + /* Switch the stack (segment:offset) */ |
| 163 | + mov eax, dword ptr cs:[BSS_CallbackReturn] |
| 164 | + shr eax, 16 |
| 165 | + mov ss, ax |
| 166 | + mov eax, dword ptr cs:[BSS_CallbackReturn] |
| 167 | + and eax, HEX(0FFFF) |
| 168 | + mov esp, eax |
| 169 | + |
| 170 | + /* Setup the registers */ |
| 171 | + mov eax, dword ptr cs:[BSS_RegisterSet + REGS_EAX] |
| 172 | + mov ebx, dword ptr cs:[BSS_RegisterSet + REGS_EBX] |
| 173 | + mov ecx, dword ptr cs:[BSS_RegisterSet + REGS_ECX] |
| 174 | + mov edx, dword ptr cs:[BSS_RegisterSet + REGS_EDX] |
| 175 | + mov esi, dword ptr cs:[BSS_RegisterSet + REGS_ESI] |
| 176 | + mov edi, dword ptr cs:[BSS_RegisterSet + REGS_EDI] |
| 177 | + /* FIXME: Don't setup ebp, we only use it as output! */ |
| 178 | + |
| 179 | + /* Jump to the new CS:IP (e.g. jump to bootsector code...) */ |
| 180 | + .byte HEX(0EA) /* ljmp16 segment:offset */ |
| 181 | +Relocator16Address: |
| 182 | + .word HEX(7C00) /* Default offset */ |
| 183 | + .word HEX(0000) /* Default segment */ |
| 184 | + nop |
0 commit comments