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