%define USBKEY 1 ;much faster than floppy disk & its motor !!! Boot DOS from an USB KEY

;learned : 0f4H INCORRECT, code 0f4h or 0F4h 
;learned : xchg eax,eax is coded as a short NOP (db 90h) by yasm 0.4 
;
;****************************************************************************
;
;AMDO64 by valy, 2004-2005. Alpha version
;For AMD64 machines (Opteron OK... Athlon 64 : any feedback welcome
;
;DOS->RM16->PM16->PM64 long mode AND Idt64 OK->PM16->RM16->DOS
;1 GB RAM available through paging (easily extensible)
;
;note Win9x does NOT appreciate a "DOS reboot" : u should start only from DOS
;compile with yasm 0.4 : yasm mypgm.asm -fbin -omypgm.com
;launch this demo with a previous "mode con lines=50" to have a real screen,
;can u live with only 25 lines ?
;
;This source code is FRIENDWARE :
;if u want to use it, mention my name
;if u find some bugs, if SMP is easy to implement, please tell me
;
;****************************************************************************
;
;What's new ? kbd bug solved : actually OsKbdHandlerDummy must at least
;             make an "in al,60h" else pressing ESC several times may bug
;
;nasm/yasm cannot compile lea rcx,[rcx-something] and error msg is ambiguous :
;code this instead : lea rcx,[dword rcx-something] !!!
;if I make an assembler, the default will be the shorter command :-P
;
;****************************************************************************


;****************************************************************************
;from Masm32 to YASM
%define SHL <<
%define SHR >>
%define AND &
%define use64 [BITS 64]
%define ptr
%define offset

;****************************************************************************
;asm equates ;simpler, always simpler
%define b byte
%define w word
%define d dword
%define f fword
%define q qword
%define t tword

%define rb resb
%define rw resw
%define rd resd
%define rq resq

;****************************************************************************
;tiny constant equates
EOI equ 0x20
SP16 equ 0fff0h

;****************************************************************************
;OS constant equates
_OsDbgLine equ 0
_OsDbgCol  equ 0

_OsIsrErrB equ 00000000000000100111110100000000b

_OsKbd8259M equ 0x20
_OsKbd8259S equ 0xA0
_OsKbdPortA equ 0x60

_OsKbdF0  equ   1
_OsKbdE0  equ   2
_OsKbdE1  equ   4
_OsKbdEat equ 080h
_OsKbdAck	EQU	0fah

KBD_8042_PORT_STATUS		EQU	64h
KBD_8042_PORT_CMD		EQU	64h
KBD_8042_PORT_DATA		EQU	60h

;---------------------------
; Status register bits
;---------------------------
KBD_8042_STATUS_PERR	EQU	1 SHL 7	;PARITY Error in keyboard data
KBD_8042_STATUS_TO	EQU	1 SHL 6	;Timeout for Rx or Tx
KBD_8042_STATUS_MOBF	EQU	1 SHL 5	;Mouse Output Buffer Full
KBD_8042_STATUS_INH	EQU	1 SHL 4	;Keyboard communication INHIBITED
KBD_8042_STATUS_A2	EQU	1 SHL 3	;Port last written: 0=60h , 1=64h
KBD_8042_STATUS_SYS	EQU	1 SHL 2	;Sys reset type: 0=cold, 1=warm
KBD_8042_STATUS_IBF	EQU	1 SHL 1	;Input Buffer full 	CPU  -> 8042
KBD_8042_STATUS_OBF	EQU	1 SHL 0	;Output Buffer Full 	8042 -> CPU

;-----------------------------
; 8042 Commands
;-----------------------------
KBD_8042_CMD_MOUSE_WRITE EQU 0D4h
KBD_8042_CMD_MOUSE_AUX_ENABLE	EQU	0A8h
KBD_8042_CMD_MOUSE_ENABLE EQU 0F4h


;****************************************************************************
;code equates
%define JMP0 db 0ebh,0

;****************************************************************************
;OS code equates
%define _OsKbdDelay db 90h,0ebh,0,0ebh,0


;OS structure
%define _OsCr3  90000h
%define _OsPage 0
%define _OsPagePml4 _OsPage
%define _OsPagePdpe _OsPage + 4096
%define _OsPagePde  _OsPage + 4096*2
%define _OsPagePte  _OsPage + 4096*3


%define _OsTaskMax        4 ;make it even, for speed
%define _OsStackSize   4096
%define _OsRegStackShl    9
%define _OsRegStackSize 512
;%define _OsTaskSCREEN         82100h ;output demo
;%define _OsTaskCUR            82110h
;%define _OsTaskNEXT           82118h
;%define _OsTaskTOT            82120h
;%define _OsTaskUNUSED         82128h
;
;;trying xtask
;%define _OsTASK1               82130h
;%define _OsTASK1.RIP           82138h
;%define _OsTASK1.RSP           82140h
;
;%define _OsTaskMODE.CALLDEBUG 82148h
;%define _OsTaskMODE.CALLMULTI 82150h
;%define _OsTaskMODE.CALLMONO  82158h
;
;%define _OsTaskMODE.DEBUG     -1
;%define _OsTaskMODE.MULTI      0
;%define _OsTaskMODE.MONO       1
;%define _OsTaskCURMODE        _OsTaskMODE.DEBUG
;%define _OsSTACK.PROT           64
;;...
;
;%define _OsTaskTSTACK         82200h
;%define _OsTaskTSTACKZ        _OsTaskTSTACK+_OsTaskMAX*_OsSTACK.SIZE
;%define _OsTaskTREGSTACK      _OsTaskTSTACKZ
;%define _OsTaskTREGSTACKZ     _OsTaskTREGSTACK+_OsTaskMAX*_OsREGSTACK.SIZE
;%define _OsTaskRIP            _OsTaskTREGSTACKZ ;align 16 compulsory
;%define _OsTaskRSP            _OsTaskRIP+ 8*_OsTaskMAX
;%define _OsTaskRFLAGS         _OsTaskRIP+16*_OsTaskMAX
;%define _OsTaskRFLAGSZ        _OsTaskRIP+24*_OsTaskMAX

;... KBD

%define _OsKbdBufSize            4096
%define _OsKbdBufMod             _OsKbdBufSize - 1

%define _OsStack 5FFF0h
%define O 60000h ;? bugs with 80000h

;****************************************************************************
struc OS
  .KbdBuf: rd _OsKbdBufSize
  .KbdTiming: rd _OsKbdBufSize

  .KbdBufPtr: rd 1
  .KbdOldTickN: rd 1
  .KbdCurTickN: rd 1
  .KbdTimerTickN: rd 1
  .KbdCursor: rd 1
  .KbdCode9: rd 1

  .KbdLedStatus: rb 1
  .KbdCurPressed: rb 1
  .KbdOldSet: rb 1
  .KbdCcb: rb 1
  .KbdCcbNew: rb 1
  .KbdF0: rb 1
  .KbdDummy: rb 1
  .KbdCursorColor: rb 1

  .Scr: rq 2

  .Cs16: rq 1
  .Sp16: rq 1

endstruc


;macros
use64
%macro MTimSecond 0
  mov ecx,040000000h ;for my 1.4 MHz CPU :-/
align 4
%%1:  
  dec ecx
  jnz %%1
%endmacro

;%macro MGprPusha 0
;  call OsGprPusha
;  ;sub rsp,16*8+8  
;%endmacro

;%macro MGprPopa 0
;  call OsGprPopa
;  add rsp,16*8+8  
;%endmacro

%macro _MMmxPush 1
  sub rsp,8
  movq q[rsp],%1
%endmacro

%macro _MMmxPop 1
  movq %1,q[rsp]
  add rsp,8
%endmacro

%macro _MXmmPush 1
  sub rsp,16
  movups [rsp],%1
%endmacro

%macro _MXmmPop 1
  movups %1,[rsp]
  add rsp,16
%endmacro

%macro MMmxPusha 0
  _MMmxPush mm7
  _MMmxPush mm6
  _MMmxPush mm5
  _MMmxPush mm4
  _MMmxPush mm3
  _MMmxPush mm2
  _MMmxPush mm1
  _MMmxPush mm0
%endmacro

%macro MMmxPopa 0
  _MMmxPop mm0
  _MMmxPop mm1
  _MMmxPop mm2
  _MMmxPop mm3
  _MMmxPop mm4
  _MMmxPop mm5
  _MMmxPop mm6
  _MMmxPop mm7
%endmacro

%macro MXmmPusha 0
  _MXmmPush xmm7
  _MXmmPush xmm6
  _MXmmPush xmm5
  _MXmmPush xmm4
  _MXmmPush xmm3
  _MXmmPush xmm2
  _MXmmPush xmm1
  _MXmmPush xmm0
%endmacro

%macro MXmmPopa 0
  _MXmmPop xmm0
  _MXmmPop xmm1
  _MXmmPop xmm2
  _MXmmPop xmm3
  _MXmmPop xmm4
  _MXmmPop xmm5
  _MXmmPop xmm6
  _MXmmPop xmm7
%endmacro

%macro MyDbg 3
  mov rax,%1
  mov edi,0b8000h + (160 * %2) + (2 * %3)
  ;no chk then   mov edx,160 * %2 + 2 * %3
  ;mov edx,%2+256*%3
  call printR
%endmacro

%macro MyDbgR 3
  mov rax,%1
  mov edi,0b8000h+160*(_OsDbgLine+%2) +2*(_OsDbgCol+%3) ;
  call printR
%endmacro

%macro MyDbgN 4
  mov rax,%1
  mov ecx,%4
  mov edi,0b8000h+160*(_OsDbgLine+%2) +2*(_OsDbgCol+%3) ;
  call printN
%endmacro

%macro MyDbgM 4
  movd rax,%1
  mov ecx,%4
  mov edi,0b8000h+160*(_OsDbgLine+%2) +2*(_OsDbgCol+%3) ;
  call printN
%endmacro

%macro MKbdCmdWait 0
%%1:
  in	al,64h
	test al,KBD_8042_STATUS_IBF
  jnz %%1
%endmacro

%macro MKbdCmdSend 1
	mov	al,%1	
	out	_OsKbdPortA,al ;send cmd
%endmacro

%macro MKbdDataWait 0
%%1:
  in al,64h
	test al,KBD_8042_STATUS_OBF
  jz %%1
%endmacro

;****************************************************************************
;****************************************************************************
;****************************************************************************

use16
[org 100h]
;************
section .text
;************

mainRM16:
  ;jmp .1
.numlockOFF:
  mov ax,040h
  mov es,ax
  btr w[es:17h],5 
  jnc .numlockOFFz
  ;btr es:w[97],1
  mov al,45h
  out 60h,al ;write "Numlock" to kbd 
  btr w[es:97h],1 
  MKbdCmdWait
  MKbdCmdSend 0edh
  MKbdDataWait
  MKbdCmdWait
  MKbdCmdSend 0
                 
.numlockOFFz:
  ;wait for the FDD motor to stop
  xor ecx,ecx
%ifdef USBKEY
  mov ecx,070000000h
%endif
  
.1:
  inc ecx
  jns .1
  cli

;DISABLE NMI to enter 64-bit mode later

  ;/* save IRQ masks */
  in al,_OsKbd8259M+1
  mov byte [OldIrqMask],al
  in al,_OsKbd8259S+1
  mov byte [OldIrqMask+1],al

  ;/* setup PIC to redirect external interrupts to range 32-47 */
  mov bl,0x20
  mov bh,0x28
  call PicSetup

  ;/* set new IRQ masks */
  mov al,0xfc ;1st bit is for timer, 2nd for keyboard (master)
  out _OsKbd8259M+1,al
  mov al,0xff
  out _OsKbd8259S+1,al                   ;/* disable all (slave) */


  push word 2
  popf
  mov ax,fs
  mov [FsSaved],ax
  mov ax,gs
  mov [GsSaved],ax
  xor ax,ax
  mov fs,ax
  mov gs,ax
  
  movd mm6,esp
  mov esp,SP16
  
  xor ebx,ebx
  mov bx,cs
  shl ebx,4 ;ebx is our CS relocation
  movd mm7,ebx
  
  add [pGDT32+2],ebx
  add [pIdt64+2],ebx
  add [jmp_64+2],ebx
  add [jmp64_16+3],ebx
  add [BootCode16+2],ebx
  add [BootData16+2],ebx
  add [IdtPatch+4],ebx
  add [IdtPatch2+4],ebx
  add [BootVideo16+2],d 0b8000h
  
  ;build Idt64
  pxor mm0,mm0
  mov ecx,63*16
  mov edx,int6463
  add edx,ebx

.idtentry:
  mov eax,edx
  shr eax,16
  mov w[Idt64+0+ecx],dx
  mov w[Idt64+2+ecx],(BootCode64-Gdt)
  mov w[Idt64+4+ecx],08E00h ;1000111000000000b
  mov w[Idt64+6+ecx],ax
  movq [Idt64+8+ecx],mm0
  sub edx,64 ;sizeof(int64xx)
  sub ecx,16 ;sizeof(idt_entry)
  jns .idtentry


;enable A20 gate
  call  A20Enable

  mov ax,0b800h
  mov es,ax
  call OsPageInit

  lgdt [pGDT32]

;Enable protected mode (CR0.PE=1).
  mov eax,cr0
  or al,1
  mov cr0,eax

;
;Execute a far jump to turn protected mode on.
;code16_sel must point to the previously-established 16-bit
;code descriptor located in the GDT (for the code currently
;being executed).
;
  db 0eah ;Far jump...
  dw PMnow
  dw BootCode16-Gdt ;in current code segment.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;At this point we are in 16-bit protected mode,but long
;mode is still disabled.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PMnow:

;
;Set up the protected-mode stack pointer,SS:ESP.
;Stack_sel must point to the previously-established stack
;descriptor (read/write data segment),located in the GDT.
;

  mov ax,BootData16-Gdt
  mov ds,ax
  mov ss,ax

  mov ax,BootVideo16-Gdt
  mov es,ax
  mov esp,SP16 ;normally esp==SP16 before that

  mov [es:160*6+150],d 'P M '
  mov [es:160*6+154],d '1 6 '
  
  xor eax,eax
  mov cr2,eax

;
;Enable the 64-bit page-translation-table entries by
;setting CR4.PAE=1 (this is _required_before activating
;long mode).Paging is not enabled until after long mode
;is enabled.
;
  mov eax,cr4
  bts eax,5 ;PAE
  bts eax,8 ;PCE, Perf Counters
  bts eax,9 ;OSFXSR, Save/Restore of x87/64/128-bit states, enabling XMM too
  mov cr4,eax

;
;Create the long-mode page tables,and initialize the
;64-bit CR3 (page-table base address)to point to the base
;of the Pml4 page table.The Pml4 page table must be located
;below 4 Gbytes because only 32 bits of CR3 are loaded when
;the processor is not in 64-bit mode.
;

  mov eax,_OsCr3 ;+_OsPagePml4 ;Pointer to Pml4 table (<4GB).
  mov cr3,eax ;Initialize CR3 with Pml4 base.

;
;Enable long mode (set EFER.LME=1).
;
  mov ecx,0c0000080h ;EFER MSR number.
  rdmsr ;Read EFER.
  bts eax,8 ;Set LME=1.
  wrmsr ;Write EFER.

;
;Enable paging to activate long mode (set CR0.PG=1)
;
  mov eax,cr0 ;Read CR0.
  bts eax,31 ;Set PE=1.
  mov cr0,eax ;Write CR0.
  JMP0

;
;At this point,we are in 16-bit compatibility mode
;(LMA=1,CS.L=0,CS.D=0 ).
;Now,jump to the 64-bit code segment.The offset must be
;equal to the linear address of the 64-bit entry point,
;because 64-bit code is in an unsegmented address space.
;The selector points to the 32/64-bit code selector in the
;current GDT.
;

  mov edx,2000000
  mov ebx,0b8000h + 160*15 + 10
  and esp,0fff0h

jmp_64:
  db 066h
  db 0eah
  dd main64
  dw BootCode64-Gdt ;do NOT bother ds,es,ss : cs descriptor is enough
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;
;;;Start of 64-bit code
;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

align 8
use64
main64:;At this point,we're using 64-bit code

  mov rsp,_OsStack
  JMP0

  mov eax,O+OS.Sp16 ;not to place just after entering 64-bit mode (else bugs)
  movd rbx,mm6
  mov [rax],rbx
  
  mov eax,O+OS.Cs16
  movd rbx,mm7
  mov [rax],rbx
  
  movd ebx,mm7
  add ebx,pIdt64
IdtPatch:
  lidt [pIdt64] ;yasm : DB 0fh,1,1ch,25h,dword
  JMP0
  
  mov b[O+OS.KbdCode9],0
  mov eax,09DB09DBh ;07000700h normally
  mov [O+OS.Scr],eax
  mov [O+OS.Scr+4],eax
  mov [O+OS.Scr+8],eax
  mov [O+OS.Scr+12],eax
  
  xor eax,eax
;  ;beginning of a dark buggy tunnel : benign interrupts rush, timer masking
;  ;is inefficient :-( ???  OH, THAT COULD BE MY FLOPPY DISK MOTOR
;  sti
;  mov al,al
;  sti
;  mov b[0b8000h+160*49+0],'!'
;  sti
;  mov eax,eax
;  int 21h
;  int 21h
;  int 21h
;  int 21h
;  int 21h
;  sti
;  nop
;  nop
;  nop
;  mov al,al
;  cli
  ;end of dark tunnel : Idt64 should work now

  call OsScrClr
  sti
  mov ebx,0b8000h+160*7 + 152
  mov rax,'P M 6 4 '
  mov [rbx],rax
  mov rax, "I D T ! "
  mov [rbx+160],rax

  ;test it ; try divide by 0 too : it brings u back to DOS
  int 22h
  
  mov d[O+OS.KbdTimerTickN],0 ;begin OsTimer routines
  call OsKbdInit ;begin OsKbd routines

;	call KbdRateInit
;	add al,6+48 ;ACK=>'0'
;  mov dl,al
  
;  mov b[OsKbdLedStatus],0
;  call KbdLedWrite
;	add al,6+48 ;ACK=>'0'
;  mov dl,al

  cli

  ;kbd: go further
	xor ebx,ebx
	call KbdScancodeGet
  mov b[O+OS.KbdOldSet],al

  mov al,20h
  out 64h,al ;both these lines mean : read CCB
  MKbdDataWait
  in al,60h
  mov b[O+OS.KbdCcb],al

  call KbdXlatNo
  
  call OsScrInit

;testing my dbg/pusha/popa routines
  ;YASM 0.4 does NOT recognize them :-(
  ;movq mm8,mm8
  ;movd mm9,rsp
  ;movd mm10,rsp
  ;pxor mm8,mm0
  movq2dq xmm8,mm0
  movq2dq xmm9,mm0
  movq2dq xmm10,mm0
  pcmpeqd xmm11,xmm11

  pcmpeqd mm0,mm0
  pxor mm1,mm1
  punpcklbw mm1,mm0

  pcmpeqd xmm0,xmm0
  pxor xmm1,xmm1
  punpcklbw xmm1,xmm0
  movq xmm7,xmm0
  punpcklwd xmm7,xmm1

  ;Privalov, test 1a => RAX=-1
  xor rax,rax  
  lea rax,[0ffffffffh]
  call OsDbg
  mov bl,76h
  call OsKbdCharGet

  ;Privalov, test 1b => RAX=00000000FFFFFFFFh
  xor rax,rax  
  db 67h
  lea rax,[0ffffffffh]
  call OsDbg
  mov bl,76h
  call OsKbdCharGet

  ;Privalov, test 1c => RAX=00000000FFFFFFFFh
  db 48h,67h,8dh,04h,25h,0ffh,0ffh,0ffh,0ffh
  call OsDbg
  mov bl,76h
  call OsKbdCharGet


  ;Privalov, test 2a => RAX=-1 : NOP is KEPT
  mov rax,-1
  db 90h
  call OsDbg
  mov bl,76h
  call OsKbdCharGet

  ;Privalov, test 2b 
  mov rax,-1
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  xchg eax,eax ;RAX=-1 =>ya NOP : yasm 0.4 codes it as "DB 90h"
  mov rbp,0fedcba9876543210h
  xchg ebp,ebp ;RBP=76543210h
  call OsDbg
  mov bl,76h
  call OsKbdCharGet

  ;Privalov, test 2c => XCHG EAX,R8D OK (zeroes the 32 upper bits as expected too)
  mov rax,0fedcba9876543210h
  mov r8 ,00101010101010101h
  db 41h,90h
  call OsDbg
  mov bl,76h
  call OsKbdCharGet


  call OsDbg
  mov bl,76h
  call OsKbdCharGet

  call OsDbg
  mov bl,76h
  call OsKbdCharGet

  call OsScrInit


  sti
  
  mov b[O+OS.KbdCode9],0
.wait_esc:
  cmp b[O+OS.KbdCode9],76h ;81h ;5ah ;40h;81h ;9Ch
  jne .wait_esc
.wait_escz:

  cli
  mov ecx,16
  call OsScrHighlight
;  movzx ebx,b[OsKbdOldSet]
;	call KbdScancodeSet

 ;kill timer/kbd interrupt
  call KbdFlush

  ;kbd: go further
;	mov bl,2
;	call KbdScancodeSet
  call KbdXlatYes
  call KbdReset  
    
  cli
  mov ebx,[O+OS.Cs16]
  mov edx,ebx
  add edx,OsTimerHandlerDummy
  mov eax,edx
  shr eax,16
  mov w[ebx+Idt64+0+(32*16)],dx
  mov w[ebx+Idt64+6+(32*16)],ax
  
  mov ebx,[O+OS.Cs16]
  mov edx,ebx
  add edx,OsKbdHandlerDummy
  mov eax,edx
  shr eax,16
  mov w[ebx+Idt64+0+(33*16)],dx
  mov w[ebx+Idt64+6+(33*16)],ax

  mov ebx,[O+OS.Cs16]
  add ebx,pIdt64
IdtPatch2:
  lidt [pIdt64] ;yasm : DB 0fh,1,1ch,25h,dword
  JMP0
  sti

 ;test dummy isr functions with the patched IDT64
  mov edx,1000000000
.wait:
  dec edx
  jnz .wait

  ;call OsKbdDbg
  ;call xmmrip
  cli

gobacktoPM16:
;return to PM16 : jmp far INdirect needed they say (and much coffee too)
;  call KbdXlatYes
  call KbdReset ;improves stability for DOS's comeback, in particular with LSHIFT
  ;call KbdFlush
  in al,60h
  in al,60h
  in al,60h
  in al,60h
  in al,60h
  in al,60h
  in al,60h
  in al,60h
  
  movd mm6,[O+OS.Sp16]
  movd mm7,[O+OS.Cs16]
jmp64_16:
  db 0ffh,2ch,25h
  dd jmpmem

use16
PM64Z:

  mov esp,SP16
  mov ax,BootData16-Gdt ;necessary to successfully go back to RM !!
  mov ds,ax
  mov es,ax
  mov ss,ax
  
  ;disable paging
  mov eax,cr0 ;Read CR0.
  btr eax,31 ;Set PE=0.
  mov cr0,eax ;Write CR0.
  JMP0
  
  ;disable LME
  mov ecx,0c0000080h ;EFER MSR number.
  rdmsr ;Read EFER.
  btr eax,8 ;Set LME=0.
  wrmsr ;Write EFER.
  JMP0
  
  ;leave PM
  mov eax,cr0
  and al,0feh
  mov cr0,eax
  JMP0
  
  movd eax,mm7
  shr eax,4
  push ax
  push word RM16
  retf

RM16:
  mov ds,ax
  mov ss,ax
  mov ax,0b800h
  mov es,ax
  mov [es:160*9+152],d 'E N '
  mov [es:160*9+156],d 'D ! '
  movd esp,mm6

  mov w[pIDT16.limit],03ffh
  mov d[pIDT16.base],0
  mov ax,[FsSaved]
  mov fs,ax
  mov ax,[GsSaved]
  mov gs,ax

  lidt [pIDT16]

;RESTORE NMI
  ;/* setup PIC */
  mov bl,8
  mov bh,0x70
  call PicSetup

  ;/* restore IRQ masks */
  mov al,byte [OldIrqMask]
  out _OsKbd8259M+1,al
  mov al,byte [OldIrqMask+1]
  out _OsKbd8259S+1,al

  sti

theend:
ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
use16

;IN  bl=master vector,bh=slave vector
;OUT
;UPD al
PicSetup:
  mov al,0x11
  out _OsKbd8259M,al             ;/* start 8259 initialization */
  out _OsKbd8259S,al
  mov al,bl ;master_vector      ;/* master base interrupt vector */
  out _OsKbd8259M+1,al
  mov al,bh ;slave_vector       ;/* slave base interrupt vector */
  out _OsKbd8259S+1,al
  mov al,4 ;1<<2                ;/* bitmask for cascade on IRQ2 */
  out _OsKbd8259M+1,al
  mov al,2
  out _OsKbd8259S+1,al           ;/* cascade on IRQ2 */
  mov al,1
  out _OsKbd8259M+1,al           ;/* finish 8259 initialization */
  out _OsKbd8259S+1,al
ret

use16
A20Enable:
	call  A20Enable1
  jnz A20Enablez
	mov al,0d1h
	out 64h,al
	call A20Enable1
  jnz A20Enablez
	mov al,0dfh
	out 60h,al

A20Enable1:
	mov ecx,20000h
A20Enable1l:
  jmp short $+2
	in al,64h
	test al,2
	loopnz A20Enable1l
A20Enablez:
	ret

use16
OsPageInit: ;here, 512*2 MB bytes = 1 GB
  mov ax,ds
  push ax ;!!! NO push cs !!!
  
  mov ax,_OsCr3 SHR 4 ;9000h
  mov ds,ax
  
  xor eax,eax
  mov ecx,2048
  pxor mm0,mm0
  xor esi,esi
.1:
  movq [ds:esi],mm0
  add esi,8
  dec ecx
  jnz .1
  
  ;Pml4/Pdpe/Pde
  mov [ds:_OsPagePml4],d _OsCr3 + _OsPagePdpe+15
  mov [ds:_OsPagePdpe],d _OsCr3 + _OsPagePde +15
  ;PDE
  xor esi,esi
  mov ecx,15+128 ;128==PDE.PS
  mov eax,1 SHL 21 ;2097152
  
.2:
  mov [ds:_OsPagePde+esi],ecx
  add ecx,eax
  add esi,8
  cmp esi,8*512 ;we paginate 512*2 MB bytes
  jne .2
  
  pop ax
  mov ds,ax
ret

;****************************************************************************
;****************************************************************************
use64
printR8:

  mov bl,al
  shr bl,4
  cmp bl,10
  jl .1
  add bl,7
.1:
  add bl,48
  mov b[rdi],bl
  and al,15
  cmp al,10
  jl .2
  add al,7
.2:
  add al,48
  mov b[b rdi+2],al
  
ret
  
use64
printRX:
  add rdi,b 30
  mov ecx,16
.1:
  movzx ebx,al
  and bl,15
  cmp bl,10
  jl .2
  add bl,7
.2:
  add bl,48
  mov b[rdi],al
  shr rax,4
  sub rdi,b 2
  dec ecx
  jnz .1
  
ret

use64
printR:
  push rcx
  push rdi

  mov cl,8
.1
  mov b[edi],al
  ror rax,8
  add edi,b 2
  dec cl
  jnz .1

  pop rdi
  pop rcx
ret

use64
printS:
  lea rdi,[rdi+rcx*2]
  add rsi,rcx
.1
  mov al,[rsi]
  mov b[rdi],al
  add rdi,b 2
  dec rsi
  dec ecx
  jnz .1

ret
		
use64
printN:
  mov rsi,rdi

  mov rdx,2020202020202020h
  mov [rsi],rdx
  mov [b rsi+8],rdx
  mov [b rsi+16],rdx
  mov [b rsi+24],rdx
  mov [b rsi+32],rdx
  mov [b rsi+40],rdx
  mov [b rsi+48],rdx
  mov [b rsi+56],rdx
  add rsi,b 62
	
  xor rdx,rdx
  mov dl,10
  or ecx,ecx
  cmovz ecx,edx

  xor rbx,rbx
  xor rdx,rdx
  xor rdi,rdi
.1:
  div rcx
  cmp dl,10
  setl bl
  dec ebx
  and ebx,7
  lea edx,[edx+ebx+48] ;add dl,'0'
  mov byte[rsi],dl
  sub rsi,b 2
  add rdi,b 2
  xor dl,dl
  or rax,rax
  jnz .1
  
  lea rax,[b rsi+1] ;output offset
  mov ebx,edi ;len
ret



use64
align 16
OsKbdHandlerDummy:
  in al,60h
  mov al,EOI
  out _OsKbd8259M,al
iretq

align 16
OsTimerHandlerDummy:
  inc d[O+OS.KbdTimerTickN]
  mov al,EOI
  out _OsKbd8259M,al
iretq

use64
align 16
OsKbdHandle:

.ok:
  in al,_OsKbdPortA
  mov [O+OS.KbdCode9],al

  mov ecx,[O+OS.KbdBufPtr]
  mov edx,[O+OS.KbdTimerTickN]
  mov b[O+OS.KbdBuf+ecx],al
  
  mov eax,edx
  mov ebx,255
  sub eax,[O+OS.KbdCurTickN]
  cmp eax,256
  cmovge eax,ebx
  mov b[O+OS.KbdTiming+ecx],al
  
  mov eax,d[O+OS.KbdCurTickN]
  mov d[O+OS.KbdOldTickN],eax
  mov d[O+OS.KbdCurTickN],edx
  
  inc ecx
  and ecx,_OsKbdBufMod
  mov d[O+OS.KbdBufPtr],ecx
  
  ;call OsKbdActionCurTaskPtr
ret

;IN
;OUT
;UPD ax,di
use64
align 16
TimerHandler:
  mov edi,0b8000h+160*49+79*2
  mov al,[edi]
  inc al
  mov byte [edi],al
  
  inc d[O+OS.KbdTimerTickN]
  ;mov al,EOI
  ;out _OsKbd8259M,al
ret

use64
align 4
OsScrClr:
  mov edi,0b8000h
  movaps xmm0,[O+OS.Scr]
.1:
  movaps [edi],xmm0
  add edi,16
  cmp edi,0b8000h+50*160
  jl .1
ret

use64
%macro myint 1
int64%1:
 
  cli

  mov bl,%1
.reboot:
  call myint.debug
  jmp gobacktoPM16

int64z%1:
  times (64-int64z%1+int64%1) db 0    
%endmacro

use64
%macro myint2 1
int64%1:
 
;;  cli
  push rax
  push rbx
  mov bl,%1
  call int64soft
  
  mov al,EOI
  out _OsKbd8259M,al

  pop rbx
  pop rax
;;  sti
iretq

int64z%1:
  times (64-int64z%1+int64%1) db 0    
%endmacro

align 16
%assign i 0
%rep 32
  myint i
%assign i i+1
%endrep
%assign i 32
%rep 32
  myint2 i
%assign i i+1
%endrep

use64
int64soft:
  push rax
  push rbx
  
.timer:
  cmp bl,20h
  jne .timerz ;short .skip
  call TimerHandler
  ;call myint.debug
  jmp .z
.timerz:

.kbd:
  cmp bl,b 21h
  jne .kbdz ;short .skip
  call OsKbdHandle
.kbdz:

  call KbdHandler0
.skip:
.z:
  pop rbx
  pop rax
ret

use64
KbdHandler0:
  call OsKbdSys ;OsKbdDbg ;OsScrClr
ret

use64
;set 2, NOT xlated
OsKbdSys:

;;;  cli

  mov ecx,d[O+OS.KbdBufPtr]
  sub ecx,1 
  and ecx,_OsKbdBufMod
  mov al,b[O+OS.KbdBuf+ecx]
  cmp al,0f0h
  je .f0
  cmp al,0e0h
  je .e0
  cmp al,0e1h
  je .e1
  cmp al,_OsKbdAck
  je .z
  or al,al
  js .err

  ;handling only keys when released : add both these lines and remove the two after them
  ;;test b[OsKbdF0],_OsKbdF0
  ;;jz .z
  test b[O+OS.KbdF0],_OsKbdF0
  jnz .updateF0
    
  mov ebx,d[O+OS.KbdCursor]
  xor edx,edx
  cmp al,5ah
  je .enter
  cmp al,7dh
  je .pgup
  cmp al,7ah
  je .pgdn
  cmp al,6ch
  je .home
  cmp al,69h
  je .end
  
  cmp al,75h
  je .up
  cmp al,6bh
  je .left
  cmp al,72h
  je .down
  cmp al,74h
  je .right
  cmp al,76h
  je .esc
  jmp .z
  
.enter:
  cmp ebx,0b8000h
  je .pgm0
  cmp ebx,0b8000h+160
  je .pgm1
  cmp ebx,0b8000h+160*2
  jne .z
.pgm2:
  MyDbg " HELLO !",2,16
  MTimSecond
  call OsScrInit
  ;kbd bug if "int 0"
  jmp .z
  
.pgm1:
  call xmmrip
  MTimSecond
  call OsScrInit
  jmp .z

.pgm0:
  call OsKbdDbg
  MTimSecond
  call OsScrInit
  jmp .z
  
  
.pgup:
  mov ecx,16
  call OsScrHighlight
  mov ebx,0b8000h
  xor edx,edx
  jmp .update
    
.pgdn:
  mov ecx,16
  call OsScrHighlight
  mov ebx,0b8000h+160*48
  xor edx,edx
  jmp .update
    
.home:
  mov eax,ebx
  sub eax,0b8000h
  mov ecx,160
  div ecx
  mov ecx,16
  call OsScrHighlight
  sub ebx,edx
  jmp .update

.end:
  mov eax,ebx
  sub eax,0b8000h
  mov ecx,160
  div ecx
  mov ecx,16
  call OsScrHighlight
  sub ebx,edx
  add ebx,128
  jmp .update

.up:
  cmp ebx,0b8000h+160
  jl .z
  mov ecx,16
  call OsScrHighlight
  sub ebx,160
  xor edx,edx
  jmp .update
    
.left:
  mov eax,ebx
  sub eax,0b8000h
  mov ecx,160
  div ecx
  shr edx,5
  jz .updateF0
  mov ecx,16
  call OsScrHighlight
  sub ebx,32
  jmp .update
.down:
  cmp ebx,0b8000h+160*48
  jge .z
  mov ecx,16
  call OsScrHighlight
  add ebx,160
  jmp .update
.right:
  mov eax,ebx
  sub eax,0b8000h
  mov ecx,160
  div ecx
  shr edx,5
  cmp edx,4
  je .updateF0
  mov ecx,16
  call OsScrHighlight
  add ebx,32
  jmp .update

.esc:
  jmp .z
        
.f0:
  or b[O+OS.KbdF0],_OsKbdF0
  jmp .z
.e0:
  or b[O+OS.KbdF0],_OsKbdE0
  jmp .z
.e1:
  or b[O+OS.KbdF0],_OsKbdE1
  jmp .z

.update:
  mov d[O+OS.KbdCursor],ebx
  ;mov eax,ebx
  mov ecx,16
  call OsScrHighlight
.updateF0
  mov b[O+OS.KbdF0],0
      
.z:
ret
.err:
  push rdi
  push rcx
  push rax
  mov edi,0b8000h+160*49
  mov ecx,16
  call printR8
  pop rax
  pop rcx
  pop rdi
;  call OsKbdDbg ;later!!!
ret

;INPUT ecx=len
;DELETED none ;eax,ebx,ecx
OsScrHighlight:
  push rax
  push rbx
  push rcx
  push rdx
  
  mov eax,d[O+OS.KbdCursor]
  xor ebx,ebx
  xor edx,edx
  xor esi,esi
  xor edi,edi
  xor ebp,ebp
  dec ecx
  js .z
  and ecx,8191
  mov bl,[O+OS.KbdCursorColor]  
.1:
  xor b[ecx*2+eax+1],bl
  dec ecx
  jns .1
  
.z:
  pop rdx
  pop rcx
  pop rbx
  pop rax
ret

use64
myint.debug:
 
  MyDbg "EXC #   ",24,70
  
  mov edi,0b8000h+160*24+78*2
  mov al,bl
  and al,0fh
  shr bl,4
  add al,48
  add bl,48
  mov b[edi],bl
  mov b[edi+2],al
  
  mov rax,cr0
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+0)   +2*_OsDbgCol ;
  call printN
  
  mov rax,cr2
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+1)   +2*_OsDbgCol ;
  call printN
  
  mov rax,cr3
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+2) +2*_OsDbgCol ;
  call printN
  
  mov rax,cr4
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+3) +2*_OsDbgCol ;
  call printN
  
  mov rax,rsp
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+4) +2*_OsDbgCol ;
  call printN
  
  MyDbg "  CR0   ",0,32
  MyDbg "  CR2   ",1,32
  MyDbg "  CR3   ",2,32
  MyDbg "  CR4   ",3,32
  MyDbg "  RSP   ",4,32
  
  MyDbg "00000000",5,0
  MyDbg "00IVVAVR",5,8
  MyDbg "0NIOODIT",5,16
  MyDbg "SZ0A0P1C",5,24
  MyDbg "  RFLAGS",5,32
  
  MyDbg "        ",6,0
  MyDbg "   PFCMF",6,8
  MyDbg " TPL    ",6,16
  MyDbg "        ",6,24
  
  MyDbg "DOSDEBUG",11,32
  MyDbg "  RIP   ",12,32
  MyDbg "   CS   ",13,32
  MyDbg " EFLAGS ",14,32
  MyDbg " @RSP   ",15,32
  MyDbg "   SS   ",16,32
  
  MyDbg "  CS16  ",18,32
  MyDbg "   CS   ",19,32
  MyDbg "   DS   ",20,32
  MyDbg "   ES   ",21,32
  MyDbg "   FS   ",22,32
  MyDbg "   GS   ",23,32
  MyDbg "   SS   ",24,32
  
  pushfq
  mov rax,[rsp]
  mov ecx,2
  mov edi,0b8000h+160*(_OsDbgLine+7) +2*_OsDbgCol ;
  call printN
  popfq
  
  mov rax,rsp
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+9)+2*_OsDbgCol
  call printN
  
  mov rax,[rsp+8]
  sub rax,[O+OS.Cs16]
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+11)+2*_OsDbgCol
  call printN
  
  mov rax,[rsp+8]
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+12)+2*_OsDbgCol
  call printN
  
  mov rax,[rsp+16]
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+13)+2*_OsDbgCol
  call printN
  
  mov rax,[rsp+24]
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+14)+2*_OsDbgCol
  call printN
  
  mov rax,[rsp+32]
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+15)+2*_OsDbgCol
  call printN
  
  mov rax,[rsp+40]
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+16)+2*_OsDbgCol
  call printN
  
  movd rax,mm7
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+18)+2*_OsDbgCol
  call printN
  
  mov eax,cs
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+19)+2*_OsDbgCol
  call printN
  
  mov eax,ds
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+20)+2*_OsDbgCol
  call printN
  
  mov eax,es
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+21)+2*_OsDbgCol
  call printN
  
  mov eax,fs
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+22)+2*_OsDbgCol
  call printN
  
  mov eax,gs
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+23)+2*_OsDbgCol
  call printN
  
  mov eax,ss
  mov ecx,16
  mov edi,0b8000h+160*(_OsDbgLine+24)+2*_OsDbgCol
  call printN
  
  mov al,b[0b8000h+160*49+0]
  inc al
  mov b[0b8000h+160*49+0],al

