;                 * * *
;               DISCLAIMER
;
;     A PARTITION TABLE IS REQUIRED
;       TO BUILD A WORKING IMAGE
;
;      PLEASE KNOW WHAT YOU ARE DOING
;                 * * *
;
;       IDE PC Bootloader for 386+
;
;               Have Fun!
;

 use16
 org 07C00h
start:
 file "header.bin"  ;OPTIONAL, to keep USB stick readable

  in AL,070h	      ;
  or AL,080h	      ; Turn NMI off
  out 070h,AL	      ;
  cli		      ;Disable interrupts
  cld		      ;ret => neat snippet!

  jmp 0:($+5)	      ;RealMode Init snippet
  mov AX,CS
  mov DS,AX
  mov ES,AX
  mov SS,AX
  mov SP,0600h	      ;500h-600h: Return Stack

  rdtsc 	      ;Wait for keypress
  mov BX,DX
  inc BX
 db 066h,066h,090h    ;Alignment
TestLoop:
  in AL,064h	      ;Poll Keyboard
  test AL,01
  jnz Pmode	      ;The byte(s) are still at 060h!
  rdtsc
  cmp BX,DX	      ;Wait four billion cycles
  jge TestLoop	      ;couple of seconds on my
		      ;1.7GHz P4

  mov SI,07C00h       ;Relocate current code
  mov DI,07A00h
  mov CX,0256
  rep movsw
  jmp (Boot-200h)
 db 066h,090h	      ;Alignment
;======================

LBAFetch:	      ;wired to master device
  lodsb
  out DX,AL
  inc DX
  lodsb
  out DX,AL
  inc DX
  lodsb
  out DX,AL
  inc DX
  lodsb
  or AL,0E0h	      ;LBA bit set, DEV bit clear
  out DX,AL	      ;or AL,0F0h for slave
  inc DX
  ret
  nop

IDE_Idle:
  inc DH
  inc DH
  dec DL	      ;(Optional?)
  in AL,DX	      ;Wait one cycle by
  dec DH	      ;reading the corresponding
  dec DH	      ;alternate status register
  inc DL

  in AL,DX	      ;Status Register
  test AL,010000000b  ;BSY?
  jnz IDE_Idle	      ;wait for it
  test AL,000001000b  ;DRQ?
  jnz IDE_IdleRet     ;proceed
  pop AX	      ;Break Loop
  nop		      ;Alignment
IDE_IdleRet:
  sub DX, 07	      ;Data Port
  ret

Boot:
  in AL,070h	      ;
  and AL,07Fh	      ; Turn NMI on
  out 070h,AL	      ;
  sti		      ;Enable interrupts

  mov DI,07C00h       ;Destination for data
  push DI	      ;and for return
  mov SI,07BC6h       ;[SourceLBA]
  mov AX,01	      ;SectorCount (0==256)
  mov DX,01F2h	      ;Base I/O address+2

MasterHDFetch:
  nop		      ;Alignment
  out DX,AL
  inc DX
  call LBAFetch
  db 066h,090h	      ;*Patch padding
  mov AL,020h	      ;"READ SECTOR(S)" command
  out DX,AL
IDE_PIO_In:
  sub CX,CX	      ; 256 bytes
  inc CH	      ; at a time
  call IDE_Idle
 db 066h,066h,090h    ;*Patch Padding
  rep insw	      ;16 bits wide bus
  add DX, 07	      ;Status register
  jmp IDE_PIO_In


;================================================

Pmode:
  in AL,092h	      ;
  or AL,02	      ; Enable the fast A20 gate
  out 080h,AL	      ; 1ms port read
  out 092h,AL	      ;

  mov BX,010h	      ;Load selector
  lgdt [GDT]	      ;Initialize the GDT
  mov EAX,CR0
  inc AX
  mov CR0,EAX	      ;Enter PMode
  jmp 08:Protected    ;Flush pipeline

 align 08	      ;Optional, for speed

GDT:		      ;Flat, minimal GDT
 dw 023 	      ; Blank descriptor
 dd GDT 	      ; contains the GDT
 dw 0		      ; pointer
 dw 0FFFFh,0,09A00h,0CFh ;32bit code descriptor
 dw 0FFFFh,0,09200h,0CFh ;32bit data descriptor

Beurk:
 dd 01

 use32

Protected:	      ;Now in 32 bit protected mode
  mov ES,EBX	      ;
  mov SS,EBX	      ; Initialize needed descriptors
  mov DS,EBX	      ;
  mov FS,EBX	      ;Alignment purpose

  ;Let's patch the backward calls of the 16 bits code!!
  mov dword [IDE_PIO_In+07],066F3FFFFh ;also insw fix
  sub dword [IDE_PIO_In+05],02
  mov word [MasterHDFetch+06],0FFFFh
  sub word [MasterHDFetch+04],02

  mov EDI,0100000h    ;Destination for data
  push EDI	      ;and for return
  mov ESI,Beurk       ;[SourceLBA]
  mov EAX,062	      ;SectorCount (0==256)
  mov EDX,01F2h       ;Base I/O address+2
  jmp MasterHDFetch

 times (start+446-$) nop

 file "partable.bin"  ;Partition Table of current drive
;
;
;=>PC Memory map at bootup (from OSD)
;===================
;000000-0003FF interrupt vector table
;000400-0004FF BIOS data area
;000500-007BFF FREE CONVENTIONAL MEMORY
;007C00-007DFF boot sector
;007E00-09FBFF FREE CONVENTIONAL MEMORY
;09FC00-09FFFF extended BDA (variable length)
;0A0000-0FFFFF video memory and BIOS ROMs
;100000-10FFEF high memory area (HMA)
;10FFF0-       FREE EXTENDED MEMORY
;
;
;*Only a complement to ATA/ATAPI-6 PDF document @ T13
;Best webpage: http://www.stanford.edu/~csapuntz/ide.html
;
;=>IDE I/O ports Map (from EIDE-2 faq @ faqs.org)
;===================
;10.4.  How are the ATA(-2,PI) I/O ports assigned?
;
;  The registers of the primary ATA channel occupy the following I/O
;  addresses (in hexadecimal notation):
;
;     Register      Read Function             Write Function
;
;     01F0h         Read Data                 Write Data
;                   (16 Bits)                 (16 bits)
;     01F1h         Error register            Set Features Data
;     01F2h         Status of sector          Write sector count
;                   count                     for command setup
;     01F3h         Location of starting      Write sector start
;                   sector                    for command setup
;     01F4h         Location of Cyl-low       Write cyl-low location
;                                             for command setup
;     01F5h         Location of Cyl-high      Write cyl-high location
;                                             for command setup
;     01F6h         Head/device selection     Write device selection
;                                             and head selection for
;                                             command setup
;     01F7h         Device Status             Device command
;
;     03F6h         Alternate Status          Device Control
;     03F7h         Drive Address
;
;  Note that the floppy disk controller's disk change flag shares 03F7h
;  which makes life difficult for designers that want to implement disk
;  and floppy controllers separately. [...]
;
;    Interface number     CS0-decode    CS1-decode    IRQ number
;
;            1            01F0h-01F7h   03F6h-03F7h    14
;            2            0170h-0177h   0376h-0377h    15 or 10
;            3            01E8h-01EFh   03EEh-03EFh    12 or 11
;            4            0168h-016Fh   036Eh-036Fh    10 or 9
;
;=> Keyboard Scancode set 1 (from OSD)
;
;Most keys:
;        one-byte make code      = nn
;        one-byte repeat code    = nn
;        one-byte break code     = 80h + nn
;
;"Gray" keys (not on original 84-key keyboard):
;        two-byte make code      = E0nn
;        two-byte repeat code    = E0nn
;        two-byte break code     = E0 followed by 80h + nn
;
;code key        code key        code key        code key
;---- ---        ---- ---        ---- ---        ---- ---
;01   Esc        0F   Tab        1D   L Ctrl     2B   \|
;02   1!         10   Q          1E   A          2C   Z
;03   2"         11   W          1F   S          2D   X
;04   3#         12   E          20   D          2E   C
;05   4$         13   R          21   F          2F   V
;06   5%         14   T          22   G          30   B
;07   6^         15   Y          23   H          31   N
;08   7&         16   U          24   J          32   M
;09   8*         17   I          25   K          33   ,<
;0A   9(         18   O          26   L          34   .>
;0B   0)         19   P          27   ;:         35   /?
;0C   -_         1A   [{         28   '"         36   R Shift
;0D   =+         1B   ]}         29   `~         37   *
;0E   BackSpace  1C   Enter      2A   L Shift    38   L Alt
;
;code key        code key        code key        code key
;---- ---        ---- ---        ---- ---        ---- ---
;39   Space      41   F7         49   PageUp 9   51   PageDown 3
;3A   CapsLock   42   F8         4A   -          52   Insert 0
;3B   F1         43   F9         4B   (left) 4   53   Del .
;3C   F2         44   F10        4C   5
;3D   F3         45   NumLock    4D   (right) 6  57   F11
;3E   F4         46   ScrollLock 4E   +          58   F12
;3F   F5         47   Home  7    4F   End 1
;40   F6         48   (up) 8     50   (down) 2
;
;code            key
;----            ---
;E01C            Enter (on numeric keypad)
;E01D            R Ctrl
;E02A            make code prefix for keyboard internal numlock
;E02AE037        PrintScreen make code
;E035            /
;E037            PrintScreen repeat code
;E038            R Alt
;E047            Home
;E048            (up)
;E049            PageUp
;E04B            (left)
;E04D            (right)
;E04F            End
;E050            (down)
;E051            PageDown
;E052            Insert
;E053            Del
;E05B            L Win
;E05C            R Win
;E05D            Menu
;E0AA            break code suffix for keyboard internal numlock
;E0B7E0AA        PrintScreen break code
;E11D45E19DC5    Pause
;
