176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; ----------------------------------------------------------------------- 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; Copyright 2009 Intel Corporation; author: H. Peter Anvin 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; This program is free software; you can redistribute it and/or modify 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; it under the terms of the GNU General Public License as published by 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; Boston MA 02111-1307, USA; either version 2 of the License, or 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; (at your option) any later version; incorporated herein by reference. 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; ----------------------------------------------------------------------- 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; pm.inc 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; Functions to enter and exit 32-bit protected mode, handle interrupts 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; and cross-mode calls. 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; PM refers to 32-bit flat protected mode; RM to 16-bit real mode. 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman;; 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 16 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; _pm_call: call PM routine in low memory from RM 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; on stack = PM routine to call (a 32-bit address) 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; ECX, ESI, EDI passed to the called function; 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; EAX = EBP in the called function points to the stack frame 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; which includes all registers (which can be changed if desired.) 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; All registers and the flags saved/restored 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; This routine is invoked by the pm_call macro. 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman_pm_call: 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pushfd 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pushad 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push ds 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push es 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push fs 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push gs 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov bp,sp 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ax,cs 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ebx,.pm 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ds,ax 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp enter_pm 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 32 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .textnr 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.pm: 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; EAX points to the top of the RM stack, which is EFLAGS 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman test RM_FLAGSH,02h ; RM EFLAGS.IF 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jz .no_sti 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sti 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.no_sti: 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call [ebp+4*2+9*4+2] ; Entrypoint on RM stack 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov bx,.rm 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp enter_rm 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 16 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.rm: 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop gs 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop fs 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop es 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop ds 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman popad 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman popfd 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret 4 ; Drop entrypoint 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; enter_pm: Go to PM with interrupt service configured 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; EBX = PM entry point 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; EAX = EBP = on exit, points to the RM stack as a 32-bit value 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; ECX, EDX, ESI, EDI preserved across this routine 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Assumes CS == DS 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; This routine doesn't enable interrupts, but the target routine 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; can enable interrupts by executing STI. 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 16 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenter_pm: 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cli 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor eax,eax 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ds,ax 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ax,ss 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov [RealModeSSSP],sp 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov [RealModeSSSP+2],ax 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman movzx ebp,sp 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman shl eax,4 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman add ebp,eax ; EBP -> top of real-mode stack 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cld 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call enable_a20 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.a20ok: 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov byte [bcopy_gdt.TSS+5],89h ; Mark TSS unbusy 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lgdt [bcopy_gdt] ; We can use the same GDT just fine 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lidt [PM_IDT_ptr] ; Set up the IDT 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov eax,cr0 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman or al,1 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov cr0,eax ; Enter protected mode 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp PM_CS32:.in_pm 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 32 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .textnr 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.in_pm: 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor eax,eax ; Available for future use... 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov fs,eax 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov gs,eax 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lldt ax 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov al,PM_DS32 ; Set up data segments 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov es,eax 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ds,eax 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ss,eax 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov al,PM_TSS ; Be nice to Intel's VT by 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ltr ax ; giving it a valid TR 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov esp,[PMESP] ; Load protmode %esp 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov eax,ebp ; EAX -> top of real-mode stack 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp ebx ; Go to where we need to go 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; enter_rm: Return to RM from PM 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; BX = RM entry point (CS = 0) 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; ECX, EDX, ESI, EDI preserved across this routine 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; EAX clobbered 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; EBP reserved 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; This routine doesn't enable interrupts, but the target routine 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; can enable interrupts by executing STI. 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 32 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .textnr 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenter_rm: 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cli 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cld 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov [PMESP],esp ; Save exit %esp 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp PM_CS16:.in_pm16 ; Return to 16-bit mode first 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 16 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.in_pm16: 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ax,PM_DS16 ; Real-mode-like segment 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov es,ax 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ds,ax 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ss,ax 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov fs,ax 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov gs,ax 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lidt [RM_IDT_ptr] ; Real-mode IDT (rm needs no GDT) 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor dx,dx 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov eax,cr0 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman and al,~1 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov cr0,eax 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp 0:.in_rm 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.in_rm: ; Back in real mode 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lss sp,[cs:RealModeSSSP] ; Restore stack 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman movzx esp,sp ; Make sure the high bits are zero 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ds,dx ; Set up sane segments 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov es,dx 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov fs,dx 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov gs,dx 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp bx ; Go to whereever we need to go... 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .data16 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman alignz 4 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman extern __stack_end 17976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPMESP dd __stack_end ; Protected-mode ESP 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPM_IDT_ptr: dw 8*256-1 ; Length 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dd IDT ; Offset 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; This is invoked on getting an interrupt in protected mode. At 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; this point, we need to context-switch to real mode and invoke 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; the interrupt routine. 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; When this gets invoked, the registers are saved on the stack and 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; AL contains the register number. 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 32 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .textnr 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanpm_irq: 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pushad 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman movzx esi,byte [esp+8*4] ; Interrupt number 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inc dword [CallbackCtr] 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ebx,.rm 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp enter_rm ; Go to real mode 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 16 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.rm: 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pushf ; Flags on stack 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call far [cs:esi*4] ; Call IVT entry 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ebx,.pm 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp enter_pm ; Go back to PM 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 32 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .textnr 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.pm: 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dec dword [CallbackCtr] 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz .skip 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call [core_pm_hook] 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.skip: 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman popad 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman add esp,4 ; Drop interrupt number 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iretd 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Initially, the core_pm_hook does nothing; it is available for the 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; threaded derivatives to run the scheduler, or examine the result from 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; interrupt routines. 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman global core_pm_null_hook 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmancore_pm_null_hook: 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .data16 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman alignz 4 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman global core_pm_hook 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmancore_pm_hook: dd core_pm_null_hook 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bits 16 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Routines to enable and disable (yuck) A20. These routines are gathered 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; from tips from a couple of sources, including the Linux kernel and 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; http://www.x86.org/. The need for the delay to be as large as given here 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; is indicated by Donnie Barnes of RedHat, the problematic system being an 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; IBM ThinkPad 760EL. 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .data16 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman alignz 2 24676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanA20Ptr dw a20_dunno 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .bss16 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman alignb 4 25076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanA20Test resd 1 ; Counter for testing A20 status 25176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanA20Tries resb 1 ; Times until giving up on A20 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenable_a20: 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pushad 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov byte [cs:A20Tries],255 ; Times to try to make this work 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantry_enable_a20: 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; First, see if we are on a system with no A20 gate, or the A20 gate 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; is already enabled for us... 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_none: 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call a20_test 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz a20_done 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; Otherwise, see if we had something memorized... 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp word [cs:A20Ptr] 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Next, try the BIOS (INT 15h AX=2401h) 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_dunno: 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_bios: 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov word [cs:A20Ptr], a20_bios 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov ax,2401h 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pushf ; Some BIOSes muck with IF 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int 15h 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman popf 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call a20_test 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz a20_done 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Enable the keyboard controller A20 gate 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_kbc: 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov dl, 1 ; Allow early exit 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call empty_8042 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz a20_done ; A20 live, no need to use KBC 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov word [cs:A20Ptr], a20_kbc ; Starting KBC command sequence 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov al,0D1h ; Write output port 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman out 064h, al 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call empty_8042_uncond 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov al,0DFh ; A20 on 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman out 060h, al 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call empty_8042_uncond 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; Apparently the UHCI spec assumes that A20 toggle 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; ends with a null command (assumed to be for sychronization?) 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; Put it here to see if it helps anything... 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov al,0FFh ; Null command 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman out 064h, al 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call empty_8042_uncond 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; Verify that A20 actually is enabled. Do that by 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; observing a word in low memory and the same word in 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; the HMA until they are no longer coherent. Note that 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; we don't do the same check in the disable case, because 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; we don't want to *require* A20 masking (SYSLINUX should 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; work fine without it, if the BIOS does.) 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.kbc_wait: push cx 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor cx,cx 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.kbc_wait_loop: 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call a20_test 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz a20_done_pop 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loop .kbc_wait_loop 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop cx 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Running out of options here. Final attempt: enable the "fast A20 gate" 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_fast: 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov word [cs:A20Ptr], a20_fast 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman in al, 092h 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman or al,02h 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman and al,~01h ; Don't accidentally reset the machine! 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman out 092h, al 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.fast_wait: push cx 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor cx,cx 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.fast_wait_loop: 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call a20_test 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz a20_done_pop 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loop .fast_wait_loop 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop cx 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; and report failure to the user. 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dec byte [cs:A20Tries] 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz a20_dunno ; Did we get the wrong type? 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov si, err_a20 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pm_call pm_writestr 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp kaboom 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .data16 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; A20 unmasked, proceed... 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_done_pop: pop cx 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_done: popad 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; This routine tests if A20 is enabled (ZF = 0). This routine 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; must not destroy any register contents. 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; The no-write early out avoids the io_delay in the (presumably common) 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; case of A20 already enabled (e.g. from a previous call.) 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmana20_test: 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push es 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push cx 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push eax 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov cx,0FFFFh ; HMA = segment 0FFFFh 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov es,cx 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov eax,[cs:A20Test] 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov cx,32 ; Loop count 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp .test ; First iteration = early out 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.wait: add eax,0x430aea41 ; A large prime number 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov [cs:A20Test],eax 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman io_delay ; Serialize, and fix delay 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.test: cmp eax,[es:A20Test+10h] 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loopz .wait 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.done: pop eax 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop cx 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop es 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; Routine to empty the 8042 KBC controller. If dl != 0 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; then we will test A20 in the loop and exit if A20 is 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; suddenly enabled. 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanempty_8042_uncond: 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor dl,dl 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanempty_8042: 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman call a20_test 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jz .a20_on 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman and dl,dl 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz .done 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.a20_on: io_delay 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman in al, 064h ; Status port 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman test al,1 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jz .no_output 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman io_delay 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman in al, 060h ; Read input 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jmp short empty_8042 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.no_output: 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman test al,2 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman jnz empty_8042 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman io_delay 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.done: ret 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; This initializes the protected-mode interrupt thunk set 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman; 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanpm_init: 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xor edi,edi 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov bx,IDT 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov di,IRQStubs 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov eax,7aeb006ah ; push byte .. jmp short .. 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov cx,8 ; 8 groups of 32 IRQs 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.gloop: 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman push cx 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov cx,32 ; 32 entries per group 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman.eloop: 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov [bx],di ; IDT offset [15:0] 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov word [bx+2],PM_CS32 ; IDT segment 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov dword [bx+4],08e00h ; IDT offset [31:16], 32-bit interrupt 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; gate, CPL 0 (we don't have a TSS 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; set up...) 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman add bx,8 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stosd 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; Increment IRQ, decrement jmp short offset 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman add eax,(-4 << 24)+(1 << 8) 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loop .eloop 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; At the end of each group, replace the EBxx with 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; the final E9xxxxxxxx 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman add di,3 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov byte [di-5],0E9h ; JMP NEAR 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov edx,pm_irq 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sub edx,edi 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mov [di-4],edx 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman add eax,(0x80 << 24) ; Proper offset for the next one 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pop cx 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loop .gloop 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; pm_init is called before bss clearing, so put these 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ; in .earlybss! 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .earlybss 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman alignb 8 46276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanIDT: resq 256 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman global RealModeSSSP 46476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanRealModeSSSP resd 1 ; Real-mode SS:SP 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .gentextnr ; Autogenerated 32-bit code 46776d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanIRQStubs: resb 4*256+3*8 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman section .text16 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman%include "callback.inc" ; Real-mode callbacks 472