ret


;%include "kbd8042.asm"
;kbd controller 8042/8048
use64


OsKbdInit:
  mov d[O+OS.KbdBufPtr],0
  mov eax,d[O+OS.KbdTimerTickN]
  mov d[O+OS.KbdOldTickN],eax
  mov b[O+OS.KbdF0],0
  mov d[O+OS.KbdCursor],0b8000h
  mov b[O+OS.KbdCursorColor],1
  mov d[O+OS.KbdBuf],0fafafafah
  mov d[O+OS.KbdBuf+_OsKbdBufMod-3],0fafafafah
ret

OsKbdDbg:
  call OsScrClr
  mov edi,0b8000h+16
  mov ecx,d[O+OS.KbdBufPtr]
  cmp ecx,50
  jl .1
  mov ecx,50
.1:
  dec ecx
  js .z
  imul ebx,ecx,160
  add edi,ebx

.2:
  movzx rax,b[O+OS.KbdBuf+ecx]
  call printR8
  add edi,32
  movzx rax,b[O+OS.KbdTiming+ecx]
  call printR8
  sub edi,32

  sub edi,160
  dec ecx
  jns .2
.z:
ret

KbdCmdWait:
	MKbdCmdWait
ret

KbdDataWait:
	MKbdDataWait
ret

;send 0xF0 (Set Scan Code Set) 
;kbd responds with ACK
;send set : 1, 2, 3 (or 0 to know the current set)
;kbd responds with ACK again...
; ...followed by a 2nd byte YOU MUST WAIT : the current scan code set if the given set is 0 
;INPUT ebx = scancode set
;OUTPUT al = ACK normally !!!
KbdScancodeSet:
.1:
	MKbdCmdWait
  MKbdCmdSend 0f0h
.2:  
  MKbdDataWait
  in al,60h
  cmp al,0feh
  je .1
  cmp al,_OsKbdAck
  jne .2
       
.3:
  MKbdCmdWait
  MKbdCmdSend bl
  MKbdCmdWait
  MKbdDataWait
  in al,60h ;ACK normally
  ;;;in al,20h  ;;;try!!! Cf KBD.PDF
  cmp al,0feh
  je .3
	ret

;OUTPUT al = current scancode set
KbdScancodeGet:
	xor ebx,ebx
	call KbdScancodeSet
.1:
	MKbdDataWait
  in al,60h
  cmp al,_OsKbdAck
  je .1
	;if different from 1, 2 or 3... worry !!! under win9x DOS, I get 41h !!!??? OK : set Xlated !
ret


;INPUT bl ;bit7=0, bits5-6: 00 = 250 ms... 11 = 1000 ms ; bits0-4: 00 = 30 cps, 1Fh = 2 cps
KbdRateInit:
	MKbdCmdWait
  MKbdCmdSend 0f3h
  MKbdDataWait
  in al,60h
     
  MKbdCmdWait
  MKbdCmdSend bl
  MKbdDataWait
  in al,60h
ret

;INPUT b[OsKbdLedStatus]
;OUTPUT guess
KbdLedWrite:
  MKbdCmdWait
  MKbdCmdSend 0edh
  MKbdDataWait
  MKbdCmdWait
  MKbdCmdSend b[O+OS.KbdLedStatus]
ret

KbdFlush:
.read:
  in al,64h
  test al,1 ;sthg to read ?
  jz .readz
  ;_OsKbdDelay
	in al,60h		;yes, read it
  _OsKbdDelay
  jmp .read

.readz:
  test al,2 ;sthg to write ? if yes, wait for ACK
  jnz .read
ret

;INPUT -
;OUTPUT -
KbdReset:
  call KbdFlush
.1:
  MKbdCmdWait
  MKbdCmdSend 0f6h ;0ffh ?! ;0f6h works fine ;put 0f5h and wait... wait... forever
  MKbdDataWait
  in al,60h
  cmp al,0feh
  je .1
ret

;INPUT -
;OUTPUT -
KbdXlatNo:
  call KbdFlush
  mov al,60h ;both these lines mean : write to CCB
  out 64h,al ;both these lines mean : write to CCB
  MKbdCmdWait ;write what follows to CCB
  MKbdCmdSend 21h ;xlation OFF,mouse off,irq12_mouse off,irq1_kbd on

  MKbdCmdWait
  MKbdCmdSend 0f0h
  MKbdCmdWait
  MKbdCmdSend 2; 3 ;set 3
  MKbdCmdWait
