Better LBA support
[reactos.git] / freeldr / freeldr / asmcode.S
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 .text
21 .code16
22
23 #define ASM
24 #include "asmcode.h"
25
26
27 EXTERN(start)
28
29 cli
30
31 /* Setup segment registers */
32 xorw %ax,%ax
33 movw %ax,%ds
34 movw %ax,%es
35 movw %ax,%fs
36 movw %ax,%gs
37 movw %ax,%ss
38 /* Setup a stack */
39 movw stack16,%sp
40
41 sti
42
43 /* Init pmode */
44 call switch_to_prot
45
46 .code32
47
48 /* Store the boot drive */
49 movb %dl,(_BootDrive)
50
51 /* GO! */
52 call _BootMain
53
54 call switch_to_real
55 .code16
56
57 int $0x19
58
59 /* We should never get here */
60 stop:
61 jmp stop
62
63
64 /*
65 * Switches the processor to protected mode
66 * it destroys eax
67 */
68 EXTERN(switch_to_prot)
69
70 .code16
71
72 cli /* None of these */
73
74 /* Get the return address off the stack */
75 popw (code32ret)
76
77 /* Save 16-bit stack pointer */
78 movw %sp,stack16
79
80 /* Load the GDT */
81 lgdt gdtptr
82
83 /* Enable Protected Mode */
84 mov %cr0,%eax
85 orl $CR0_PE_SET,%eax
86 mov %eax,%cr0
87
88 /* Clear prefetch queue & correct CS */
89 ljmp $PMODE_CS, $inpmode
90
91
92 .code32
93
94 inpmode:
95 /* Setup segment selectors */
96 movw $PMODE_DS,%ax
97 movw %ax,%ds
98 movw %ax,%es
99 movw %ax,%fs
100 movw %ax,%gs
101 movw %ax,%ss
102 movl stack32,%esp
103
104 /* Put the return address back onto the stack */
105 pushl (code32ret)
106
107 /* Now return in p-mode! */
108 ret
109
110 /*
111 * Switches the processor back to real mode
112 * it destroys eax
113 */
114 EXTERN(switch_to_real)
115
116 .code32
117
118 /* Get the return address off the stack */
119 popl (code16ret)
120
121 /* Save 32-bit stack pointer */
122 movl %esp,stack32
123
124 /* jmp to 16-bit segment to set the limit correctly */
125 ljmp $RMODE_CS, $switch_to_real16
126
127 switch_to_real16:
128 .code16
129
130 /* Restore segment registers to correct limit */
131 movw $RMODE_DS,%ax
132 movw %ax,%ds
133 movw %ax,%es
134 movw %ax,%fs
135 movw %ax,%gs
136 movw %ax,%ss
137
138 /* Disable Protected Mode */
139 mov %cr0,%eax
140 andl $CR0_PE_CLR,%eax
141 mov %eax,%cr0
142
143 /* Clear prefetch queue & correct CS */
144 ljmp $0, $inrmode
145
146 inrmode:
147 movw %cs,%ax
148 movw %ax,%ds
149 movw %ax,%es
150 movw %ax,%fs
151 movw %ax,%gs
152 movw %ax,%ss
153 movw stack16,%sp
154
155 /* Put the return address back onto the stack */
156 pushw (code16ret)
157
158 sti /* These are ok now */
159
160 /* Now return in r-mode! */
161 ret
162
163
164 /*
165 * void putchar(int ch);
166 */
167 EXTERN(_putchar)
168 .code32
169
170 push %eax
171 push %ebx
172 push %ebp
173
174 /* Get character to display */
175 movb 0x10(%esp),%bl
176
177 /* If we are displaying a CR '\n' then do a LF also */
178 cmpb $0x0a,%bl
179 jnz putchar_1
180
181 /* Display the LF */
182 pushl $0x0d
183 call _putchar
184 popl %eax
185
186 putchar_1:
187 /* If we are displaying a TAB '\t' then display 8 spaces ' ' */
188 cmpb $0x09,%bl
189 jnz putchar_2
190
191 /* Display the 8 spaces ' ' */
192 pushl $0x20
193 call _putchar
194 call _putchar
195 call _putchar
196 call _putchar
197 call _putchar
198 call _putchar
199 call _putchar
200 call _putchar
201 popl %eax
202 pop %ebp
203 pop %ebx
204 pop %eax
205 ret
206
207 putchar_2:
208 call switch_to_real
209
210 .code16
211
212 /* Display the character via BIOS int 0x10 function 0x0e */
213 movb $0x0e,%ah
214 movb %bl,%al
215 movw $1,%bx
216 int $0x10
217
218 call switch_to_prot
219
220 .code32
221
222 pop %ebp
223 pop %ebx
224 pop %eax
225 ret
226
227 /*
228 * void clrscr(void);
229 */
230 EXTERN(_clrscr)
231 .code32
232
233 push %eax
234 push %ebp
235
236 call switch_to_real
237
238 .code16
239
240 /* Int 0x10, AH = 0x0F - Get Current Video Mode */
241 movb $0x0f,%ah
242 int $0x10
243
244 /* Int 0x10, AH = 0x00 - Set Current Video Mode, also clears the screen */
245 movb $0x00,%ah
246 int $0x10
247
248 call switch_to_prot
249
250 .code32
251
252 pop %ebp
253 pop %eax
254 ret
255
256 /*
257 * int kbhit(void);
258 */
259 EXTERN(_kbhit)
260 .code32
261
262 push %ebp
263 push %ebx
264
265 call switch_to_real
266
267 .code16
268
269 /* Int 0x16, AH = 0x01 - Get Keyboard Status */
270 movb $0x01,%ah
271 int $0x16
272 jz kbhit_1 // ZF=0 if no key is available
273
274 /* Return value is non-zero if a key is available */
275 movl $1,%ebx
276 jmp kbhit_done
277
278 kbhit_1:
279 /* Return value is zero if no key is available */
280 movl $0,%ebx
281
282 kbhit_done:
283
284 call switch_to_prot
285
286 .code32
287
288 /* Get return value from ebx */
289 movl %ebx,%eax
290
291 pop %ebx
292 pop %ebp
293 ret
294
295 /*
296 * int getch(void);
297 */
298 extended_scancode:
299 .byte 0
300 EXTERN(_getch)
301 .code32
302
303 push %ebp
304 push %ebx
305
306 call switch_to_real
307
308 .code16
309
310 /* Check and see if we have an extended scancode to return */
311 movb extended_scancode,%al
312 movb $0,extended_scancode
313 movzbl %al,%ebx
314 cmpb $0,%al
315 jnz getch_done
316
317 /* Int 0x16, AH = 0x00 - Wait for keypress */
318 movb $0,%ah
319 int $0x16
320
321 /* If al is zero then it is an extended key */
322 cmp $0,%al
323 jnz getch_1
324
325 /* Save the scan code to be returned on the next call to getch() */
326 movb %ah,extended_scancode
327
328 getch_1:
329 /* Store character in ebx */
330 movzbl %al,%ebx
331
332 getch_done:
333 call switch_to_prot
334
335 .code32
336
337 /* Get return value from ebx */
338 movl %ebx,%eax
339
340 pop %ebx
341 pop %ebp
342 ret
343
344 /*
345 * void gotoxy(int x, int y);
346 */
347 EXTERN(_gotoxy)
348 .code32
349
350 push %ebp
351 push %eax
352 push %ebx
353 push %edx
354
355 /* Get cursor positions */
356 movb 0x14(%esp),%dl
357 movb 0x18(%esp),%dh
358
359 call switch_to_real
360
361 .code16
362
363 /* Update the cursor position */
364 movb $2,%ah
365 movb $0,%bh
366 int $0x10
367
368 call switch_to_prot
369
370 .code32
371
372 pop %edx
373 pop %ebx
374 pop %eax
375 pop %ebp
376 ret
377
378 /*
379 * BOOL BiosInt13Read(ULONG Drive, ULONG Head, ULONG Track, ULONG Sector, ULONG SectorCount, PVOID Buffer);
380 */
381 _biosdisk_drive:
382 .long 0
383 _biosdisk_head:
384 .long 0
385 _biosdisk_track:
386 .long 0
387 _biosdisk_sector:
388 .long 0
389 _biosdisk_nsects:
390 .long 0
391 _biosdisk_buffer:
392 .long 0
393 _biosdisk_retval:
394 .long 0
395 _biosdisk_retrycount:
396 .byte 0
397 EXTERN(_BiosInt13Read)
398 .code32
399
400 push %ebp
401 push %esi
402 push %edi
403 push %ebx
404 push %ecx
405 push %edx
406
407 /* Get parameters */
408 movl 0x1c(%esp),%eax
409 movl %eax,_biosdisk_drive
410 movl 0x20(%esp),%eax
411 movl %eax,_biosdisk_head
412 movl 0x24(%esp),%eax
413 movl %eax,_biosdisk_track
414 movl 0x28(%esp),%eax
415 movl %eax,_biosdisk_sector
416 movl 0x2c(%esp),%eax
417 movl %eax,_biosdisk_nsects
418 movl 0x30(%esp),%eax
419 movl %eax,_biosdisk_buffer
420
421 call switch_to_real
422
423 .code16
424 pushw %es // Save this just in case
425 movb $3,_biosdisk_retrycount // Set the retry count to 3
426
427 _biosdisk_read:
428 movl _biosdisk_buffer,%eax // Get buffer address in eax
429 shrl $4,%eax // Make linear address into segment
430 movw %ax,%es // Load ES with segment
431 movl _biosdisk_buffer,%ebx // and BX with offset
432 andl $0x0f,%ebx // so that data gets loaded to [ES:BX]
433 movb _biosdisk_sector,%cl // Get the sector in CL
434 movw _biosdisk_track,%ax // Cylinder in AX
435 movb %al,%ch // Now put it in CH
436 rorb $1,%ah // Low 8 bits of cylinder in CH, high 2 bits
437 rorb $1,%ah // in CL shifted to bits 6 & 7
438 andb $0xc0,%ah // Clear out low six bits
439 orb %ah,%cl // Or with sector number
440 movb _biosdisk_head,%dh // Get the head
441 movb _biosdisk_drive,%dl // Get the drive
442 movb $2,%ah // BIOS int 0x13, function 2 - Read Disk Sectors
443 movb _biosdisk_nsects,%al // Number of sectors to read
444 int $0x13 // Read a sector
445
446 // I have recently learned that not all bioses return
447 // the sector read count in the AL register (at least mine doesn't)
448 // even if the sectors were read correctly. So instead
449 // of checking the sector read count we will rely solely
450 // on the carry flag being set on error
451
452 //jmp _biosdisk_done
453 //cmpb _biosdisk_nsects,%al // See how many sectors we actually read
454 //jne _biosdisk_error // Jump if no error
455
456 movb $1,%al // Set the return value to be one (will be set to zero later if needed)
457 jc _biosdisk_error // Jump if error (CF = 1 on error)
458 jmp _biosdisk_done
459
460
461 _biosdisk_error:
462 cmpb $0x11,%ah // Check and see if it was a corrected ECC error
463 je _biosdisk_done // If so then the data is still good, if not fail
464
465 movb _biosdisk_retrycount,%al// Get the current retry count
466 decb %al // Decrement it
467 movb %al,_biosdisk_retrycount// Save it
468 cmpb $0,%al // Is it zero?
469 jz _biosdisk_zero // Yes, return zero
470
471 movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System
472 movb _biosdisk_drive,%dl // Get the drive
473 int $0x13 // Reset the disk system
474 jmp _biosdisk_read // Try reading again
475
476 _biosdisk_zero:
477 movb $0,%al // We will return zero
478
479 _biosdisk_done:
480 movzbl %al,%eax // Put the number of sectors read into EAX
481 movl %eax,_biosdisk_retval // Save it as the return value
482
483 popw %es // Restore ES
484 call switch_to_prot
485
486 .code32
487
488 movl _biosdisk_retval,%eax // Get return value
489 //movl $1,%eax
490
491 pop %edx
492 pop %ecx
493 pop %ebx
494 pop %edi
495 pop %esi
496 pop %ebp
497 ret
498
499 /*
500 * BOOL BiosInt13ReadExtended(ULONG Drive, ULONG Sector, ULONG SectorCount, PVOID Buffer);
501 */
502 _disk_address_packet:
503 _packet_size:
504 .byte 0x10
505 _packet_reserved:
506 .byte 0
507 _packet_sector_count:
508 .word 0
509 _packet_transfer_buffer_segment:
510 .word 0
511 _packet_transfer_buffer_offset:
512 .word 0
513 _packet_lba_sector_number:
514 .quad 0
515 _packet_64bit_flat_address:
516 .quad 0
517 _int13_extended_drive:
518 .long 0
519 _int13_extended_sector_count:
520 .long 0
521 _int13_extended_retval:
522 .long 0
523 _int13_extended_retrycount:
524 .byte 0
525 EXTERN(_BiosInt13ReadExtended)
526 .code32
527
528 push %ebp
529 push %esi
530 push %edi
531 push %ebx
532 push %ecx
533 push %edx
534
535 /* Get parameters */
536 movl 0x1c(%esp),%eax
537 movl %eax,_int13_extended_drive
538 movl 0x20(%esp),%eax
539 movl %eax,_packet_lba_sector_number
540 movl 0x24(%esp),%eax
541 movw %ax,_packet_sector_count
542 movl %eax,_int13_extended_sector_count
543 movl 0x28(%esp),%eax // Get buffer address in eax
544 shrl $4,%eax // Make linear address into segment
545 movw %ax,_packet_transfer_buffer_segment // Save segment
546 movl 0x28(%esp),%eax // Get buffer address in eax
547 andl $0x0f,%eax // Make linear address into offset
548 movw %ax,_packet_transfer_buffer_offset // Save offset
549
550 call switch_to_real
551
552 .code16
553 pushw %es // Save this just in case
554 movb $3,_int13_extended_retrycount // Set the retry count to 3
555
556 _int13_extended_read:
557 movb _int13_extended_drive,%dl // Get the drive
558 movb $42,%ah // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ
559 movw $_disk_address_packet,%si // DS:SI -> disk address packet
560 int $0x13 // Read sectors
561
562 movb $1,%al // Set the return value to be one (will be set to zero later if needed)
563 jc _int13_extended_error // Jump if error (CF = 1 on error)
564
565 movl _int13_extended_sector_count,%eax // Get the sector count in eax
566 cmpw _packet_sector_count,%ax // See how many sectors we actually read (returned in disk address packet sector count)
567 jne _int13_extended_error // Jump if not equal
568
569 jmp _int13_extended_done
570
571
572 _int13_extended_error:
573 cmpb $0x11,%ah // Check and see if it was a corrected ECC error
574 je _int13_extended_done // If so then the data is still good, if not fail
575
576 movb _int13_extended_retrycount,%al // Get the current retry count
577 decb %al // Decrement it
578 movb %al,_int13_extended_retrycount // Save it
579 cmpb $0,%al // Is it zero?
580 jz _int13_extended_zero // Yes, return zero
581
582 movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System
583 movb _int13_extended_drive,%dl // Get the drive
584 int $0x13 // Reset the disk system
585 jmp _int13_extended_read // Try reading again
586
587 _int13_extended_zero:
588 movb $0,%al // We will return zero
589
590 _int13_extended_done:
591 movzbl %al,%eax // Put the number of sectors read into EAX
592 movl %eax,_int13_extended_retval // Save it as the return value
593
594 popw %es // Restore ES
595 call switch_to_prot
596
597 .code32
598
599 movl _int13_extended_retval,%eax // Get return value
600 //movl $1,%eax
601
602 pop %edx
603 pop %ecx
604 pop %ebx
605 pop %edi
606 pop %esi
607 pop %ebp
608 ret
609
610 /*
611 * BOOL BiosInt13ExtensionsSupported(ULONG Drive);
612 */
613 _int13_extension_check_drive:
614 .long 0
615 _int13_extension_check_retval:
616 .long 0
617 EXTERN(_BiosInt13ExtensionsSupported)
618 .code32
619
620 push %ebp
621 push %esi
622 push %edi
623 push %ebx
624 push %ecx
625 push %edx
626
627 /* Get parameters */
628 movl 0x1c(%esp),%eax
629 movl %eax,_int13_extension_check_drive
630
631 call switch_to_real
632
633 .code16
634 // Now make sure this computer supports extended reads
635 movb $0x41,%ah // AH = 41h
636 movw $0x55aa,%bx // BX = 55AAh
637 movb _int13_extension_check_drive,%dl // DL = drive (80h-FFh)
638 int $0x13 // IBM/MS INT 13 Extensions - INSTALLATION CHECK
639 jc _int13_extension_check_error // CF set on error (extensions not supported)
640 cmpw $0x55aa,%bx // BX = AA55h if installed
641 jne _int13_extension_check_error
642 testb $1,%cl // CX = API subset support bitmap
643 jz _int13_extension_check_error // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported
644
645 // If we get here then we passed all the int13 extension tests
646 movl $1,_int13_extension_check_retval // Set return value to TRUE
647 jmp _int13_extension_check_done
648
649 _int13_extension_check_error:
650
651 movl $0,_int13_extension_check_retval // The tests failed so return FALSE
652
653 _int13_extension_check_done:
654
655 call switch_to_prot
656
657 .code32
658
659 movl _int13_extension_check_retval,%eax // Get return value
660
661 pop %edx
662 pop %ecx
663 pop %ebx
664 pop %edi
665 pop %esi
666 pop %ebp
667 ret
668
669 /*
670 * int getyear(void);
671 */
672 EXTERN(_getyear)
673 .code32
674
675 push %ebp
676 push %ebx
677 push %ecx
678 push %edx
679
680 call switch_to_real
681
682 .code16
683
684 /* Get the date */
685 movb $4,%ah
686 int $0x1a
687
688 /* Convert from BCD to normal */
689 movb %ch,%al
690 andb $0x0f,%al
691 movb %al,%dl
692 movb %ch,%al
693 shrb $0x04,%al
694 andb $0x0f,%al
695 movb $0x0a,%bl
696 mulb %bl
697 addb %al,%dl
698 movb %dl,%dh
699
700 movb %cl,%al
701 andb $0x0f,%al
702 movb %al,%dl
703 movb %cl,%al
704 shrb $0x04,%al
705 andb $0x0f,%al
706 movb $0x0a,%bl
707 mulb %bl
708 addb %al,%dl
709
710 movb %dl,%cl
711
712 movzbl %dh,%eax
713 movl $100,%ebx
714 mull %ebx
715 movl %eax,%edx
716 addb %cl,%dl
717
718 /* Save return value */
719 movl %edx,%edx
720
721 call switch_to_prot
722
723 .code32
724
725 /* Restore return value */
726 movl %edx,%eax
727
728 pop %edx
729 pop %ecx
730 pop %ebx
731 pop %ebp
732 ret
733
734 /*
735 * int getday(void);
736 */
737 EXTERN(_getday)
738 .code32
739
740 push %ebp
741 push %ebx
742 push %ecx
743 push %edx
744
745 call switch_to_real
746
747 .code16
748
749 /* Get the date */
750 movb $4,%ah
751 int $0x1a
752
753 /* Convert from BCD to normal */
754 movb %dl,%al
755 andb $0x0f,%al
756 movb %al,%cl
757 movb %dl,%al
758 shrb $0x04,%al
759 andb $0x0f,%al
760 movb $0x0a,%bl
761 mulb %bl
762 addb %al,%cl
763
764 /* Save return value */
765 movzbl %cl,%edx
766
767 call switch_to_prot
768
769 .code32
770
771 /* Restore return value */
772 movl %edx,%eax
773
774 pop %edx
775 pop %ecx
776 pop %ebx
777 pop %ebp
778 ret
779
780 /*
781 * int getmonth(void);
782 */
783 EXTERN(_getmonth)
784 .code32
785
786 push %ebp
787 push %ebx
788 push %ecx
789 push %edx
790
791 call switch_to_real
792
793 .code16
794
795 /* Get the date */
796 movb $4,%ah
797 int $0x1a
798
799 /* Convert from BCD to normal */
800 movb %dh,%al
801 andb $0x0f,%al
802 movb %al,%dl
803 movb %dh,%al
804 shrb $0x04,%al
805 andb $0x0f,%al
806 movb $0x0a,%bl
807 mulb %bl
808 addb %al,%dl
809
810 /* Save return value */
811 movzbl %dl,%edx
812
813 call switch_to_prot
814
815 .code32
816
817 /* Restore return value */
818 movl %edx,%eax
819
820 pop %edx
821 pop %ecx
822 pop %ebx
823 pop %ebp
824 ret
825
826 /*
827 * int gethour(void);
828 */
829 EXTERN(_gethour)
830 .code32
831
832 push %ebp
833 push %ebx
834 push %ecx
835 push %edx
836
837 call switch_to_real
838
839 .code16
840
841 /* Get the time */
842 movb $2,%ah
843 int $0x1a
844
845 /* Convert from BCD to normal */
846 movb %ch,%al
847 andb $0x0f,%al
848 movb %al,%dl
849 movb %ch,%al
850 shrb $0x04,%al
851 andb $0x0f,%al
852 movb $0x0a,%bl
853 mulb %bl
854 addb %al,%dl
855
856 /* Save return value */
857 movzbl %dl,%edx
858
859 call switch_to_prot
860
861 .code32
862
863 /* Restore return value */
864 movl %edx,%eax
865
866 pop %edx
867 pop %ecx
868 pop %ebx
869 pop %ebp
870 ret
871
872 /*
873 * int getminute(void);
874 */
875 EXTERN(_getminute)
876 .code32
877
878 push %ebp
879 push %ebx
880 push %ecx
881 push %edx
882
883 call switch_to_real
884
885 .code16
886
887 /* Get the time */
888 movb $2,%ah
889 int $0x1a
890
891 /* Convert from BCD to normal */
892 movb %cl,%al
893 andb $0x0f,%al
894 movb %al,%dl
895 movb %cl,%al
896 shrb $0x04,%al
897 andb $0x0f,%al
898 movb $0x0a,%bl
899 mulb %bl
900 addb %al,%dl
901
902 /* Save return value */
903 movzbl %dl,%edx
904
905 call switch_to_prot
906
907 .code32
908
909 /* Restore return value */
910 movl %edx,%eax
911
912 pop %edx
913 pop %ecx
914 pop %ebx
915 pop %ebp
916 ret
917
918 /*
919 * int getsecond(void);
920 */
921 EXTERN(_getsecond)
922 .code32
923
924 push %ebp
925 push %ebx
926 push %ecx
927 push %edx
928
929 call switch_to_real
930
931 .code16
932
933 /* Get the time */
934 movb $2,%ah
935 int $0x1a
936
937 /* Convert from BCD to normal */
938 movb %dh,%al
939 andb $0x0f,%al
940 movb %al,%dl
941 movb %dh,%al
942 shrb $0x04,%al
943 andb $0x0f,%al
944 movb $0x0a,%bl
945 mulb %bl
946 addb %al,%dl
947
948 /* Save return value */
949 movzbl %dl,%edx
950
951 call switch_to_prot
952
953 .code32
954
955 /* Restore return value */
956 movl %edx,%eax
957
958 pop %edx
959 pop %ecx
960 pop %ebx
961 pop %ebp
962 ret
963
964 /*
965 * void hidecursor(void);
966 */
967 EXTERN(_hidecursor)
968 .code32
969
970 push %ebp
971 push %ebx
972 push %ecx
973 push %edx
974
975 call switch_to_real
976
977 .code16
978
979 /* Hide the cursor */
980 movb $1,%ah
981 movw $0x2000,%cx
982 int $0x10
983
984 call switch_to_prot
985
986 .code32
987
988 pop %edx
989 pop %ecx
990 pop %ebx
991 pop %ebp
992 ret
993
994 /*
995 * void showcursor(void);
996 */
997 EXTERN(_showcursor)
998 .code32
999
1000 push %ebp
1001 push %ebx
1002 push %ecx
1003 push %edx
1004
1005 call switch_to_real
1006
1007 .code16
1008
1009 /* Show the cursor */
1010 movb $1,%ah
1011 movb $0x0d,%ch
1012 movb $0x0e,%cl
1013 int $0x10
1014
1015 call switch_to_prot
1016
1017 .code32
1018
1019 pop %edx
1020 pop %ecx
1021 pop %ebx
1022 pop %ebp
1023 ret
1024
1025 /*
1026 * int wherex(void);
1027 */
1028 EXTERN(_wherex)
1029 .code32
1030
1031 push %ebp
1032 push %ebx
1033 push %ecx
1034 push %edx
1035
1036 call switch_to_real
1037
1038 .code16
1039
1040 /* Get the cursor position */
1041 movb $3,%ah
1042 movb $0,%bh
1043 int $0x10
1044
1045 /* Save return value */
1046 movzbl %dl,%edx
1047
1048 call switch_to_prot
1049
1050 .code32
1051
1052 /* Restore return value */
1053 movl %edx,%eax
1054
1055 pop %edx
1056 pop %ecx
1057 pop %ebx
1058 pop %ebp
1059 ret
1060
1061 /*
1062 * int wherey(void);
1063 */
1064 EXTERN(_wherey)
1065 .code32
1066
1067 push %ebp
1068 push %ebx
1069 push %ecx
1070 push %edx
1071
1072 call switch_to_real
1073
1074 .code16
1075
1076 /* Get the cursor position */
1077 movb $3,%ah
1078 movb $0,%bh
1079 int $0x10
1080
1081 /* Save return value */
1082 movzbl %dh,%edx
1083
1084 call switch_to_prot
1085
1086 .code32
1087
1088 /* Restore return value */
1089 movl %edx,%eax
1090
1091 pop %edx
1092 pop %ecx
1093 pop %ebx
1094 pop %ebp
1095 ret
1096
1097 /*
1098 * void stop_floppy(void);
1099 *
1100 * Stops the floppy drive from spinning, so that other software is
1101 * jumped to with a known state.
1102 */
1103 EXTERN(_stop_floppy)
1104 .code32
1105
1106 push %eax
1107 push %edx
1108
1109 call switch_to_real
1110
1111 .code16
1112
1113 movw $0x3F2, %dx
1114 xorb %al, %al
1115 outb %al, %dx
1116
1117 call switch_to_prot
1118
1119 .code32
1120
1121 pop %edx
1122 pop %eax
1123 ret
1124
1125 /*
1126 * int get_heads(int drive);
1127 */
1128 EXTERN(_get_heads)
1129 .code32
1130
1131 push %ebx
1132 push %ecx
1133 push %edx
1134 push %edi
1135 push %es
1136
1137 /* Get drive */
1138 movl 0x18(%esp),%eax
1139 movl %eax,_biosdisk_drive
1140
1141 call switch_to_real
1142
1143 .code16
1144
1145 movb $0x08,%ah
1146 movb _biosdisk_drive,%dl
1147 int $0x13
1148 jc _get_heads_error
1149
1150 incb %dh
1151 movzbl %dh,%edx
1152 movl %edx,_biosdisk_retval
1153 jmp _get_heads_done
1154
1155 _get_heads_error:
1156 movl $0xff,_biosdisk_retval
1157
1158 _get_heads_done:
1159
1160 call switch_to_prot
1161
1162 .code32
1163
1164 movl _biosdisk_retval,%eax // Get return value
1165
1166 pop %es
1167 pop %edi
1168 pop %edx
1169 pop %ecx
1170 pop %ebx
1171
1172 ret
1173
1174 /*
1175 * int get_cylinders(int drive);
1176 */
1177 EXTERN(_get_cylinders)
1178 .code32
1179
1180 push %ebx
1181 push %ecx
1182 push %edx
1183 push %edi
1184 push %es
1185
1186 /* Get drive */
1187 movl 0x18(%esp),%eax
1188 movl %eax,_biosdisk_drive
1189
1190 call switch_to_real
1191
1192 .code16
1193
1194 movb $0x08,%ah
1195 movb _biosdisk_drive,%dl
1196 int $0x13
1197 jc _get_cylinders_error
1198
1199 xorl %edx,%edx
1200 andb $0xc0,%cl
1201 shrb $0x06,%cl
1202 movb %cl,%dh
1203 movb %ch,%dl
1204 incl %edx
1205 movl %edx,_biosdisk_retval
1206 jmp _get_cylinders_done
1207
1208 _get_cylinders_error:
1209 movl $0xff,_biosdisk_retval
1210
1211 _get_cylinders_done:
1212
1213 call switch_to_prot
1214
1215 .code32
1216
1217 movl _biosdisk_retval,%eax // Get return value
1218
1219 pop %es
1220 pop %edi
1221 pop %edx
1222 pop %ecx
1223 pop %ebx
1224
1225 ret
1226
1227 /*
1228 * int get_sectors(int drive);
1229 */
1230 EXTERN(_get_sectors)
1231 .code32
1232
1233 push %ebx
1234 push %ecx
1235 push %edx
1236 push %edi
1237 push %es
1238
1239 /* Get drive */
1240 movl 0x18(%esp),%eax
1241 movl %eax,_biosdisk_drive
1242
1243 call switch_to_real
1244
1245 .code16
1246
1247 movb $0x08,%ah
1248 movb _biosdisk_drive,%dl
1249 int $0x13
1250 jc _get_sectors_error
1251
1252 andb $0x3f,%cl
1253 movzbl %cl,%ecx
1254 movl %ecx,_biosdisk_retval
1255 jmp _get_sectors_done
1256
1257 _get_sectors_error:
1258 movl $0xff,_biosdisk_retval
1259
1260 _get_sectors_done:
1261
1262 call switch_to_prot
1263
1264 .code32
1265
1266 movl _biosdisk_retval,%eax // Get return value
1267
1268 pop %es
1269 pop %edi
1270 pop %edx
1271 pop %ecx
1272 pop %ebx
1273
1274 ret
1275
1276
1277 /*
1278 * Needed for enabling the a20 address line
1279 */
1280 .code16
1281 empty_8042:
1282 .word 0x00eb,0x00eb // jmp $+2, jmp $+2
1283 inb $0x64,%al
1284 testb $0x02,%al
1285 jnz empty_8042
1286 ret
1287
1288 /*
1289 * Enable the A20 address line (to allow access to over 1mb)
1290 */
1291 .code32
1292 EXTERN(_enable_a20)
1293 call switch_to_real
1294 .code16
1295
1296 call empty_8042
1297 movb $0xD1,%al // command write
1298 outb %al,$0x64
1299 call empty_8042
1300 mov $0xDF,%al // A20 on
1301 out %al,$0x60
1302 call empty_8042
1303 call switch_to_prot
1304 .code32
1305
1306 ret
1307
1308
1309
1310
1311 /* 16-bit stack pointer */
1312 stack16:
1313 .word STACK16ADDR
1314
1315 /* 32-bit stack pointer */
1316 stack32:
1317 .long STACK32ADDR
1318
1319 /* 16-bit return address */
1320 code16ret:
1321 .long 0
1322
1323 /* 32-bit return address */
1324 code32ret:
1325 .long 0
1326
1327
1328 .p2align 2 /* force 4-byte alignment */
1329 gdt:
1330 /* NULL Descriptor */
1331 .word 0x0000
1332 .word 0x0000
1333 .word 0x0000
1334 .word 0x0000
1335
1336 /* 32-bit flat CS */
1337 .word 0xFFFF
1338 .word 0x0000
1339 .word 0x9A00
1340 .word 0x00CF
1341
1342 /* 32-bit flat DS */
1343 .word 0xFFFF
1344 .word 0x0000
1345 .word 0x9200
1346 .word 0x00CF
1347
1348 /* 16-bit real mode CS */
1349 .word 0xFFFF
1350 .word 0x0000
1351 .word 0x9E00
1352 .word 0x0000
1353
1354 /* 16-bit real mode DS */
1355 .word 0xFFFF
1356 .word 0x0000
1357 .word 0x9200
1358 .word 0x0000
1359
1360 /* GDT table pointer */
1361 gdtptr:
1362 .word 0x27 /* Limit */
1363 .long gdt /* Base Address */
1364
1365 EXTERN(_BootDrive)
1366 .long 0