Merge remote branch 'pam/hdt-0.3.6'
[profile/ivi/syslinux.git] / memdisk / memdisk.inc
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
3 ;
4 ;  memdisk.inc
5 ;
6 ;  A program to emulate an INT 13h disk BIOS from a "disk" in extended
7 ;  memory.
8 ;
9 ;   Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
10 ;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
11 ;   Portions copyright 2009 Shao Miller [El Torito code]
12 ;
13 ;  This program is free software; you can redistribute it and/or modify
14 ;  it under the terms of the GNU General Public License as published by
15 ;  the Free Software Foundation, Inc., 53 Temple Place Ste 330,
16 ;  Boston MA 02111-1307, USA; either version 2 of the License, or
17 ;  (at your option) any later version; incorporated herein by reference.
18 ;
19 ; ****************************************************************************
20
21 %include "../version.gen"
22
23 ; %define DEBUG_TRACERS                 ; Uncomment to get debugging tracers
24
25 %ifdef DEBUG_TRACERS
26
27 %macro TRACER   1
28         call debug_tracer
29         db %1
30 %endmacro
31 %macro WRITEHEX2 0-1 al
32 %ifnidni %1,al
33         push ax
34         mov al,%1
35         call writehex2
36         pop ax
37 %else
38         call writehex2
39 %endif
40 %endmacro
41 %macro WRITEHEX4 0-1 ax
42 %ifnidni %1,ax
43         push ax
44         mov ax,%1
45         call writehex4
46         pop ax
47 %else
48         call writehex4
49 %endif
50 %endmacro
51 %macro WRITEHEX8 0-1 eax
52 %ifnidni %1,eax
53         push eax
54         mov eax,%1
55         call writehex8
56         pop eax
57 %else
58         call writehex8
59 %endif
60 %endmacro
61
62 %else   ; DEBUG_TRACERS
63
64 %macro  TRACER  1
65 %endmacro
66 %macro WRITEHEX2 0-1
67 %endmacro
68 %macro WRITEHEX4 0-1
69 %endmacro
70 %macro WRITEHEX8 0-1
71 %endmacro
72
73 %endif  ; DEBUG_TRACERS
74
75 ; Flags we test our configuration against
76 %define CONFIG_READONLY 0x01
77 %define CONFIG_RAW      0x02
78 %define CONFIG_SAFEINT  0x04
79 %define CONFIG_BIGRAW   0x08            ; MUST be 8!
80
81                 org 0h
82
83 %define SECTORSIZE      (1 << SECTORSIZE_LG2)
84
85                 ; Parameter registers definition; this is the definition
86                 ; of the stack frame.
87 %define         P_DS            word [bp+34]
88 %define         P_ES            word [bp+32]
89 %define         P_EAX           dword [bp+28]
90 %define         P_HAX           word [bp+30]
91 %define         P_AX            word [bp+28]
92 %define         P_AL            byte [bp+28]
93 %define         P_AH            byte [bp+29]
94 %define         P_ECX           dword [bp+24]
95 %define         P_HCX           word [bp+26]
96 %define         P_CX            word [bp+24]
97 %define         P_CL            byte [bp+24]
98 %define         P_CH            byte [bp+25]
99 %define         P_EDX           dword [bp+20]
100 %define         P_HDX           word [bp+22]
101 %define         P_DX            word [bp+20]
102 %define         P_DL            byte [bp+20]
103 %define         P_DH            byte [bp+21]
104 %define         P_EBX           dword [bp+16]
105 %define         P_HBX           word [bp+18]
106 %define         P_HBXL          byte [bp+18]
107 %define         P_BX            word [bp+16]
108 %define         P_BL            byte [bp+16]
109 %define         P_BH            byte [bp+17]
110 %define         P_EBP           dword [bp+8]
111 %define         P_BP            word [bp+8]
112 %define         P_ESI           dword [bp+4]
113 %define         P_SI            word [bp+4]
114 %define         P_EDI           dword [bp]
115 %define         P_DI            word [bp]
116
117                 section .text
118                 ; These pointers are used by the installer and
119                 ; must be first in the binary
120 Pointers:       dw Int13Start
121                 dw Int15Start
122                 dw PatchArea
123                 dw TotalSize
124                 dw IretPtr
125
126 IretPtr         equ Int13Start.iret
127 Int13Start:
128                 cmp word [cs:Recursive],0
129                 jne recursive
130
131                 ; Swap stack
132                 mov [cs:Stack],esp
133                 mov [cs:Stack+4],ss
134                 mov [cs:SavedAX],ax
135                 mov ax,cs
136                 mov ss,ax
137                 mov sp,[cs:MyStack]
138
139 %if ELTORITO
140                 cmp word [cs:SavedAX],4a00h     ; El Torito function?
141                 jae our_drive                   ; We grab it
142 %endif
143                 ; See if DL points to our class of device (FD, HD)
144                 push dx
145                 push dx
146                 xor dl,[cs:DriveNo]
147                 pop dx
148                 js .nomatch             ; If SF=0, we have a class match here
149                                         ; 0x00 the sign bit for FD
150                                         ; 0x80 the sign bit for HD
151                 jz our_drive            ; If ZF=1, we have an exact match
152                 cmp dl,[cs:DriveNo]
153                 jb .nomatch             ; Drive < Our drive
154                 cmp dl,[cs:DriveShiftLimit]
155                 jae .nomatch            ; Drive > The maximum drive
156                                         ; number that we will shift for.
157                                         ; This leaves any higher-up BIOS
158                                         ; drives alone, such as an optical
159                                         ; disc drive 0xA0 or 0xE0
160                 dec dl                  ; Drive > Our drive, adjust drive #
161 .nomatch:
162                 TRACER '!'
163                 WRITEHEX2 dl
164                 TRACER ','
165                 mov ax,[cs:SavedAX]
166                 WRITEHEX4
167                 inc word [cs:Recursive]
168                 pushf
169                 call far [cs:OldInt13]
170                 pushf
171                 dec word [cs:Recursive]
172                 push bp
173                 mov bp,sp
174                 cmp byte [cs:SavedAX+1],08h     ; Get drive params function?
175                 je .norestoredl                 ; DL = number of drives
176                 cmp byte [cs:SavedAX+1],15h     ; Get disk type function?
177                 jne .restoredl
178                 test byte [bp+4],80h            ; Hard disk?
179                 jnz .norestoredl                ; CX:DX = size of device
180 .restoredl:
181                 mov dl,[bp+4]
182 .norestoredl:
183                 push ax
184                 push ebx
185                 push ds
186                 mov ax,[bp+2]           ; Flags
187                 lds ebx,[cs:Stack]
188                 mov [bx+4],al           ; Arithmetic flags
189                 pop ds
190                 pop ebx
191                 pop ax
192                 pop bp
193                 lss esp,[cs:Stack]
194 .iret:          iret
195
196 recursive:
197                 TRACER '@'
198 jmp_oldint13:
199                 jmp far [cs:OldInt13]
200
201 our_drive:
202                 ; Set up standard entry frame
203                 push ds
204                 push es
205                 mov ds,ax
206                 mov es,ax
207                 mov ax,[SavedAX]
208                 pushad
209                 mov bp,sp               ; Point BP to the entry stack frame
210                 TRACER 'F'
211                 WRITEHEX4
212                 ; Note: AX == P_AX here
213                 cmp ah,Int13FuncsCnt-1
214                 ja Invalid_jump
215 %if ELTORITO
216                 mov al,[CD_PKT.type]    ; Check if we are in
217                 cmp al,0                ; El Torito no emulation mode
218                 ja .emulation           ; No.  We support the function
219                 cmp ah,3fh              ; Yes.  We must not support functions
220                 jbe Invalid_jump        ; 0 through 3Fh.  Check and decide
221 .emulation:
222 %endif
223                 xor al,al               ; AL = 0 is standard entry condition
224                 mov di,ax
225                 shr di,7                ; Convert AH to an offset in DI
226                 call [Int13Funcs+di]
227
228 Done:           ; Standard routine for return
229                 mov P_AX,ax
230 DoneWeird:
231                 TRACER 'D'
232                 xor bx,bx
233                 mov es,bx
234                 mov bx,[StatusPtr]
235                 mov [es:bx],ah          ; Save status
236                 and ah,ah
237
238                 lds ebx,[Stack]
239                 ; This sets the low byte (the arithmetic flags) of the
240                 ; FLAGS on stack to either 00h (no flags) or 01h (CF)
241                 ; depending on if AH was zero or not.
242                 setnz [bx+4]            ; Set CF iff error
243                 popad
244                 pop es
245                 pop ds
246                 lss esp,[cs:Stack]
247                 iret
248
249 Reset:
250                 ; Reset affects multiple drives, so we need to pass it on
251                 TRACER 'R'
252                 xor ax,ax               ; Bottom of memory
253                 mov es,ax
254                 test dl,dl              ; Always pass it on if we are
255                                         ; resetting HD
256                 js .hard_disk           ; Bit 7 set
257                 ; Some BIOSes get very unhappy if we pass a reset floppy
258                 ; command to them and don't actually have any floppies.
259                 ; This is a bug, but we have to deal with it nontheless.
260                 ; Therefore, if we are the *ONLY* floppy drive, and the
261                 ; user didn't request HD reset, then just drop the command.
262                 ; BIOS equipment byte, top two bits + 1 == total # of floppies
263                 test byte [es:0x410],0C0h
264                 jz success
265                 jmp .pass_on            ; ... otherwise pass it to the BIOS
266 .hard_disk:
267                 ; ... same thing for hard disks, sigh ...
268                 cmp byte [es:0x475],1   ; BIOS variable for number of hard
269                                         ; disks
270                 jbe success
271
272 .pass_on:
273                 pop ax                  ; Drop return address
274                 popad                   ; Restore all registers
275                 pop es
276                 pop ds
277                 lss esp,[cs:Stack]      ; Restore the stack
278                 and dl,80h              ; Clear all but the type bit
279                 jmp jmp_oldint13
280
281
282 Invalid:
283                 pop dx                  ; Drop return address
284 Invalid_jump:
285                 TRACER 'I'
286                 mov ah,01h              ; Unsupported function
287                 jmp short Done
288
289 GetDriveType:
290                 test byte [DriveNo],80h
291                 mov bl,02h              ; Type 02h = floppy with changeline
292                 jz .floppy
293                 ; Hard disks only!  DO NOT set CX:DX for floppies...
294                 ; it apparently causes Win98SE DOS to go into an loop
295                 ; resetting the drive over and over.  Sigh.
296                 inc bx                  ; Type = 03h
297                 mov dx,[DiskSize]       ; Return the disk size in sectors
298                 mov P_DX,dx
299                 mov cx,[DiskSize+2]
300                 mov P_CX,cx
301 .floppy:
302                 mov P_AH,bl             ; 02h floppy, 03h hard disk
303                 pop ax                  ; Drop return address
304                 xor ax,ax               ; Success...
305                 jmp DoneWeird           ; But don't stick it into P_AX
306
307 GetStatus:
308                 xor ax,ax
309                 mov es,ax
310                 mov bx,[StatusPtr]
311                 mov ah,[bx]             ; Copy last status
312                 ret
313
314 ReadMult:
315                 TRACER 'm'
316 Read:
317                 TRACER 'R'
318                 call setup_regs
319 do_copy:
320                 TRACER '<'
321                 call bcopy
322                 TRACER '>'
323                 movzx ax,P_AL           ; AH = 0, AL = transfer count
324                 ret
325
326 WriteMult:
327                 TRACER 'M'
328 Write:
329                 TRACER 'W'
330                 test byte [ConfigFlags],CONFIG_READONLY
331                 jnz .readonly
332                 call setup_regs
333                 xchg esi,edi            ; Opposite direction of a Read!
334                 jmp short do_copy
335 .readonly:      mov ah,03h              ; Write protected medium
336                 ret
337
338                 ; Verify integrity; just bounds-check
339 Seek:
340 Verify:
341                 call setup_regs         ; Returns error if appropriate
342                 ; And fall through to success
343
344 CheckIfReady:                           ; These are always-successful noop functions
345 Recalibrate:
346 InitWithParms:
347 DetectChange:
348 EDDDetectChange:
349 EDDLock:
350 SetMode:
351 success:
352                 xor ax,ax               ; Always successful
353                 ret
354
355 GetParms:
356                 TRACER 'G'
357                 mov dl,[DriveCnt]       ; Cached data
358                 mov P_DL,dl
359                 test byte [DriveNo],80h
360                 jnz .hd
361                 mov P_DI,DPT
362                 mov P_ES,cs
363                 mov bl,[DriveType]
364                 mov P_BL,bl
365 .hd:
366                 mov ax,[Cylinders]
367                 dec ax                  ; We report the highest #, not the count
368                 xchg al,ah
369                 shl al,6
370                 or al,[Sectors]
371                 mov P_CX,ax
372                 mov ax,[Heads]
373                 dec ax
374                 mov P_DH,al
375
376                 ;
377                 ; Is this MEMDISK installation check?
378                 ;
379                 cmp P_HAX,'ME'
380                 jne .notic
381                 cmp P_HCX,'MD'
382                 jne .notic
383                 cmp P_HDX,'IS'
384                 jne .notic
385                 cmp P_HBX,'K?'
386                 jne .notic
387
388                 ; MEMDISK installation check...
389                 mov P_HAX,'!M'
390                 mov P_HCX,'EM'
391                 mov P_HDX,'DI'
392                 mov P_HBX,'SK'
393                 mov P_ES,cs
394                 mov P_DI,MemDisk_Info
395
396 .notic:
397                 xor ax,ax
398                 ret
399 ;
400 ; EDD functions -- only if enabled
401 ;
402 %if EDD
403 EDDPresence:
404                 TRACER 'E'
405                 TRACER 'c'
406
407                 cmp P_BX,55AAh
408                 jne Invalid
409                 mov P_BX,0AA55h         ; EDD signature
410                 mov P_AX,03000h         ; EDD 3.0
411                 mov P_CX,0007h          ; Bit 0 - Fixed disk access subset
412                                         ; Bit 1 - Locking and ejecting subset
413                                         ; Bit 2 - EDD subset
414                 pop ax                  ; Drop return address
415                 xor ax,ax               ; Success
416                 jmp DoneWeird           ; Success, but AH != 0, sigh...
417
418 EDDRead:
419                 TRACER 'E'
420                 TRACER 'r'
421
422                 call edd_setup_regs
423                 call bcopy
424                 xor ax,ax
425                 ret
426
427 EDDWrite:
428                 TRACER 'E'
429                 TRACER 'w'
430
431                 call edd_setup_regs
432                 xchg esi,edi            ; Opposite direction of a Read!
433                 call bcopy
434                 xor ax,ax
435                 ret
436
437 EDDVerify:
438 EDDSeek:
439                 call edd_setup_regs     ; Just bounds checking
440                 xor ax,ax
441                 ret
442
443 EDDGetParms:
444                 TRACER 'E'
445                 TRACER 'p'
446
447                 mov es,P_DS
448                 mov di,P_SI
449                 mov si,EDD_DPT
450
451                 lodsw                   ; Length of our DPT
452                 mov cx,[es:di]
453                 cmp cx,26               ; Minimum size
454                 jb .overrun
455
456                 cmp cx,ax
457                 jb .oksize
458                 mov cx,ax
459
460 .oksize:
461                 mov ax,cx
462                 stosw
463                 dec cx
464                 dec cx
465                 rep movsb
466
467                 xor ax,ax
468                 ret
469
470 .overrun:
471                 mov ax,0100h
472                 ret
473 %endif ; EDD
474
475                 ; Set up registers as for a "Read", and compares against disk
476                 ; size.
477                 ; WARNING: This fails immediately, even if we can transfer some
478                 ; sectors.  This isn't really the correct behaviour.
479 setup_regs:
480
481                 ; Convert a CHS address in P_CX/P_DH into an LBA in eax
482                 ; CH = cyl[7:0]
483                 ; CL[0:5] = sector (1-based)  CL[7:6] = cyl[9:8]
484                 ; DH = head
485                 movzx ecx,P_CX
486                 movzx ebx,cl            ; Sector number
487                 and bl,3Fh
488                 dec ebx                 ; Sector number is 1-based
489                 cmp bx,[Sectors]
490                 jae .overrun
491                 movzx edi,P_DH          ; Head number
492                 movzx eax,word [Heads]
493                 cmp di,ax
494                 jae .overrun
495                 shr cl,6
496                 xchg cl,ch              ; Now (E)CX <- cylinder number
497                 mul ecx                 ; eax <- Heads*cyl# (edx <- 0)
498                 add eax,edi
499                 mul dword [Sectors]
500                 add eax,ebx
501                 ; Now eax = LBA, edx = 0
502
503                 ;
504                 ; setup_regs continues...
505                 ;
506                 ; Note: edi[31:16] and ecx[31:16] = 0 already
507                 mov di,P_BX             ; Get linear address of target buffer
508                 mov cx,P_ES
509                 shl ecx,4
510                 add edi,ecx             ; EDI = address to fetch to
511                 movzx ecx,P_AL          ; Sector count
512                 mov esi,eax
513                 add eax,ecx             ; LBA of final sector + 1
514                 shl esi,SECTORSIZE_LG2  ; LBA -> byte offset
515                 add esi,[DiskBuf]       ; Get address in high memory
516                 cmp eax,[DiskSize]      ; Check the high mark against limit
517                 ja .overrun
518                 shl ecx,SECTORSIZE_LG2-2 ; Convert count to dwords
519                 ret
520
521 .overrun:       pop ax                  ; Drop setup_regs return address
522                 mov ax,0200h            ; Missing address mark
523                 ret                     ; Return to Done
524
525                 ; Set up registers as for an EDD Read, and compares against disk size.
526 %if EDD
527 edd_setup_regs:
528                 push es
529                 mov si,P_SI             ; DS:SI -> DAPA
530                 mov es,P_DS
531
532                 mov dx,[es:si]
533                 cmp dx,16
534                 jb .baddapa
535
536                 cmp dword [es:si+4],-1
537                 je .linear_address
538
539                 movzx ebx,word [es:si+4]        ; Offset
540                 movzx edi,word [es:si+6]        ; Segment
541                 shl edi,4
542                 add ebx,edi
543                 jmp .got_address
544
545 .linear_address:
546                 cmp dx,24               ; Must be large enough to hold
547                                         ; linear address
548                 jb .baddapa
549
550                 cmp dword [es:si+20],0  ; > 4 GB addresses not supported
551                 mov ax,0900h            ; "Data boundary error" - bogus, but
552                                         ; no really better code available
553                 jne .error
554
555                 mov ebx,[es:si+16]
556
557 .got_address:
558                 cmp dword [es:si+12],0          ; LBA too large?
559                 jne .overrun
560
561                 movzx ecx, word [es:si+2]       ; Sectors to transfer
562                 mov esi,[es:si+8]               ; Starting sector
563                 mov eax,esi
564                 add eax,ecx
565                 jc .overrun
566                 cmp eax,[DiskSize]
567                 ja .overrun
568
569                 shl ecx,SECTORSIZE_LG2-2        ; Convert to dwords
570                 shl esi,SECTORSIZE_LG2          ; Convert to an offset
571                 add esi,[DiskBuf]
572                 mov edi,ebx
573                 pop es
574                 ret
575
576 .baddapa:
577                 mov ax,0100h            ; Invalid command
578                 pop es
579                 pop ax                  ; Drop setup_regs return address
580                 ret
581
582 .overrun:
583                 mov ax,0200h            ; "Address mark not found" =
584                                         ; LBA beyond end of disk
585 .error:
586                 and word [es:si+2],0    ; No sectors transferred
587                 pop es
588                 pop ax
589                 ret
590
591 EDDEject:
592                 mov ax,0B200h           ; Volume Not Removable
593                 ret
594 %if ELTORITO
595 ElToritoTerminate:
596                 TRACER 'T'
597                 mov ax,[cs:SavedAX]
598                 cmp al,1                ; We only support query, not terminate
599                 jne ElToritoErr         ; Fail
600                 mov es,P_DS             ; Caller's DS:SI pointed to packet
601                 mov di,P_SI             ; We'll use ES:DI
602                 mov si,CD_PKT.size      ; First byte is packet size
603                 xor cx,0                ; Empty our count
604                 ;mov cl,[ds:si]         ; We'll copy that many bytes
605                 mov cl,13h
606                 rep movsb               ; Copy until CX is zero
607                 mov ax,0                ; Success
608                 ret
609 ElToritoEmulate:
610 ElToritoBoot:
611 ElToritoCatalog:
612 ElToritoErr:
613                 TRACER '!'
614                 mov ax,100h             ; Invalid parameter
615                 ret
616 %endif ; ELTORITO
617 %endif ; EDD
618
619 ;
620 ; INT 15h intercept routines
621 ;
622 int15_e820:
623                 cmp edx,534D4150h       ; "SMAP"
624                 jne oldint15
625                 cmp ecx,20              ; Need 20 bytes
626                 jb err86
627                 push ds
628                 push cs
629                 pop ds
630                 push edx                ; "SMAP"
631                 and ebx,ebx
632                 jne .renew
633                 mov ebx,E820Table
634 .renew:
635                 add bx,12               ; Advance to next
636                 mov eax,[bx-4]          ; Type
637                 and eax,eax             ; Null type?
638                 jz .renew               ; If so advance to next
639                 mov [es:di+16],eax
640                 mov eax,[bx-12]         ; Start addr (low)
641                 mov edx,[bx-8]          ; Start addr (high)
642                 mov [es:di],eax
643                 mov [es:di+4],edx
644                 mov eax,[bx]            ; End addr (low)
645                 mov edx,[bx+4]          ; End addr (high)
646                 sub eax,[bx-12]         ; Derive the length
647                 sbb edx,[bx-8]
648                 mov [es:di+8],eax       ; Length (low)
649                 mov [es:di+12],edx      ; Length (high)
650                 cmp dword [bx+8],-1     ; Type of next = end?
651                 jne .notdone
652                 xor ebx,ebx             ; Done with table
653 .notdone:
654                 pop eax                 ; "SMAP"
655                 mov edx,eax             ; Some systems expect eax = edx = SMAP
656                 mov ecx,20              ; Bytes loaded
657                 pop ds
658 int15_success:
659                 mov byte [bp+6], 02h    ; Clear CF
660                 pop bp
661                 iret
662
663 err86:
664                 mov byte [bp+6], 03h    ; Set CF
665                 mov ah,86h
666                 pop bp
667                 iret
668
669 Int15Start:
670                 push bp
671                 mov bp,sp
672                 cmp ax,0E820h
673                 je near int15_e820
674                 cmp ax,0E801h
675                 je int15_e801
676                 cmp ax,0E881h
677                 je int15_e881
678                 cmp ah,88h
679                 je int15_88
680 oldint15:       pop bp
681                 jmp far [cs:OldInt15]
682
683 int15_e801:                             ; Get mem size for > 64 MB config
684                 mov ax,[cs:Mem1MB]
685                 mov cx,ax
686                 mov bx,[cs:Mem16MB]
687                 mov dx,bx
688                 jmp short int15_success
689
690 int15_e881:                             ; Get mem size for > 64 MB config
691                                         ; 32-bit code
692                 mov eax,[cs:Mem1MB]
693                 mov ecx,eax
694                 mov ebx,[cs:Mem16MB]
695                 mov edx,ebx
696                 jmp short int15_success
697
698 int15_88:                               ; Get extended mem size
699                 mov ax,[cs:MemInt1588]
700                 jmp short int15_success
701
702 ;
703 ; Routine to copy in/out of high memory
704 ; esi = linear source address
705 ; edi = linear target address
706 ; ecx = 32-bit word count
707 ;
708 ; Assumes cs = ds = es
709 ;
710 bcopy:
711                 push eax
712                 push ebx
713                 push edx
714                 push ebp
715
716                 mov bx, real_int15_stub
717
718                 test byte [ConfigFlags], CONFIG_RAW|CONFIG_SAFEINT
719                 jz .anymode             ; Always do the real INT 15h
720
721                 smsw ax                 ; Unprivileged!
722                 test al,01h
723                 jnz .protmode           ; Protmode -> do real INT 15h
724
725 .realmode:
726                 ; Raw or Safeint mode, and we're in real mode...
727
728                 test byte [ConfigFlags], CONFIG_SAFEINT
729                 jnz .fakeint15
730
731 .raw:
732                 TRACER 'r'
733                 ; We're in real mode, do it outselves
734
735                 pushfd                  ; <A>
736                 push ds                 ; <B>
737                 push es                 ; <C>
738
739                 cli
740                 cld
741
742                 xor ebx,ebx
743                 mov bx,cs
744                 shl ebx,4
745                 lea edx,[Shaker+ebx]
746                 mov [Shaker+2],edx
747
748                 ; Test to see if A20 is enabled or not
749                 xor ax,ax
750                 mov ds,ax
751                 dec ax
752                 mov es,ax
753
754                 mov ax,[0]
755                 mov bx,ax
756                 xor bx,[es:10h]
757                 not ax
758                 mov [0],ax
759                 mov dx,ax
760                 xor dx,[es:10h]
761                 not ax
762                 mov [0],ax
763
764                 or dx,bx
765                 push dx                 ; <D> Save A20 status
766                 jnz .skip_a20e
767
768                 mov ax,2401h            ; Enable A20
769                 int 15h
770 .skip_a20e:
771                 mov dl,[ConfigFlags]
772                 and dx,CONFIG_BIGRAW
773                 add dx,8
774                 ; DX = 16 for BIGRAW, 8 for RAW
775                 ;  8 is selector for a 64K flat segment,
776                 ; 16 is selector for a 4GB flat segment.
777
778                 lgdt [cs:Shaker]
779                 mov eax,cr0
780                 or al,01h
781                 mov cr0,eax
782
783                 mov bx,16               ; Large flat segment
784                 mov ds,bx
785                 mov es,bx
786
787                 a32 rep movsd
788
789                 ; DX has the appropriate value to put in
790                 ; the registers on return
791                 mov ds,dx
792                 mov es,dx
793
794                 and al,~01h
795                 mov cr0,eax
796
797                 pop dx                  ; <D> A20 status
798                 pop es                  ; <C>
799                 pop ds                  ; <B>
800
801                 and dx,dx
802                 jnz .skip_a20d
803                 mov ax,2400h            ; Disable A20
804                 int 15h
805 .skip_a20d:
806                 popfd                   ; <A>
807                 jmp .done
808
809 .fakeint15:
810                 ; We're in real mode with CONFIG_SAFEINT, invoke the
811                 ; original INT 15h vector.  We used to test for the
812                 ; INT 15h vector being unchanged here, but that is
813                 ; *us*; however, the test was wrong for years (always
814                 ; negative) so instead of fixing the test do what we
815                 ; tested and don't bother probing.
816                 mov bx, fake_int15_stub
817
818 .protmode:
819                 TRACER 'p'
820 .anymode:
821
822 .copy_loop:
823                 push esi
824                 push edi
825                 push ecx
826                 cmp ecx,4000h
827                 jna .safe_size
828                 mov ecx,4000h
829 .safe_size:
830                 push ecx        ; Transfer size this cycle
831                 mov eax, esi
832                 mov [Mover_src1], si
833                 shr eax, 16
834                 mov [Mover_src1+2], al
835                 mov [Mover_src2], ah
836                 mov eax, edi
837                 mov [Mover_dst1], di
838                 shr eax, 16
839                 mov [Mover_dst1+2], al
840                 mov [Mover_dst2], ah
841                 mov si,Mover
842                 mov ah, 87h
843                 shl cx,1        ; Convert to 16-bit words
844                 call bx         ; INT 15h stub
845                 pop eax         ; Transfer size this cycle
846                 pop ecx
847                 pop edi
848                 pop esi
849                 jc .error
850                 lea esi,[esi+4*eax]
851                 lea edi,[edi+4*eax]
852                 sub ecx, eax
853                 jnz .copy_loop
854                 ; CF = 0
855 .error:
856 .done:
857                 pop ebp
858                 pop edx
859                 pop ebx
860                 pop eax
861                 ret
862
863 real_int15_stub:
864                 int 15h
865                 cli             ; Some BIOSes enable interrupts on INT 15h
866                 ret
867
868 fake_int15_stub:
869                 pushf
870                 call far [OldInt15]
871                 cli
872                 ret
873
874 %ifdef DEBUG_TRACERS
875 debug_tracer:   pushad
876                 pushfd
877                 mov bp,sp
878                 mov bx,[bp+9*4]
879                 mov al,[cs:bx]
880                 inc word [bp+9*4]
881                 mov ah,0Eh
882                 mov bx,7
883                 int 10h
884                 popfd
885                 popad
886                 ret
887
888 writehex2:      pushad
889                 pushfd
890                 mov cx,2
891                 ror eax,4
892                 jmp writehex_common
893 writehex4:      pushad
894                 pushfd
895                 mov cx,4
896                 ror eax,12
897                 jmp writehex_common
898 writehex8:      pushad
899                 pushfd
900                 mov cx,8
901                 ror eax,28
902 writehex_common:
903 .loop:          push cx
904                 push eax
905                 and al,0Fh
906                 cmp al,10
907                 jb .isdec
908                 add al,'a'-'0'-10
909 .isdec:         add al,'0'
910                 mov ah,0Eh
911                 mov bx,7
912                 int 10h
913                 pop eax
914                 rol eax,4
915                 pop cx
916                 loop .loop
917                 popfd
918                 popad
919                 ret
920 %endif
921
922                 section .data
923                 alignb 2
924 Int13Funcs      dw Reset                ; 00h - RESET
925                 dw GetStatus            ; 01h - GET STATUS
926                 dw Read                 ; 02h - READ
927                 dw Write                ; 03h - WRITE
928                 dw Verify               ; 04h - VERIFY
929                 dw Invalid              ; 05h - FORMAT TRACK
930                 dw Invalid              ; 06h - FORMAT TRACK AND SET BAD FLAGS
931                 dw Invalid              ; 07h - FORMAT DRIVE AT TRACK
932                 dw GetParms             ; 08h - GET PARAMETERS
933                 dw InitWithParms        ; 09h - INITIALIZE CONTROLLER WITH
934                                         ;       DRIVE PARAMETERS
935                 dw Invalid              ; 0Ah
936                 dw Invalid              ; 0Bh
937                 dw Seek                 ; 0Ch - SEEK TO CYLINDER
938                 dw Reset                ; 0Dh - RESET HARD DISKS
939                 dw Invalid              ; 0Eh
940                 dw Invalid              ; 0Fh
941                 dw CheckIfReady         ; 10h - CHECK IF READY
942                 dw Recalibrate          ; 11h - RECALIBRATE
943                 dw Invalid              ; 12h
944                 dw Invalid              ; 13h
945                 dw Invalid              ; 14h
946                 dw GetDriveType         ; 15h - GET DRIVE TYPE
947                 dw DetectChange         ; 16h - DETECT DRIVE CHANGE
948 %if EDD
949                 dw Invalid              ; 17h
950                 dw Invalid              ; 18h
951                 dw Invalid              ; 19h
952                 dw Invalid              ; 1Ah
953                 dw Invalid              ; 1Bh
954                 dw Invalid              ; 1Ch
955                 dw Invalid              ; 1Dh
956                 dw Invalid              ; 1Eh
957                 dw Invalid              ; 1Fh
958                 dw Invalid              ; 20h
959                 dw ReadMult             ; 21h - READ MULTIPLE
960                 dw WriteMult            ; 22h - WRITE MULTIPLE
961                 dw SetMode              ; 23h - SET CONTROLLER FEATURES
962                 dw SetMode              ; 24h - SET MULTIPLE MODE
963                 dw Invalid              ; 25h - IDENTIFY DRIVE
964                 dw Invalid              ; 26h
965                 dw Invalid              ; 27h
966                 dw Invalid              ; 28h
967                 dw Invalid              ; 29h
968                 dw Invalid              ; 2Ah
969                 dw Invalid              ; 2Bh
970                 dw Invalid              ; 2Ch
971                 dw Invalid              ; 2Dh
972                 dw Invalid              ; 2Eh
973                 dw Invalid              ; 2Fh
974                 dw Invalid              ; 30h
975                 dw Invalid              ; 31h
976                 dw Invalid              ; 32h
977                 dw Invalid              ; 33h
978                 dw Invalid              ; 34h
979                 dw Invalid              ; 35h
980                 dw Invalid              ; 36h
981                 dw Invalid              ; 37h
982                 dw Invalid              ; 38h
983                 dw Invalid              ; 39h
984                 dw Invalid              ; 3Ah
985                 dw Invalid              ; 3Bh
986                 dw Invalid              ; 3Ch
987                 dw Invalid              ; 3Dh
988                 dw Invalid              ; 3Eh
989                 dw Invalid              ; 3Fh
990                 dw Invalid              ; 40h
991                 dw EDDPresence          ; 41h - EDD PRESENCE DETECT
992                 dw EDDRead              ; 42h - EDD READ
993                 dw EDDWrite             ; 43h - EDD WRITE
994                 dw EDDVerify            ; 44h - EDD VERIFY
995                 dw EDDLock              ; 45h - EDD LOCK/UNLOCK MEDIA
996                 dw EDDEject             ; 46h - EDD EJECT
997                 dw EDDSeek              ; 47h - EDD SEEK
998                 dw EDDGetParms          ; 48h - EDD GET PARAMETERS
999                 dw EDDDetectChange      ; 49h - EDD MEDIA CHANGE STATUS
1000 %if ELTORITO                            ; EDD El Torito Functions
1001                                         ; ELTORITO _must_ also have EDD
1002                 dw ElToritoEmulate      ; 4Ah - Initiate Disk Emulation
1003                 dw ElToritoTerminate    ; 4Bh - Terminate Disk Emulation
1004                 dw ElToritoBoot         ; 4Ch - Initiate Disk Emu. and Reboot
1005                 dw ElToritoCatalog      ; 4Dh - Return Boot Catalog
1006 %endif ; ELTORITO
1007 %endif ; EDD
1008
1009 Int13FuncsEnd   equ $
1010 Int13FuncsCnt   equ (Int13FuncsEnd-Int13Funcs) >> 1
1011
1012
1013                 alignb 8, db 0
1014 Shaker          dw ShakerEnd-$-1        ; Descriptor table limit
1015                 dd 0                    ; Pointer to self
1016                 dw 0
1017
1018 Shaker_RMDS:    dd 0x0000ffff           ; 64K data segment
1019                 dd 0x00009300
1020
1021 Shaker_DS:      dd 0x0000ffff           ; 4GB data segment
1022                 dd 0x008f9300
1023
1024 ShakerEnd       equ $
1025
1026                 alignb 8, db 0
1027
1028 Mover           dd 0, 0, 0, 0           ; Must be zero
1029                 dw 0ffffh               ; 64 K segment size
1030 Mover_src1:     db 0, 0, 0              ; Low 24 bits of source addy
1031                 db 93h                  ; Access rights
1032                 db 00h                  ; Extended access rights
1033 Mover_src2:     db 0                    ; High 8 bits of source addy
1034                 dw 0ffffh               ; 64 K segment size
1035 Mover_dst1:     db 0, 0, 0              ; Low 24 bits of target addy
1036                 db 93h                  ; Access rights
1037                 db 00h                  ; Extended access rights
1038 Mover_dst2:     db 0                    ; High 8 bits of source addy
1039 Mover_dummy2:   dd 0, 0, 0, 0           ; More space for the BIOS
1040
1041                 alignb 4, db 0
1042 MemDisk_Info    equ $                   ; Pointed to by installation check
1043 MDI_Bytes       dw MDI_Len              ; Total bytes in MDI structure
1044 MDI_Version     db VERSION_MINOR, VERSION_MAJOR ; MEMDISK version
1045
1046 PatchArea       equ $                   ; This gets filled in by the installer
1047
1048 DiskBuf         dd 0                    ; Linear address of high memory disk
1049 DiskSize        dd 0                    ; Size of disk in blocks
1050 CommandLine     dw 0, 0                 ; Far pointer to saved command line
1051
1052 OldInt13        dd 0                    ; INT 13h in chain
1053 OldInt15        dd 0                    ; INT 15h in chain
1054
1055 OldDosMem       dw 0                    ; Old position of DOS mem end
1056 BootLoaderID    db 0                    ; Boot loader ID from header
1057                 db 0                    ; pad
1058
1059 DPT_ptr         dw 0                    ; If nonzero, pointer to DPT
1060                                         ; Original DPT pointer follows
1061
1062 MDI_Len         equ $-MemDisk_Info
1063
1064 ; ---- MDI structure ends here ---
1065 DriveShiftLimit db 0ffh                 ; Installer will [soon] probe for
1066                                         ; a range of contiguous drives.
1067                                         ; Any BIOS drives above this region
1068                                         ; shall not be impacted by our
1069                                         ; shifting behaviour
1070                 db 0                    ; pad to a DWORD
1071                 dw 0                    ; pad to a QWORD
1072 MemInt1588      dw 0                    ; 1MB-65MB memory amount (1K)
1073
1074 Cylinders       dw 0                    ; Cylinder count
1075 Heads           dw 0                    ; Head count
1076 Sectors         dd 0                    ; Sector count (zero-extended)
1077
1078 Mem1MB          dd 0                    ; 1MB-16MB memory amount (1K)
1079 Mem16MB         dd 0                    ; 16MB-4G memory amount (64K)
1080
1081 DriveNo         db 0                    ; Our drive number
1082 DriveType       db 0                    ; Our drive type (floppies)
1083 DriveCnt        db 0                    ; Drive count (from the BIOS)
1084
1085 ConfigFlags     db 0                    ; Bit 0 - readonly
1086
1087 MyStack         dw 0                    ; Offset of stack
1088 StatusPtr       dw 0                    ; Where to save status (zeroseg ptr)
1089
1090 DPT             times 16 db 0           ; BIOS parameter table pointer (floppies)
1091 OldInt1E        dd 0                    ; Previous INT 1E pointer (DPT)
1092
1093 %if EDD
1094 EDD_DPT:
1095 .length         dw 30
1096 .info           dw 0029h
1097                 ; Bit 0 - DMA boundaries handled transparently
1098                 ; Bit 3 - Device supports write verify
1099                 ; Bit 5 - Media is lockable
1100 .cylinders      dd 0                    ; Filled in by installer
1101 .heads          dd 0                    ; Filled in by installer
1102 .sectors        dd 0                    ; Filled in by installer
1103 .totalsize      dd 0, 0                 ; Filled in by installer
1104 .bytespersec    dw SECTORSIZE
1105 .eddtable       dw -1, -1               ; Invalid DPTE pointer
1106 .dpikey         dw 0BEDDh               ; Device Path Info magic
1107 .dpilen         db 2ch                  ; DPI len
1108 .res1           db 0                    ; Reserved
1109 .res2           dw 0                    ; Reserved
1110 .bustype        dd 'MEM '               ; Host bus type (4 bytes, space padded)
1111 .inttype        dd 'MEMORY  '           ; Interface type (8 bytes, spc. padded)
1112 .intpath        dd 0, 0                 ; Interface path
1113 .devpath        dd 0, 0, 0, 0           ; Device path
1114 .res3           db 0                    ; Reserved
1115 .chksum         db 0                    ; DPI checksum
1116
1117 %if ELTORITO
1118 ; El Torito CD Specification Packet - mostly filled in by installer
1119 CD_PKT:
1120 .size           db 13h  ; Packet size (19 bytes)
1121 .type           db 0    ; Boot media type (flags)
1122 .driveno        db 0E0h ; INT 13h drive number
1123 .controller     db 0    ; Controller index
1124 .start          dd 0    ; Starting LBA of image
1125 .devno          dw 0    ; Device number
1126 .user_buf       dw 0    ; User buffer segment
1127 .load_seg       dw 0    ; Load segment
1128 .sect_count     dw 0    ; Emulated sectors to load
1129 .geom1          db 0    ; Cylinders bits 0 thru 7
1130 .geom2          db 0    ; Sects/track 0 thru 5, cyls 8, 9
1131 .geom3          db 0    ; Heads
1132 %endif ; ELTORITO
1133
1134 %endif ; EDD
1135
1136                 ; End patch area
1137                 alignb 4, db 0
1138 Stack           dd 0                    ; Saved SS:ESP on invocation
1139                 dw 0
1140 SavedAX         dw 0                    ; AX saved on invocation
1141 Recursive       dw 0                    ; Recursion counter
1142
1143                 alignb 4, db 0          ; We *MUST* end on a dword boundary
1144
1145 E820Table       equ $                   ; The installer loads the E820 table here
1146 TotalSize       equ $                   ; End pointer