ret

KbdXlatYes:
;  MKbdCmdWait
;  MKbdCmdSend 0f0h
;  MKbdCmdWait
;  MKbdCmdSend 2 ;set 2

  call KbdFlush
  mov al,60h ;both these lines mean : write to CCB
  out 64h,al ;both these lines mean : write to CCB
  MKbdCmdWait ;write what follows to CCB
  MKbdCmdSend b[O+OS.KbdCcb] ;comeback to DOS
ret

OsGprPusha: ;emulate PUSHA
  push rax
  push rcx
  push rdx
  push rbx
  push rsp ;rcx
  push rbp
  push rsi
  push rdi
  push r8
  push r9
  push r10
  push r11
  push r12
  push r13
  push r14
  push r15
  ;sub rsp,128 only if not using push method
jmp q[rsp+128]

use64
OsGprPopa:
  mov r15,[rsp+8]
  mov r14,[rsp+16]
  mov r13,[rsp+24]
  mov r12,[rsp+32]
  mov r11,[rsp+40]
  mov r10,[rsp+48]
  mov r9, [rsp+56]
  mov r8, [rsp+64]
  mov rdi,[rsp+72]
  mov rsi,[rsp+80]
  mov rbp,[rsp+88]
  ;mov rsp,[rsp+96]
  mov rbx,[rsp+104]
  mov rdx,[rsp+112]
  mov rcx,[rsp+120]
  mov rax,[rsp+128]
  add rsp,128+8+8
jmp q[rsp-128-8-8]

OsMmxPusha:
  movq [rsp-8],mm0
  movq [rsp-16],mm1
  movq [rsp-24],mm2
  movq [rsp-32],mm3
  movq [rsp-40],mm4
  movq [rsp-48],mm5
  movq [rsp-56],mm6
  movq [rsp-64],mm7
  sub rsp,64
jmp q[rsp+64]

OsMmxPopa:
  movq mm7,[rsp+8]
  movq mm6,[rsp+16]
  movq mm5,[rsp+24]
  movq mm4,[rsp+32]
  movq mm3,[rsp+40]
  movq mm2,[rsp+48]
  movq mm1,[rsp+56]
  movq mm0,[rsp+64]
  add rsp,64+8+8
jmp q[rsp-64-8-8]

OsXmmPusha:
  movdqu [rsp-16],xmm0 ;!!! -16 !!!
  movdqu [rsp-32],xmm1
  movdqu [rsp-48],xmm2
  movdqu [rsp-64],xmm3
  movdqu [rsp-80],xmm4
  movdqu [rsp-96],xmm5
  movdqu [rsp-112],xmm6
  movdqu [rsp-128],xmm7
  movdqu [rsp-144],xmm8
  movdqu [rsp-160],xmm9
  movdqu [rsp-176],xmm10
  movdqu [rsp-192],xmm11
  movdqu [rsp-208],xmm12
  movdqu [rsp-224],xmm13
  movdqu [rsp-240],xmm14
  movdqu [rsp-256],xmm15
  sub rsp,256
jmp q[rsp+256]

OsXmmPopa:
  movdqu xmm15,[rsp+16]
  movdqu xmm14,[rsp+32]
  movdqu xmm13,[rsp+48]
  movdqu xmm12,[rsp+64]
  movdqu xmm11,[rsp+80]
  movdqu xmm10,[rsp+96]
  movdqu xmm9,[rsp+112]
  movdqu xmm8,[rsp+128]
  movdqu xmm7,[rsp+144]
  movdqu xmm6,[rsp+160]
  movdqu xmm5,[rsp+176]
  movdqu xmm4,[rsp+192]
  movdqu xmm3,[rsp+208]
  movdqu xmm2,[rsp+224]
  movdqu xmm1,[rsp+240]
  movdqu xmm0,[rsp+256]
  add rsp,256+8+8 ;+8+8 : 1 call for pusha, 1 call for popa
jmp q[rsp-256-8-8]

;OsXmmPusha:
;  movdqu [rsp-16],xmm0 ;!!! -16 !!!
;  movdqu [rsp-32],xmm1
;  movdqu [rsp-48],xmm2
;  movdqu [rsp-64],xmm3
;  movdqu [rsp-80],xmm4
;  movdqu [rsp-96],xmm5
;  movdqu [rsp-112],xmm6
;  movdqu [rsp-128],xmm7
;  sub rsp,128
;jmp q[rsp+128]
;
;OsXmmPopa:
;  movdqu xmm7,[rsp+16]
;  movdqu xmm6,[rsp+32]
;  movdqu xmm5,[rsp+48]
;  movdqu xmm4,[rsp+64]
;  movdqu xmm3,[rsp+80]
;  movdqu xmm2,[rsp+96]
;  movdqu xmm1,[rsp+112]
;  movdqu xmm0,[rsp+128]
;  add rsp,128+8+8 ;+8+8 : 1 call for pusha, 1 call for popa
;jmp q[rsp-128-8-8]
;
use64
OsGprDbg:
  push rax
  push rcx
  push rdx
  push rbx
  push rsp
  push rbp
  push rsi
  push rdi
  
%assign i 0
%rep 8
  mov rax,[b rsp+56-i*8]
  mov ecx,16
  mov edi,0b8000h+160*(i+25)+80
  call printN
%assign i i+1
%endrep
  MyDbg "   RAX  ",25,32
  MyDbg "   RCX  ",26,32
  MyDbg "   RDX  ",27,32
  MyDbg "   RBX  ",28,32
  MyDbg "   RSP  ",29,32
  MyDbg "   RBP  ",30,32
  MyDbg "   RSI  ",31,32
  MyDbg "   RDI  ",32,32
;  MyDbg "   R8   ", 8,32
;  MyDbg "   R9   ", 9,32
;  MyDbg "   R10  ",10,32
;  MyDbg "   R11  ",11,32
;  MyDbg "   R12  ",12,32
;  MyDbg "   R13  ",13,32
;  MyDbg "   R14  ",14,32
;  MyDbg "   R15  ",15,32
  
  pop  rdi
  pop  rsi
  pop  rbp
  add rsp,8 ;pop rsp
  pop  rbx
  pop  rdx
  pop  rcx
  pop  rax
  
ret

use64
xmmrip:
  ;try 64-bit movd and rip relative-addressing
  jmp trymovd
align 16
tryxmm:
  db 'X M M ! '
  db 'R I P ! '
trymovd:
  movq mm0,[rip-15]
  mov rdi,0b8000h+160*19+144 ;add rbx,1600
  ;no need for rex, below
  movd rax,mm0
  mov [rdi],rax
  
  ;try xmm  OK
  movd rcx,mm7
  movaps xmm0,[rcx+tryxmm]
  movaps [0b8000h+160*20+144],xmm0
  movdq2q mm0,xmm0
  movq [0b8000h+160*21+144],mm0
ret

