Import of original zoneinfo code and database - tzcode
[minix3.git] / boot / boothead.s
blobb79689c3b610a21688204b942874c01e9ebb0017
1 ! Boothead.s - 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 ! The primary bootstrap code supplies the following parameters in registers:
9 ! dl = Boot-device.
10 ! es:si = Partition table entry if hard disk.
12 .text
14 o32 = 0x66 ! This assembler doesn't know 386 extensions
15 BOOTOFF = 0x7C00 ! 0x0000:BOOTOFF load a bootstrap here
16 LOADSEG = 0x1000 ! Where this code is loaded.
17 BUFFER = 0x0600 ! First free memory
18 PENTRYSIZE = 16 ! Partition table entry size.
19 a_flags = 2 ! From a.out.h, struct exec
20 a_text = 8
21 a_data = 12
22 a_bss = 16
23 a_total = 24
24 A_SEP = 0x20 ! Separate I&D flag
25 K_I386 = 0x0001 ! Call Minix in 386 mode
26 K_RET = 0x0020 ! Returns to the monitor on reboot
27 K_INT86 = 0x0040 ! Requires generic INT support
28 K_MEML = 0x0080 ! Pass a list of free memory
30 DS_SELECTOR = 3*8 ! Kernel data selector
31 ES_SELECTOR = 4*8 ! Flat 4 Gb
32 SS_SELECTOR = 5*8 ! Monitor stack
33 CS_SELECTOR = 6*8 ! Kernel code
34 MCS_SELECTOR= 7*8 ! Monitor code
36 ESC = 0x1B ! Escape character
38 ! Imported variables and functions:
39 .extern _caddr, _daddr, _runsize, _edata, _end ! Runtime environment
40 .extern _device ! BIOS device number
41 .extern _rem_part ! To pass partition info
42 .extern _k_flags ! Special kernel flags
43 .extern _mem ! Free memory list
45 .text
47 ! Set segment registers and stack pointer using the programs own header!
48 ! The header is either 32 bytes (short form) or 48 bytes (long form). The
49 ! bootblock will jump to address 0x10030 in both cases, calling one of the
50 ! two jmpf instructions below.
52 jmpf boot, LOADSEG+3 ! Set cs right (skipping long a.out header)
53 .space 11 ! jmpf + 11 = 16 bytes
54 jmpf boot, LOADSEG+2 ! Set cs right (skipping short a.out header)
55 boot:
56 mov ax, #LOADSEG
57 mov ds, ax ! ds = header
59 movb al, a_flags
60 testb al, #A_SEP ! Separate I&D?
61 jnz sepID
62 comID: xor ax, ax
63 xchg ax, a_text ! No text
64 add a_data, ax ! Treat all text as data
65 sepID:
66 mov ax, a_total ! Total nontext memory usage
67 and ax, #0xFFFE ! Round down to even
68 mov a_total, ax ! total - text = data + bss + heap + stack
69 cli ! Ignore interrupts while stack in limbo
70 mov sp, ax ! Set sp at the top of all that
72 mov ax, a_text ! Determine offset of ds above cs
73 movb cl, #4
74 shr ax, cl
75 mov cx, cs
76 add ax, cx
77 mov ds, ax ! ds = cs + text / 16
78 mov ss, ax
79 sti ! Stack ok now
80 push es ! Save es, we need it for the partition table
81 mov es, ax
82 cld ! C compiler wants UP
84 ! Clear bss
85 xor ax, ax ! Zero
86 mov di, #_edata ! Start of bss is at end of data
87 mov cx, #_end ! End of bss (begin of heap)
88 sub cx, di ! Number of bss bytes
89 shr cx, #1 ! Number of words
90 rep
91 stos ! Clear bss
93 ! Copy primary boot parameters to variables. (Can do this now that bss is
94 ! cleared and may be written into).
95 xorb dh, dh
96 mov _device, dx ! Boot device (probably 0x00 or 0x80)
97 mov _rem_part+0, si ! Remote partition table offset
98 pop _rem_part+2 ! and segment (saved es)
100 ! Remember the current video mode for restoration on exit.
101 movb ah, #0x0F ! Get current video mode
102 int 0x10
103 andb al, #0x7F ! Mask off bit 7 (no blanking)
104 movb old_vid_mode, al
105 movb cur_vid_mode, al
107 ! Give C code access to the code segment, data segment and the size of this
108 ! process.
109 xor ax, ax
110 mov dx, cs
111 call seg2abs
112 mov _caddr+0, ax
113 mov _caddr+2, dx
114 xor ax, ax
115 mov dx, ds
116 call seg2abs
117 mov _daddr+0, ax
118 mov _daddr+2, dx
119 push ds
120 mov ax, #LOADSEG
121 mov ds, ax ! Back to the header once more
122 mov ax, a_total+0
123 mov dx, a_total+2 ! dx:ax = data + bss + heap + stack
124 add ax, a_text+0
125 adc dx, a_text+2 ! dx:ax = text + data + bss + heap + stack
126 pop ds
127 mov _runsize+0, ax
128 mov _runsize+2, dx ! 32 bit size of this process
130 ! Determine available memory as a list of (base,size) pairs as follows:
131 ! mem[0] = low memory, mem[1] = memory between 1M and 16M, mem[2] = memory
132 ! above 16M. Last two coalesced into mem[1] if adjacent.
133 mov di, #_mem ! di = memory list
134 int 0x12 ! Returns low memory size (in K) in ax
135 mul c1024
136 mov 4(di), ax ! mem[0].size = low memory size in bytes
137 mov 6(di), dx
138 call _getprocessor
139 cmp ax, #286 ! Only 286s and above have extended memory
140 jb no_ext
141 cmp ax, #486 ! Assume 486s were the first to have >64M
142 jb small_ext ! (It helps to be paranoid when using the BIOS)
143 big_ext:
144 mov ax, #0xE801 ! Code for get memory size for >64M
145 int 0x15 ! ax = mem at 1M per 1K, bx = mem at 16M per 64K
146 jnc got_ext
147 small_ext:
148 movb ah, #0x88 ! Code for get extended memory size
149 clc ! Carry will stay clear if call exists
150 int 0x15 ! Returns size (in K) in ax for AT's
151 jc no_ext
152 test ax, ax ! An AT with no extended memory?
153 jz no_ext
154 xor bx, bx ! bx = mem above 16M per 64K = 0
155 got_ext:
156 mov cx, ax ! cx = copy of ext mem at 1M
157 mov 10(di), #0x0010 ! mem[1].base = 0x00100000 (1M)
158 mul c1024
159 mov 12(di), ax ! mem[1].size = "ext mem at 1M" * 1024
160 mov 14(di), dx
161 test bx, bx
162 jz no_ext ! No more ext mem above 16M?
163 cmp cx, #15*1024 ! Chunks adjacent? (precisely 15M at 1M?)
164 je adj_ext
165 mov 18(di), #0x0100 ! mem[2].base = 0x01000000 (16M)
166 mov 22(di), bx ! mem[2].size = "ext mem at 16M" * 64K
167 jmp no_ext
168 adj_ext:
169 add 14(di), bx ! Add ext mem above 16M to mem below 16M
170 no_ext:
173 ! Time to switch to a higher level language (not much higher)
174 call _boot
176 ! void ..exit(int status)
177 ! Exit the monitor by rebooting the system.
178 .define _exit, __exit, ___exit ! Make various compilers happy
179 _exit:
180 __exit:
181 ___exit:
182 mov bx, sp
183 cmp 2(bx), #0 ! Good exit status?
184 jz reboot
185 quit: mov ax, #any_key
186 push ax
187 call _printf
188 xorb ah, ah ! Read character from keyboard
189 int 0x16
190 reboot: call dev_reset
191 call restore_video
192 int 0x19 ! Reboot the system
193 .data
194 any_key:
195 .ascii "\nHit any key to reboot\n\0"
196 .text
198 ! u32_t mon2abs(void *ptr)
199 ! Address in monitor data to absolute address.
200 .define _mon2abs
201 _mon2abs:
202 mov bx, sp
203 mov ax, 2(bx) ! ptr
204 mov dx, ds ! Monitor data segment
205 jmp seg2abs
207 ! u32_t vec2abs(vector *vec)
208 ! 8086 interrupt vector to absolute address.
209 .define _vec2abs
210 _vec2abs:
211 mov bx, sp
212 mov bx, 2(bx)
213 mov ax, (bx)
214 mov dx, 2(bx) ! dx:ax vector
215 !jmp seg2abs ! Translate
217 seg2abs: ! Translate dx:ax to the 32 bit address dx-ax
218 push cx
219 movb ch, dh
220 movb cl, #4
221 shl dx, cl
222 shrb ch, cl ! ch-dx = dx << 4
223 add ax, dx
224 adcb ch, #0 ! ch-ax = ch-dx + ax
225 movb dl, ch
226 xorb dh, dh ! dx-ax = ch-ax
227 pop cx
230 abs2seg: ! Translate the 32 bit address dx-ax to dx:ax
231 push cx
232 movb ch, dl
233 mov dx, ax ! ch-dx = dx-ax
234 and ax, #0x000F ! Offset in ax
235 movb cl, #4
236 shr dx, cl
237 shlb ch, cl
238 orb dh, ch ! dx = ch-dx >> 4
239 pop cx
242 ! void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count)
243 ! Copy count bytes from srcaddr to dstaddr. Don't do overlaps.
244 ! Also handles copying words to or from extended memory.
245 .define _raw_copy
246 _raw_copy:
247 push bp
248 mov bp, sp
249 push si
250 push di ! Save C variable registers
251 copy:
252 cmp 14(bp), #0
253 jnz bigcopy
254 mov cx, 12(bp)
255 jcxz copydone ! Count is zero, end copy
256 cmp cx, #0xFFF0
257 jb smallcopy
258 bigcopy:mov cx, #0xFFF0 ! Don't copy more than about 64K at once
259 smallcopy:
260 push cx ! Save copying count
261 mov ax, 4(bp)
262 mov dx, 6(bp)
263 cmp dx, #0x0010 ! Copy to extended memory?
264 jae ext_copy
265 cmp 10(bp), #0x0010 ! Copy from extended memory?
266 jae ext_copy
267 call abs2seg
268 mov di, ax
269 mov es, dx ! es:di = dstaddr
270 mov ax, 8(bp)
271 mov dx, 10(bp)
272 call abs2seg
273 mov si, ax
274 mov ds, dx ! ds:si = srcaddr
275 shr cx, #1 ! Words to move
277 movs ! Do the word copy
278 adc cx, cx ! One more byte?
280 movsb ! Do the byte copy
281 mov ax, ss ! Restore ds and es from the remaining ss
282 mov ds, ax
283 mov es, ax
284 jmp copyadjust
285 ext_copy:
286 mov x_dst_desc+2, ax
287 movb x_dst_desc+4, dl ! Set base of destination segment
288 mov ax, 8(bp)
289 mov dx, 10(bp)
290 mov x_src_desc+2, ax
291 movb x_src_desc+4, dl ! Set base of source segment
292 mov si, #x_gdt ! es:si = global descriptor table
293 shr cx, #1 ! Words to move
294 movb ah, #0x87 ! Code for extended memory move
295 int 0x15
296 copyadjust:
297 pop cx ! Restore count
298 add 4(bp), cx
299 adc 6(bp), #0 ! srcaddr += copycount
300 add 8(bp), cx
301 adc 10(bp), #0 ! dstaddr += copycount
302 sub 12(bp), cx
303 sbb 14(bp), #0 ! count -= copycount
304 jmp copy ! and repeat
305 copydone:
306 pop di
307 pop si ! Restore C variable registers
308 pop bp
311 ! u16_t get_word(u32_t addr);
312 ! void put_word(u32_t addr, u16_t word);
313 ! Read or write a 16 bits word at an arbitrary location.
314 .define _get_word, _put_word
315 _get_word:
316 mov bx, sp
317 call gp_getaddr
318 mov ax, (bx) ! Word to get from addr
319 jmp gp_ret
320 _put_word:
321 mov bx, sp
322 push 6(bx) ! Word to store at addr
323 call gp_getaddr
324 pop (bx) ! Store the word
325 jmp gp_ret
326 gp_getaddr:
327 mov ax, 2(bx)
328 mov dx, 4(bx)
329 call abs2seg
330 mov bx, ax
331 mov ds, dx ! ds:bx = addr
333 gp_ret:
334 push es
335 pop ds ! Restore ds
338 ! void relocate(void);
339 ! After the program has copied itself to a safer place, it needs to change
340 ! the segment registers. Caddr has already been set to the new location.
341 .define _relocate
342 _relocate:
343 pop bx ! Return address
344 mov ax, _caddr+0
345 mov dx, _caddr+2
346 call abs2seg
347 mov cx, dx ! cx = new code segment
348 mov ax, cs ! Old code segment
349 sub ax, cx ! ax = -(new - old) = -Moving offset
350 mov dx, ds
351 sub dx, ax
352 mov ds, dx ! ds += (new - old)
353 mov es, dx
354 mov ss, dx
355 xor ax, ax
356 call seg2abs
357 mov _daddr+0, ax
358 mov _daddr+2, dx ! New data address
359 push cx ! New text segment
360 push bx ! Return offset of this function
361 retf ! Relocate
363 ! void *brk(void *addr)
364 ! void *sbrk(size_t incr)
365 ! Cannot fail implementations of brk(2) and sbrk(3), so we can use
366 ! malloc(3). They reboot on stack collision instead of returning -1.
367 .data
368 .align 2
369 break: .data2 _end ! A fake heap pointer
370 .text
371 .define _brk, __brk, _sbrk, __sbrk
372 _brk:
373 __brk: ! __brk is for the standard C compiler
374 xor ax, ax
375 jmp sbrk ! break= 0; return sbrk(addr);
376 _sbrk:
377 __sbrk:
378 mov ax, break ! ax= current break
379 sbrk: push ax ! save it as future return value
380 mov bx, sp ! Stack is now: (retval, retaddr, incr, ...)
381 add ax, 4(bx) ! ax= break + increment
382 mov break, ax ! Set new break
383 lea dx, -1024(bx) ! sp minus a bit of breathing space
384 cmp dx, ax ! Compare with the new break
385 jb heaperr ! Suffocating noises
386 lea dx, -4096(bx) ! A warning when heap+stack goes < 4K
387 cmp dx, ax
388 jae plenty ! No reason to complain
389 mov ax, #memwarn
390 push ax
391 call _printf ! Warn about memory running low
392 pop ax
393 movb memwarn, #0 ! No more warnings
394 plenty: pop ax ! Return old break (0 for brk)
396 heaperr:mov ax, #chmem
397 push ax
398 mov ax, #nomem
399 push ax
400 call _printf
401 jmp quit
402 .data
403 nomem: .ascii "\nOut of%s\0"
404 memwarn:.ascii "\nLow on"
405 chmem: .ascii " memory, use chmem to increase the heap\n\0"
406 .text
408 ! int dev_open(void);
409 ! Given the device "_device" figure out if it exists and what its number
410 ! of heads and sectors may be. Return the BIOS error code on error,
411 ! otherwise 0.
412 .define _dev_open
413 _dev_open:
414 call dev_reset ! Optionally reset the disks
415 movb dev_state, #0 ! State is "closed"
416 push es
417 push di ! Save registers used by BIOS calls
418 movb dl, _device ! The default device
419 cmpb dl, #0x80 ! Floppy < 0x80, winchester >= 0x80
420 jae winchester
421 floppy:
422 mov di, #3 ! Three tries to init drive by reading sector 0
423 finit0: xor ax, ax
424 mov es, ax
425 mov bx, #BUFFER ! es:bx = scratch buffer
426 mov ax, #0x0201 ! Read sector, #sectors = 1
427 mov cx, #0x0001 ! Track 0, first sector
428 xorb dh, dh ! Drive dl, head 0
429 int 0x13
430 jnc finit0ok ! Sector 0 read ok?
431 cmpb ah, #0x80 ! Disk timed out? (Floppy drive empty)
432 je geoerr
433 dec di
434 jz geoerr
435 xorb ah, ah ! Reset drive
436 int 0x13
437 jc geoerr
438 jmp finit0 ! Retry once more, it may need to spin up
439 finit0ok:
440 mov di, #seclist ! List of per floppy type sectors/track
441 flast: movb cl, (di) ! Sectors per track to test
442 cmpb cl, #9 ! No need to do the last 720K/360K test
443 je ftestok
444 xor ax, ax
445 mov es, ax
446 mov bx, #BUFFER ! es:bx = scratch buffer
447 mov ax, #0x0201 ! Read sector, #sectors = 1
448 xorb ch, ch ! Track 0, last sector
449 xorb dh, dh ! Drive dl, head 0
450 int 0x13
451 jnc ftestok ! Sector cl read ok?
452 xorb ah, ah ! Reset drive
453 int 0x13
454 jc geoerr
455 inc di ! Try next sec/track number
456 jmp flast
457 ftestok:
458 movb dh, #2 ! Floppies have two sides
459 jmp geoboth
460 winchester:
461 movb ah, #0x08 ! Code for drive parameters
462 int 0x13 ! dl still contains drive
463 jc geoerr ! No such drive?
464 andb cl, #0x3F ! cl = max sector number (1-origin)
465 incb dh ! dh = 1 + max head number (0-origin)
466 geoboth:
467 movb sectors, cl ! Sectors per track
468 movb al, cl ! al = sectors per track
469 mulb dh ! ax = heads * sectors
470 mov secspcyl, ax ! Sectors per cylinder = heads * sectors
471 movb dev_state, #1 ! Device state is "open"
472 xor ax, ax ! Code for success
473 geodone:
474 pop di
475 pop es ! Restore di and es registers
477 geoerr: movb al, ah
478 xorb ah, ah ! ax = BIOS error code
479 jmp geodone
480 .data
481 seclist:
482 .data1 18, 15, 9 ! 1.44M, 1.2M, and 360K/720K floppy sec/track
483 .text
485 ! int dev_close(void);
486 ! Close the current device. Under the BIOS this does nothing much.
487 .define _dev_close
488 _dev_close:
489 xor ax, ax
490 movb dev_state, al ! State is "closed"
493 ! Reset the disks if needed. Minix may have messed things up.
494 dev_reset:
495 cmpb dev_state, #0 ! Need reset if dev_state < 0
496 jge 0f
497 xorb ah, ah ! Reset (ah = 0)
498 movb dl, #0x80 ! All disks
499 int 0x13
500 movb dev_state, #0 ! State is "closed"
501 0: ret
503 ! int dev_boundary(u32_t sector);
504 ! True if a sector is on a boundary, i.e. sector % sectors == 0.
505 .define _dev_boundary
506 _dev_boundary:
507 mov bx, sp
508 xor dx, dx
509 mov ax, 4(bx) ! divide high half of sector number
510 div sectors
511 mov ax, 2(bx) ! divide low half of sector number
512 div sectors ! dx = sector % sectors
513 sub dx, #1 ! CF = dx == 0
514 sbb ax, ax ! ax = -CF
515 neg ax ! ax = (sector % sectors) == 0
518 ! int readsectors(u32_t bufaddr, u32_t sector, u8_t count)
519 ! int writesectors(u32_t bufaddr, u32_t sector, u8_t count)
520 ! Read/write several sectors from/to disk or floppy. The buffer must
521 ! be between 64K boundaries! Count must fit in a byte. The external
522 ! variables _device, sectors and secspcyl describe the disk and its
523 ! geometry. Returns 0 for success, otherwise the BIOS error code.
525 .define _readsectors, _writesectors
526 _writesectors:
527 push bp
528 mov bp, sp
529 movb 13(bp), #0x03 ! Code for a disk write
530 jmp rwsec
531 _readsectors:
532 push bp
533 mov bp, sp
534 movb 13(bp), #0x02 ! Code for a disk read
535 rwsec: push si
536 push di
537 push es
538 cmpb dev_state, #0 ! Device state?
539 jg 0f ! >0 if open
540 call _dev_open ! Initialize
541 test ax, ax
542 jnz badopen
543 0: mov ax, 4(bp)
544 mov dx, 6(bp)
545 call abs2seg
546 mov bx, ax
547 mov es, dx ! es:bx = bufaddr
548 mov di, #3 ! Execute 3 resets on floppy error
549 cmpb _device, #0x80
550 jb nohd
551 mov di, #1 ! But only 1 reset on hard disk error
552 nohd: cmpb 12(bp), #0 ! count equals zero?
553 jz done
554 more: mov ax, 8(bp)
555 mov dx, 10(bp) ! dx:ax = abs sector. Divide it by sectors/cyl
556 cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
557 jae bigdisk
558 div secspcyl ! ax = cylinder, dx = sector within cylinder
559 xchg ax, dx ! ax = sector within cylinder, dx = cylinder
560 movb ch, dl ! ch = low 8 bits of cylinder
561 divb sectors ! al = head, ah = sector (0-origin)
562 xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
563 shr dx, #1
564 shr dx, #1 ! dl[6..7] = high cylinder
565 orb dl, ah ! dl[0..5] = sector (0-origin)
566 movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
567 incb cl ! cl[0..5] = sector (1-origin)
568 movb dh, al ! dh = head
569 movb dl, _device ! dl = device to use
570 movb al, sectors ! Sectors per track - Sector number (0-origin)
571 subb al, ah ! = Sectors left on this track
572 cmpb al, 12(bp) ! Compare with # sectors to transfer
573 jbe doit ! Can't go past the end of a cylinder?
574 movb al, 12(bp) ! 12(bp) < sectors left on this track
575 doit: movb ah, 13(bp) ! Code for disk read (0x02) or write (0x03)
576 push ax ! Save al = sectors to read
577 int 0x13 ! call the BIOS to do the transfer
578 pop cx ! Restore al in cl
579 jmp rdeval
580 bigdisk:
581 mov si, #ext_rw ! si = extended read/write parameter packet
582 movb cl, 12(bp)
583 movb 2(si), cl ! Fill in # blocks to transfer
584 mov 4(si), bx ! Buffer address = es:bx
585 mov 6(si), es
586 mov 8(si), ax ! Starting block number = dx:ax
587 mov 10(si), dx
588 movb dl, _device ! dl = device to use
589 mov ax, #0x4000 ! This, or-ed with 0x02 or 0x03 becomes
590 orb ah, 13(bp) ! extended read (0x4200) or write (0x4300)
591 int 0x13
592 !jmp rdeval
593 rdeval:
594 jc ioerr ! I/O error
595 movb al, cl ! Restore al = sectors read
596 addb bh, al ! bx += 2 * al * 256 (add bytes transferred)
597 addb bh, al ! es:bx = where next sector is located
598 add 8(bp), ax ! Update address by sectors transferred
599 adc 10(bp), #0 ! Don't forget high word
600 subb 12(bp), al ! Decrement sector count by sectors transferred
601 jnz more ! Not all sectors have been transferred
602 done: xorb ah, ah ! No error here!
603 jmp finish
604 ioerr: cmpb ah, #0x80 ! Disk timed out? (Floppy drive empty)
605 je finish
606 cmpb ah, #0x03 ! Disk write protected?
607 je finish
608 dec di ! Do we allow another reset?
609 jl finish ! No, report the error
610 xorb ah, ah ! Code for a reset (0)
611 int 0x13
612 jnc more ! Succesful reset, try request again
613 finish: movb al, ah
614 xorb ah, ah ! ax = error number
615 badopen:pop es
616 pop di
617 pop si
618 pop bp
620 .data
621 .align 4
622 ! Extended read/write commands require a parameter packet.
623 ext_rw:
624 .data1 0x10 ! Length of extended r/w packet
625 .data1 0 ! Reserved
626 .data2 0 ! Blocks to transfer (to be filled in)
627 .data2 0 ! Buffer address offset (tbfi)
628 .data2 0 ! Buffer address segment (tbfi)
629 .data4 0 ! Starting block number low 32 bits (tbfi)
630 .data4 0 ! Starting block number high 32 bits
631 .text
633 ! int getch(void);
634 ! Read a character from the keyboard, and check for an expired timer.
635 ! A carriage return is changed into a linefeed for UNIX compatibility.
636 .define _getch
637 _getch:
638 xor ax, ax
639 xchg ax, unchar ! Ungotten character?
640 test ax, ax
641 jnz gotch
642 getch:
643 hlt ! Play dead until interrupted (see pause())
644 movb ah, #0x01 ! Keyboard status
645 int 0x16
646 jz 0f ! Nothing typed
647 xorb ah, ah ! Read character from keyboard
648 int 0x16
649 jmp press ! Keypress
650 0: mov dx, line ! Serial line?
651 test dx, dx
652 jz 0f
653 add dx, #5 ! Line Status Register
654 inb dx
655 testb al, #0x01 ! Data Ready?
656 jz 0f
657 mov dx, line
658 !add dx, 0 ! Receive Buffer Register
659 inb dx ! Get character
660 jmp press
661 0: call _expired ! Timer expired?
662 test ax, ax
663 jz getch
664 mov ax, #ESC ! Return ESC
666 press:
667 cmpb al, #0x0D ! Carriage return?
668 jnz nocr
669 movb al, #0x0A ! Change to linefeed
670 nocr: cmpb al, #ESC ! Escape typed?
671 jne noesc
672 inc escape ! Set flag
673 noesc: xorb ah, ah ! ax = al
674 gotch: ret
676 ! int ungetch(void);
677 ! Return a character to undo a getch().
678 .define _ungetch
679 _ungetch:
680 mov bx, sp
681 mov ax, 2(bx)
682 mov unchar, ax
685 ! int escape(void);
686 ! True if ESC has been typed.
687 .define _escape
688 _escape:
689 movb ah, #0x01 ! Keyboard status
690 int 0x16
691 jz escflg ! Keypress?
692 cmpb al, #ESC ! Escape typed?
693 jne escflg
694 xorb ah, ah ! Discard the escape
695 int 0x16
696 inc escape ! Set flag
697 escflg: xor ax, ax
698 xchg ax, escape ! Escape typed flag
701 ! int putch(int c);
702 ! Write a character in teletype mode. The putk synonym is
703 ! for the kernel printf function that uses it.
704 ! Newlines are automatically preceded by a carriage return.
706 .define _putch, _putk
707 _putch:
708 _putk: mov bx, sp
709 movb al, 2(bx) ! al = character to be printed
710 testb al, al ! Kernel printf adds a null char to flush queue
711 jz nulch
712 cmpb al, #0x0A ! al = newline?
713 jnz putc
714 movb al, #0x0D
715 call putc ! putc('\r')
716 movb al, #0x0A ! Restore the '\n' and print it
717 putc: movb ah, #0x0E ! Print character in teletype mode
718 mov bx, #0x0001 ! Page 0, foreground color
719 int 0x10
720 mov bx, line ! Serial line?
721 test bx, bx
722 jz nulch
723 push ax ! Save character to print
724 call _get_tick ! Current clock tick counter
725 mov cx, ax
726 add cx, #2 ! Don't want to see it count twice
727 1: lea dx, 5(bx) ! Line Status Register
728 inb dx
729 testb al, #0x20 ! Transmitter Holding Register Empty?
730 jnz 0f
731 call _get_tick
732 cmp ax, cx ! Clock ticked more than once?
733 jne 1b
734 0: pop ax ! Restore character to print
735 mov dx, bx ! Transmit Holding Register
736 outb dx ! Send character down the serial line
737 nulch: ret
739 ! void pause(void);
740 ! Wait for an interrupt using the HLT instruction. This either saves
741 ! power, or tells an x86 emulator that nothing is happening right now.
742 .define _pause
743 _pause:
747 ! void set_mode(unsigned mode);
748 ! void clear_screen(void);
749 ! Set video mode / clear the screen.
750 .define _set_mode, _clear_screen
751 _set_mode:
752 mov bx, sp
753 mov ax, 2(bx) ! Video mode
754 cmp ax, cur_vid_mode
755 je modeok ! Mode already as requested?
756 mov cur_vid_mode, ax
757 _clear_screen:
758 xor ax, ax
759 mov es, ax ! es = Vector segment
760 mov ax, cur_vid_mode
761 movb ch, ah ! Copy of the special flags
762 andb ah, #0x0F ! Test bits 8-11, clear special flags
763 jnz xvesa ! VESA extended mode?
764 int 0x10 ! Reset video (ah = 0)
765 jmp md_480
766 xvesa: mov bx, ax ! bx = extended mode
767 mov ax, #0x4F02 ! Reset video
768 int 0x10
769 md_480: ! Basic video mode is set, now build on it
770 testb ch, #0x20 ! 480 scan lines requested?
771 jz md_14pt
772 mov dx, #0x3CC ! Get CRTC port
773 inb dx
774 movb dl, #0xD4
775 testb al, #1 ! Mono or color?
776 jnz 0f
777 movb dl, #0xB4
778 0: mov ax, #0x110C ! Vertical sync end (also unlocks CR0-7)
779 call out2
780 mov ax, #0x060B ! Vertical total
781 call out2
782 mov ax, #0x073E ! (Vertical) overflow
783 call out2
784 mov ax, #0x10EA ! Vertical sync start
785 call out2
786 mov ax, #0x12DF ! Vertical display end
787 call out2
788 mov ax, #0x15E7 ! Vertical blank start
789 call out2
790 mov ax, #0x1604 ! Vertical blank end
791 call out2
792 push dx
793 movb dl, #0xCC ! Misc output register (read)
794 inb dx
795 movb dl, #0xC2 ! (write)
796 andb al, #0x0D ! Preserve clock select bits and color bit
797 orb al, #0xE2 ! Set correct sync polarity
798 outb dx
799 pop dx ! Index register still in dx
800 md_14pt:
801 testb ch, #0x40 ! 9x14 point font requested?
802 jz md_8pt
803 mov ax, #0x1111 ! Load ROM 9 by 14 font
804 xorb bl, bl ! Load block 0
805 int 0x10
806 testb ch, #0x20 ! 480 scan lines?
807 jz md_8pt
808 mov ax, #0x12DB ! VGA vertical display end
809 call out2
810 eseg movb 0x0484, #33 ! Tell BIOS the last line number
811 md_8pt:
812 testb ch, #0x80 ! 8x8 point font requested?
813 jz setcur
814 mov ax, #0x1112 ! Load ROM 8 by 8 font
815 xorb bl, bl ! Load block 0
816 int 0x10
817 testb ch, #0x20 ! 480 scan lines?
818 jz setcur
819 mov ax, #0x12DF ! VGA vertical display end
820 call out2
821 eseg movb 0x0484, #59 ! Tell BIOS the last line number
822 setcur:
823 xor dx, dx ! dl = column = 0, dh = row = 0
824 xorb bh, bh ! Page 0
825 movb ah, #0x02 ! Set cursor position
826 int 0x10
827 push ss
828 pop es ! Restore es
829 modeok: ret
831 ! Out to the usual [index, data] port pair that are common for VGA devices
832 ! dx = port, ah = index, al = data.
833 out2:
834 push dx
835 push ax
836 movb al, ah
837 outb dx ! Set index
838 inc dx
839 pop ax
840 outb dx ! Send data
841 pop dx
844 restore_video: ! To restore the video mode on exit
845 mov ax, old_vid_mode
846 push ax
847 call _set_mode
848 pop ax
851 ! void serial_init(int line)
852 ! Initialize copying console I/O to a serial line.
853 .define _serial_init
854 _serial_init:
855 mov bx, sp
856 mov dx, 2(bx) ! Line number
857 mov line, #0
858 test dx, dx ! Off if line number < 0
859 js 0f
860 push ds
861 xor ax, ax
862 mov ds, ax ! Vector and BIOS data segment
863 mov bx, dx ! Line number
864 shl bx, #1 ! Word offset
865 mov bx, 0x0400(bx) ! I/O port for the given line
866 pop ds
867 mov line, bx ! Remember I/O port
868 serial_init:
869 mov bx, line
870 test bx, bx ! I/O port must be nonzero
871 jz 0f
872 mov ax, #0x00E3 ! 9600 N-8-1
873 int 0x14 ! Initialize serial line dx
874 lea dx, 4(bx) ! Modem Control Register
875 movb al, #0x0B ! DTR, RTS, OUT2
876 outb dx
877 0: ret
879 ! u32_t get_tick(void);
880 ! Return the current value of the clock tick counter. This counter
881 ! increments 18.2 times per second. Poll it to do delays. Does not
882 ! work on the original PC, but works on the PC/XT.
883 .define _get_tick
884 _get_tick:
885 push cx
886 xorb ah, ah ! Code for get tick count
887 int 0x1A
888 mov ax, dx
889 mov dx, cx ! dx:ax = cx:dx = tick count
890 pop cx
894 ! Functions used to obtain info about the hardware. Boot uses this information
895 ! itself, but will also pass them on to a pure 386 kernel, because one can't
896 ! make BIOS calls from protected mode. The video type could probably be
897 ! determined by the kernel too by looking at the hardware, but there is a small
898 ! chance on errors that the monitor allows you to correct by setting variables.
900 .define _get_bus ! returns type of system bus
901 .define _get_video ! returns type of display
903 ! u16_t get_bus(void)
904 ! Return type of system bus, in order: XT, AT, MCA.
905 _get_bus:
906 call _getprocessor
907 xor dx, dx ! Assume XT
908 cmp ax, #286 ! An AT has at least a 286
909 jb got_bus
910 inc dx ! Assume AT
911 movb ah, #0xC0 ! Code for get configuration
912 int 0x15
913 jc got_bus ! Carry clear and ah = 00 if supported
914 testb ah, ah
915 jne got_bus
916 eseg
917 movb al, 5(bx) ! Load feature byte #1
918 inc dx ! Assume MCA
919 testb al, #0x02 ! Test bit 1 - "bus is Micro Channel"
920 jnz got_bus
921 dec dx ! Assume AT
922 testb al, #0x40 ! Test bit 6 - "2nd 8259 installed"
923 jnz got_bus
924 dec dx ! It is an XT
925 got_bus:
926 push ds
927 pop es ! Restore es
928 mov ax, dx ! Return bus code
929 mov bus, ax ! Keep bus code, A20 handler likes to know
932 ! u16_t get_video(void)
933 ! Return type of display, in order: MDA, CGA, mono EGA, color EGA,
934 ! mono VGA, color VGA.
935 _get_video:
936 mov ax, #0x1A00 ! Function 1A returns display code
937 int 0x10 ! al = 1A if supported
938 cmpb al, #0x1A
939 jnz no_dc ! No display code function supported
941 mov ax, #2
942 cmpb bl, #5 ! Is it a monochrome EGA?
943 jz got_video
944 inc ax
945 cmpb bl, #4 ! Is it a color EGA?
946 jz got_video
947 inc ax
948 cmpb bl, #7 ! Is it a monochrome VGA?
949 jz got_video
950 inc ax
951 cmpb bl, #8 ! Is it a color VGA?
952 jz got_video
954 no_dc: movb ah, #0x12 ! Get information about the EGA
955 movb bl, #0x10
956 int 0x10
957 cmpb bl, #0x10 ! Did it come back as 0x10? (No EGA)
958 jz no_ega
960 mov ax, #2
961 cmpb bh, #1 ! Is it monochrome?
962 jz got_video
963 inc ax
964 jmp got_video
966 no_ega: int 0x11 ! Get bit pattern for equipment
967 and ax, #0x30 ! Isolate color/mono field
968 sub ax, #0x30
969 jz got_video ! Is it an MDA?
970 mov ax, #1 ! No it's CGA
972 got_video:
976 ! Functions to leave the boot monitor.
977 .define _bootstrap ! Call another bootstrap
978 .define _minix ! Call Minix
980 ! void _bootstrap(int device, struct part_entry *entry)
981 ! Call another bootstrap routine to boot MS-DOS for instance. (No real
982 ! need for that anymore, now that you can format floppies under Minix).
983 ! The bootstrap must have been loaded at BOOTSEG from "device".
984 _bootstrap:
985 call restore_video
986 mov bx, sp
987 movb dl, 2(bx) ! Device to boot from
988 mov si, 4(bx) ! ds:si = partition table entry
989 xor ax, ax
990 mov es, ax ! Vector segment
991 mov di, #BUFFER ! es:di = buffer in low core
992 mov cx, #PENTRYSIZE ! cx = size of partition table entry
993 rep movsb ! Copy the entry to low core
994 mov si, #BUFFER ! es:si = partition table entry
995 mov ds, ax ! Some bootstraps need zero segment registers
997 mov ss, ax
998 mov sp, #BOOTOFF ! This should do it
1000 jmpf BOOTOFF, 0 ! Back to where the BIOS loads the boot code
1002 ! void minix(u32_t koff, u32_t kcs, u32_t kds,
1003 ! char *bootparams, size_t paramsize, u32_t aout);
1004 ! Call Minix.
1005 _minix:
1006 push bp
1007 mov bp, sp ! Pointer to arguments
1009 mov dx, #0x03F2 ! Floppy motor drive control bits
1010 movb al, #0x0C ! Bits 4-7 for floppy 0-3 are off
1011 outb dx ! Kill the motors
1012 push ds
1013 xor ax, ax ! Vector & BIOS data segments
1014 mov ds, ax
1015 andb 0x043F, #0xF0 ! Clear diskette motor status bits of BIOS
1016 pop ds
1017 cli ! No more interruptions
1019 test _k_flags, #K_I386 ! Switch to 386 mode?
1020 jnz minix386
1022 ! Call Minix in real mode.
1023 minix86:
1024 test _k_flags, #K_MEML ! New memory arrangements?
1025 jz 0f
1026 push 22(bp) ! Address of a.out headers
1027 push 20(bp)
1029 push 18(bp) ! # bytes of boot parameters
1030 push 16(bp) ! Address of boot parameters
1032 test _k_flags, #K_RET ! Can the kernel return?
1033 jz noret86
1034 xor dx, dx ! If little ext mem then monitor not preserved
1035 xor ax, ax
1036 cmp _mon_return, ax ! Minix can return to the monitor?
1037 jz 0f
1038 mov dx, cs ! Monitor far return address
1039 mov ax, #ret86
1040 0: push dx ! Push monitor far return address or zero
1041 push ax
1042 noret86:
1044 mov ax, 8(bp)
1045 mov dx, 10(bp)
1046 call abs2seg
1047 push dx ! Kernel code segment
1048 push 4(bp) ! Kernel code offset
1049 mov ax, 12(bp)
1050 mov dx, 14(bp)
1051 call abs2seg
1052 mov ds, dx ! Kernel data segment
1053 mov es, dx ! Set es to kernel data too
1054 retf ! Make a far call to the kernel
1056 ! Call Minix in 386 mode.
1057 minix386:
1058 cseg mov cs_real-2, cs ! Patch CS and DS into the instructions that
1059 cseg mov ds_real-2, ds ! reload them when switching back to real mode
1060 .data1 0x0F,0x20,0xC0 ! mov eax, cr0
1061 orb al, #0x01 ! Set PE (protection enable) bit
1062 .data1 o32
1063 mov msw, ax ! Save as protected mode machine status word
1065 mov dx, ds ! Monitor ds
1066 mov ax, #p_gdt ! dx:ax = Global descriptor table
1067 call seg2abs
1068 mov p_gdt_desc+2, ax
1069 movb p_gdt_desc+4, dl ! Set base of global descriptor table
1071 mov ax, 12(bp)
1072 mov dx, 14(bp) ! Kernel ds (absolute address)
1073 mov p_ds_desc+2, ax
1074 movb p_ds_desc+4, dl ! Set base of kernel data segment
1076 mov dx, ss ! Monitor ss
1077 xor ax, ax ! dx:ax = Monitor stack segment
1078 call seg2abs ! Minix starts with the stack of the monitor
1079 mov p_ss_desc+2, ax
1080 movb p_ss_desc+4, dl
1082 mov ax, 8(bp)
1083 mov dx, 10(bp) ! Kernel cs (absolute address)
1084 mov p_cs_desc+2, ax
1085 movb p_cs_desc+4, dl
1087 mov dx, cs ! Monitor cs
1088 xor ax, ax ! dx:ax = Monitor code segment
1089 call seg2abs
1090 mov p_mcs_desc+2, ax
1091 movb p_mcs_desc+4, dl
1093 push #MCS_SELECTOR
1094 test _k_flags, #K_INT86 ! Generic INT86 support?
1095 jz 0f
1096 push #int86 ! Far address to INT86 support
1097 jmp 1f
1098 0: push #bios13 ! Far address to BIOS int 13 support
1100 test _k_flags, #K_MEML ! New memory arrangements?
1101 jz 0f
1102 .data1 o32
1103 push 20(bp) ! Address of a.out headers
1105 push #0
1106 push 18(bp) ! 32 bit size of parameters on stack
1107 push #0
1108 push 16(bp) ! 32 bit address of parameters (ss relative)
1110 test _k_flags, #K_RET ! Can the kernel return?
1111 jz noret386
1112 push #MCS_SELECTOR
1113 push #ret386 ! Monitor far return address
1114 noret386:
1116 push #0
1117 push #CS_SELECTOR
1118 push 6(bp)
1119 push 4(bp) ! 32 bit far address to kernel entry point
1121 call real2prot ! Switch to protected mode
1122 mov ax, #DS_SELECTOR ! Kernel data
1123 mov ds, ax
1124 mov ax, #ES_SELECTOR ! Flat 4 Gb
1125 mov es, ax
1126 .data1 o32 ! Make a far call to the kernel
1127 retf
1129 ! Minix-86 returns here on a halt or reboot.
1130 ret86:
1131 mov _reboot_code+0, ax
1132 mov _reboot_code+2, dx ! Return value (obsolete method)
1133 jmp return
1135 ! Minix-386 returns here on a halt or reboot.
1136 ret386:
1137 .data1 o32
1138 mov _reboot_code, ax ! Return value (obsolete method)
1139 call prot2real ! Switch to real mode
1141 return:
1142 mov sp, bp ! Pop parameters
1143 sti ! Can take interrupts again
1145 call _get_video ! MDA, CGA, EGA, ...
1146 movb dh, #24 ! dh = row 24
1147 cmp ax, #2 ! At least EGA?
1148 jb is25 ! Otherwise 25 rows
1149 push ds
1150 xor ax, ax ! Vector & BIOS data segments
1151 mov ds, ax
1152 movb dh, 0x0484 ! Number of rows on display minus one
1153 pop ds
1154 is25:
1155 xorb dl, dl ! dl = column 0
1156 xorb bh, bh ! Page 0
1157 movb ah, #0x02 ! Set cursor position
1158 int 0x10
1160 movb dev_state, #-1 ! Minix may have upset the disks, must reset.
1161 call serial_init ! Likewise with our serial console
1163 call _getprocessor
1164 cmp ax, #286
1165 jb noclock
1166 xorb al, al
1167 tryclk: decb al
1168 jz noclock
1169 movb ah, #0x02 ! Get real-time clock time (from CMOS clock)
1170 int 0x1A
1171 jc tryclk ! Carry set, not running or being updated
1172 movb al, ch ! ch = hour in BCD
1173 call bcd ! al = (al >> 4) * 10 + (al & 0x0F)
1174 mulb c60 ! 60 minutes in an hour
1175 mov bx, ax ! bx = hour * 60
1176 movb al, cl ! cl = minutes in BCD
1177 call bcd
1178 add bx, ax ! bx = hour * 60 + minutes
1179 movb al, dh ! dh = seconds in BCD
1180 call bcd
1181 xchg ax, bx ! ax = hour * 60 + minutes, bx = seconds
1182 mul c60 ! dx-ax = (hour * 60 + minutes) * 60
1183 add bx, ax
1184 adc dx, #0 ! dx-bx = seconds since midnight
1185 mov ax, dx
1186 mul c19663
1187 xchg ax, bx
1188 mul c19663
1189 add dx, bx ! dx-ax = dx-bx * (0x1800B0 / (2*2*2*2*5))
1190 mov cx, ax ! (0x1800B0 = ticks per day of BIOS clock)
1191 mov ax, dx
1192 xor dx, dx
1193 div c1080
1194 xchg ax, cx
1195 div c1080 ! cx-ax = dx-ax / (24*60*60 / (2*2*2*2*5))
1196 mov dx, ax ! cx-dx = ticks since midnight
1197 movb ah, #0x01 ! Set system time
1198 int 0x1A
1199 noclock:
1201 pop bp
1202 ret ! Return to monitor as if nothing much happened
1204 ! Transform BCD number in al to a regular value in ax.
1205 bcd: movb ah, al
1206 shrb ah, #4
1207 andb al, #0x0F
1208 .data1 0xD5,10 ! aad ! ax = (al >> 4) * 10 + (al & 0x0F)
1209 ret ! (BUG: assembler messes up aad & aam!)
1211 ! Support function for Minix-386 to make a BIOS int 13 call (disk I/O).
1212 bios13:
1213 mov bp, sp
1214 call prot2real
1215 sti ! Enable interrupts
1217 mov ax, 8(bp) ! Load parameters
1218 mov bx, 10(bp)
1219 mov cx, 12(bp)
1220 mov dx, 14(bp)
1221 mov es, 16(bp)
1222 int 0x13 ! Make the BIOS call
1223 mov 8(bp), ax ! Save results
1224 mov 10(bp), bx
1225 mov 12(bp), cx
1226 mov 14(bp), dx
1227 mov 16(bp), es
1229 cli ! Disable interrupts
1230 call real2prot
1231 mov ax, #DS_SELECTOR ! Kernel data
1232 mov ds, ax
1233 .data1 o32
1234 retf ! Return to the kernel
1236 ! Support function for Minix-386 to make an 8086 interrupt call.
1237 int86:
1238 mov bp, sp
1239 call prot2real
1241 .data1 o32
1242 xor ax, ax
1243 mov es, ax ! Vector & BIOS data segments
1244 .data1 o32
1245 eseg mov 0x046C, ax ! Clear BIOS clock tick counter
1247 sti ! Enable interrupts
1249 movb al, #0xCD ! INT instruction
1250 movb ah, 8(bp) ! Interrupt number?
1251 testb ah, ah
1252 jnz 0f ! Nonzero if INT, otherwise far call
1253 push cs
1254 push #intret+2 ! Far return address
1255 .data1 o32
1256 push 12(bp) ! Far driver address
1257 mov ax, #0x90CB ! RETF; NOP
1259 cseg cmp ax, intret ! Needs to be changed?
1260 je 0f ! If not then avoid a huge I-cache stall
1261 cseg mov intret, ax ! Patch 'INT n' or 'RETF; NOP' into code
1262 jmp .+2 ! Clear instruction queue
1264 mov ds, 16(bp) ! Load parameters
1265 mov es, 18(bp)
1266 .data1 o32
1267 mov ax, 20(bp)
1268 .data1 o32
1269 mov bx, 24(bp)
1270 .data1 o32
1271 mov cx, 28(bp)
1272 .data1 o32
1273 mov dx, 32(bp)
1274 .data1 o32
1275 mov si, 36(bp)
1276 .data1 o32
1277 mov di, 40(bp)
1278 .data1 o32
1279 mov bp, 44(bp)
1281 intret: int 0xFF ! Do the interrupt or far call
1283 .data1 o32 ! Save results
1284 push bp
1285 .data1 o32
1286 pushf
1287 mov bp, sp
1288 .data1 o32
1289 pop 8+8(bp) ! eflags
1290 mov 8+16(bp), ds
1291 mov 8+18(bp), es
1292 .data1 o32
1293 mov 8+20(bp), ax
1294 .data1 o32
1295 mov 8+24(bp), bx
1296 .data1 o32
1297 mov 8+28(bp), cx
1298 .data1 o32
1299 mov 8+32(bp), dx
1300 .data1 o32
1301 mov 8+36(bp), si
1302 .data1 o32
1303 mov 8+40(bp), di
1304 .data1 o32
1305 pop 8+44(bp) ! ebp
1307 cli ! Disable interrupts
1309 xor ax, ax
1310 mov ds, ax ! Vector & BIOS data segments
1311 .data1 o32
1312 mov cx, 0x046C ! Collect lost clock ticks in ecx
1314 mov ax, ss
1315 mov ds, ax ! Restore monitor ds
1316 call real2prot
1317 mov ax, #DS_SELECTOR ! Kernel data
1318 mov ds, ax
1319 .data1 o32
1320 retf ! Return to the kernel
1322 ! Switch from real to protected mode.
1323 real2prot:
1324 movb ah, #0x02 ! Code for A20 enable
1325 call gate_A20
1327 lgdt p_gdt_desc ! Global descriptor table
1328 .data1 o32
1329 mov ax, pdbr ! Load page directory base register
1330 .data1 0x0F,0x22,0xD8 ! mov cr3, eax
1331 .data1 0x0F,0x20,0xC0 ! mov eax, cr0
1332 .data1 o32
1333 xchg ax, msw ! Exchange real mode msw for protected mode msw
1334 .data1 0x0F,0x22,0xC0 ! mov cr0, eax
1335 jmpf cs_prot, MCS_SELECTOR ! Set code segment selector
1336 cs_prot:
1337 mov ax, #SS_SELECTOR ! Set data selectors
1338 mov ds, ax
1339 mov es, ax
1340 mov ss, ax
1343 ! Switch from protected to real mode.
1344 prot2real:
1345 lidt p_idt_desc ! Real mode interrupt vectors
1346 .data1 0x0F,0x20,0xD8 ! mov eax, cr3
1347 .data1 o32
1348 mov pdbr, ax ! Save page directory base register
1349 .data1 0x0F,0x20,0xC0 ! mov eax, cr0
1350 .data1 o32
1351 xchg ax, msw ! Exchange protected mode msw for real mode msw
1352 .data1 0x0F,0x22,0xC0 ! mov cr0, eax
1353 jmpf cs_real, 0xDEAD ! Reload cs register
1354 cs_real:
1355 mov ax, #0xBEEF
1356 ds_real:
1357 mov ds, ax ! Reload data segment registers
1358 mov es, ax
1359 mov ss, ax
1361 xorb ah, ah ! Code for A20 disable
1362 !jmp gate_A20
1364 ! Enable (ah = 0x02) or disable (ah = 0x00) the A20 address line.
1365 gate_A20:
1366 cmp bus, #2 ! PS/2 bus?
1367 je gate_PS_A20
1368 call kb_wait
1369 movb al, #0xD1 ! Tell keyboard that a command is coming
1370 outb 0x64
1371 call kb_wait
1372 movb al, #0xDD ! 0xDD = A20 disable code if ah = 0x00
1373 orb al, ah ! 0xDF = A20 enable code if ah = 0x02
1374 outb 0x60
1375 call kb_wait
1376 movb al, #0xFF ! Pulse output port
1377 outb 0x64
1378 call kb_wait ! Wait for the A20 line to settle down
1380 kb_wait:
1381 inb 0x64
1382 testb al, #0x02 ! Keyboard input buffer full?
1383 jnz kb_wait ! If so, wait
1386 gate_PS_A20: ! The PS/2 can twiddle A20 using port A
1387 inb 0x92 ! Read port A
1388 andb al, #0xFD
1389 orb al, ah ! Set A20 bit to the required state
1390 outb 0x92 ! Write port A
1391 jmp .+2 ! Small delay
1392 A20ok: inb 0x92 ! Check port A
1393 andb al, #0x02
1394 cmpb al, ah ! A20 line settled down to the new state?
1395 jne A20ok ! If not then wait
1398 ! void int15(bios_env_t *ep)
1399 ! Do an "INT 15" call, primarily for APM (Power Management).
1400 .define _int15
1401 _int15:
1402 push si ! Save callee-save register si
1403 mov si, sp
1404 mov si, 4(si) ! ep
1405 mov ax, (si) ! ep->ax
1406 mov bx, 2(si) ! ep->bx
1407 mov cx, 4(si) ! ep->cx
1408 int 0x15 ! INT 0x15 BIOS call
1409 pushf ! Save flags
1410 mov (si), ax ! ep->ax
1411 mov 2(si), bx ! ep->bx
1412 mov 4(si), cx ! ep->cx
1413 pop 6(si) ! ep->flags
1414 pop si ! Restore
1417 ! void scan_keyboard(void)
1418 ! Read keyboard character. Needs to be done in case one is waiting.
1419 .define _scan_keyboard
1420 _scan_keyboard:
1421 inb 0x60
1422 inb 0x61
1423 movb ah, al
1424 orb al, #0x80
1425 outb 0x61
1426 movb al, ah
1427 outb 0x61
1430 .data
1431 .ascii "(null)\0" ! Just in case someone follows a null pointer
1432 .align 2
1433 c60: .data2 60 ! Constants for MUL and DIV
1434 c1024: .data2 1024
1435 c1080: .data2 1080
1436 c19663: .data2 19663
1438 ! Global descriptor tables.
1439 UNSET = 0 ! Must be computed
1441 ! For "Extended Memory Block Move".
1442 x_gdt:
1443 x_null_desc:
1444 ! Null descriptor
1445 .data2 0x0000, 0x0000
1446 .data1 0x00, 0x00, 0x00, 0x00
1447 x_gdt_desc:
1448 ! Descriptor for this descriptor table
1449 .data2 6*8-1, UNSET
1450 .data1 UNSET, 0x00, 0x00, 0x00
1451 x_src_desc:
1452 ! Source segment descriptor
1453 .data2 0xFFFF, UNSET
1454 .data1 UNSET, 0x92, 0x00, 0x00
1455 x_dst_desc:
1456 ! Destination segment descriptor
1457 .data2 0xFFFF, UNSET
1458 .data1 UNSET, 0x92, 0x00, 0x00
1459 x_bios_desc:
1460 ! BIOS segment descriptor (scratch for int 0x15)
1461 .data2 UNSET, UNSET
1462 .data1 UNSET, UNSET, UNSET, UNSET
1463 x_ss_desc:
1464 ! BIOS stack segment descriptor (scratch for int 0x15)
1465 .data2 UNSET, UNSET
1466 .data1 UNSET, UNSET, UNSET, UNSET
1468 ! Protected mode descriptor table.
1469 p_gdt:
1470 p_null_desc:
1471 ! Null descriptor
1472 .data2 0x0000, 0x0000
1473 .data1 0x00, 0x00, 0x00, 0x00
1474 p_gdt_desc:
1475 ! Descriptor for this descriptor table
1476 .data2 8*8-1, UNSET
1477 .data1 UNSET, 0x00, 0x00, 0x00
1478 p_idt_desc:
1479 ! Real mode interrupt descriptor table descriptor
1480 .data2 0x03FF, 0x0000
1481 .data1 0x00, 0x00, 0x00, 0x00
1482 p_ds_desc:
1483 ! Kernel data segment descriptor (4 Gb flat)
1484 .data2 0xFFFF, UNSET
1485 .data1 UNSET, 0x92, 0xCF, 0x00
1486 p_es_desc:
1487 ! Physical memory descriptor (4 Gb flat)
1488 .data2 0xFFFF, 0x0000
1489 .data1 0x00, 0x92, 0xCF, 0x00
1490 p_ss_desc:
1491 ! Monitor data segment descriptor (64 kb flat)
1492 .data2 0xFFFF, UNSET
1493 .data1 UNSET, 0x92, 0x00, 0x00
1494 p_cs_desc:
1495 ! Kernel code segment descriptor (4 Gb flat)
1496 .data2 0xFFFF, UNSET
1497 .data1 UNSET, 0x9A, 0xCF, 0x00
1498 p_mcs_desc:
1499 ! Monitor code segment descriptor (64 kb flat)
1500 .data2 0xFFFF, UNSET
1501 .data1 UNSET, 0x9A, 0x00, 0x00
1503 .bss
1504 .comm old_vid_mode, 2 ! Video mode at startup
1505 .comm cur_vid_mode, 2 ! Current video mode
1506 .comm dev_state, 2 ! Device state: reset (-1), closed (0), open (1)
1507 .comm sectors, 2 ! # sectors of current device
1508 .comm secspcyl, 2 ! (Sectors * heads) of current device
1509 .comm msw, 4 ! Saved machine status word (cr0)
1510 .comm pdbr, 4 ! Saved page directory base register (cr3)
1511 .comm escape, 2 ! Escape typed?
1512 .comm bus, 2 ! Saved return value of _get_bus
1513 .comm unchar, 2 ! Char returned by ungetch(c)
1514 .comm line, 2 ! Serial line I/O port to copy console I/O to.