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