kvm: qemu: ftruncate() is not supported by hugetlbfs on older hosts
[kvm-userspace.git] / extboot / extboot.S
blob9eb933383421d1ea2058e4b84bcb8c21e842d69a
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 %ax
29         push %bx
30         push %cx
31         push %dx
32         push %ds
34         /* setup ds so we can access the IVT */
35         xor %ax, %ax
36         mov %ax, %ds
38         /* save old int 19 at int 2b */
39         mov $(0x19 * 4), %bx
40         mov 0(%bx), %ax
41         mov 2(%bx), %cx
43         mov $(0x2b * 4), %bx
44         mov %ax, 0(%bx)
45         mov %cx, 2(%bx)
47         /* install out int 19 handler */
48         mov $(0x19 * 4), %bx
49         mov $int19_handler, %ax
50         mov %ax, 0(%bx)
51         mov %cs, 2(%bx)
53         pop %ds
54         pop %dx
55         pop %cx
56         pop %bx
57         pop %ax
58         lret
60 int19_handler:
61         push %ax
62         push %bx
63         push %cx
64         push %dx
65         push %ds
67         movw $0x404, %dx
68         inb %dx, %al
69         cmp $1, %al
70         je 1f
71         cmp $2, %al
72         je 2f
73         jmp 3f
75 1: /* hook int13: intb(0x404) == 1 */
76         /* setup ds to access IVT */
77         xor %ax, %ax
78         mov %ax, %ds
80         /* save old int 13 to int 2c */
81         mov $(0x13 * 4), %bx
82         mov 0(%bx), %ax
83         mov 2(%bx), %cx
85         mov $(0x2c * 4), %bx
86         mov %ax, 0(%bx)
87         mov %cx, 2(%bx)
89         /* install our int 13 handler */
90         mov $(0x13 * 4), %bx
91         mov $int13_handler, %ax
93         mov %ax, 0(%bx)
94         mov %cs, 2(%bx)
95         jmp 3f
97 2: /* linux boot: intb(0x404) == 2 */
98         cli
99         cld
100         mov $0x9000, %ax
101         mov %ax, %ds
102         mov %ax, %es
103         mov %ax, %fs
104         mov %ax, %gs
105         mov %ax, %ss
106         mov $0x8ffe, %sp
107         ljmp $0x9000 + 0x20, $0
109 3: /* fall through: inb(0x404) == 0 */
110         pop %ds
111         pop %dx
112         pop %cx
113         pop %bx
114         pop %ax
115         int $0x2b
117 #define FLAGS_CF        0x01
119 .macro clc
120         push %ax
121         pushf
122         pop %ax
123         and $(~FLAGS_CF), %ax
124         push %ax
125         popf
126         pop %ax
127 .endm
129 .macro stc
130         push %ax
131         pushf
132         pop %ax
133         or $(FLAGS_CF), %ax
134         push %ax
135         popf
136         pop %ax
137 .endm
139 /* we clobber %bx */
140 .macro alloca size
141         push %ds
142         push %bp
143         mov %sp, %bp  /* remember the current stack position */
145         mov %ss, %bx
146         mov %bx, %ds
148         sub \size, %sp
149         and $(~0x0F), %sp
150         mov %sp, %bx
152         push %bp
153         mov 0(%bp), %bp
154 .endm
156 /* we clobber %bp */
157 .macro allocbpa size
158         mov %sp, %bp  /* remember the current stack position */
159         sub \size, %sp
160         and $(~0x0F), %sp
161         push %bp
162         mov %sp, %bp
163         add $2, %bp
164 .endm
166 .macro freea
167         pop %sp
168         add $2, %sp
169         pop %ds
170 .endm
172 .macro freebpa
173         pop %sp
174 .endm
176 .macro dump reg
177         push %ax
178         push %dx
180         mov \reg, %ax
181         mov $0x406, %dx
182         outw %ax, %dx
184         pop %dx
185         pop %ax
186 .endm
188 .macro callout value
189         push %bp
190         push %bx
191         mov %sp, %bp
192         alloca $16
193         push %ax
194         push %dx
196         mov %ax, 0(%bx)     /* ax */
197         mov 0(%bp), %ax     /* bx */
198         mov %ax, 2(%bx)
199         mov %cx, 4(%bx)     /* cx */
200         mov %dx, 6(%bx)     /* dx */
201         mov %si, 8(%bx)     /* si */
202         mov %ds, 10(%bx)    /* ds */
203         mov %es, 12(%bx)    /* ds */
204         movw \value, 14(%bx) /* value */
206         mov %bx, %ax
207         shr $4, %ax
208         mov %ds, %dx
209         add %dx, %ax
211         mov $0x407, %dx
212         outw %ax, %dx
214         pop %dx
215         pop %ax
216         freea
217         pop %bx
218         pop %bp
219 .endm
221 send_command:
222         push %bp
223         mov %sp, %bp
224         push %ax
225         push %bx
226         push %dx
228         mov 4(%bp), %ax
229         shr $4, %ax
230         and $0x0FFF, %ax
231         mov %ss, %bx
232         add %bx, %ax
234         mov $0x405, %dx
235         outw %ax, %dx
237         pop %dx
238         pop %bx
239         pop %ax
240         pop %bp
242         push %ax
243         mov 2(%bx), %ax
244         pop %ax
246         ret
248 add32:  /* lo, hi, lo, hi */
249         push %bp
250         mov %sp, %bp
252         movw 4(%bp), %cx  /* hi */
253         movw 6(%bp), %dx  /* lo */
255         add  10(%bp), %dx
256         jnc 1f
257         add $1, %cx
258 1:      add 8(%bp), %cx
260         pop %bp
261         ret
263 mul32:  /* lo,      hi,     lo,     hi */
264         /* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
265         push %bp
266         mov %sp, %bp
267         push %ax
268         push %bx
270         xor %cx, %cx
271         xor %dx, %dx
273         /* for (i = 0; i < 16;) */
274         xor %bx, %bx
276         cmp $16, %bx
277         jge 2f
279         mov 6(%bp), %ax
280         and $1, %ax
281         cmp $1, %ax
282         jne 1f
283         push 10(%bp)
284         push 8(%bp)
285         push %dx
286         push %cx
287         call add32
288         add $8, %sp
290         shlw $1, 8(%bp)
291         movw 10(%bp), %ax
292         and $0x8000, %ax
293         cmp $0x8000, %ax
294         jne 1f
295         orw $1, 8(%bp)
297         shlw $1, 10(%bp)
298         shrw $1, 6(%bp)
300         /* i++) { */
301         add $1, %bx
302         jmp 0b
305         pop %bx
306         pop %ax
307         pop %bp
308         ret
310 disk_reset:
311         movb $0, %ah
312         clc
313         ret
315 /* this really should be a function, not a macro but i'm lazy */
316 .macro read_write_disk_sectors cmd
317         push %ax
318         push %bx
319         push %cx
320         push %dx
321         push %si
323         push %bp
324         sub $10, %sp
325         mov %sp, %bp
327         /* save nb_sectors */
328         mov %al, 6(%bp)
329         movb $0, 7(%bp)
331         /* save buffer */
332         mov %bx, 8(%bp)
334         /* cylinders */
335         xor %ax, %ax
336         mov %cl, %al
337         shl $2, %ax
338         and $0x300, %ax
339         mov %ch, %al
340         mov %ax, 0(%bp)
342         /* heads */
343         xor %ax, %ax
344         mov %dh, %al
345         mov %ax, 2(%bp)
347         /* sectors - 1 */
348         xor %ax, %ax
349         mov %cl, %al
350         and $0x3F, %al
351         sub $1, %ax
352         mov %ax, 4(%bp)
354         alloca $16
356         movw $0, 0(%bx) /* read c,h,s */
357         push %bx
358         call send_command
359         add $2, %sp
361         mov 6(%bx), %ax /* total_sectors */
362         mov 2(%bp), %si /* *= heads */
363         mul %si
364         add 4(%bp), %ax /* += sectors - 1 */
366         push 4(%bx) /* total_heads */
367         push $0
368         push 6(%bx) /* total_sectors */
369         push $0
370         call mul32
371         add $8, %sp
373         push 0(%bp) /* cylinders */
374         push $0
375         push %dx
376         push %cx
377         call mul32
378         add $8, %sp
380         add %ax, %dx
381         jnc 1f
382         add $1, %cx
384         freea
386         alloca $16
388         movw \cmd, 0(%bx) /* read */
389         movw 6(%bp), %ax /* nb_sectors */
390         movw %ax, 2(%bx)
391         movw %es, 4(%bx) /* segment */
392         movw 8(%bp), %ax /* offset */
393         mov %ax, 6(%bx)
394         movw %dx, 8(%bx) /* sector */
395         movw %cx, 10(%bx)
396         movw $0, 12(%bx)
397         movw $0, 14(%bx)
399         push %bx
400         call send_command
401         add $2, %sp
403         freea
405         add $10, %sp
406         pop %bp
408         pop %si
409         pop %dx
410         pop %cx
411         pop %bx
412         pop %ax
414         mov $0, %ah
415         clc
416         ret
417 .endm
419 read_disk_sectors:
420         read_write_disk_sectors $0x01
422 write_disk_sectors:
423         read_write_disk_sectors $0x02
425 read_disk_drive_parameters:
426         push %bx
428         /* allocate memory for packet, pointer gets returned in bx */
429         alloca $16
431         /* issue command */
432         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
433         push %bx
434         call send_command
435         add $2, %sp
437         /* normalize sector value */
438         movb 6(%bx), %cl
439         andb $0x3F, %cl
440         movb %cl, 6(%bx)
442         /* normalize cylinders */
443         subw $2, 2(%bx)
445         /* normalize heads */
446         subw $1, 4(%bx)
448         /* return code */
449         mov $0, %ah
451         /* cylinders */
452         movb 2(%bx), %ch
453         movb 3(%bx), %cl
454         shlb $6, %cl
455         andb $0xC0, %cl
457         /* sectors */
458         orb 6(%bx), %cl
460         /* heads */
461         movb 4(%bx), %dh
463         /* drives */
464         movb $1, %dl
466         /* status */
467         mov $0, %ah
469         freea
471         pop %bx
473         /* do this last since it's the most sensitive */
474         clc
475         ret
477 alternate_disk_reset:
478         movb $0, %ah
479         clc
480         ret
482 read_disk_drive_size:
483         push %bx
484         alloca $16
486         movw $0, 0(%bx) /* cmd = 0, read c,h,s */
487         push %bx
488         call send_command
489         add $2, %sp
491         /* cylinders - 1 to cx:dx */
492         mov 2(%bx), %dx
493         xor %cx, %cx
494         sub $1, %dx
496         /* heads */
497         push 4(%bx)
498         push $0
499         push %dx
500         push %cx
501         call mul32
502         add $8, %sp
504         /* sectors */
505         push 6(%bx)
506         push $0
507         push %dx
508         push %cx
509         call mul32
510         add $8, %sp
512         /* status */
513         mov $3, %ah
515         freea
516         pop %bx
518         clc
519         ret
521 check_if_extensions_present:
522         mov $0x30, %ah
523         mov $0xAA55, %bx
524         mov $0x07, %cx
525         clc
526         ret
528 .macro extended_read_write_sectors cmd
529         cmpb $10, 0(%si)
530         jg 1f
531         mov $1, %ah
532         stc
533         ret
535         push %ax
536         push %bp
537         allocbpa $16
539         movw \cmd, 0(%bp) /* read */
540         movw 2(%si), %ax   /* nb_sectors */
541         movw %ax, 2(%bp)
542         movw 4(%si), %ax   /* offset */
543         movw %ax, 6(%bp)
544         movw 6(%si), %ax   /* segment */
545         movw %ax, 4(%bp)
546         movw 8(%si), %ax   /* block */
547         movw %ax, 8(%bp)
548         movw 10(%si), %ax
549         movw %ax, 10(%bp)
550         movw 12(%si), %ax
551         movw %ax, 12(%bp)
552         movw 14(%si), %ax
553         movw %ax, 14(%bp)
555         push %bp
556         call send_command
557         add $2, %sp
559         freebpa
560         pop %bp
561         pop %ax
563         mov $0, %ah
564         clc
565         ret
566 .endm
568 extended_read_sectors:
569         extended_read_write_sectors $0x01
571 extended_write_sectors:
572         extended_read_write_sectors $0x02
574 get_extended_drive_parameters:
575         push %ax
576         push %bp
577         push %cx
578         push %dx
580         allocbpa $16
582         movw $0, 0(%bp) /* read c,h,s */
583         push %bp
584         call send_command
585         add $2, %sp
587         /* write size */
588         movw $26, 0(%si)
590         /* set flags to 2 */
591         movw $2, 2(%si)
593         /* cylinders */
594         mov 2(%bp), %ax
595         mov %ax, 4(%si)
596         xor %ax, %ax
597         mov %ax, 6(%si)
599         /* heads */
600         mov 4(%bp), %ax
601         mov %ax, 8(%si)
602         xor %ax, %ax
603         mov %ax, 10(%si)
605         /* sectors */
606         mov 6(%bp), %ax
607         mov %ax, 12(%si)
608         xor %ax, %ax
609         mov %ax, 14(%si)
611         /* set total number of sectors */
612         mov 8(%bp), %ax
613         mov %ax, 16(%si)
614         mov 10(%bp), %ax
615         mov %ax, 18(%si)
616         mov 12(%bp), %ax
617         mov %ax, 20(%si)
618         mov 14(%bp), %ax
619         mov %ax, 22(%si)
621         /* number of bytes per sector */
622         movw $512, 24(%si)
624         freebpa
626         pop %dx
627         pop %cx
628         pop %bp
629         pop %ax
631         mov $0, %ah
632         clc
633         ret
635 terminate_disk_emulation:
636         mov $1, %ah
637         stc
638         ret
640 int13_handler:
641         cmp $0x80, %dl
642         je 1f
643         int $0x2c
644         iret
646         cmp $0x0, %ah
647         jne 1f
648         call disk_reset
649         iret
651         cmp $0x2, %ah
652         jne 1f
653         call read_disk_sectors
654         iret
656         cmp $0x8, %ah
657         jne 1f
658         call read_disk_drive_parameters
659         iret
661         cmp $0x15, %ah
662         jne 1f
663         call read_disk_drive_size
664         iret
666         cmp $0x41, %ah
667         jne 1f
668         call check_if_extensions_present
669         iret
671         cmp $0x42, %ah
672         jne 1f
673         call extended_read_sectors
674         iret
676         cmp $0x48, %ah
677         jne 1f
678         call get_extended_drive_parameters
679         iret
681         cmp $0x4b, %ah
682         jne 1f
683         call terminate_disk_emulation
684         iret
686         cmp $0x0d, %ah
687         jne 1f
688         call alternate_disk_reset
689         iret
691         cmp $0x03, %ah
692         jne 1f
693         call write_disk_sectors
694         iret
696         cmp $0x43, %ah
697         jne 1f
698         call extended_write_sectors
699         iret
701         int $0x18  /* boot failed */
702         iret
704 .align 512, 0
705 _end: