Device-assignment: free device if hotplug fails
[qemu-kvm/fedora.git] / kvm / extboot / extboot.S
blob2630abb4a43678d30e39a966f9ac9ddc74113a2e
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 .code16
23 .text
24         .global _start
25 _start:
26         .short 0xaa55
27         .byte (_end - _start) / 512
28         push %eax
29         push %ds
31         /* setup ds so we can access the IVT */
32         xor %ax, %ax
33         mov %ax, %ds
35         /* save old int 19 */
36         mov (0x19*4), %eax
37         mov %eax, %cs:old_int19
39         /* install out int 19 handler */
40         movw $int19_handler, (0x19*4)
41         mov %cs, (0x19*4+2)
43         pop %ds
44         pop %eax
45         lret
47 int19_handler:
48         push %eax
49         push %bx
50         push %cx
51         push %dx
52         push %ds
54         /* setup ds to access IVT */
55         xor %ax, %ax
56         mov %ax, %ds
58         movw $0x404, %dx
59         inb %dx, %al
60         cmp $1, %al
61         je 1f
62         cmp $2, %al
63         je 2f
64         jmp 3f
66 1: /* hook int13: intb(0x404) == 1 */
67         /* save old int 13 to int 2c */
68         mov (0x13*4), %eax
69         mov %eax, %cs:old_int13
71         /* install our int 13 handler */
72         movw $int13_handler, (0x13*4)
73         mov %cs, (0x13*4+2)
74         jmp 3f
76 2: /* linux boot: intb(0x404) == 2 */
77         cli
78         cld
79         mov $0x9000, %ax
80         mov %ax, %ds
81         mov %ax, %es
82         mov %ax, %fs
83         mov %ax, %gs
84         mov %ax, %ss
85         mov $0x8ffe, %sp
86         ljmp $0x9000 + 0x20, $0
88 3: /* fall through: inb(0x404) == 0 */
89         /* restore previous int $0x19 handler */
90         mov %cs:old_int19,%eax
91         mov %eax,(0x19*4)
92         
93         pop %ds
94         pop %dx
95         pop %cx
96         pop %bx
97         pop %eax
98         ljmpw *%cs:old_int19
100 #define FLAGS_CF        0x01
102 .macro clc
103         push %ax
104         pushf
105         pop %ax
106         and $(~FLAGS_CF), %ax
107         push %ax
108         popf
109         pop %ax
110 .endm
112 .macro stc
113         push %ax
114         pushf
115         pop %ax
116         or $(FLAGS_CF), %ax
117         push %ax
118         popf
119         pop %ax
120 .endm
122 /* we clobber %bx */
123 .macro alloca size
124         push %ds
125         push %bp
126         mov %sp, %bp  /* remember the current stack position */
128         mov %ss, %bx
129         mov %bx, %ds
131         sub \size, %sp
132         and $(~0x0F), %sp
133         mov %sp, %bx
135         push %bp
136         mov 0(%bp), %bp
137 .endm
139 /* we clobber %bp */
140 .macro allocbpa size
141         mov %sp, %bp  /* remember the current stack position */
142         sub \size, %sp
143         and $(~0x0F), %sp
144         push %bp
145         mov %sp, %bp
146         add $2, %bp
147 .endm
149 .macro freea
150         pop %sp
151         add $2, %sp
152         pop %ds
153 .endm
155 .macro freebpa
156         pop %sp
157 .endm
159 .macro dump reg
160         push %ax
161         push %dx
163         mov \reg, %ax
164         mov $0x406, %dx
165         outw %ax, %dx
167         pop %dx
168         pop %ax
169 .endm
171 .macro callout value
172         push %bp
173         push %bx
174         mov %sp, %bp
175         alloca $16
176         push %ax
177         push %dx
179         mov %ax, 0(%bx)     /* ax */
180         mov 0(%bp), %ax     /* bx */
181         mov %ax, 2(%bx)
182         mov %cx, 4(%bx)     /* cx */
183         mov %dx, 6(%bx)     /* dx */
184         mov %si, 8(%bx)     /* si */
185         mov %ds, 10(%bx)    /* ds */
186         mov %es, 12(%bx)    /* ds */
187         movw \value, 14(%bx) /* value */
189         mov %bx, %ax
190         shr $4, %ax
191         mov %ds, %dx
192         add %dx, %ax
194         mov $0x407, %dx
195         outw %ax, %dx
197         pop %dx
198         pop %ax
199         freea
200         pop %bx
201         pop %bp
202 .endm
204 send_command:
205         push %bp
206         mov %sp, %bp
207         push %ax
208         push %bx
209         push %dx
211         mov 4(%bp), %ax
212         shr $4, %ax
213         and $0x0FFF, %ax
214         mov %ss, %bx
215         add %bx, %ax
217         mov $0x405, %dx
218         outw %ax, %dx
220         pop %dx
221         pop %bx
222         pop %ax
223         pop %bp
225         push %ax
226         mov 2(%bx), %ax
227         pop %ax
229         ret
231 add32:  /* lo, hi, lo, hi */
232         push %bp
233         mov %sp, %bp
235         movw 4(%bp), %cx  /* hi */
236         movw 6(%bp), %dx  /* lo */
238         add  10(%bp), %dx
239         jnc 1f
240         add $1, %cx
241 1:      add 8(%bp), %cx
243         pop %bp
244         ret
246 mul32:  /* lo,      hi,     lo,     hi */
247         /* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
248         push %bp
249         mov %sp, %bp
250         push %ax
251         push %bx
253         xor %cx, %cx
254         xor %dx, %dx
256         /* for (i = 0; i < 16;) */
257         xor %bx, %bx
259         cmp $16, %bx
260         jge 2f
262         mov 6(%bp), %ax
263         and $1, %ax
264         cmp $1, %ax
265         jne 1f
266         push 10(%bp)
267         push 8(%bp)
268         push %dx
269         push %cx
270         call add32
271         add $8, %sp
273         shlw $1, 8(%bp)
274         movw 10(%bp), %ax
275         and $0x8000, %ax
276         cmp $0x8000, %ax
277         jne 1f
278         orw $1, 8(%bp)
280         shlw $1, 10(%bp)
281         shrw $1, 6(%bp)
283         /* i++) { */
284         add $1, %bx
285         jmp 0b
288         pop %bx
289         pop %ax
290         pop %bp
291         ret
293 disk_reset:
294         movb $0, %ah
295         clc
296         ret
298 /* this really should be a function, not a macro but i'm lazy */
299 .macro read_write_disk_sectors cmd
300         push %ax
301         push %bx
302         push %cx
303         push %dx
304         push %si
306         push %bp
307         sub $10, %sp
308         mov %sp, %bp
310         /* save nb_sectors */
311         mov %al, 6(%bp)
312         movb $0, 7(%bp)
314         /* save buffer */
315         mov %bx, 8(%bp)
317         /* cylinders */
318         xor %ax, %ax
319         mov %cl, %al
320         shl $2, %ax
321         and $0x300, %ax
322         mov %ch, %al
323         mov %ax, 0(%bp)
325         /* heads */
326         xor %ax, %ax
327         mov %dh, %al
328         mov %ax, 2(%bp)
330         /* sectors - 1 */
331         xor %ax, %ax
332         mov %cl, %al
333         and $0x3F, %al
334         sub $1, %ax
335         mov %ax, 4(%bp)
337         alloca $16
339         movw $0, 0(%bx) /* read c,h,s */
340         push %bx
341         call send_command
342         add $2, %sp
344         mov 6(%bx), %ax /* total_sectors */
345         mov 2(%bp), %si /* *= heads */
346         mul %si
347         add 4(%bp), %ax /* += sectors - 1 */
349         push 4(%bx) /* total_heads */
350         push $0
351         push 6(%bx) /* total_sectors */
352         push $0
353         call mul32
354         add $8, %sp
356         push 0(%bp) /* cylinders */
357         push $0
358         push %dx
359         push %cx
360         call mul32
361         add $8, %sp
363         add %ax, %dx
364         jnc 1f
365         add $1, %cx
367         freea
369         alloca $16
371         movw \cmd, 0(%bx) /* read */
372         movw 6(%bp), %ax /* nb_sectors */
373         movw %ax, 2(%bx)
374         movw %es, 4(%bx) /* segment */
375         movw 8(%bp), %ax /* offset */
376         mov %ax, 6(%bx)
377         movw %dx, 8(%bx) /* sector */
378         movw %cx, 10(%bx)
379         movw $0, 12(%bx)
380         movw $0, 14(%bx)
382         push %bx
383         call send_command
384         add $2, %sp
386         freea
388         add $10, %sp
389         pop %bp
391         pop %si
392         pop %dx
393         pop %cx
394         pop %bx
395         pop %ax
397         mov $0, %ah
398         clc
399         ret
400 .endm
402 read_disk_sectors:
403         read_write_disk_sectors $0x01
405 write_disk_sectors:
406         read_write_disk_sectors $0x02
408 read_disk_drive_parameters:
409         push %bx
411         /* allocate memory for packet, pointer gets returned in bx */
412         alloca $16
414         /* issue command */
415         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
416         push %bx
417         call send_command
418         add $2, %sp
420         /* normalize sector value */
421         movb 6(%bx), %cl
422         andb $0x3F, %cl
423         movb %cl, 6(%bx)
425         /* normalize cylinders */
426         subw $2, 2(%bx)
428         /* normalize heads */
429         subw $1, 4(%bx)
431         /* return code */
432         mov $0, %ah
434         /* cylinders */
435         movb 2(%bx), %ch
436         movb 3(%bx), %cl
437         shlb $6, %cl
438         andb $0xC0, %cl
440         /* sectors */
441         orb 6(%bx), %cl
443         /* heads */
444         movb 4(%bx), %dh
446         /* drives */
447         movb $1, %dl
449         /* status */
450         mov $0, %ah
452         freea
454         pop %bx
456         /* do this last since it's the most sensitive */
457         clc
458         ret
460 alternate_disk_reset:
461         movb $0, %ah
462         clc
463         ret
465 read_disk_drive_size:
466         push %bx
467         alloca $16
469         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
470         push %bx
471         call send_command
472         add $2, %sp
474         /* cylinders - 1 to cx:dx */
475         mov 2(%bx), %dx
476         xor %cx, %cx
477         sub $1, %dx
479         /* heads */
480         push 4(%bx)
481         push $0
482         push %dx
483         push %cx
484         call mul32
485         add $8, %sp
487         /* sectors */
488         push 6(%bx)
489         push $0
490         push %dx
491         push %cx
492         call mul32
493         add $8, %sp
495         /* status */
496         mov $3, %ah
498         freea
499         pop %bx
501         clc
502         ret
504 check_if_extensions_present:
505         mov $0x30, %ah
506         mov $0xAA55, %bx
507         mov $0x07, %cx
508         clc
509         ret
511 .macro extended_read_write_sectors cmd
512         cmpb $10, 0(%si)
513         jg 1f
514         mov $1, %ah
515         stc
516         ret
518         push %ax
519         push %bp
520         allocbpa $16
522         movw \cmd, 0(%bp) /* read */
523         movw 2(%si), %ax   /* nb_sectors */
524         movw %ax, 2(%bp)
525         movw 4(%si), %ax   /* offset */
526         movw %ax, 6(%bp)
527         movw 6(%si), %ax   /* segment */
528         movw %ax, 4(%bp)
529         movw 8(%si), %ax   /* block */
530         movw %ax, 8(%bp)
531         movw 10(%si), %ax
532         movw %ax, 10(%bp)
533         movw 12(%si), %ax
534         movw %ax, 12(%bp)
535         movw 14(%si), %ax
536         movw %ax, 14(%bp)
538         push %bp
539         call send_command
540         add $2, %sp
542         freebpa
543         pop %bp
544         pop %ax
546         mov $0, %ah
547         clc
548         ret
549 .endm
551 extended_read_sectors:
552         extended_read_write_sectors $0x01
554 extended_write_sectors:
555         extended_read_write_sectors $0x02
557 get_extended_drive_parameters:
558         push %ax
559         push %bp
560         push %cx
561         push %dx
563         allocbpa $16
565         movw $0, 0(%bp) /* read c,h,s */
566         push %bp
567         call send_command
568         add $2, %sp
570         /* write size */
571         movw $26, 0(%si)
573         /* set flags to 2 */
574         movw $2, 2(%si)
576         /* cylinders */
577         mov 2(%bp), %ax
578         mov %ax, 4(%si)
579         xor %ax, %ax
580         mov %ax, 6(%si)
582         /* heads */
583         mov 4(%bp), %ax
584         mov %ax, 8(%si)
585         xor %ax, %ax
586         mov %ax, 10(%si)
588         /* sectors */
589         mov 6(%bp), %ax
590         mov %ax, 12(%si)
591         xor %ax, %ax
592         mov %ax, 14(%si)
594         /* set total number of sectors */
595         mov 8(%bp), %ax
596         mov %ax, 16(%si)
597         mov 10(%bp), %ax
598         mov %ax, 18(%si)
599         mov 12(%bp), %ax
600         mov %ax, 20(%si)
601         mov 14(%bp), %ax
602         mov %ax, 22(%si)
604         /* number of bytes per sector */
605         movw $512, 24(%si)
607         freebpa
609         pop %dx
610         pop %cx
611         pop %bp
612         pop %ax
614         mov $0, %ah
615         clc
616         ret
618 terminate_disk_emulation:
619         mov $1, %ah
620         stc
621         ret
623 int13_handler:
624         cmp $0x80, %dl
625         je 1f
626         ljmpw *%cs:old_int13
628         cmp $0x0, %ah
629         jne 1f
630         call disk_reset
631         iret
633         cmp $0x2, %ah
634         jne 1f
635         call read_disk_sectors
636         iret
638         cmp $0x8, %ah
639         jne 1f
640         call read_disk_drive_parameters
641         iret
643         cmp $0x15, %ah
644         jne 1f
645         call read_disk_drive_size
646         iret
648         cmp $0x41, %ah
649         jne 1f
650         call check_if_extensions_present
651         iret
653         cmp $0x42, %ah
654         jne 1f
655         call extended_read_sectors
656         iret
658         cmp $0x48, %ah
659         jne 1f
660         call get_extended_drive_parameters
661         iret
663         cmp $0x4b, %ah
664         jne 1f
665         call terminate_disk_emulation
666         iret
668         cmp $0x0d, %ah
669         jne 1f
670         call alternate_disk_reset
671         iret
673         cmp $0x03, %ah
674         jne 1f
675         call write_disk_sectors
676         iret
678         cmp $0x43, %ah
679         jne 1f
680         call extended_write_sectors
681         iret
683         int $0x18  /* boot failed */
684         iret
686 /* Variables */
687 .align 4, 0
688 old_int13:      .long 0
689 old_int19:      .long 0
690         
691 .align 512, 0
692 _end: