pci_cap_init: add 82599 VF quirk
[qemu-kvm.git] / pc-bios / optionrom / extboot.S
blobdb6c2b673ce49a2817cfb55cd228b8e778de11b4
1 /*
2  * Extended Boot Option ROM
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Copyright IBM Corporation, 2007
19  *   Authors: Anthony Liguori <aliguori@us.ibm.com>
20  */
22 #define OLD_INT19       (0x80 * 4)      /* re-use INT 0x80 BASIC vector */
23 #define OLD_INT13       (0x81 * 4)      /* re-use INT 0x81 BASIC vector */
25 .code16
26 .text
27         .global _start
28 _start:
29         .short 0xaa55
30         .byte (_end - _start) / 512
31         push %eax
32         push %ds
34         /* setup ds so we can access the IVT */
35         xor %ax, %ax
36         mov %ax, %ds
38         /* there is one more bootable HD */
39         incb 0x0475
41         /* save old int 19 */
42         mov (0x19*4), %eax
43         mov %eax, (OLD_INT19)
45         /* install out int 19 handler */
46         movw $int19_handler, (0x19*4)
47         mov %cs, (0x19*4+2)
49         pop %ds
50         pop %eax
51         lret
53 int19_handler:
54         push %eax /* reserve space for lret */
55         push %eax
56         push %bx
57         push %cx
58         push %dx
59         push %ds
61         /* setup ds to access IVT */
62         xor %ax, %ax
63         mov %ax, %ds
65         /* save old int 13 to int 2c */
66         mov (0x13*4), %eax
67         mov %eax, (OLD_INT13)
69         /* install our int 13 handler */
70         movw $int13_handler, (0x13*4)
71         mov %cs, (0x13*4+2)
73         /* restore previous int $0x19 handler */
74         mov (OLD_INT19),%eax
75         mov %eax,(0x19*4)
77         /* write old handler as return address onto stack */
78         push %bp
79         mov %sp, %bp
80         mov %eax, 14(%bp)
81         pop %bp
83         pop %ds
84         pop %dx
85         pop %cx
86         pop %bx
87         pop %eax
88         lret
90 #define FLAGS_CF        0x01
92 /* The two macro below clear/set the carry flag to indicate the status
93  * of the interrupt execution. It is not enough to issue a clc/stc instruction,
94  * since the value of the flags register will be overwritten by whatever is
95  * in the stack frame
96  */
97 .macro clc_stack
98         push %bp
99         mov %sp, %bp
100         /* 8 = 2 (bp, just pushed) + 2 (ip) + 3 (real mode interrupt frame) */
101         and $(~FLAGS_CF), 8(%bp)
102         pop %bp
103 .endm
105 .macro stc_stack
106         push %bp
107         /* 8 = 2 (bp, just pushed) + 2 (ip) + 3 (real mode interrupt frame) */
108         or $(FLAGS_CF), 8(%bp)
109         pop %bp
110 .endm
112 /* we clobber %bx */
113 .macro alloca size
114         push %ds
115         push %bp
116         mov %sp, %bp  /* remember the current stack position */
118         mov %ss, %bx
119         mov %bx, %ds
121         sub \size, %sp
122         and $(~0x0F), %sp
123         mov %sp, %bx
125         push %bp
126         mov 0(%bp), %bp
127 .endm
129 /* we clobber %bp */
130 .macro allocbpa size
131         mov %sp, %bp  /* remember the current stack position */
132         sub \size, %sp
133         and $(~0x0F), %sp
134         push %bp
135         mov %sp, %bp
136         add $2, %bp
137 .endm
139 .macro freea
140         pop %sp
141         add $2, %sp
142         pop %ds
143 .endm
145 .macro freebpa
146         pop %sp
147 .endm
149 .macro dump reg
150         push %ax
151         push %dx
153         mov \reg, %ax
154         mov $0x406, %dx
155         outw %ax, %dx
157         pop %dx
158         pop %ax
159 .endm
161 .macro callout value
162         push %bp
163         push %bx
164         mov %sp, %bp
165         alloca $16
166         push %ax
167         push %dx
169         mov %ax, 0(%bx)     /* ax */
170         mov 0(%bp), %ax     /* bx */
171         mov %ax, 2(%bx)
172         mov %cx, 4(%bx)     /* cx */
173         mov %dx, 6(%bx)     /* dx */
174         mov %si, 8(%bx)     /* si */
175         mov %ds, 10(%bx)    /* ds */
176         mov %es, 12(%bx)    /* ds */
177         movw \value, 14(%bx) /* value */
179         mov %bx, %ax
180         shr $4, %ax
181         mov %ds, %dx
182         add %dx, %ax
184         mov $0x407, %dx
185         outw %ax, %dx
187         pop %dx
188         pop %ax
189         freea
190         pop %bx
191         pop %bp
192 .endm
194 send_command:
195         push %bp
196         mov %sp, %bp
197         push %ax
198         push %bx
199         push %dx
201         mov 4(%bp), %ax
202         shr $4, %ax
203         and $0x0FFF, %ax
204         mov %ss, %bx
205         add %bx, %ax
207         mov $0x405, %dx
208         outw %ax, %dx
210         pop %dx
211         pop %bx
212         pop %ax
213         pop %bp
215         push %ax
216         mov 2(%bx), %ax
217         pop %ax
219         ret
221 add32:  /* lo, hi, lo, hi */
222         push %bp
223         mov %sp, %bp
225         movw 4(%bp), %cx  /* hi */
226         movw 6(%bp), %dx  /* lo */
228         add  10(%bp), %dx
229         jnc 1f
230         add $1, %cx
231 1:      add 8(%bp), %cx
233         pop %bp
234         ret
236 mul32:  /* lo,      hi,     lo,     hi */
237         /* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
238         push %bp
239         mov %sp, %bp
240         push %ax
241         push %bx
243         xor %cx, %cx
244         xor %dx, %dx
246         /* for (i = 0; i < 16;) */
247         xor %bx, %bx
249         cmp $16, %bx
250         jge 2f
252         mov 6(%bp), %ax
253         and $1, %ax
254         cmp $1, %ax
255         jne 1f
256         push 10(%bp)
257         push 8(%bp)
258         push %dx
259         push %cx
260         call add32
261         add $8, %sp
263         shlw $1, 8(%bp)
264         movw 10(%bp), %ax
265         and $0x8000, %ax
266         cmp $0x8000, %ax
267         jne 1f
268         orw $1, 8(%bp)
270         shlw $1, 10(%bp)
271         shrw $1, 6(%bp)
273         /* i++) { */
274         add $1, %bx
275         jmp 0b
278         pop %bx
279         pop %ax
280         pop %bp
281         ret
283 disk_reset:
284         movb $0, %ah
285         clc_stack
286         ret
288 /* this really should be a function, not a macro but i'm lazy */
289 .macro read_write_disk_sectors cmd
290         push %ax
291         push %bx
292         push %cx
293         push %dx
294         push %si
296         push %bp
297         sub $10, %sp
298         mov %sp, %bp
300         /* save nb_sectors */
301         mov %al, 6(%bp)
302         movb $0, 7(%bp)
304         /* save buffer */
305         mov %bx, 8(%bp)
307         /* cylinders */
308         xor %ax, %ax
309         mov %cl, %al
310         shl $2, %ax
311         and $0x300, %ax
312         mov %ch, %al
313         mov %ax, 0(%bp)
315         /* heads */
316         xor %ax, %ax
317         mov %dh, %al
318         mov %ax, 2(%bp)
320         /* sectors - 1 */
321         xor %ax, %ax
322         mov %cl, %al
323         and $0x3F, %al
324         sub $1, %ax
325         mov %ax, 4(%bp)
327         alloca $16
329         movw $0, 0(%bx) /* read c,h,s */
330         push %bx
331         call send_command
332         add $2, %sp
334         mov 6(%bx), %ax /* total_sectors */
335         mov 2(%bp), %si /* *= heads */
336         mul %si
337         add 4(%bp), %ax /* += sectors - 1 */
339         push 4(%bx) /* total_heads */
340         push $0
341         push 6(%bx) /* total_sectors */
342         push $0
343         call mul32
344         add $8, %sp
346         push 0(%bp) /* cylinders */
347         push $0
348         push %dx
349         push %cx
350         call mul32
351         add $8, %sp
353         add %ax, %dx
354         jnc 1f
355         add $1, %cx
357         freea
359         alloca $16
361         movw \cmd, 0(%bx) /* read */
362         movw 6(%bp), %ax /* nb_sectors */
363         movw %ax, 2(%bx)
364         movw %es, 4(%bx) /* segment */
365         movw 8(%bp), %ax /* offset */
366         mov %ax, 6(%bx)
367         movw %dx, 8(%bx) /* sector */
368         movw %cx, 10(%bx)
369         movw $0, 12(%bx)
370         movw $0, 14(%bx)
372         push %bx
373         call send_command
374         add $2, %sp
376         freea
378         add $10, %sp
379         pop %bp
381         pop %si
382         pop %dx
383         pop %cx
384         pop %bx
385         pop %ax
387         mov $0, %ah
388         clc_stack
389         ret
390 .endm
392 read_disk_sectors:
393         read_write_disk_sectors $0x01
395 write_disk_sectors:
396         read_write_disk_sectors $0x02
398 read_disk_drive_parameters:
399         push %bx
401         /* allocate memory for packet, pointer gets returned in bx */
402         alloca $16
404         /* issue command */
405         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
406         push %bx
407         call send_command
408         add $2, %sp
410         /* normalize sector value */
411         movb 6(%bx), %cl
412         andb $0x3F, %cl
413         movb %cl, 6(%bx)
415         /* normalize cylinders */
416         subw $2, 2(%bx)
418         /* normalize heads */
419         subw $1, 4(%bx)
421         /* return code */
422         mov $0, %ah
424         /* cylinders */
425         movb 2(%bx), %ch
426         movb 3(%bx), %cl
427         shlb $6, %cl
428         andb $0xC0, %cl
430         /* sectors */
431         orb 6(%bx), %cl
433         /* heads */
434         movb 4(%bx), %dh
436         /* drives */
437         movb $1, %dl
439         /* status */
440         mov $0, %ah
442         freea
444         pop %bx
446         /* do this last since it's the most sensitive */
447         clc_stack
448         ret
450 alternate_disk_reset:
451         movb $0, %ah
452         clc_stack
453         ret
455 read_disk_drive_size:
456         push %bx
457         alloca $16
459         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
460         push %bx
461         call send_command
462         add $2, %sp
464         /* cylinders - 1 to cx:dx */
465         mov 2(%bx), %dx
466         xor %cx, %cx
467         sub $1, %dx
469         /* heads */
470         push 4(%bx)
471         push $0
472         push %dx
473         push %cx
474         call mul32
475         add $8, %sp
477         /* sectors */
478         push 6(%bx)
479         push $0
480         push %dx
481         push %cx
482         call mul32
483         add $8, %sp
485         /* status */
486         mov $3, %ah
488         freea
489         pop %bx
491         clc_stack
492         ret
494 check_if_extensions_present:
495         mov $0x30, %ah
496         mov $0xAA55, %bx
497         mov $0x07, %cx
498         clc_stack
499         ret
501 .macro extended_read_write_sectors cmd
502         cmpb $10, 0(%si)
503         jg 1f
504         mov $1, %ah
505         stc_stack
506         ret
508         push %ax
509         push %bp
510         allocbpa $16
512         movw \cmd, 0(%bp) /* read */
513         movw 2(%si), %ax   /* nb_sectors */
514         movw %ax, 2(%bp)
515         movw 4(%si), %ax   /* offset */
516         movw %ax, 6(%bp)
517         movw 6(%si), %ax   /* segment */
518         movw %ax, 4(%bp)
519         movw 8(%si), %ax   /* block */
520         movw %ax, 8(%bp)
521         movw 10(%si), %ax
522         movw %ax, 10(%bp)
523         movw 12(%si), %ax
524         movw %ax, 12(%bp)
525         movw 14(%si), %ax
526         movw %ax, 14(%bp)
528         push %bp
529         call send_command
530         add $2, %sp
532         freebpa
533         pop %bp
534         pop %ax
536         mov $0, %ah
537         clc_stack
538         ret
539 .endm
541 extended_read_sectors:
542         extended_read_write_sectors $0x01
544 extended_write_sectors:
545         extended_read_write_sectors $0x02
547 get_extended_drive_parameters:
548         push %ax
549         push %bp
550         push %cx
551         push %dx
553         allocbpa $16
555         movw $0, 0(%bp) /* read c,h,s */
556         push %bp
557         call send_command
558         add $2, %sp
560         /* write size */
561         movw $26, 0(%si)
563         /* set flags to 2 */
564         movw $2, 2(%si)
566         /* cylinders */
567         mov 2(%bp), %ax
568         mov %ax, 4(%si)
569         xor %ax, %ax
570         mov %ax, 6(%si)
572         /* heads */
573         mov 4(%bp), %ax
574         mov %ax, 8(%si)
575         xor %ax, %ax
576         mov %ax, 10(%si)
578         /* sectors */
579         mov 6(%bp), %ax
580         mov %ax, 12(%si)
581         xor %ax, %ax
582         mov %ax, 14(%si)
584         /* set total number of sectors */
585         mov 8(%bp), %ax
586         mov %ax, 16(%si)
587         mov 10(%bp), %ax
588         mov %ax, 18(%si)
589         mov 12(%bp), %ax
590         mov %ax, 20(%si)
591         mov 14(%bp), %ax
592         mov %ax, 22(%si)
594         /* number of bytes per sector */
595         movw $512, 24(%si)
597         freebpa
599         pop %dx
600         pop %cx
601         pop %bp
602         pop %ax
604         mov $0, %ah
605         clc_stack
606         ret
608 terminate_disk_emulation:
609         mov $1, %ah
610         stc_stack
611         ret
613 int13_handler:
614         cmp $0x80, %dl
615         je 1f
617         /* write old handler as return address onto stack */
618         push %eax
619         push %eax
620         push %ds
621         push %bp
622         mov %sp, %bp
623         xor %ax, %ax
624         mov %ax, %ds
625         mov (OLD_INT13), %eax
626         mov %eax, 8(%bp)
627         pop %bp
628         pop %ds
629         pop %eax
630         lret
632         cmp $0x0, %ah
633         jne 1f
634         call disk_reset
635         iret
637         cmp $0x2, %ah
638         jne 1f
639         call read_disk_sectors
640         iret
642         cmp $0x8, %ah
643         jne 1f
644         call read_disk_drive_parameters
645         iret
647         cmp $0x15, %ah
648         jne 1f
649         call read_disk_drive_size
650         iret
652         cmp $0x41, %ah
653         jne 1f
654         call check_if_extensions_present
655         iret
657         cmp $0x42, %ah
658         jne 1f
659         call extended_read_sectors
660         iret
662         cmp $0x48, %ah
663         jne 1f
664         call get_extended_drive_parameters
665         iret
667         cmp $0x4b, %ah
668         jne 1f
669         call terminate_disk_emulation
670         iret
672         cmp $0x0d, %ah
673         jne 1f
674         call alternate_disk_reset
675         iret
677         cmp $0x03, %ah
678         jne 1f
679         call write_disk_sectors
680         iret
682         cmp $0x43, %ah
683         jne 1f
684         call extended_write_sectors
685         iret
687         int $0x18  /* boot failed */
688         iret
690 .align 512, 0
691 _end: