kvm: extboot: Update number of HDs reported by BIOS
[qemu-kvm/fedora.git] / kvm / extboot / extboot.S
blob1e60f68785a7cadd5602ca9a4157e579ddd81419
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         /* there is one more bootable HD */
36         incb 0x0475
38         /* save old int 19 */
39         mov (0x19*4), %eax
40         mov %eax, %cs:old_int19
42         /* install out int 19 handler */
43         movw $int19_handler, (0x19*4)
44         mov %cs, (0x19*4+2)
46         pop %ds
47         pop %eax
48         lret
50 int19_handler:
51         push %eax
52         push %bx
53         push %cx
54         push %dx
55         push %ds
57         /* setup ds to access IVT */
58         xor %ax, %ax
59         mov %ax, %ds
61         movw $0x404, %dx
62         inb %dx, %al
63         cmp $1, %al
64         je 1f
65         cmp $2, %al
66         je 2f
67         jmp 3f
69 1: /* hook int13: intb(0x404) == 1 */
70         /* save old int 13 to int 2c */
71         mov (0x13*4), %eax
72         mov %eax, %cs:old_int13
74         /* install our int 13 handler */
75         movw $int13_handler, (0x13*4)
76         mov %cs, (0x13*4+2)
77         jmp 3f
79 2: /* linux boot: intb(0x404) == 2 */
80         cli
81         cld
82         mov $0x9000, %ax
83         mov %ax, %ds
84         mov %ax, %es
85         mov %ax, %fs
86         mov %ax, %gs
87         mov %ax, %ss
88         mov $0x8ffe, %sp
89         ljmp $0x9000 + 0x20, $0
91 3: /* fall through: inb(0x404) == 0 */
92         /* restore previous int $0x19 handler */
93         mov %cs:old_int19,%eax
94         mov %eax,(0x19*4)
95         
96         pop %ds
97         pop %dx
98         pop %cx
99         pop %bx
100         pop %eax
101         ljmpw *%cs:old_int19
103 #define FLAGS_CF        0x01
105 /* The two macro below clear/set the carry flag to indicate the status
106  * of the interrupt execution. It is not enough to issue a clc/stc instruction,
107  * since the value of the flags register will be overwritten by whatever is
108  * in the stack frame
109  */
110 .macro clc_stack
111         push %bp
112         mov %sp, %bp
113         /* 8 = 2 (bp, just pushed) + 2 (ip) + 3 (real mode interrupt frame) */
114         and $(~FLAGS_CF), 8(%bp)
115         pop %bp
116 .endm
118 .macro stc_stack
119         push %bp
120         /* 8 = 2 (bp, just pushed) + 2 (ip) + 3 (real mode interrupt frame) */
121         or $(FLAGS_CF), 8(%bp)
122         pop %bp
123 .endm
125 /* we clobber %bx */
126 .macro alloca size
127         push %ds
128         push %bp
129         mov %sp, %bp  /* remember the current stack position */
131         mov %ss, %bx
132         mov %bx, %ds
134         sub \size, %sp
135         and $(~0x0F), %sp
136         mov %sp, %bx
138         push %bp
139         mov 0(%bp), %bp
140 .endm
142 /* we clobber %bp */
143 .macro allocbpa size
144         mov %sp, %bp  /* remember the current stack position */
145         sub \size, %sp
146         and $(~0x0F), %sp
147         push %bp
148         mov %sp, %bp
149         add $2, %bp
150 .endm
152 .macro freea
153         pop %sp
154         add $2, %sp
155         pop %ds
156 .endm
158 .macro freebpa
159         pop %sp
160 .endm
162 .macro dump reg
163         push %ax
164         push %dx
166         mov \reg, %ax
167         mov $0x406, %dx
168         outw %ax, %dx
170         pop %dx
171         pop %ax
172 .endm
174 .macro callout value
175         push %bp
176         push %bx
177         mov %sp, %bp
178         alloca $16
179         push %ax
180         push %dx
182         mov %ax, 0(%bx)     /* ax */
183         mov 0(%bp), %ax     /* bx */
184         mov %ax, 2(%bx)
185         mov %cx, 4(%bx)     /* cx */
186         mov %dx, 6(%bx)     /* dx */
187         mov %si, 8(%bx)     /* si */
188         mov %ds, 10(%bx)    /* ds */
189         mov %es, 12(%bx)    /* ds */
190         movw \value, 14(%bx) /* value */
192         mov %bx, %ax
193         shr $4, %ax
194         mov %ds, %dx
195         add %dx, %ax
197         mov $0x407, %dx
198         outw %ax, %dx
200         pop %dx
201         pop %ax
202         freea
203         pop %bx
204         pop %bp
205 .endm
207 send_command:
208         push %bp
209         mov %sp, %bp
210         push %ax
211         push %bx
212         push %dx
214         mov 4(%bp), %ax
215         shr $4, %ax
216         and $0x0FFF, %ax
217         mov %ss, %bx
218         add %bx, %ax
220         mov $0x405, %dx
221         outw %ax, %dx
223         pop %dx
224         pop %bx
225         pop %ax
226         pop %bp
228         push %ax
229         mov 2(%bx), %ax
230         pop %ax
232         ret
234 add32:  /* lo, hi, lo, hi */
235         push %bp
236         mov %sp, %bp
238         movw 4(%bp), %cx  /* hi */
239         movw 6(%bp), %dx  /* lo */
241         add  10(%bp), %dx
242         jnc 1f
243         add $1, %cx
244 1:      add 8(%bp), %cx
246         pop %bp
247         ret
249 mul32:  /* lo,      hi,     lo,     hi */
250         /* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
251         push %bp
252         mov %sp, %bp
253         push %ax
254         push %bx
256         xor %cx, %cx
257         xor %dx, %dx
259         /* for (i = 0; i < 16;) */
260         xor %bx, %bx
262         cmp $16, %bx
263         jge 2f
265         mov 6(%bp), %ax
266         and $1, %ax
267         cmp $1, %ax
268         jne 1f
269         push 10(%bp)
270         push 8(%bp)
271         push %dx
272         push %cx
273         call add32
274         add $8, %sp
276         shlw $1, 8(%bp)
277         movw 10(%bp), %ax
278         and $0x8000, %ax
279         cmp $0x8000, %ax
280         jne 1f
281         orw $1, 8(%bp)
283         shlw $1, 10(%bp)
284         shrw $1, 6(%bp)
286         /* i++) { */
287         add $1, %bx
288         jmp 0b
291         pop %bx
292         pop %ax
293         pop %bp
294         ret
296 disk_reset:
297         movb $0, %ah
298         clc_stack
299         ret
301 /* this really should be a function, not a macro but i'm lazy */
302 .macro read_write_disk_sectors cmd
303         push %ax
304         push %bx
305         push %cx
306         push %dx
307         push %si
309         push %bp
310         sub $10, %sp
311         mov %sp, %bp
313         /* save nb_sectors */
314         mov %al, 6(%bp)
315         movb $0, 7(%bp)
317         /* save buffer */
318         mov %bx, 8(%bp)
320         /* cylinders */
321         xor %ax, %ax
322         mov %cl, %al
323         shl $2, %ax
324         and $0x300, %ax
325         mov %ch, %al
326         mov %ax, 0(%bp)
328         /* heads */
329         xor %ax, %ax
330         mov %dh, %al
331         mov %ax, 2(%bp)
333         /* sectors - 1 */
334         xor %ax, %ax
335         mov %cl, %al
336         and $0x3F, %al
337         sub $1, %ax
338         mov %ax, 4(%bp)
340         alloca $16
342         movw $0, 0(%bx) /* read c,h,s */
343         push %bx
344         call send_command
345         add $2, %sp
347         mov 6(%bx), %ax /* total_sectors */
348         mov 2(%bp), %si /* *= heads */
349         mul %si
350         add 4(%bp), %ax /* += sectors - 1 */
352         push 4(%bx) /* total_heads */
353         push $0
354         push 6(%bx) /* total_sectors */
355         push $0
356         call mul32
357         add $8, %sp
359         push 0(%bp) /* cylinders */
360         push $0
361         push %dx
362         push %cx
363         call mul32
364         add $8, %sp
366         add %ax, %dx
367         jnc 1f
368         add $1, %cx
370         freea
372         alloca $16
374         movw \cmd, 0(%bx) /* read */
375         movw 6(%bp), %ax /* nb_sectors */
376         movw %ax, 2(%bx)
377         movw %es, 4(%bx) /* segment */
378         movw 8(%bp), %ax /* offset */
379         mov %ax, 6(%bx)
380         movw %dx, 8(%bx) /* sector */
381         movw %cx, 10(%bx)
382         movw $0, 12(%bx)
383         movw $0, 14(%bx)
385         push %bx
386         call send_command
387         add $2, %sp
389         freea
391         add $10, %sp
392         pop %bp
394         pop %si
395         pop %dx
396         pop %cx
397         pop %bx
398         pop %ax
400         mov $0, %ah
401         clc_stack
402         ret
403 .endm
405 read_disk_sectors:
406         read_write_disk_sectors $0x01
408 write_disk_sectors:
409         read_write_disk_sectors $0x02
411 read_disk_drive_parameters:
412         push %bx
414         /* allocate memory for packet, pointer gets returned in bx */
415         alloca $16
417         /* issue command */
418         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
419         push %bx
420         call send_command
421         add $2, %sp
423         /* normalize sector value */
424         movb 6(%bx), %cl
425         andb $0x3F, %cl
426         movb %cl, 6(%bx)
428         /* normalize cylinders */
429         subw $2, 2(%bx)
431         /* normalize heads */
432         subw $1, 4(%bx)
434         /* return code */
435         mov $0, %ah
437         /* cylinders */
438         movb 2(%bx), %ch
439         movb 3(%bx), %cl
440         shlb $6, %cl
441         andb $0xC0, %cl
443         /* sectors */
444         orb 6(%bx), %cl
446         /* heads */
447         movb 4(%bx), %dh
449         /* drives */
450         movb $1, %dl
452         /* status */
453         mov $0, %ah
455         freea
457         pop %bx
459         /* do this last since it's the most sensitive */
460         clc_stack
461         ret
463 alternate_disk_reset:
464         movb $0, %ah
465         clc_stack
466         ret
468 read_disk_drive_size:
469         push %bx
470         alloca $16
472         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
473         push %bx
474         call send_command
475         add $2, %sp
477         /* cylinders - 1 to cx:dx */
478         mov 2(%bx), %dx
479         xor %cx, %cx
480         sub $1, %dx
482         /* heads */
483         push 4(%bx)
484         push $0
485         push %dx
486         push %cx
487         call mul32
488         add $8, %sp
490         /* sectors */
491         push 6(%bx)
492         push $0
493         push %dx
494         push %cx
495         call mul32
496         add $8, %sp
498         /* status */
499         mov $3, %ah
501         freea
502         pop %bx
504         clc_stack
505         ret
507 check_if_extensions_present:
508         mov $0x30, %ah
509         mov $0xAA55, %bx
510         mov $0x07, %cx
511         clc_stack
512         ret
514 .macro extended_read_write_sectors cmd
515         cmpb $10, 0(%si)
516         jg 1f
517         mov $1, %ah
518         stc_stack
519         ret
521         push %ax
522         push %bp
523         allocbpa $16
525         movw \cmd, 0(%bp) /* read */
526         movw 2(%si), %ax   /* nb_sectors */
527         movw %ax, 2(%bp)
528         movw 4(%si), %ax   /* offset */
529         movw %ax, 6(%bp)
530         movw 6(%si), %ax   /* segment */
531         movw %ax, 4(%bp)
532         movw 8(%si), %ax   /* block */
533         movw %ax, 8(%bp)
534         movw 10(%si), %ax
535         movw %ax, 10(%bp)
536         movw 12(%si), %ax
537         movw %ax, 12(%bp)
538         movw 14(%si), %ax
539         movw %ax, 14(%bp)
541         push %bp
542         call send_command
543         add $2, %sp
545         freebpa
546         pop %bp
547         pop %ax
549         mov $0, %ah
550         clc_stack
551         ret
552 .endm
554 extended_read_sectors:
555         extended_read_write_sectors $0x01
557 extended_write_sectors:
558         extended_read_write_sectors $0x02
560 get_extended_drive_parameters:
561         push %ax
562         push %bp
563         push %cx
564         push %dx
566         allocbpa $16
568         movw $0, 0(%bp) /* read c,h,s */
569         push %bp
570         call send_command
571         add $2, %sp
573         /* write size */
574         movw $26, 0(%si)
576         /* set flags to 2 */
577         movw $2, 2(%si)
579         /* cylinders */
580         mov 2(%bp), %ax
581         mov %ax, 4(%si)
582         xor %ax, %ax
583         mov %ax, 6(%si)
585         /* heads */
586         mov 4(%bp), %ax
587         mov %ax, 8(%si)
588         xor %ax, %ax
589         mov %ax, 10(%si)
591         /* sectors */
592         mov 6(%bp), %ax
593         mov %ax, 12(%si)
594         xor %ax, %ax
595         mov %ax, 14(%si)
597         /* set total number of sectors */
598         mov 8(%bp), %ax
599         mov %ax, 16(%si)
600         mov 10(%bp), %ax
601         mov %ax, 18(%si)
602         mov 12(%bp), %ax
603         mov %ax, 20(%si)
604         mov 14(%bp), %ax
605         mov %ax, 22(%si)
607         /* number of bytes per sector */
608         movw $512, 24(%si)
610         freebpa
612         pop %dx
613         pop %cx
614         pop %bp
615         pop %ax
617         mov $0, %ah
618         clc_stack
619         ret
621 terminate_disk_emulation:
622         mov $1, %ah
623         stc_stack
624         ret
626 int13_handler:
627         cmp $0x80, %dl
628         je 1f
629         ljmpw *%cs:old_int13
631         cmp $0x0, %ah
632         jne 1f
633         call disk_reset
634         iret
636         cmp $0x2, %ah
637         jne 1f
638         call read_disk_sectors
639         iret
641         cmp $0x8, %ah
642         jne 1f
643         call read_disk_drive_parameters
644         iret
646         cmp $0x15, %ah
647         jne 1f
648         call read_disk_drive_size
649         iret
651         cmp $0x41, %ah
652         jne 1f
653         call check_if_extensions_present
654         iret
656         cmp $0x42, %ah
657         jne 1f
658         call extended_read_sectors
659         iret
661         cmp $0x48, %ah
662         jne 1f
663         call get_extended_drive_parameters
664         iret
666         cmp $0x4b, %ah
667         jne 1f
668         call terminate_disk_emulation
669         iret
671         cmp $0x0d, %ah
672         jne 1f
673         call alternate_disk_reset
674         iret
676         cmp $0x03, %ah
677         jne 1f
678         call write_disk_sectors
679         iret
681         cmp $0x43, %ah
682         jne 1f
683         call extended_write_sectors
684         iret
686         int $0x18  /* boot failed */
687         iret
689 /* Variables */
690 .align 4, 0
691 old_int13:      .long 0
692 old_int19:      .long 0
693         
694 .align 512, 0
695 _end: