kvm: external module: fix preempt notifier emulation clash with hardware debug
[kvm-userspace.git] / extboot / extboot.S
blob584d36d560419726bf8c72b7358fd3d105975bab
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 $8
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 $8
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 $8
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         mov $1, %ah
576         stc
577         ret
578 #if 0
579         /* this function is seriously borked */
581         push %ax
582         push %bp
583         push %cx
584         push %dx
586         allocbpa $8
588         movw $0, 0(%bp) /* read c,h,s */
589         push %bp
590         call send_command
591         add $2, %sp
593         /* check the size of the passed in data */
594         cmpw $26, 0(%si)
595         mov 0(%si), %ax
596         dump %ax
597         jle 0b
599         /* set flags to 2 */
600         movw $2, 2(%si)
602         /* cylinders */
603         mov 2(%bp), %ax
604         mov %ax, 4(%si)
605         xor %ax, %ax
606         mov %ax, 6(%si)
608         /* heads */
609         mov 4(%bp), %ax
610         mov %ax, 8(%si)
611         xor %ax, %ax
612         mov %ax, 10(%si)
614         /* sectors */
615         mov 6(%bp), %ax
616         mov %ax, 12(%si)
617         xor %ax, %ax
618         mov %ax, 14(%si)
620         /* calculate total sectors */
622         /* cx:dx = cylinders */
623         mov 2(%bp), %dx
624         xor %cx, %cx
626         /* *= heads */
627         push 4(%bp)
628         push $0
629         push %dx
630         push %cx
631         call mul32
632         add $8, %sp
634         /* *= sectors */
635         push 6(%bp)
636         push $0
637         push %dx
638         push %cx
639         call mul32
640         add $8, %sp
642         /* total number of sectors */
643         mov %dx, 16(%si)
644         mov %cx, 18(%si)
645         xor %ax, %ax
646         mov %ax, 20(%si)
647         mov %ax, 22(%si)
649         /* number of bytes per sector */
650         movw $512, 24(%si)
652         /* optional segmention:offset to EDD config */
653         cmpw $30, 0(%si)
654         jl 1f
656         movw $0xFFFF, 26(%si)
657         movw $0xFFFF, 28(%si)
660         freebpa
662         pop %dx
663         pop %cx
664         pop %bp
665         pop %ax
667         mov $0, %ah
668         clc
669         ret
670 #endif
672 terminate_disk_emulation:
673         mov $1, %ah
674         stc
675         ret
677 int13_handler:
678         cmp $0x80, %dl
679         je 1f
680         int $0x2c
681         iret
683         cmp $0x0, %ah
684         jne 1f
685         call disk_reset
686         iret
688         cmp $0x2, %ah
689         jne 1f
690         call read_disk_sectors
691         iret
693         cmp $0x8, %ah
694         jne 1f
695         call read_disk_drive_parameters
696         iret
698         cmp $0x15, %ah
699         jne 1f
700         call read_disk_drive_size
701         iret
703         cmp $0x41, %ah
704         jne 1f
705         call check_if_extensions_present
706         iret
708         cmp $0x42, %ah
709         jne 1f
710         call extended_read_sectors
711         iret
713         cmp $0x48, %ah
714         jne 1f
715         call get_extended_drive_parameters
716         iret
718         cmp $0x4b, %ah
719         jne 1f
720         call terminate_disk_emulation
721         iret
723         cmp $0x0d, %ah
724         jne 1f
725         call alternate_disk_reset
726         iret
728         cmp $0x03, %ah
729         jne 1f
730         call write_disk_sectors
731         iret
733         cmp $0x43, %ah
734         jne 1f
735         call extended_write_sectors
736         iret
738         int $0x18  /* boot failed */
739         iret
741 .align 512, 0
742 _end: