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