1 ! Doshead.s
- DOS
& BIOS support for boot.c Author
: Kees J. Bot
4 ! This file contains the startup
and low level support for the secondary
5 ! boot program. It contains functions for disk
, tty
and keyboard I
/O
,
6 ! copying memory to arbitrary locations
, etc.
8 ! This runs under MS-DOS as
a .COM file. A .COM file is what Minix calls
9 ! a common I
&D executable
, except that the first
256 bytes contains DOS
12 .sect .text; .sect .rom; .sect .data; .sect .bss
14 K_I386
= 0x0001 ! Call Minix in
386 mode
15 STACK
= 16384 ! Number of bytes for the stack
17 DS_SELECTOR
= 3*8 ! Kernel data selector
18 ES_SELECTOR
= 4*8 ! Flat
4 Gb
19 SS_SELECTOR
= 5*8 ! Monitor stack
20 CS_SELECTOR
= 6*8 ! Kernel code
21 MCS_SELECTOR
= 7*8 ! Monitor code
23 ESC
= 0x1B ! Escape character
25 ! Imported variables
and functions
:
26 .extern _caddr, _daddr, _runsize, _edata, _end ! Runtime environment
27 .extern _k_flags ! Special kernel flags
28 .extern _mem ! Free memory list
29 .extern _vdisk ! Name of the virtual disk
33 .use16 ! Tell 386 assembler we're in 16-bit mode
37 .space 256 ! Program Segment Prefix
40 cld ! C compiler wants UP
42 mov di, _edata ! Start of bss is at end of data
43 mov cx, _end ! End of bss (begin of heap)
44 sub cx, di ! Number of bss bytes
45 shr cx, 1 ! Number of words
49 mov sp, _end+STACK ! "chmem" to 16 kb
52 ! Are we called with the /U option?
53 movb cl, (_PSP+0x80) ! Argument byte count
55 mov bx, _PSP+0x81 ! Argument string
57 cmpb (bx), 0x20 ! Whitespace?
62 1: cmp cx, 2 ! '/U' is two bytes
64 cmpb (bx), 0x2F ! '/'?
67 andb al, ~0x20 ! Ignore case
70 jmp keepumb ! Go grab an UMB
73 ! Remember the current video mode for restoration on exit.
74 movb ah, 0x0F ! Get current video mode
76 andb al, 0x7F ! Mask off bit 7 (no blanking)
77 movb (old_vid_mode), al
78 movb (cur_vid_mode), al
80 ! We require at least MS-DOS 3.0.
81 mov ax, 0x3000 ! Get DOS version
83 cmpb al, 3 ! DOS 3.0+ ?
89 tellbaddos: .ascii "MS-DOS 3.0 or better required\n\0"
93 ! Find out how much "low" memory there is available, where it starts and
95 mov di, _mem ! di = memory list
96 mov ax, _PSP+0x80 ! From PSP:80 to next PSP is ours
100 mov 2(di), dx ! mem[0].base = ds * 16 + 0x80
102 mov dx, (_PSP+2) ! First in-use segment far above us
105 sbb dx, 2(di) ! Minus base gives size
107 mov 6(di), dx ! mem[1].size = free low memory size
109 ! Give C code access to the code segment, data segment and the size of this
122 mov dx, ss ! End of stack = end of program
125 sbb dx, (_caddr+2) ! Minus start of our code
127 mov (_runsize+2), dx ! Is our size
129 ! Patch the regular _getprocessor library routine to jump to 'getprocessor',
130 ! that checks if we happen to be in a V8086 straightjacket by returning '86'.
131 cseg movb (_getprocessor+0), 0xE9
133 sub ax, _getprocessor+3
134 cseg mov (_getprocessor+1), ax
136 ! Grab the largest chunk of extended memory available.
138 cmp ax, 286 ! Only 286s and above have extended memory
140 mov ax, 0x4300 ! XMS driver check
142 cmpb al, 0x80 ! XMS driver exists?
144 get_ext: ! No driver, so can use all ext memory directly
146 cmp ax, 486 ! Assume 486s were the first to have >64M
147 jb small_ext ! (It helps to be paranoid when using the BIOS)
149 mov ax, 0xE801 ! Code for get memory size for >64M
150 int 0x15 ! ax = mem at 1M per 1K, bx = mem at 16M per 64K
153 movb ah, 0x88 ! Code for get extended memory size
154 clc ! Carry will stay clear if call exists
155 int 0x15 ! Returns size (in K) in ax for AT's
157 test ax
, ax
! An AT with no extended memory?
159 xor bx
, bx
! bx
= mem above
16M per
64K
= 0
161 mov cx
, ax
! cx
= copy of ext mem at
1M
162 mov
10(di
), 0x0010 ! mem
[1].base = 0x00100000 (1M)
164 mov
12(di
), ax
! mem
[1].size = "ext mem at 1M" * 1024
167 jz no_ext
! No more ext mem above
16M?
168 cmp cx
, 15*1024 ! Chunks adjacent?
(precisely
15M at
1M?
)
170 mov
18(di
), 0x0100 ! mem
[2].base = 0x01000000 (16M)
171 mov
22(di
), bx
! mem
[2].size = "ext mem at 16M" * 64K
174 add 14(di
), bx
! Add ext mem above
16M to mem below
16M
179 mov ax
, 0x4310 ! Get XMS driver address
181 mov
(xms_driver+
0), bx
182 mov
(xms_driver+
2), es
185 movb ah
, 0x08 ! Query free extended memory
190 push ax
! ax
= size of largest block in kb
193 mov
14(di
), dx
! mem
[1].size = ax * 1024
194 pop dx
! dx
= size of largest block in kb
195 movb ah
, 0x09 ! Allocate XMS block of size dx
199 mov
(xms_handle
), dx
! Save handle
200 movb ah
, 0x0C ! Lock XMS block
(handle in dx
)
205 mov
10(di
), dx
! mem
[1].base = Address of locked block
208 ! If we
're running in a DOS box then they're might
be an Upper Memory Block
209 ! we can use. Every little bit helps when in real mode.
211 or ax
, 22(di
) ! Can we use mem
[2]?
213 mov dx
, 0xFFFF ! dx
= Maximum size
, i.e. gimme all
214 call getumb
! Get UMB
, dx
= segment
, cx
= length
215 test cx
, cx
! Did we get
a block?
217 xor ax
, ax
! dx
:ax
= memory block
220 mov
18(di
), dx
! mem
[2].base = memory block base
222 xor ax
, ax
! dx
:ax
= length of memory block
225 mov
22(di
), dx
! mem
[2].size = memory block length
228 ! Set up an INT
24 "critical error" handler that returns
"fail". This way
229 ! Minix won
't suffer from "(A)bort, (R)etry, (I)nfluence with a large hammer?".
230 mov (0x007C), 0x03B0 ! movb al, 0x03 (fail code)
231 movb (0x007E), 0xCF ! iret
232 movb ah, 0x25 ! Set interrupt vector
233 mov dx, 0x007C ! ds:dx = ds:0x007C = interrupt handler
236 ! Time to switch to a higher level language (not much higher)
239 ! void ..exit(int status)
240 ! Exit the monitor by returning to DOS.
241 .define _exit, __exit, ___exit ! Make various compilers happy
246 cmp dx, -1 ! Is there an ext mem block in use?
248 movb ah, 0x0D ! Unlock extended memory block
251 movb ah, 0x0A ! Free extended memory block
256 pop ax ! Return code in al
257 movb ah, 0x4C ! Terminate with return code
272 tellxmserr: .ascii "Extended memory problem, error 0x%02x\n\0"
275 ! int getprocessor(void)
276 ! Prefix for the regular _getprocessor call that first checks if we're
277 ! running in
a virtual
8086 box.
279 push sp
! Is pushed sp equal to sp?
282 jne gettrueproc
! If
not then it
's a plain 8086 or 80186
283 .data1 0x0F,0x01,0xE0 ! Use old 286 SMSW instruction to get the MSW
284 testb al, 0x01 ! Protected mode enabled?
285 jz gettrueproc ! If not then a 286 or better in real mode
286 mov ax, 86 ! Forget fancy tricks, say it's an
8086
288 gettrueproc
: ! Get the true processor type
289 push bp
! _getprocessor prologue that is patched over.
293 ! Try to get an Upper Memory Block under MS-DOS
5+. Try to get one up to size
294 ! dx
, return segment of UMB found in dx
and size in paragraphs in cx.
296 xor cx
, cx
! Initially nothing found
297 mov ax
, 0x3000 ! Get DOS version
299 cmpb al
, 5 ! MS-DOS
5.0 or better?
301 mov ax
, 0x544D ! Get UMB kept by BOOT
/U
302 int
0x15 ! Returns dx
= segment
, cx
= size
304 cmp ax
, 0x4D54 ! Carry clear
and ax byte swapped?
306 0: mov ax
, 0x5802 ! Get UMB link state
309 push ax
! Save UMB link state
310 mov ax
, 0x5803 ! Set UMB link state
311 mov bx
, 0x0001 ! Add UMBs to DOS memory chain
313 mov ax
, 0x5800 ! Get memory allocation strategy
315 push ax
! Save allocation strategy
316 mov ax
, 0x5801 ! Set memory allocation strategy
317 mov bx
, 0x0080 ! First fit
, try high then low memory
319 movb ah
, 0x48 ! Allocate memory
320 mov bx
, dx
! Number of paragraphs wanted
321 int
0x21 ! Fails with bx
= size of largest
322 jnc
0f
! Succeeds with ax
= allocated block
323 test bx
, bx
! Is there any?
325 movb ah
, 0x48 ! Allocate memory
327 jc no_umb
! Did we get some?
328 0: mov dx
, ax
! dx
= segment
329 mov cx
, bx
! cx
= size
330 no_umb
: mov ax
, 0x5801 ! Set memory allocation strategy
331 pop bx
! bx
= saved former strategy
333 mov ax
, 0x5803 ! Set UMB link state
334 pop bx
! bx
= saved former link state
338 ! 'BOOT /U' instructs this program to grab the biggest available UMB
and to
339 ! sit on it until the next invocation of BOOT wants it back. These shenanigans
340 ! are necessary because Windows
95 keeps all UMBs to itself unless you get hold
342 umb
= 0x80 ! UMB base
and size
343 old15
= 0x84 ! Old
15 interrupt vector
344 new15
= 0x88 ! New
15 interrupt handler
346 mov ax
, 0x544D ! "Keep UMB" handler already present?
350 je exitumb
! Already present
, so quit
356 rep movsb
! Copy handler into place
359 shr di
, cl
! di
= first segment above handler
361 cmp cx
, 0xA000 ! Are we loaded high perchance?
365 mov
(umb+
0), cx
! Use my own memory as the UMB to keep
366 mov ax
, (_PSP+
2) ! Up to the next in-use segment
367 sub ax
, dx
! ax
= size of my free memory
368 cmp ax
, 0x1000 ! At least
64K?
369 jb exitumb
! Don
't bother if less
370 mov (umb+2), 0x1000 ! Size of UMB
371 add di, 0x1000 ! Keep my code plus 64K when TSR
375 call getumb ! Grab an UMB of at most 64K
376 cmp cx, 0x1000 ! Did we get 64K?
377 jb exitumb ! Otherwise don't bother
381 mov ax
, 0x3515 ! Get interrupt vector
384 mov
(old15+
2), es
! Old
15 interrupt
385 mov ax
, 0x2515 ! Set interrupt vector
386 mov dx
, new15
! ds
:dx
= new
15 handler
388 mov ax
, 0x3100 ! Terminate
and stay resident
389 mov dx
, di
! dx
= di
= paragraphs we keep
392 mov ax
, 0x4C00 ! exit
(0)
395 new15start
: ! New interrupt
15 handler
397 cmp ax
, 0x544D ! Is it my call?
400 cseg jmpf
(old15
) ! No
, continue with old
15
404 andb
6(bp
), ~
0x01 ! clear carry
, call will succeed
405 xchgb al
, ah
! ax
= 4D54
, also means call works
406 cseg mov dx
, (umb+
0) ! dx
= base of UMB
407 cseg mov cx
, (umb+
2) ! cx
= size of UMB
409 iret
! return to caller
412 ! u32_t mon2abs
(void
*ptr
)
413 ! Address in monitor data to absolute address.
418 mov dx
, ds
! Monitor data segment
421 seg2abs
: ! Translate dx
:ax to the
32 bit address dx-ax
426 shrb ch
, cl
! ch-dx
= dx
<< 4
428 adcb ch
, 0 ! ch-ax
= ch-dx
+ ax
430 xorb dh
, dh
! dx-ax
= ch-ax
434 abs2seg
: ! Translate the
32 bit address dx-ax to dx
:ax
437 mov dx
, ax
! ch-dx
= dx-ax
438 and ax
, 0x000F ! Offset in ax
442 orb dh
, ch
! dx
= ch-dx
>> 4
446 ! void raw_copy
(u32_t dstaddr
, u32_t srcaddr
, u32_t count
)
447 ! Copy count bytes from srcaddr to dstaddr. Don
't do overlaps.
448 ! Also handles copying words to or from extended memory.
454 push di ! Save C variable registers
459 jcxz copydone ! Count is zero, end copy
462 bigcopy:mov cx, 0xFFF0 ! Don't copy more than about
64K at once
464 push cx
! Save copying count
467 cmp dx
, 0x0010 ! Copy to extended memory?
469 cmp 10(bp
), 0x0010 ! Copy from extended memory?
473 mov es
, dx
! es
:di
= dstaddr
478 mov ds
, dx
! ds
:si
= srcaddr
479 shr cx
, 1 ! Words to move
480 rep movs
! Do the word copy
481 adc cx
, cx
! One more byte?
482 rep movsb
! Do the byte copy
483 mov ax
, ss
! Restore ds
and es from the remaining ss
488 mov
(x_dst_desc+
2), ax
489 movb
(x_dst_desc+
4), dl
! Set base of destination segment
492 mov
(x_src_desc+
2), ax
493 movb
(x_src_desc+
4), dl
! Set base of source segment
494 mov si
, x_gdt
! es
:si
= global descriptor table
495 shr cx
, 1 ! Words to move
496 movb ah
, 0x87 ! Code for extended memory move
499 pop cx
! Restore count
501 adc
6(bp
), 0 ! srcaddr
+= copycount
503 adc
10(bp
), 0 ! dstaddr
+= copycount
505 sbb
14(bp
), 0 ! count
-= copycount
506 jmp copy
! and repeat
509 pop si
! Restore C variable registers
513 ! u16_t get_word
(u32_t addr
);
514 ! void put_word
(u32_t addr
, u16_t word
);
515 ! Read
or write
a 16 bits word at an arbitrary location.
516 .define _get_word, _put_word
520 mov ax
, (bx
) ! Word to get from addr
524 push
6(bx
) ! Word to store at addr
526 pop
(bx
) ! Store the word
533 mov ds
, dx
! ds
:bx
= addr
540 ! void relocate
(void
);
541 ! After the program has copied itself to
a safer place
, it needs to change
542 ! the segment registers. Caddr has already been set to the new location.
545 pop bx
! Return address
549 mov cx
, dx
! cx
= new code segment
550 mov ax
, cs
! Old code segment
551 sub ax
, cx
! ax
= -(new
- old
) = -Moving offset
554 mov ds
, dx
! ds
+= (new
- old
)
560 mov
(_daddr+
2), dx
! New data address
561 push cx
! New text segment
562 push bx
! Return offset of this function
565 ! void
*brk
(void
*addr
)
566 ! void
*sbrk
(size_t incr
)
567 ! Cannot fail implementations of brk
(2) and sbrk
(3), so we can use
568 ! malloc
(3). They reboot on stack collision instead of returning -1.
571 break
: .data2 _end ! A fake heap pointer
573 .define _brk, __brk, _sbrk, __sbrk
575 __brk
: ! __brk is for the standard C compiler
577 jmp sbrk
! break
= 0; return sbrk
(addr
);
580 mov ax
, (break
) ! ax
= current break
581 sbrk
: push ax
! save it as future return value
582 mov bx
, sp
! Stack is now
: (retval
, retaddr
, incr
, ...)
583 add ax
, 4(bx
) ! ax
= break
+ increment
584 mov
(break
), ax
! Set new break
585 lea dx
, -1024(bx
) ! sp minus
a bit of breathing space
586 cmp dx
, ax
! Compare with the new break
587 jb heaperr
! Suffocating noises
588 pop ax
! Return old break
(0 for brk
)
594 nomem
: .ascii "\nOut of memory\n\0"
597 ! int dev_open
(void
);
598 ! Open file
'vdisk' to use as the Minix virtual disk. Store handle in
599 ! vfd. Returns
0 for success
, otherwise the DOS error code.
602 call _dev_close
! If already open then first close
603 mov dx
, (_vdisk
) ! ds
:dx
= Address of file name
604 mov ax
, 0x3D22 ! Open file read-write
& deny write
606 jnc opok
! Open succeeded?
607 cmp ax
, 5 ! Open failed
, "access denied"?
609 mov ax
, 0x3D40 ! Open file read-only
612 opok
: mov
(vfd
), ax
! File handle to open file
613 xor ax
, ax
! Zero for success
616 ! int dev_close
(void
);
617 ! Close the dos virtual disk.
621 cmp (vfd
), bx
! Already closed?
623 movb ah
, 0x3E ! Close file
624 xchg bx
, (vfd
) ! bx
= vfd; vfd
= -1;
630 ! int dev_boundary
(u32_t sector
);
631 ! Returns false; files have no visible boundaries.
632 .define _dev_boundary
637 ! int readsectors
(u32_t bufaddr
, u32_t sector
, u8_t count
)
638 ! int writesectors
(u32_t bufaddr
, u32_t sector
, u8_t count
)
639 ! Read
/write several sectors from
/to the Minix virtual disk. Count
640 ! must fit in
a byte. The external variable vfd is the file handle.
641 ! Returns
0 for success
, otherwise the DOS error code.
643 .define _readsectors, _writesectors
647 movb
13(bp
), 0x40 ! Code for
a file write
652 movb
13(bp
), 0x3F ! Code for
a file read
654 cmp (vfd
), -1 ! Currently closed?
656 call _dev_open
! Open file if needed
660 mov bx
, 10(bp
) ! bx-dx
= Sector number
663 rcl bx
, 1 ! bx-dx
*= 512
665 mov cx
, bx
! cx-dx
= Byte position in file
666 mov bx
, (vfd
) ! bx
= File handle
667 mov ax
, 0x4200 ! Lseek absolute
670 mov bx
, (vfd
) ! bx
= File handle
672 mov dx
, 6(bp
) ! dx-ax
= Address to transfer data to
/from
675 mov dx
, ax
! ds
:dx
= Address to transfer data to
/from
677 movb ch
, 12(bp
) ! ch
= Number of sectors to transfer
678 shl cx
, 1 ! cx
= Number of bytes to transfer
680 movb ah
, 13(bp
) ! Read
or write
682 pop cx
! Restore count
686 cmp ax
, cx
! All bytes transferred?
688 mov ax
, 0x05 ! The DOS code for
"I/O error", but different
690 rwall
: call wheel
! Display tricks
696 ! Read
a character from the keyboard
, and check for an expired timer.
697 ! A carriage return is changed into
a linefeed for UNIX compatibility.
701 xchg ax
, (unchar
) ! Ungotten character?
704 getch
: hlt
! Play dead until interrupted
(see pause
())
705 movb ah
, 0x01 ! Keyboard status
707 jnz press
! Keypress?
708 call _expired
! Timer expired?
711 mov ax
, ESC
! Return ESC
714 xorb ah
, ah
! Read character from keyboard
716 cmpb al
, 0x0D ! Carriage return?
718 movb al
, 0x0A ! Change to linefeed
719 nocr
: cmpb al
, ESC
! Escape typed?
721 inc
(escape
) ! Set flag
722 noesc
: xorb ah
, ah
! ax
= al
726 ! Return
a character to undo
a getch
().
735 ! True if ESC has been typed.
738 movb ah
, 0x01 ! Keyboard status
740 jz escflg
! Keypress?
741 cmpb al
, ESC
! Escape typed?
743 xorb ah
, ah
! Discard the escape
745 inc
(escape
) ! Set flag
747 xchg ax
, (escape
) ! Escape typed flag
751 ! Write
a character in teletype mode. The putk synonym is
752 ! for the kernel printf function that uses it.
753 ! Newlines are automatically preceded by
a carriage return.
755 .define _putch, _putk
758 movb al
, 2(bx
) ! al
= character to
be printed
759 testb al
, al
! Kernel printf adds
a null char to flush queue
761 cmpb al
, 0x0A ! al
= newline?
763 movb al
, 0x20 ! Erase wheel
and do
a carriage return
764 call plotc
! plotc
(' ');
765 nodirt
: movb al
, 0x0D
766 call putc
! putc
('\r')
767 movb al
, 0x0A ! Restore the
'\n' and print it
768 putc
: movb ah
, 0x0E ! Print character in teletype mode
769 mov bx
, 0x0001 ! Page
0, foreground color
770 int
0x10 ! Call BIOS VIDEO_IO
773 ! |
/-\|
/-\|
/-\|
/-\|
/-\
(playtime
)
780 0: mov
(gp
), bx
! gp
= gp
== glyphs
+ 4 ? glyphs
: gp;
782 plotc
: movb ah
, 0x0A ! 0x0A = write character at cursor
783 mov bx
, 0x0001 ! Page
0, foreground color
784 mov cx
, 0x0001 ! Just one character
790 glyphs
: .ascii "|/-\\"
794 ! Wait for an interrupt using the HLT instruction. This either saves
795 ! power
, or tells an x86 emulator that nothing is happening right now.
801 ! void set_mode
(unsigned mode
);
802 ! void clear_screen
(void
);
803 ! Set video mode
/ clear the screen.
804 .define _set_mode, _clear_screen
807 mov ax
, 2(bx
) ! Video mode
808 cmp ax
, (cur_vid_mode
)
809 je modeok
! Mode already as requested?
810 mov
(cur_vid_mode
), ax
812 mov ax
, (cur_vid_mode
)
813 andb ah
, 0x7F ! Test bits
8-14, clear bit
15 (8x8 flag
)
814 jnz xvesa
! VESA extended mode?
815 int
0x10 ! Reset video
(ah
= 0)
817 xvesa
: mov bx
, ax
! bx
= extended mode
818 mov ax
, 0x4F02 ! Reset video
820 mdset
: testb
(cur_vid_mode+
1), 0x80
821 jz setcur
! 8x8 font requested?
822 mov ax
, 0x1112 ! Load ROM
8 by
8 double-dot patterns
823 xorb
bl, bl ! Load block
0
825 setcur
: xor dx
, dx
! dl
= column
= 0, dh
= row
= 0
827 movb ah
, 0x02 ! Set cursor position
831 restore_video
: ! To restore the video mode on exit
833 call plotc
! Erase wheel
839 ! u32_t get_tick
(void
);
840 ! Return the current value of the clock tick counter. This counter
841 ! increments
18.2 times per second. Poll it to do delays. Does
not
842 ! work on the original PC
, but works on the PC
/XT.
845 xorb ah
, ah
! Code for get tick count
848 mov dx
, cx
! dx
:ax
= cx
:dx
= tick count
852 ! Functions used to obtain info about the hardware. Boot uses this information
853 ! itself
, but will also pass them on to
a pure
386 kernel
, because one can
't
854 ! make BIOS calls from protected mode. The video type could probably be
855 ! determined by the kernel too by looking at the hardware, but there is a small
856 ! chance on errors that the monitor allows you to correct by setting variables.
858 .define _get_bus ! returns type of system bus
859 .define _get_video ! returns type of display
861 ! u16_t get_bus(void)
862 ! Return type of system bus, in order: XT, AT, MCA.
865 xor dx, dx ! Assume XT
866 cmp ax, 286 ! An AT has at least a 286
869 movb ah, 0xC0 ! Code for get configuration
871 jc got_bus ! Carry clear and ah = 00 if supported
874 eseg movb al, 5(bx) ! Load feature byte #1
876 testb al, 0x02 ! Test bit 1 - "bus is Micro Channel"
879 testb al, 0x40 ! Test bit 6 - "2nd 8259 installed"
885 mov ax, dx ! Return bus code
886 mov (bus), ax ! Keep bus code, A20 handler likes to know
889 ! u16_t get_video(void)
890 ! Return type of display, in order: MDA, CGA, mono EGA, color EGA,
891 ! mono VGA, color VGA.
893 mov ax, 0x1A00 ! Function 1A returns display code
894 int 0x10 ! al = 1A if supported
896 jnz no_dc ! No display code function supported
899 cmpb bl, 5 ! Is it a monochrome EGA?
902 cmpb bl, 4 ! Is it a color EGA?
905 cmpb bl, 7 ! Is it a monochrome VGA?
908 cmpb bl, 8 ! Is it a color VGA?
911 no_dc: movb ah, 0x12 ! Get information about the EGA
914 cmpb bl, 0x10 ! Did it come back as 0x10? (No EGA)
918 cmpb bh, 1 ! Is it monochrome?
923 no_ega: int 0x11 ! Get bit pattern for equipment
924 and ax, 0x30 ! Isolate color/mono field
926 jz got_video ! Is it an MDA?
927 mov ax, 1 ! No it's CGA
933 ! Function to leave the boot monitor
and run Minix.
936 ! void minix
(u32_t koff
, u32_t kcs
, u32_t kds
,
937 ! char
*bootparams
, size_t paramsize
, u32_t aout
);
940 mov bp
, sp
! Pointer to arguments
942 mov dx
, 0x03F2 ! Floppy motor drive control bits
943 movb al
, 0x0C ! Bits
4-7 for floppy
0-3 are off
944 outb dx
! Kill the motors
946 xor ax
, ax
! Vector
& BIOS data segments
948 andb
(0x043F), 0xF0 ! Clear diskette motor status bits of BIOS
950 cli ! No more interruptions
952 test
(_k_flags
), K_I386
! Minix-
386?
955 ! Call Minix in real mode.
957 push
22(bp
) ! Address of
a.out headers
960 push
18(bp
) ! # bytes of boot parameters
961 push
16(bp
) ! Address of boot parameters
963 mov dx
, cs
! Monitor far return address
965 cmp (_mem+
14), 0 ! Any extended memory?
(mem
[1].size > 0 ?)
967 xor dx
, dx
! If no ext mem then monitor
not preserved
969 0: push dx
! Push monitor far return address
or zero
975 push dx
! Kernel code segment
976 push
4(bp
) ! Kernel code offset
980 mov ds
, dx
! Kernel data segment
981 mov es
, dx
! Set es to kernel data too
982 retf
! Make
a far call to the kernel
984 ! Call
386 Minix in
386 mode.
986 cseg mov
(cs_real-
2), cs
! Patch CS
and DS into the instructions that
987 cseg mov
(ds_real-
2), ds
! reload them when switching back to real mode
989 orb al
, 0x01 ! Set PE
(protection enable
) bit
990 o32 mov
(msw
), eax
! Save as protected mode machine status word
992 mov dx
, ds
! Monitor ds
993 mov ax
, p_gdt
! dx
:ax
= Global descriptor table
995 mov
(p_gdt_desc+
2), ax
996 movb
(p_gdt_desc+
4), dl
! Set base of global descriptor table
999 mov dx
, 14(bp
) ! Kernel ds
(absolute address
)
1000 mov
(p_ds_desc+
2), ax
1001 movb
(p_ds_desc+
4), dl
! Set base of kernel data segment
1003 mov dx
, ss
! Monitor ss
1004 xor ax
, ax
! dx
:ax
= Monitor stack segment
1005 call seg2abs
! Minix starts with the stack of the monitor
1006 mov
(p_ss_desc+
2), ax
1007 movb
(p_ss_desc+
4), dl
1010 mov dx
, 10(bp
) ! Kernel cs
(absolute address
)
1011 mov
(p_cs_desc+
2), ax
1012 movb
(p_cs_desc+
4), dl
1014 mov dx
, cs
! Monitor cs
1015 xor ax
, ax
! dx
:ax
= Monitor code segment
1017 mov
(p_mcs_desc+
2), ax
1018 movb
(p_mcs_desc+
4), dl
1021 push int86
! Far address to INT86 support
1023 o32 push
20(bp
) ! Address of
a.out headers
1026 push
18(bp
) ! 32 bit size of parameters on stack
1028 push
16(bp
) ! 32 bit address of parameters
(ss relative
)
1031 push ret386
! Monitor far return address
1036 push
4(bp
) ! 32 bit far address to kernel entry point
1038 call real2prot
! Switch to protected mode
1040 mov ds
, ax
! Kernel data
1042 mov es
, ax
! Flat
4 Gb
1043 o32 retf
! Make
a far call to the kernel
1045 ! Minix-
86 returns here on
a halt
or reboot.
1048 mov
10(bp
), dx
! Return value
1051 ! Minix-
386 returns here on
a halt
or reboot.
1053 o32 mov
8(bp
), eax
! Return value
1054 call prot2real
! Switch to real mode
1057 mov sp
, bp
! Pop parameters
1058 sti
! Can take interrupts again
1060 call _get_video
! MDA
, CGA
, EGA
, ...
1061 movb dh
, 24 ! dh
= row
24
1062 cmp ax
, 2 ! At least EGA?
1063 jb is25
! Otherwise
25 rows
1065 xor ax
, ax
! Vector
& BIOS data segments
1067 movb dh
, (0x0484) ! Number of rows on display minus one
1070 xorb dl
, dl
! dl
= column
0
1071 xorb bh
, bh
! Page
0
1072 movb ah
, 0x02 ! Set cursor position
1075 xorb ah
, ah
! Whack the disk system
, Minix may have messed
1076 movb dl
, 0x80 ! it up
1085 movb ah
, 0x02 ! Get real-time clock time
(from CMOS clock
)
1087 jc tryclk
! Carry set
, not running
or being updated
1088 movb al
, ch
! ch
= hour in BCD
1089 call bcd
! al
= (al
>> 4) * 10 + (al
& 0x0F)
1090 mulb
(c60
) ! 60 minutes in an hour
1091 mov bx
, ax
! bx
= hour
* 60
1092 movb al
, cl
! cl
= minutes in BCD
1094 add bx
, ax
! bx
= hour
* 60 + minutes
1095 movb al
, dh
! dh
= seconds in BCD
1097 xchg ax
, bx
! ax
= hour
* 60 + minutes
, bx
= seconds
1098 mul (c60
) ! dx-ax
= (hour
* 60 + minutes
) * 60
1100 adc dx
, 0 ! dx-bx
= seconds since midnight
1105 add dx
, bx
! dx-ax
= dx-bx
* (0x1800B0 / (2*2*2*2*5))
1106 mov cx
, ax
! (0x1800B0 = ticks per day of BIOS clock
)
1111 div (c1080
) ! cx-ax
= dx-ax
/ (24*60*60 / (2*2*2*2*5))
1112 mov dx
, ax
! cx-dx
= ticks since midnight
1113 movb ah
, 0x01 ! Set system time
1118 mov dx
, 10(bp
) ! dx-ax
= return value from the kernel
1120 ret
! Return to monitor as if nothing much happened
1122 ! Transform BCD number in al to
a regular value in ax.
1126 aad
! ax
= (al
>> 4) * 10 + (al
& 0x0F)
1129 ! Support function for Minix-
386 to make an
8086 interrupt call.
1135 mov es
, ax
! Vector
& BIOS data segments
1136 o32 eseg mov
(0x046C), eax
! Clear BIOS clock tick counter
1138 sti
! Enable interrupts
1140 movb al
, 0xCD ! INT instruction
1141 movb ah
, 8(bp
) ! Interrupt number?
1143 jnz
0f
! Nonzero if INT
, otherwise far call
1145 push intret+
2 ! Far return address
1146 o32 push
12(bp
) ! Far driver address
1147 mov ax
, 0x90CB ! RETF;
NOP
1148 0: cseg mov
(intret
), ax
! Patch
'INT n' or 'RETF; NOP' into code
1150 mov ds
, 16(bp
) ! Load parameters
1160 intret
: int
0xFF ! Do the interrupt
or far call
1162 o32 push ebp
! Save results
1165 o32 pop
8+8(bp
) ! eflags
1168 o32 mov
8+20(bp
), eax
1169 o32 mov
8+24(bp
), ebx
1170 o32 mov
8+28(bp
), ecx
1171 o32 mov
8+32(bp
), edx
1172 o32 mov
8+36(bp
), esi
1173 o32 mov
8+40(bp
), edi
1174 o32 pop
8+44(bp
) ! ebp
1176 cli ! Disable interrupts
1179 mov ds
, ax
! Vector
& BIOS data segments
1180 o32 mov cx
, (0x046C) ! Collect lost clock ticks in ecx
1183 mov ds
, ax
! Restore monitor ds
1185 mov ax
, DS_SELECTOR
! Kernel data
1187 o32 retf
! Return to the kernel
1189 ! Switch from real to protected mode.
1191 movb ah
, 0x02 ! Code for A20 enable
1194 lgdt
(p_gdt_desc
) ! Global descriptor table
1195 o32 mov eax
, (pdbr
) ! Load page directory base register
1198 o32 xchg eax
, (msw
) ! Exchange real mode msw for protected mode msw
1200 jmpf MCS_SELECTOR
:cs_prot
! Set code segment selector
1202 mov ax
, SS_SELECTOR
! Set data selectors
1208 ! Switch from protected to real mode.
1210 lidt
(p_idt_desc
) ! Real mode interrupt vectors
1212 o32 mov
(pdbr
), eax
! Save page directory base register
1214 o32 xchg eax
, (msw
) ! Exchange protected mode msw for real mode msw
1216 jmpf
0xDEAD:cs_real
! Reload cs register
1220 mov ds
, ax
! Reload data segment registers
1224 xorb ah
, ah
! Code for A20 disable
1227 ! Enable
(ah
= 0x02) or disable
(ah
= 0x00) the A20 address line.
1229 cmp (bus
), 2 ! PS
/2 bus?
1232 movb al
, 0xD1 ! Tell keyboard that
a command is coming
1235 movb al
, 0xDD ! 0xDD = A20 disable code if ah
= 0x00
1236 orb al
, ah
! 0xDF = A20 enable code if ah
= 0x02
1239 movb al
, 0xFF ! Pulse output port
1241 call kb_wait
! Wait for the A20 line to settle down
1245 testb al
, 0x02 ! Keyboard input buffer full?
1246 jnz kb_wait
! If so
, wait
1249 gate_PS_A20
: ! The PS
/2 can twiddle A20 using port
A
1250 inb
0x92 ! Read port
A
1252 orb al
, ah
! Set A20 bit to the required state
1253 outb
0x92 ! Write port
A
1254 jmp
.+2 ! Small delay
1255 A20ok
: inb
0x92 ! Check port
A
1257 cmpb al
, ah
! A20 line settled down to the new state?
1258 jne A20ok
! If
not then wait
1261 ! void int15
(bios_env_t
*ep
)
1262 ! Do an
"INT 15" call
, primarily for APM
(Power Management
).
1265 push si
! Save callee-save register si
1268 mov ax
, (si
) ! ep-
>ax
1269 mov bx
, 2(si
) ! ep-
>bx
1270 mov cx
, 4(si
) ! ep-
>cx
1271 int
0x15 ! INT
0x15 BIOS call
1273 mov
(si
), ax
! ep-
>ax
1274 mov
2(si
), bx
! ep-
>bx
1275 mov
4(si
), cx
! ep-
>cx
1276 pop
6(si
) ! ep-
>flags
1282 c60
: .data2 60 ! Constants for MUL and DIV
1285 c19663
: .data2 19663
1290 ! Global descriptor tables.
1291 UNSET
= 0 ! Must
be computed
1293 ! For
"Extended Memory Block Move".
1297 .data2 0x0000, 0x0000
1298 .data1 0x00, 0x00, 0x00, 0x00
1300 ! Descriptor for this descriptor table
1302 .data1 UNSET, 0x00, 0x00, 0x00
1304 ! Source segment descriptor
1305 .data2 0xFFFF, UNSET
1306 .data1 UNSET, 0x92, 0x00, 0x00
1308 ! Destination segment descriptor
1309 .data2 0xFFFF, UNSET
1310 .data1 UNSET, 0x92, 0x00, 0x00
1312 ! BIOS segment descriptor
(scratch for int
0x15)
1314 .data1 UNSET, UNSET, UNSET, UNSET
1316 ! BIOS stack segment descriptor
(scratch for int
0x15)
1318 .data1 UNSET, UNSET, UNSET, UNSET
1320 ! Protected mode descriptor table.
1324 .data2 0x0000, 0x0000
1325 .data1 0x00, 0x00, 0x00, 0x00
1327 ! Descriptor for this descriptor table
1329 .data1 UNSET, 0x00, 0x00, 0x00
1331 ! Real mode interrupt descriptor table descriptor
1332 .data2 0x03FF, 0x0000
1333 .data1 0x00, 0x00, 0x00, 0x00
1335 ! Kernel data segment descriptor
(4Gb flat
)
1336 .data2 0xFFFF, UNSET
1337 .data1 UNSET, 0x92, 0xCF, 0x00
1339 ! Physical memory descriptor
(4Gb flat
)
1340 .data2 0xFFFF, 0x0000
1341 .data1 0x00, 0x92, 0xCF, 0x00
1343 ! Monitor data segment descriptor
(64Kb flat
)
1344 .data2 0xFFFF, UNSET
1345 .data1 UNSET, 0x92, 0x00, 0x00
1347 ! Kernel code segment descriptor
(4Gb flat
)
1348 .data2 0xFFFF, UNSET
1349 .data1 UNSET, 0x9A, 0xCF, 0x00
1351 ! Monitor code segment descriptor
(64 kb flat
) (unused
)
1352 .data2 0xFFFF, UNSET
1353 .data1 UNSET, 0x9A, 0x00, 0x00
1355 xms_handle
: .data2 -1 ! Handle of allocated XMS block
1356 vfd
: .data2 -1 ! Virtual disk file handle
1359 .comm xms_driver, 4 ! Vector to XMS driver
1360 .comm old_vid_mode, 2 ! Video mode at startup
1361 .comm cur_vid_mode, 2 ! Current video mode
1362 .comm msw, 4 ! Saved machine status word (cr0)
1363 .comm pdbr, 4 ! Saved page directory base register (cr3)
1364 .comm escape, 2 ! Escape typed?
1365 .comm bus, 2 ! Saved return value of _get_bus
1366 .comm unchar, 2 ! Char returned by ungetch(c)
1369 ! $PchId
: doshead.ack.s
,v
1.7 2002/02/27 19:37:52 philip Exp $