use64
OsScrInit:
  call OsScrClr
  mov d[O+OS.KbdCursor],0b8000h+160*25+32*2
  mov ecx,16
  call OsScrHighlight
  
  mov edi,0b8000h
  mov esi,OsPgmLst
  add esi,[O+OS.Cs16]
  call OsStrPut
  mov edi,0b8000h+160*49
  mov esi,OsStateBar
  add esi,[O+OS.Cs16]
  call OsStrPut
ret

use64
TimerSecond: ;;buggy !!! :-( why ? eax is saved... seems like timer interrupts, though no "cli"
  mov eax,d[O+OS.KbdTimerTickN]
  add eax,18
  
.1:  
;does NOT work either   hlt
  cmp eax,d[O+OS.KbdTimerTickN]
  nop
  nop
  nop
  nop
  nop
  nop
  jne .1
ret

use64
OsStrPut:
  push rsi
  push rcx
  push rdx
  push rax
    
  mov ecx,160
  xor edx,edx
.1:  
  mov al,[rsi]
  cmp al,0
  je .z
  cmp al,13
  je .cr
  cmp al,10
  je .lf
  
  mov b[rdi],al
  add rdi,b 2
.cr:
  inc rsi
  jmp .1  

.lf:
  mov eax,edi
  sub eax,0b8000h
  xor edx,edx
  div ecx
  sub edi,edx
  add edi,160
  inc rsi
  jmp .1  

.z:
  pop rax
  pop rdx
  pop rcx
  pop rsi
ret

;DEL none
;wait ESC or any std key press & release, scancode 2
;INPUT bl
;DEL -
OsKbdCharGet: 
  push rax

.1:
  in al,60h
  cmp al,bl ;76h
  jne .1
.2:
  in al,60h
  cmp al,0f0h
  jne .2
.3:
  in al,60h
  cmp al,bl ;76h
  jne .3
  
  pop rax
ret

OsDbg:
  call OsGprPusha
  call OsMmxPusha
  ;BUG call OsXmmPusha

  mov edi,0b8000h
  mov esi,OsDbgScr
  add esi,d[O+OS.Cs16]
  call OsStrPut
  MyDbgN rax,0,40,16
  MyDbgN rcx,1,40,16
  MyDbgN rdx,2,40,16
  MyDbgN rbx,3,40,16
  MyDbgN rsp,4,40,16
  MyDbgN rbp,5,40,16
  MyDbgN rsi,6,40,16
  MyDbgN rdi,7,40,16
  MyDbgN r8, 8,40,16
  MyDbgN r9, 9,40,16
  MyDbgN r10,10,40,16
  MyDbgN r11,11,40,16
  MyDbgN r12,12,40,16
  MyDbgN r13,13,40,16
  MyDbgN r14,14,40,16
  MyDbgN r15,15,40,16

  MyDbgM mm0,17,40,16
  MyDbgM mm1,18,40,16
  MyDbgM mm2,19,40,16
  MyDbgM mm3,20,40,16
  MyDbgM mm4,21,40,16
  MyDbgM mm5,22,40,16
  MyDbgM mm6,23,40,16
  MyDbgM mm7,24,40,16
  
;  MyDbgM xmm0,33,40,16
;  MyDbgM xmm1,34,40,16
;  MyDbgM xmm2,35,40,16
;  MyDbgM xmm3,36,40,16
;  MyDbgM xmm4,37,40,16
;  MyDbgM xmm5,38,40,16
;  MyDbgM xmm6,39,40,16
;  MyDbgM xmm7,40,40,16
;  MyDbgM xmm8,41,40,16
;  MyDbgM xmm9,42,40,16
;  MyDbgM xmm10,43,40,16
;  MyDbgM xmm11,44,40,16
;  MyDbgM xmm12,45,40,16
;  MyDbgM xmm13,46,40,16
;  MyDbgM xmm14,47,40,16
;  MyDbgM xmm15,48,40,16
  
  ;BUG;;;call OsXmmPopa
  call OsMmxPopa
  call OsGprPopa
ret

;************
section .data
;************
align 16
MyData:
pGDT32:
  dw Gdtz-Gdt ;gdt32_limit ;GDT limit ...
  dd Gdt ;gdt32_base ;and 32-bit GDT base
  dd 0
pGdt64: ;label tbyte ;Used by LGDT.
  dw Gdtz-Gdt ;GDT limit ...
  dq Gdt ;and 64-bit GDT base

align 8
Gdt:
  dd 0,0
GdtCs16:
BootCode16:
  dd 0ffffh
  dd 09b00h
BootData16:
  dd 0ffffh
  dd 09300h
BootVideo16:
  dd 0ffffh
  dd 09300h
gdtCS64:
BootCode64:
  dd 0ffffh
  dd 0af9b00h
Gdtz:

pIdt64:
  dw idt64z-1-Idt64 ;idt_limit
  dd Idt64 ;idt_base to be patched : linear address
  dd 0

align 16
Idt64:
;low offset,code selector,std values,medium offset,high offset,highest offset,0,0
  times 64 dw 0,BootCode64-Gdt,8E00h,0,0,0,0,0
idt64z:

jmpmem:
  dw PM64Z
  dw 0
  dw BootCode16-Gdt

align 16
MyStack:
  dq 0,0,0,0,0,0,0,0

pIDT16:
.limit:
  dw 03ffh ;idt_limit
.base:
  dd 0 ;idt_base

FsSaved dw 0
GsSaved dw 0

OldIrqMask db 0,0
IrqMask db 0,0
OsKbdOldSet db 0,0

OsPgmLst: db \
"KBD DEBUGGER    ",10, \
"PLAYING WITH RIP",10, \
"SAY HELLO       ",10,0        

OsStateBar: db \
"MOVE : use the arrow keys, PgUp, PgDn, Home, End  EXECUTE : Enter   EXIT : Esc  ",0

OsDbgScr:
db "                                                                            RAX "
db "                                                                            RCX "
db "                                                                            RDX "
db "                                                                            RBX "
db "                                                                            RSP "
db "                                                                            RBP "
db "                                                                            RSI "
db "                                                                            RDI "
db "                                                                            R8  "
db "                                                                            R9  "
db "                                                                            R10 "
db "                                                                            R11 "
db "                                                                            R12 "
db "                                                                            R13 "
db "                                                                            R14 "
db "                                                                            R15 "
db "                                                                                "
db "                                                                            MM0 "
db "                                                                            MM1 "
db "                                                                            MM2 "
db "                                                                            MM3 "
db "                                                                            MM4 "
db "                                                                            MM5 "
db "                                                                            MM6 "
db "                                                                            MM7 "
db "                                                                            MM8 "
db "                                                                            MM9 "
db "                                                                            MM10"
db "                                                                            MM11"
db "                                                                            MM12"
db "                                                                            MM13"
db "                                                                            MM14"
db "                                                                            MM15"
db "                                                                           XMM0 "
db "                                                                           XMM1 "
db "                                                                           XMM2 "
db "                                                                           XMM3 "
db "                                                                           XMM4 "
db "                                                                           XMM5 "
db "                                                                           XMM6 "
db "                                                                           XMM7 "
db "                                                                           XMM8 "
db "                                                                           XMM9 "
db "                                                                           XMM10"
db "                                                                           XMM11"
db "                                                                           XMM12"
db "                                                                           XMM13"
db "                                                                           XMM14"
db "                                                                           XMM15"
db "                                                                                "
db 0