|
|
1.1 root 1: .unixorder
2: .llen 132
3: .include as.inc
4:
5: IODELAY .macro
6: jmp .+2 / DELAY
7: jmp .+2 / DELAY
8: .endm
9:
10: / Most places where %cr3 is refreshed, it can be done through a Ring 0 gate.
11: MMUUPD .macro
12: pushfl
13: cli
14: lcall $SEG_MMUUPD,$0 / gate to mmuupdfR0
15: popfl
16: .endm
17:
18: /
19: / USTART and ESP_START map kernel stack and u area within top 4k page
20: / of virtual space.
21: / NDP context starts 0x100 bytes below u area.
22: / See also U_OFFSET, NDP_OFFSET in uproc.h
23: /
24: .set USTART,0xFFFFFC00
25: .set ESP0_START,0xFFFFF300
26: .set ESP1_START,USTART
27:
28: .set u,USTART
29: .set PSW_VAL,0x1200 / set system IOPL to 1, enable IRQ
30: / .set PSW_VAL,0x3200 / set system IOPL to 3, enable IRQ
31:
32: / (lgl-
33: / The information contained herein is a trade secret of Mark Williams
34: / Company, and is confidential information. It is provided under a
35: / license agreement, and may be copied or disclosed only under the
36: / terms of that agreement. Any reproduction or disclosure of this
37: / material without the express written authorization of Mark Williams
38: / Company or persuant to the license agreement is unlawful.
39:
40: / Copyright (c) 1982, 1992.
41: / An unpublished work by Mark Williams Company, Chicago.
42: / All rights reserved.
43:
44: / Intel 386 port and extensions
45: / Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991
46: / -lgl)
47: /
48: / $Log: as.s,v $
49: /Revision 1.18 93/06/14 13:42:14 bin
50: /Hal: kernel 78 update
51: /
52: / Revision 1.17 92/12/08 16:43:10 root
53: / ker 70
54: /
55: / Revision 1.16 92/11/12 10:04:31 root
56: / Ker #68
57: /
58: / Revision 1.15 92/11/09 17:08:28 root
59: / Just before adding vio segs.
60: /
61: / Revision 1.13 92/10/06 23:47:48 root
62: / Ker #64
63: /
64: / Revision 1.12 92/10/06 20:45:40 root
65: / Ker #63d
66: /
67: / Revision 1.10 92/07/27 18:15:43 hal
68: / Kernel #59
69: /
70: / Revision 1.9 92/07/16 16:38:14 hal
71: / Kernel #58
72: /
73: / Revision 1.8 92/07/15 13:50:55 root
74: / COH 4.0.0
75: /
76: / Revision 1.6 92/04/03 11:05:28 hal
77: / Fix missed IRQ bug.
78: / Add read_t0(), read_psw(), getusd(), putusd().
79: /
80:
81: ///////
82: / Machine language assist for
83: / Intel 80386/80486 Coherent. This contains the parts
84: / that are common to all machines as well as the machine-specific code
85: / for the IBM PC-386
86:
87:
88: ///////
89:
90: / System entry point.
91:
92: / When this code is entered, the boot program has done the following:
93: / Relocate itself above where the kernel will be (e.g., 0x20600).
94: / Load as.s binary; text at 0x02000, data at next paragraph (16-byte)
95: / boundary at or beyond end of kernel text.
96: / CS = 0x02000 <- start of kernel text ("physical" stext)
97: / ES = 0x02xxx <- start of kernel data
98: / SS,DS = 0x20xxx <- ....some address in boot data space....
99:
100: / Due to the way the kernel has been linked (see ld.master), symbol "stext"
101: / has a value of 0xFFC0_0000, which is the start of the last 4 meg segment.
102: / This value is the address in linear space once we have entered paging mode,
103: / but until that time relocation arithmetic is necessary:
104: /
105: / Before segmentation is turned on, symbols in kernel text or data space
106: / must be relocated by -SBASE<<BPCSHIFT for memory reference instructions
107: / to work.
108:
109: ///////
110:
111: stext: / kernel code starts at stext+0x100
112: .org .+0x100 / reserve stack space
113: cli / No interrupts, please.
114:
115: / put up a debugging "!" on the screen. We can still use the BIOS.
116: push %si / Save registers.
117: push %di
118:
119: movb $'!', %al
120:
121: movw $0x0007, %bx / Page 0, white on black
122: movb $0x0E, %ah / Write TTY.
123: int $VIDEO / Call video I/O in ROM.
124: pop %di
125: pop %si
126:
127: / equipment status word to AX
128: int $0x11 / Obtain int 11 value before printf().
129: movl %eax,%ecx / esw -> cx
130:
131: / val11 is a long, initially zero, in the CS.
132: / copy (long)esw to val11
133: .byte PX_ADDR / 32-bit address
134: .byte PX_OPND / 32-bit operand
135: movl %ecx,%cs:[[-SBASE]<<BPCSHIFT]+val11
136:
137: / last use of boot block's stack
138: .byte PX_ADDR / 32-bit address
139: .byte PX_OPND / 32-bit operand
140: lgdtl %cs:[[-SBASE]<<BPCSHIFT]+gdtinit
141:
142: / turn on lsbit of cr0 - Protection Enable
143: mov %cr0,%eax
144: orb $1,%al
145: mov %eax,%cr0
146:
147: / intersegment jump (48-bit address)
148: / jumping flushes the cache...
149: /
150: .byte PX_OPND
151: ljmp $SEG_386_II, $next
152:
153: next:
154: mov $SEG_386_ID,%eax
155: movw %ax,%ds
156: movw %ax,%ss
157: mov $SEG_386_UD|R_USR,%eax
158: movw %ax,%es
159: mov $stext+0x100,%eax / 256 byte stack for initialization
160: mov %eax,%esp
161:
162: push $'@' / Debugging checkpoint:
163: call chirp / protected mode is on
164: pop %ecx
165:
166: / Enable the A20 address line, which is normally disabled by the ROM BIOS.
167: / This line is under the control of the 8042 keyboard interface controller.
168:
169: sub %ecx, %ecx
170: loc0: inb $KBCTRL / Wait for 8042 input buffer to empty.
171: testb $2,%al
172: loopne loc0
173: IODELAY
174:
175: movb $0xD1, %al / Request next output byte to be
176: outb $KBCTRL / sent to the 8042 output port.
177: IODELAY
178:
179: sub %ecx, %ecx
180: loc1: inb $KBCTRL / Wait for 8042 input buffer to empty.
181: testb $2, %al
182: loopne loc1
183: IODELAY
184:
185: movb $0xDF,%al / Enable A20 address line.
186: outb $KBDATA / See Page 1-44, IBM-AT Tech Ref.
187: IODELAY
188:
189: sub %ecx, %ecx
190: loc2: inb $KBCTRL / Wait for 8042 input buffer to empty.
191: testb $2,%al / NOTE: A20 not enabled for up to 20 us.
192: loopne loc2
193:
194:
195: / Reprogram the 8253 timer so that channel 0,
196: / which is used as the clock, interrupts at exactly
197: / 100 HZ, instead of 18.2 HZ.
198:
199: movb $0x36,%al / Timer 0, LSB, MSB, mode 3
200: outb $PIT+3
201: IODELAY
202: movb $0x9C,%al / Lsb of 59659/5 = 11932
203: outb $PIT
204: IODELAY
205: movb $0x2E,%al / Msb of 59659/5 = 11932
206: outb $PIT
207: IODELAY
208:
209: / Reprogram the 1st programmable interrupt controller.
210: / Its default vector table collides with iAPX 286 protection vectors.
211: movb $0x11,%al / ICW1 - edge, ICW4
212: outb $PIC
213: IODELAY
214: movb $0x20,%al / ICW2 - Reserve 1st 32 vectors for 286
215: outb $PICM
216: IODELAY
217: movb $0x04,%al / ICW3 - master level 2
218: outb $PICM
219: IODELAY
220: movb $0x01,%al / ICW4 - 8086 mode, master.
221: outb $PICM
222: IODELAY
223:
224: / NIGEL: The original code here (and related code in "i386/md.c") turned off
225: / the chain bit in the first PIC by default (and at every subsequent
226: / opportunity) even though all the mask bits in the slave PIC are set to off.
227: / In order to support an enhanced interrupt architecture for the STREAMS and
228: / DDI/DDK subsystems I want to remove the state knowledge from the code in
229: / "i386/md.c" so that the chain bit is always left on.
230: / In order to do this, I have modified the startup code below so that the
231: / system by default allows the slave PIC to interrupt (of course, it still
232: / won't interrupt unless it is enabled to; the masking I have removed was
233: / totally redundant).
234:
235: movb $0xFA,%al / Disable interrupts from master PIC.
236: outb $PICM / (except for clock and slave PIC interrupt).
237:
238: movb $0x11,%al / ICW1 - edge, ICW4
239: outb $SPIC
240: IODELAY
241: movb $0x70,%al / ICW2 - slave starts at 0x70th interrupt
242: outb $SPICM
243: IODELAY
244: movb $0x02,%al / ICW3 - master level 2
245: outb $SPICM
246: IODELAY
247: movb $0x01,%al / ICW4 - 8086 mode.
248: outb $SPICM
249: IODELAY
250: movb $0xFF,%al
251: outb $SPICM / Disable interrupts from slave PIC.
252: /DEBUG
253: cli
254: call __cinit
255: call mchinit / C initialization
256: mov %cr0,%eax / Turn on paging
257: / use 80000001 to allow FP
258: / or $0x80000001,%eax
259: / use 80000005 to disallow FP
260: or $0x80000005,%eax
261: mov %eax,%cr0
262: ljmp $SEG_RNG0_TXT,$loc3 / clear pipeline; jump far, direct
263:
264: /
265: / Ring 0 startup code
266: /
267: loc3:
268: movw $SEG_386_KD,%ax
269: movw %ax,%ds
270: movw $SEG_RNG0_STK,%ax
271: movw %ax,%ss
272: movl $ESP0_START,%esp / Stack pointer for init
273: clts / Clear task switched flag.
274:
275: / Call the machine setup code.
276: / Call Coherent main.
277: / On return, send control off to the user
278: / at its entry point.
279:
280: sub %eax, %eax / Load local descriptor table register.
281: lldt %ax
282:
283: / movw $tss,%ax / Fix low 16 bits of tss base in gdt
284: / movw %ax,gdt+SEG_TSS+2
285:
286: / Fix tss base in gdt
287: movl $tss,%eax
288: movw %ax,gdt+SEG_TSS+2 / Fix bits 0..15
289: rorl $16,%eax / Get tss bits 16..31
290: movb %al,gdt+SEG_TSS+4 / Fix bits 16..23
291: movb %ah,gdt+SEG_TSS+7 / Fix bits 24..31
292:
293: movw $SEG_TSS,%ax / Load task state segment register.
294: ltr %ax
295: lidt idtmap / Load interrupt descriptor table
296: lgdt gdtmap
297:
298: / movw $ldt,%ax / Relocate ldt in gdt
299: / movw %ax,gdt+SEG_LDT+2
300:
301: / Fix ldt base in gdt
302: movl $ldt,%eax
303: movw %ax,gdt+SEG_LDT+2 / Fix bits 0..15
304: rorl $16,%eax / Get ldt bits 16..31
305: movb %al,gdt+SEG_LDT+4 / Fix bits 16..23
306: movb %ah,gdt+SEG_LDT+7 / Fix bits 24..31
307:
308: movw $SEG_LDT,%ax
309: lldt %ax
310:
311: call i8086 / i8086() does fixup of tss_sp0
312:
313: /
314: / Enter Ring 1 kernel from Ring 0
315: /
316: push $SEG_RNG1_STK / SS
317: push $ESP1_START / ESP
318: push $PSW_VAL / PSW
319: push $SEG_RNG1_TXT / CS
320: push $__xmain__ / IP
321: movw $SEG_386_KD,%ax / DS, ES
322: movw %ax, %ds / Map data segment
323: movw %ax, %es / Map extra segment
324: iret / Go to user state.
325:
326: /
327: / Start of Ring 1 kernel.
328: / Need Ring 1 because interrupts are about to turn on, and all irpt gates
329: / have DPL (descriptor privilege level) 1.
330: /
331: __xmain__:
332: sti / Interrupts on, and
333: call main / call Coherent mainline.
334: cli / Interrupts off.
335:
336: /
337: / Enter User mode from Ring 1 kernel
338: /
339: push $SEG_386_UD|R_USR / SS
340: push $NBPC / ESP
341: push $PSW_VAL / PSW
342: push $SEG_386_UI|R_USR / CS
343: push $0 / IP
344: movw $SEG_386_UD|R_USR,%ax / DS, ES
345: movw %ax, %ds / Map data segment
346: movw %ax, %es / Map extra segment
347: iret / Go to user state.
348:
349: ///////
350: /
351: / Trap and interrupt save.
352: /
353: / This version of tsave runs from Ring 1 trap/irpt gates.
354: /
355: ///////
356: .globl disflag
357:
358: tsave: / What level of interrupt ?
359: pusha
360: push %ds / Save current state
361: push %es
362: push %fs
363: push %gs
364:
365: mov $SEG_386_KD,%eax / Map ds
366: movw %ax,%ds
367: mov $SEG_386_UD|R_USR,%eax / Map es
368: movw %ax,%es / to system ds
369:
370: sti
371: icall X_TRAPNO(%esp) / and call the caller
372: cli
373:
374: / if got here from user mode or from idle process, call stand()
375: / else just do cleanup and return
376:
377: movb X_ERR+8(%esp),%al / trapped CS: user RPL?
378: andb $3,%al
379: cmpb $R_USR,%al
380: je tsave1a / jmp if user mode
381: cmpl $__idle__,X_ERR+4(%esp) / trapped EIP == idle process?
382: jnz tsave1b / Call stand() only if idle
383: movl $1,disflag
384:
385: tsave1a:
386: sti
387: call stand
388: tsave1b:
389: cli / No more interrupts
390: pop %gs / Restore
391: pop %fs
392: pop %es
393: pop %ds
394: popa
395: add $8,%esp / forget err, trapno
396: iret / Done.
397:
398: /
399: / Here is another version of tsave, called only from the GP vector (RING 0)
400: /
401:
402: BYPASS .macro addr
403: cmpl $addr,X_ERR+4(%esp) / trapped EIP
404: jz tsave0b
405: .endm
406:
407: tsave0: / What level of interrupt ?
408: pusha
409: push %ds / Save current state
410: push %es
411: push %fs
412: push %gs
413:
414: mov $SEG_386_KD,%eax / Map ds
415: movw %ax,%ds
416: mov $SEG_386_UD|R_USR,%eax / Map es
417: movw %ax,%es / to system ds
418:
419: jmp tsave0b
420:
421: //The following lines help find traps during startup.
422: BYPASS read_cr0
423: BYPASS read_cr2
424: BYPASS read_cr3
425: tsave0q:
426: mov 52(%esp),%eax / Print fault code.
427: cmpb $0x40,%al
428: je tsave0b / Skip over hardware interrupts.
429: push %eax
430: call print32
431: pop %ecx
432:
433: push $' '
434: call mchirp
435: pop %ecx
436:
437: mov 56(%esp),%eax / Print eip.
438: push %eax
439: call print32
440: pop %ecx
441:
442: push $' '
443: call mchirp
444: pop %ecx
445:
446: push %esp / Print esp.
447: call print32
448: pop %ecx
449:
450: tsave0a: jmp tsave0a
451: tsave0b:
452: //
453:
454: icall X_TRAPNO(%esp) / and call the caller
455:
456: pop %gs / Restore
457: pop %fs
458: pop %es
459: pop %ds
460: popa
461: add $8,%esp / forget err, trapno
462: iret / Done.
463:
464: ///////
465:
466: / Save the environment of a process
467: / envsave(p)
468: / MENV *p;
469:
470: / Save the context of a process
471: / consave(p)
472: / MCON *p;
473:
474: ///////
475:
476: envsave:
477: consave:
478: mov %edi,%ecx / Hide di.
479: mov 4(%esp), %edi / di at the MCON block.
480:
481: movw %es,%dx / save = setspace(SEG_386_KD) -- should be %edx
482: movw $SEG_386_KD,%ax
483: movw %ax,%es
484:
485: cld / Ensure increment.
486: mov %ecx, %eax / Save di
487: stosl
488: mov %esi, %eax / Save si
489: stosl
490: mov %ebx, %eax / Save bx
491: stosl
492: mov %ebp, %eax / Save bp
493: stosl
494: mov %esp, %eax / Save sp
495: stosl
496: mov (%esp), %eax / Save ra as pc
497: stosl
498: pushfl / Save fw
499: pop %eax
500: stosl
501: mov %ecx, %edi / Put di back,
502: sub %eax, %eax / indicate a state save and
503: movw %dx,%es / setspace(save)
504: ret / return to caller.
505:
506: ///////
507:
508: / Restore the environment of a process.
509: / envrest(p)
510: / MENV *p;
511:
512: ///////
513:
514: envrest:
515: cli
516: cld
517: mov 4(%esp),%esi / Pointer to context
518: lodsl / Restore di
519: mov %eax, %edi
520: lodsl / Restore si
521: mov %eax, %ecx / Save for later
522: lodsl / Restore bx
523: mov %eax, %ebx
524: lodsl / Restore bp
525: mov %eax, %ebp
526: lodsl / Restore sp
527: mov %eax, %esp
528: push %cs / Push current CS
529: lodsl / Restore pc
530: push %eax
531: lodsl / Restore flags
532: mov %eax, 8(%esp) / Stack now in form PSW,CS,IP.
533: mov %ecx, %esi / Restore si
534: mov $1,%eax / We are restoring
535: iret / Return through PSW,CS,IP.
536:
537: ///////
538:
539: / Restore the context of a process.
540: / Called with interrupts disabled from dispatch.
541: / conrest(u, o)
542: / saddr_t u;
543:
544: ///////
545:
546: conrest:
547: mov 8(%esp), %esi / Fetch syscon offset
548:
549: cli / Interrupts on hold
550: cld
551:
552: / Map new u area into linear space and update paging hardware
553:
554: mov 4(%esp),%eax / Fetch new u area saddr_t
555: orb $SEG_SRW,%al
556: mov %eax,[PTABLE1_V<<BPCSHIFT]+UADDR
557:
558: lcall $SEG_MMUUPD,$0 / strobe CR3
559:
560: / Restore context
561:
562: lodsl / Restore di
563: mov %eax,%edi
564: lodsl / Restore si
565: mov %eax,%ecx / Save for later
566: lodsl / Restore bx
567: mov %eax,%ebx
568: lodsl / Restore bp
569: mov %eax,%ebp
570: lodsl / Restore sp
571: mov %eax,%esp
572: push %cs / Push current CS
573: lodsl / Restore pc
574: push %eax
575:
576: lodsl / Restore flags
577: mov %eax,8(%esp) / Stack now in form PSW,CS,IP.
578: mov %ecx,%esi / Restore si
579: mov $1,%eax / We are restoring
580: iret / Return through PSW,CS,IP.
581:
582: / Save useful registers.
583:
584: / msysgen(p)
585: / MGEN *p;
586:
587: msysgen:
588: ret / Nothing useful to save
589:
590: / Disable interrupts. Previous value is returned.
591:
592: sphi:
593: pushf / Save flags
594: pop %eax / Return current value
595: cli / Disable interrupts
596: ret / And return
597:
598: / Enable interrupts. Previous value is returned.
599:
600: splo:
601: pushf
602: pop %eax
603: sti
604: ret
605:
606: / Change interrupt flag. Previous value is returned.
607:
608: spl:
609: pop %eax / ip
610: pop %edx / psw
611: push %edx
612: push %edx / push psw, cs, ip for iret
613: push %cs
614: push %eax
615: pushf / old psw
616: pop %eax
617: iret
618:
619: ///////
620:
621: / Idle routine.
622: / Enable interupts, and wait for something to
623: / happen. Does not do anything to the 8259, bacause
624: / this will be set up correctly.
625:
626: ///////
627: .globl idle
628: idle:
629: sti / Interupts on.
630: __idle__:
631: jmp __idle__ / Wait for an interrupt
632: ret / and return.
633:
634: ///////
635:
636: / The world is indeed grim.
637: / Hang. Keep the interrupts on so that the
638: / keyboard can get int.
639:
640: ///////
641:
642: halt: sti / Be safe,
643: __halt__
644: jmp __halt__ / And hang.
645:
646: ///////
647:
648: / Basic port level I/O.
649:
650: / Byte I/O (8 bits)
651: / int inb(port);
652: / int outb(port, data);
653:
654: / Word I/O (16 bits)
655: / int inw(port);
656: / int outw(port, data);
657:
658: / Long I/O (32 bits)
659: / int inl(port);
660: / int outl(port, data);
661:
662: ///////
663:
664: inb: mov 4(%esp),%edx
665: sub %eax,%eax
666: inb (%dx)
667: ret
668:
669: outb: movl 4(%esp),%edx
670: movl 8(%esp),%eax
671: outb (%dx)
672: ret
673:
674: inw: mov 4(%esp),%edx
675: sub %eax,%eax
676: inw (%dx)
677: ret
678:
679: outw: movl 4(%esp),%edx
680: movl 8(%esp),%eax
681: outw (%dx)
682: ret
683:
684: inl: mov 4(%esp),%edx
685: sub %eax,%eax
686: inl (%dx)
687: ret
688:
689: outl: movl 4(%esp),%edx
690: movl 8(%esp),%eax
691: outl (%dx)
692: ret
693:
694: ///////
695:
696: / AT Hard Disk Assembler Support
697:
698: / atsend( va ) - send 512 bytes from virtual address to hard disk
699: / atrecv( va ) - receive 512 bytes from hard disk into virtual address
700: / DRQ is not checked. DRQ must be true before atsend/atrecv are called.
701:
702: / va is a system global address
703: ///////
704:
705: .globl atsend
706: atsend:
707: enter $0,$4 / reserve 4 bytes (1 int) of local storage
708: push %esi
709: push %es
710: call workAlloc / get a temp virt page
711: movl %eax,-4(%ebp) / this is "work0" - a click number
712:
713: movw $SEG_386_KD,%ax
714: movw %ax,%es / save = setspace(SEG_386_KD)
715:
716: cld
717: mov 20(%esp),%eax / fetch argument va
718: shr $BPCSHIFT,%eax / get page table index from va
719: mov sysmem,%edx
720: leal (%edx,%eax,4),%esi / base = sysmem.u.pbase + btocrd(va)
721:
722: / Since the requested transfer may span a click boundary, have two clicks
723: / ready in the page table - the one containing the virtual address of the
724: / start of the user area, and the click which follows in virtual memory.
725:
726: lodsl / ptable1_V[WORK0] = *base++ | SEG_SRW
727: or $SEG_SRW,%eax
728: movl -4(%ebp),%edx / work0
729: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
730:
731: lodsl / ptable1_V[WORK1] = *base++ | SEG_SRW
732: or $SEG_SRW,%eax
733: inc %edx / work1
734: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
735:
736: MMUUPD
737:
738: / Now that page boundaries are set, work on the offsets.
739:
740: mov 20(%esp),%esi / va = ctob(WORK0) + (va & (NBPC-1))
741: and $NBPC-1,%esi / get click offset part of va
742: movl -4(%ebp),%edx / work0
743: shl $BPCSHIFT,%edx / ctob(work0)
744: add %edx,%esi
745:
746: mov $256, %ecx / copy one disk block
747: mov $0x1F0, %edx
748:
749: / Do the block transfer.
750:
751: rep
752: outsw
753:
754: MMUUPD
755:
756: push -4(%ebp) / workFree(work0)
757: call workFree
758: pop %edx
759: pop %es / setspace(save)
760: pop %esi
761: leave
762: ret
763:
764: .globl atrecv
765: atrecv:
766: enter $0,$4 / reserve 4 bytes (1 int) of local storage
767: push %esi
768: push %es
769: call workAlloc / get a temp virt page
770: movl %eax,-4(%ebp) / this is "work0" - a click number
771:
772: movw $SEG_386_KD,%ax
773: movw %ax,%es / save = setspace(SEG_386_KD)
774:
775: cld
776: mov 20(%esp),%eax
777: shr $BPCSHIFT,%eax
778: mov sysmem,%edx
779: leal (%edx,%eax,4),%esi / base = sysmem.u.pbase + btocrd(va)
780:
781: lodsl / ptable1_V[WORK1] = *base++ | SEG_SRW
782: or $SEG_SRW,%eax
783: movl -4(%ebp),%edx / work0
784: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
785:
786: lodsl / ptable1_V[WORK1] = *base++ | SEG_SRW
787: or $SEG_SRW,%eax
788: inc %edx / work1
789: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
790:
791: MMUUPD
792:
793: mov 20(%esp),%esi / va = ctob(WORK0) + (va & (NBPC-1))
794: and $NBPC-1,%esi
795: movl -4(%ebp),%edx / work0
796: shl $BPCSHIFT,%edx / ctob(work0)
797: add %edx,%esi
798:
799: mov $256, %ecx / copy one disk block
800: mov $0x1F0, %edx
801:
802: xchg %esi,%edi
803: rep / Value of the ECX register is not
804: / insw (%dx) / updated correctly
805: insw
806: xchg %esi,%edi
807:
808: MMUUPD
809:
810: push -4(%ebp) / workFree(work0)
811: call workFree
812: pop %edx
813: pop %es / setspace(save)
814: pop %esi
815: leave
816: ret
817:
818: ///////
819:
820: / This dummy routine is put in vector
821: / table slots that are unused. All it does is
822: / return to the caller.
823:
824: ///////
825:
826: vret: ret
827:
828: / mmuupd() uses a call gate.
829: mmuupd:
830: pushf
831: cli
832: lcall $SEG_MMUUPD,$0 / gates to mmuupdfR0
833: popf
834: ret
835:
836: / Ring 0 far mmu update. Called via a gate. Uses %eax.
837: / Want interrupts off when we arrive since the interrupt gates
838: / lead into Ring 1.
839: mmuupdfR0:
840: mov $PTABLE0_P<<BPCSHIFT,%eax
841: mov %eax,%cr3
842: lret
843:
844: / Ring 0 near mmu update. Called from ring 0 startup. Uses %eax.
845: mmuupdnR0:
846: mov $PTABLE0_P<<BPCSHIFT,%eax
847: mov %eax,%cr3
848: ret
849:
850: ///////
851: / Get cs selector - return 0 if in kernel, CS if not in kernel.
852: / This version is for resident drivers.
853: / There is a different version (cs_self.s) for loadable drivers.
854: / int cs_sel();
855: ///////
856:
857: cs_sel:
858: sub %eax, %eax
859: ret
860:
861: / load the 'alternate address space register' (es)
862: / with the segment reference passed as an argument.
863:
864: / The value returned is the old value of the 'es' register
865:
866: setspace:
867: movl %esp,%edx
868: sub %eax,%eax
869: movw %es,%ax
870: movl 4(%edx),%edx
871: movw %dx,%es
872: ret
873:
874: /////////////////////////
875: /
876: / From __xtrap_on__ to __xtrap_off__, GP fault and page fault will not
877: / cause panic. Normally, these two traps coming from kernel text result
878: / in panic.
879: /
880: /////////////////////////
881: .globl __xtrap_on__
882: .globl __xtrap_break__
883: .globl __xtrap_off__
884: __xtrap_on__:
885:
886: ///////
887:
888: / Fetch a short from the user's data space.
889: / Coherent 386 fetches a 16 bit short
890:
891: / getusd(u)
892: / char *u;
893:
894: ///////
895:
896: getusd:
897: call start_copy
898: mov 4(%edx),%ecx
899: sub %eax,%eax
900: movw %es:(%ecx),%ax
901: jmp end_copy
902:
903: ///////
904:
905: / Fetch a word from the user's data space.
906: / Coherent 386 fetches a 32 bit word
907:
908: / getuwd(u)
909: / char *u;
910:
911: ///////
912:
913: getuwd:
914: getupd:
915: call start_copy
916: mov 4(%edx),%ecx
917: mov %es:(%ecx),%eax
918: jmp end_copy
919:
920: ///////
921:
922: / Fetch a byte from the user's data space.
923:
924: / getubd(u)
925: / char *u;
926:
927: ///////
928:
929: getubd:
930: call start_copy
931: mov 4(%edx),%ecx
932: sub %eax,%eax
933: movb %es:(%ecx),%al
934: jmp end_copy
935:
936: ///////
937:
938: / Store a short into the user's data space.
939: / Coherent 386 stores a 16 bit short
940:
941: / putusd(u, w)
942: / char *u;
943: / int w;
944:
945: ///////
946:
947: putusd:
948: call start_copy
949: mov 8(%edx),%eax
950: mov 4(%edx),%ecx / eax
951: movw %ax,%es:(%ecx)
952: jmp end_copy
953:
954: ///////
955:
956: / Store a word into the user's data space.
957: / Coherent 386 stores a 32 bit word
958:
959: / putuwd(u, w)
960: / char *u;
961: / int w;
962:
963: ///////
964:
965: putuwi:
966: putuwd:
967: call start_copy
968: mov 8(%edx),%eax
969: mov 4(%edx),%ecx / eax
970: mov %eax,%es:(%ecx)
971: jmp end_copy
972:
973: ///////
974:
975: / Store a byte into the user's data space.
976:
977: / putubd(u, w)
978: / char *u;
979: / int w;
980:
981: ///////
982:
983: putubd:
984: call start_copy
985: mov 8(%edx),%eax / get data
986: mov 4(%edx),%ecx / get addr
987: movb %al,%es:(%ecx)
988: jmp end_copy
989:
990: ///////
991:
992: / Read a byte from a selector and offset.
993:
994: / selkcopy(sel, off)
995: / unsigned long sel;
996: / unsigned long off;
997:
998: ///////
999: .globl selkcopy
1000: selkcopy:
1001: call start_copy
1002: push %es
1003: sub %eax,%eax
1004: mov 4(%edx), %es
1005: mov 8(%edx), %ecx
1006: movb %es:(%ecx), %al
1007: pop %es
1008: jmp end_copy
1009:
1010: / startup routine for 1-element (byte/word) move
1011:
1012: / Block transfer "n" bytes from location
1013: / "k" in the system map to location "u" in the
1014: / user's data space. Return the number of bytes
1015: / transferred.
1016:
1017: / kucopy(k, u, n)
1018: / char *k;
1019: / char *u;
1020: / int n;
1021:
1022: ///////
1023:
1024: / .globl udat
1025: kucopy:
1026: / mov 8(%esp),%eax / verify user address
1027: / push %eax
1028: / call udat
1029: / cmp $0,%eax
1030: / pop %eax
1031: / jne xx00
1032: / ret
1033: /xx00:
1034:
1035: call start_copy
1036:
1037: movl 4(%edx),%esi / esi
1038: movl 8(%edx),%edi / edi
1039:
1040: mov 12(%edx),%ecx
1041: sar $2,%ecx
1042: je loc6
1043:
1044: rep
1045: movsl
1046:
1047: loc6:
1048: mov 12(%edx),%ecx
1049: andl $3,%ecx
1050: je loc7
1051:
1052: rep
1053: movsb
1054:
1055: loc7:
1056: mov 12(%edx),%eax
1057: jmp end_copy
1058:
1059: ///////
1060:
1061: / Block copy "n" bytes from location "u" in
1062: / the user data space to location "k" in the system
1063: / data space. Return the actual number of bytes
1064: / moved.
1065:
1066: / ukcopy(u, k, n)
1067: / char *u;
1068: / char *k;
1069: / int n;
1070:
1071: ///////
1072:
1073: ukcopy:
1074: call start_copy
1075:
1076: mov 4(%edx),%esi / esi
1077: mov 8(%edx),%edi / edi
1078: mov 12(%edx),%ecx
1079:
1080: push %ds / exchange ds,es
1081: movw %es,%ax / don't assume ss=ds
1082: movw %ax,%ds
1083: pop %es
1084:
1085: sar $2,%ecx
1086: je loc8
1087:
1088: rep
1089: movsl
1090:
1091: loc8: mov %ss:12(%edx),%ecx
1092: andl $3,%ecx
1093: je loc9
1094:
1095: rep
1096: movsb
1097:
1098: loc9: mov %ss:12(%edx),%eax
1099: jmp end_copy / Return
1100:
1101: ////////
1102: /
1103: / Block copy "n" bytes from far location "src" in
1104: / an arbitrary (but valid) to location "dst" in
1105: / data space. Return the actual number of bytes
1106: / moved.
1107: /
1108: / ffcopy(src, dst, n)
1109: / char far *src;
1110: / char far *dst;
1111: / int n;
1112: /
1113: ////////
1114: .globl ffcopy
1115: ffcopy:
1116: call start_copy
1117:
1118: mov 4(%edx),%esi / esi
1119: mov 8(%edx),%ebx / ds
1120: mov 12(%edx),%edi / edi
1121: mov 16(%edx),%eax / es
1122: mov 20(%edx),%ecx
1123:
1124: movw %ax,%es / now load segment regs
1125: movw %bx,%ds
1126:
1127: sar $2,%ecx
1128: je ff01
1129:
1130: rep
1131: movsl
1132:
1133: ff01: mov %ss:20(%edx),%ecx
1134: andl $3,%ecx
1135: je ff01
1136:
1137: rep
1138: movsb
1139:
1140: ff02: mov %ss:20(%edx),%eax
1141: jmp end_copy / Return
1142:
1143: ////////
1144: /
1145: / Read a byte from a selector and offset.
1146: /
1147: / ffbyte(off, sel)
1148: / unsigned long sel;
1149: / unsigned long off;
1150: /
1151: ////////
1152: .globl ffbyte
1153: ffbyte:
1154: call start_copy
1155: push %es
1156: sub %eax,%eax
1157: mov 4(%edx), %ecx
1158: mov 8(%edx), %es
1159: movb %es:(%ecx), %al
1160: pop %es
1161: jmp end_copy
1162:
1163: ////////
1164: /
1165: / write a byte using a selector and offset.
1166: /
1167: / sfbyte(off, sel, byte)
1168: / unsigned long sel;
1169: / unsigned long off;
1170: / int byte;
1171: /
1172: ////////
1173: .globl sfbyte
1174: sfbyte:
1175: call start_copy
1176: push %es
1177: mov 4(%edx), %ecx
1178: mov 8(%edx), %es
1179: mov 12(%edx), %eax
1180: movb %al, %es:(%ecx)
1181: pop %es
1182: jmp end_copy
1183:
1184: ////////
1185: /
1186: / Read a word from a selector and offset.
1187: /
1188: / ffword(off, sel)
1189: / unsigned long sel;
1190: / unsigned long off;
1191: /
1192: ////////
1193: .globl ffword
1194: ffword:
1195: call start_copy
1196: push %es
1197: sub %eax,%eax
1198: mov 4(%edx), %ecx
1199: mov 8(%edx), %es
1200: movw %es:(%ecx), %ax
1201: pop %es
1202: jmp end_copy
1203:
1204: ////////
1205: /
1206: / write a word using a selector and offset.
1207: /
1208: / sfword(off, sel, word)
1209: / unsigned long sel;
1210: / unsigned long off;
1211: / int word;
1212: /
1213: ////////
1214: .globl sfword
1215: sfword:
1216: call start_copy
1217: push %es
1218: mov 4(%edx), %ecx
1219: mov 8(%edx), %es
1220: mov 12(%edx), %eax
1221: movw %ax, %es:(%ecx)
1222: pop %es
1223: jmp end_copy
1224:
1225: / startup routine for n-element copy
1226:
1227: start_copy:
1228: pop %eax
1229: movl %esp,%edx
1230: push %esi
1231: push %edi
1232: push %ds
1233: push %es
1234: / lidt %cs:bdtmap
1235: ijmp %eax
1236:
1237: ///////
1238:
1239: / The n-element copy routines jump here
1240: / with the stack untouched, if they detect
1241: / a bounds error on a user address.
1242:
1243: ///////
1244: __xtrap_break__:
1245:
1246: / add $16,%esp / pop error code, IP, CS, PSW
1247: / movb $EFAULT,%ss:u+U_ERROR / Bad parameter error
1248: subl %eax,%eax / Return 0 to indicate error condition.
1249:
1250: / cleanup routine for n-byte copy
1251:
1252: end_copy:
1253: / lidt %cs:idtmap
1254: pop %es
1255: pop %ds
1256: pop %edi
1257: pop %esi
1258: ret / Return
1259:
1260: __xtrap_off__: / See __xtrap_on__ above.
1261:
1262: / the following four routines are used by [386/fakedma.c]
1263: / and will disappear when a 386 assembler implementation
1264: / is available
1265:
1266: / clearseg_b(nbytes, vaddr_t p, long fill) (byte clear)
1267: / clearseg_d(nbytes, vaddr_t p, long fill) (double word clear)
1268:
1269:
1270: clearseg_b: / setspace in caller
1271: mov %esp,%edx
1272: push %edi
1273: push %es
1274:
1275: mov 8(%edx),%edi
1276: mov $SEG_386_KD,%eax
1277: movw %ax,%es
1278: mov 12(%edx),%eax
1279: mov 4(%edx),%ecx
1280:
1281: cld
1282: rep
1283: stosb
1284:
1285: pop %es
1286: pop %edi
1287: ret
1288:
1289: clearseg_d: / setspace in caller
1290: mov %esp,%edx
1291: push %edi
1292: push %es
1293:
1294: mov 8(%edx),%edi
1295: mov $SEG_386_KD,%eax
1296: movw %ax,%es
1297: mov 12(%edx),%eax / mov eax,2(dx)
1298: mov 4(%edx),%ecx
1299: sar $2,%ecx / char to long
1300:
1301: cld
1302: rep
1303: stosl
1304:
1305: pop %es
1306: pop %edi
1307: ret
1308:
1309: / copyseg_b(nbytes, p, q) (byte copy)
1310: / copyseg_d(nbytes, p, q) (double word copy)
1311:
1312: / copy the user page @ virtual address "p" to virtual address "q"
1313:
1314: copyseg_d: / setspace in caller
1315: movl %esp,%edx
1316: push %esi
1317: push %edi
1318:
1319: mov 8(%edx),%esi
1320: mov 12(%edx),%edi
1321: mov 4(%edx),%ecx
1322: sar $2,%ecx
1323:
1324: cld
1325: rep
1326: movsl
1327:
1328: pop %edi
1329: pop %esi
1330: ret
1331:
1332: copyseg_b: / setspace in caller
1333: movl %esp,%edx
1334: push %esi
1335: push %edi
1336:
1337: mov 8(%edx),%esi
1338: mov 12(%edx),%edi
1339: mov 4(%edx),%ecx
1340:
1341: cld
1342: rep
1343: movsb
1344:
1345: pop %edi
1346: pop %esi
1347: ret
1348:
1349:
1350: / seg2io(long nbytes, vaddr_t p, long port)
1351:
1352: / nbytes must be a short word multiple
1353:
1354: seg2io: / setspace in caller
1355: movl %esp,%edx
1356: push %esi
1357:
1358: mov 4(%edx),%ecx
1359: mov 8(%edx),%esi
1360: mov 12(%edx),%edx / mov edx,2(dx)
1361: sar $1,%ecx / char to short
1362:
1363: cld
1364: rep
1365: outsw
1366:
1367: pop %esi
1368: ret
1369:
1370:
1371:
1372: / io2seg(long nbytes, vaddr_t p, long port)
1373:
1374: / nbytes must be a short word multiple
1375:
1376: io2seg: / setspace in caller
1377: mov %esp,%edx
1378: push %edi
1379:
1380: mov 4(%edx),%ecx
1381: mov 8(%edx),%edi
1382: mov 12(%edx),%edx / mov edx,2(dx)
1383: sar $1,%ecx / char to short
1384:
1385: cld
1386: rep / Value of the ECX register is not
1387: / insw (%dx) / updated correctly
1388: insw
1389:
1390: pop %edi
1391: ret
1392:
1393:
1394: ///////
1395: /
1396: / Profile scaling - special multiply routine is used for speed.
1397: /
1398: / pscale(a,b) is product a*b shifted right 16 bits
1399: /
1400: ///////
1401:
1402: .globl pscale
1403: pscale:
1404: mov 4(%esp),%eax / fetch first argument
1405: mull 8(%esp) / unsigned multiply by second argument
1406: shrd $16,%edx,%eax / shift 64-bit product right 16 bits
1407: ret
1408:
1409: ///////
1410:
1411: / Trap an interrupt linkage.
1412: / Each of the machine traps has a special little
1413: / linkage, that sets up the type code and sends
1414: / control off to the common trap processor. Device
1415: / interrupts, other than the clock (IR0), are
1416: / done here.
1417:
1418: ///////
1419:
1420: trap0:
1421: push $0x00 / Divide error.
1422: call tsave
1423: jmp trap
1424:
1425: / The debug vector is tricky.
1426: /
1427: / If single stepping user code, the vector must point into Ring 1 code
1428: / so that a ptraced child can be synchronized with its parent.
1429: / use trap1_usr for this
1430: /
1431: / If single stepping the kernel, the vector must point into Ring 0 code
1432: / so context switches switch out the debug stack frame.
1433: / use trap1_ker for this
1434:
1435: .globl __debug_usr__
1436: trap1_usr:
1437: push $0x01 / Single step.
1438: call tsave
1439: jmp __debug_usr__
1440:
1441: .globl __debug_ker__
1442: trap1_ker:
1443: push $0x01 / Single step.
1444: call tsave0
1445: jmp __debug_ker__
1446:
1447: trap2:
1448: push $0x02 / Non-maskable interrupt.
1449: call tsave
1450: jmp trap
1451:
1452: trap3:
1453: push $0x03 / INT 3 (breakpoint).
1454: call tsave
1455: jmp trap
1456:
1457: trap4:
1458: push $0x04 / Overflow.
1459: call tsave
1460: jmp trap
1461:
1462: trap5:
1463: push $0x05 / Bound check.
1464: call tsave
1465: jmp trap
1466:
1467: trap6:
1468: push $0x06 / Invalid opcode.
1469: call tsave
1470: jmp trap
1471:
1472: trap7:
1473: push $0x07 / Processor Extension not available.
1474: call tsave
1475: jmp emtrap
1476:
1477: trap8:
1478: / pop %ss:trapcode / Get error code from stack [always 0]
1479: add $4,%esp
1480: push $0x08 / Double Exception detected
1481: call tsave
1482: jmp trap
1483:
1484: trap9:
1485: push $0x09 / Processor extension segment overrun
1486: call tsave
1487: jmp trap
1488:
1489: trap10:
1490: / pop %ss:trapcode / Get error code from stack
1491: add $4,%esp
1492: push $0x0A / Invalid task state segment
1493: call tsave
1494: jmp trap
1495:
1496: trap11:
1497: / pop %ss:trapcode / Get error code from stack
1498: add $4,%esp
1499: push $0x0B / Segment not present
1500: call tsave
1501: jmp trap
1502:
1503: trap12:
1504: / pop %ss:trapcode / Get error code from stack
1505: add $4,%esp
1506: push $0x0C / Stack segment overrun or not present
1507: call tsave
1508: jmp trap
1509:
1510: trap13:
1511: / pop %ss:trapcode / Get error code from stack
1512: / add $4,%esp
1513: / push $0x0D / General protection
1514: call tsave0
1515: jmp gpfault
1516:
1517: trap14:
1518: / pop %ss:trapcode / Get error code from stack
1519: / add $4,%esp
1520: / push $0x0E / Page Fault
1521: call tsave
1522: jmp pagefault
1523:
1524: trap16:
1525: push $0x10 / Floating point error
1526: call tsave
1527: jmp fptrap
1528:
1529: syc:
1530: push $0x22 / Old format system calls.
1531: call tsave
1532: jmp trap
1533:
1534: .set FAKE_EFL,12
1535: syc32:
1536: push %eax / save %eax
1537: pushf / modify current flags
1538: pop %eax
1539: orw $PSW_VAL,%ax / set IF=1, IOPL=1 (user) on iret
1540: mov %eax,FAKE_EFL(%esp)
1541: pop %eax / restore %eax
1542: push $0x20 / New format system calls.
1543: call tsave
1544: jmp trap
1545:
1546: sig32:
1547: push %eax
1548: pushf
1549: pop %eax
1550: orw $PSW_VAL,%ax
1551: mov %eax,FAKE_EFL(%esp)
1552: pop %eax
1553: push $0x20 / New format signal return.
1554: call tsave
1555: jmp msigend
1556:
1557: ran:
1558: push $0x21 / Random trap.
1559: call tsave
1560: jmp trap
1561:
1562: dev1:
1563: push $0x0140 / Device 1: keyboard
1564: call tsave
1565: icall [1<<2]+vecs
1566: jmp eoi / Dismiss interrupt
1567:
1568: / Device 2: mapped into device 9
1569: dev3:
1570: push $0x0340 / Device 3: al1
1571: call tsave
1572: icall [3<<2]+vecs
1573: jmp eoi / Dismiss interrupt
1574:
1575: dev4:
1576: push $0x0440 / Device 4: al0
1577: call tsave
1578: icall [4<<2]+vecs
1579: jmp eoi / Dismiss interrupt
1580:
1581: dev5:
1582: push $0x0540 / Device 5: hard disk
1583: call tsave
1584: icall [5<<2]+vecs
1585: jmp eoi / Dismiss interrupt
1586:
1587: dev6:
1588: push $0x0640 / Device 6: floppy
1589: call tsave
1590: icall [6<<2]+vecs
1591: jmp eoi / Dismiss interrupt
1592:
1593: dev7:
1594: push $0x0740 / Device 7: lp
1595: call tsave
1596: icall [7<<2]+vecs
1597: jmp eoi / Dismiss interrupt
1598:
1599: dev8:
1600: push $0x0840 / Device 8:
1601: call tsave
1602: icall [8<<2]+vecs
1603: jmp eoi2 / Dismiss interrupt
1604:
1605: dev9:
1606: push $0x0940 / Device 9:
1607: call tsave
1608: icall [9<<2]+vecs
1609: jmp eoi2 / Dismiss interrupt
1610:
1611: dev10:
1612: push $0x0A40 / Device 10:
1613: call tsave
1614: icall [10<<2]+vecs
1615: jmp eoi2 / Dismiss interrupt
1616:
1617: dev11:
1618: push $0x0B40 / Device 11:
1619: call tsave
1620: icall [11<<2]+vecs
1621: jmp eoi2 / Dismiss interrupt
1622:
1623: dev12:
1624: push $0x0C40 / Device 12:
1625: call tsave
1626: icall [12<<2]+vecs
1627: jmp eoi2 / Dismiss interrupt
1628:
1629: .align 4
1630: dev13:
1631: / Used to be coprocessor exception interrupt
1632: / Coprocessor err had to be cleared by writing a 0 byte to port 0xF0
1633: /
1634: push $0x0D40 / Device 13:
1635: call tsave
1636: icall [13<<2]+vecs
1637: jmp eoi2 / Dismiss interrupt
1638:
1639: dev14:
1640: push $0x0E40 / Device 14:
1641: call tsave
1642: icall [14<<2]+vecs
1643: jmp eoi2 / Dismiss interrupt
1644:
1645: dev15:
1646: push $0x0F40 / Device 15:
1647: call tsave
1648: icall [15<<2]+vecs
1649: jmp eoi2 / Dismiss interrupt
1650:
1651: ///////
1652:
1653: / Clock interrupt.
1654:
1655: ///////
1656:
1657: clk:
1658: push $0x0040
1659: call tsave / Perform trap save.
1660: mov X_ERR+12(%esp),%eax / ECS at tick time
1661: and $3,%eax / This will be R_USR iff user mode
1662: push %eax
1663: mov X_ERR+12(%esp),%eax / EIP at tick time
1664: push %eax
1665: call clock / clock(eip, umode)
1666: add $8,%esp / pop arguments.
1667: jmp eoi / Dismiss interrupt
1668:
1669: ///////
1670:
1671: / This co-routine is called to dismiss an interrupt.
1672: / The interrupt code is in X_ERR(%esp)
1673:
1674: / Control returns to "tsave"
1675:
1676: ///////
1677:
1678: .globl eoi2
1679: eoi2:
1680: cli
1681: movb $0x20,%al / Send a non specific EOI
1682: outb $SPIC / to the slave PIC.
1683: IODELAY
1684: movb $0x0B,%al / OCW3 - read isr
1685: outb $SPIC
1686: IODELAY
1687: / inb $SPIC / in-service register to %eax:8..15
1688: / testb %al,%al
1689: / jnz eoi2x / no EOI to master if slave isr nonzero
1690: eoi:
1691: cli
1692: movb $0x20,%al / Send a non specific EOI
1693: outb $PIC / to the master PIC.
1694: IODELAY
1695: eoi2x: ret / Done.
1696:
1697: ///////
1698:
1699: / Read the equipment description. Use
1700: / the "int 11" interface, so that the IBM
1701: / ROM will do all the details.
1702:
1703: ///////
1704:
1705: int11: mov %cs:val11,%eax / Ask the ROM
1706: ret / to put stuff in AX
1707:
1708: ///////
1709:
1710: / Bootstrap.
1711: / Called by the keyboard driver on control-alt-del.
1712: / Requests the 8042 controller to initiate a processor reset,
1713: / which is the only way to terminate protected mode operation.
1714:
1715: / Reference: IBM-AT Technical Reference Manual,
1716: / Real-time Clock/CMOS RAM [Page 1-45]
1717: / Keyboard controller [Page 1-40]
1718: / Test 3, Page 5-68.
1719:
1720: ///////
1721:
1722: boot:
1723: cli / Disable interrupts.
1724:
1725: subl %ecx,%ecx
1726: loc12: inb $KBCTRL / Wait for 8042 input buffer to empty.
1727: testb $2, %al
1728: loopne loc12
1729: IODELAY
1730:
1731: movb $0xFE,%al / Issue a shutdown command
1732: outb $KBCTRL / to the 8042 control port.
1733:
1734: loc13: hlt / Halt until processor reset occurs.
1735: jmp loc13
1736:
1737: .globl putchar
1738:
1739: / Comment in the line below if debugging output is to go to the
1740: / printer
1741:
1742: /putchar:
1743:
1744: movb 4(%esp),%al
1745: cmpb $0xa,%al
1746: jne loc18
1747: push $0xd
1748: call putchar
1749: add $4,%esp
1750: loc18: mov $LPSTAT,%edx
1751: inb (%dx)
1752: testb $IBMNBSY,%al
1753: je loc18
1754:
1755: mov $LPCSR,%edx
1756: movb $SEL+NINIT, %al
1757: outb (%dx)
1758:
1759: mov $LPDATA, %edx
1760: movb 4(%esp),%al
1761: outb (%dx)
1762:
1763: mov $LPCSR,%edx
1764: movb $SEL+NINIT+STROBE,%al
1765: outb (%dx)
1766: movb $8, %cl
1767: l_1: decb %cl
1768: jne l_1
1769: movb $SEL+NINIT, %al
1770: outb (%dx)
1771: ret
1772:
1773: / long _canl(l) long l;
1774: / This is called by the routines that
1775: / transform longs to and from the
1776: / canonical formats.
1777:
1778: _canl:
1779: mov 4(%esp),%eax
1780: rol $16,%eax
1781: ret
1782:
1783: regcr2: mov %cr2,%eax
1784: ret
1785:
1786: regfp: mov %ebp,%eax
1787: ret
1788:
1789: .align 4 / CPU resets if val11 isn't aligned.
1790: val11: .long 0 / Value obtained from int11 [in code].
1791:
1792: aicodep:
1793: sub %ebx,%ebx
1794: sub $aicodep,%ebx
1795: lea fn(%ebx),%eax
1796: mov %eax,argl(%ebx)
1797: lea a1(%ebx),%eax
1798: mov %eax,argl+4(%ebx)
1799: lea argl+8(%ebx),%eax / No environment
1800: push %eax
1801: lea argl(%ebx),%eax / Argument list
1802: push %eax
1803: lea fn(%ebx),%eax / File name
1804: push %eax
1805: sub $4,%esp / Dummy word for exec
1806: movl $59, %eax
1807: lcall $0x7,$0
1808: jmp . / Instant page fault if exec failed!
1809: .alignoff
1810: .align 2
1811: argl: .long 0 / argv[0] = "/etc/init";
1812: .long 0 / argv[1] = "";
1813: .long 0 / argv[2] = NULL;
1814:
1815: fn: .byte "/etc/init",0
1816: a1: .byte 0
1817: sb:
1818: .set aicodes, .-aicodep
1819:
1820: ///////
1821:
1822: / Task State Segment - Coherent runs as a single protected mode 386 task.
1823:
1824: ///////
1825: .alignon
1826: .align 4
1827: .globl tss_sp0 / Use run-time fixup for tss_sp0
1828: .globl tssIoMap
1829: .globl tssIoEnd
1830: tss: / Task State Segment.
1831: tss_lnk:.long 0 / 0: Back link selector to TSS.
1832: tss_sp0:.long ESP0_START / 4: SP for CPL 0.
1833: tss_ss0:.long SEG_RNG0_STK / 8: SS for CPL 0.
1834: tss_sp1:.long ESP1_START / C: SP for CPL 1.
1835: tss_ss1:.long SEG_RNG1_STK / 10: SS for CPL 1.
1836: tss_sp2:.long u+NBPC / 14: SP for CPL 2.
1837: tss_ss2:.long SEG_386_KD / 18: SS for CPL 2.
1838: tss_cr3:.long PTABLE0_P<<BPCSHIFT / 1C: CR3 (PDBR)
1839: tss_ip: .long 0 / 20: EIP (Entry point).
1840: tss_psw:.long 0 / 24: Flag word.
1841: tss_ax: .long 0 / 28: Register AX.
1842: tss_cx: .long 0 / 2C: Register CX.
1843: tss_dx: .long 0 / 30: Register DX.
1844: tss_bx: .long 0 / 34: Register BX.
1845: tss_bp: .long 0 / 38: Register BP.
1846: tss_sp: .long 0 / 3C: Register SP.
1847: tss_si: .long 0 / 40: Register SI.
1848: tss_di: .long 0 / 44: Register DI.
1849: tss_es: .long 0 / 48: Register ES.
1850: tss_cs: .long 0 / 4C: Register CS.
1851: tss_ss: .long 0 / 50: Register SS.
1852: tss_ds: .long 0 / 54: Register DS.
1853: tss_fs: .long 0 / 58: Register FS.
1854: tss_gs: .long 0 / 5C: Register GS.
1855: tss_ldt:.long SEG_LDT / 60: Task LDT Selector.
1856: .long TSS_IOMAP_OFF / 64: T bit & I/O map base
1857: / I/O map is part of tss.
1858: / Bitmap up to port address TSS_IOMAP_LEN.
1859: / Initialize to all 1's, meaning no I/O allowed.
1860: / tss + 0x68 = tssIoMap
1861: tssIoMap:
1862: .long [TSS_IOMAP_LEN .div 32] # -1
1863: tssIoEnd:
1864: .long -1
1865: ///////
1866:
1867: / Data.
1868:
1869: ///////
1870: .data
1871: sdata:
1872:
1873: vecs: .long 16 # vret / Interrupt vector table
1874:
1875: trapcode:.long 0
1876:
1877: .text
1878: ///////
1879:
1880: / i8086 coherent clist hack.
1881:
1882: ///////
1883:
1884: /LXXX: .long NCPCL+4
1885:
1886: /cltinit:
1887: / pushf / s = sphi()
1888: / cli
1889: / mov NCLIST,%eax
1890: / imull LXXX,%eax
1891: / addl clistp,%eax
1892: / sub %ecx,%ecx
1893: / jmp loc32
1894:
1895: /loc33: mov %ecx,(%eax)
1896: / mov %eax,%ecx
1897: /loc32: sub $NCPCL+4, %eax
1898: / cmp clistp,%eax
1899: / jnb loc33
1900:
1901: / mov %ecx,cltfree
1902: / call spl
1903: / add $0x04,%esp
1904: / ret
1905:
1906: /getq:
1907: / push %esi
1908:
1909: / mov 8(%esp),%edx
1910: / sub %ecx,%ecx
1911: / cmp %ecx,(%edx) / if (cqp->cq_cc==0)
1912: / je loc21
1913:
1914: / pushf / s = sphi()
1915: / cli
1916: / mov 12(%edx),%esi / op = cqp->cq_op [%esi]
1917: / mov 16(%edx),%eax / ox = cqp->cq_ox [%eax]
1918: / movb 4(%eax,%esi),%cl
1919: / push %ecx / save = op->cl_ch[ox]
1920: / decl (%edx) / if (--cqp->cq_cc == 0)
1921: / je loc23
1922: / inc %eax / ++ox
1923: / mov %eax,16(%edx) / cqp->cq_ox = ox
1924: / cmp $NCPCL,%eax / if (ox == NCPL)
1925: / jne loc24
1926:
1927: /loc23: sub %eax,%eax
1928: / mov %eax,16(%edx) / cqp->cq_ox = 0
1929: / mov (%esi),%ecx / np = op->cl_fp
1930: / mov %ecx,12(%edx) / cqp->cq_op = np
1931: / cmp %eax,%ecx / if (np==0)
1932: / jne loc25
1933: / mov %eax,4(%edx) / cqp->cq_ip = 0
1934: / mov %eax,8(%edx) / cqp->cq_ix = 0
1935:
1936: /loc25: mov cltfree,%ecx
1937: / mov %ecx,(%esi) / op->cl_fp = cltfree
1938: / mov %esi,cltfree / cltfree = op
1939: / cmp %eax,cltwant / if (cltwant)
1940: / je loc24
1941: / mov %eax,cltwant / cltwant = 0
1942: / push $cltwant
1943: / call wakeup / wakeup(&cltwant)
1944: / pop %eax
1945:
1946: /loc24: pop %esi
1947: / call spl / spl(s)
1948: / pop %eax
1949: / mov %esi,%eax / return save
1950: / pop %esi
1951: / ret
1952: /loc21:
1953: / mov $-1,%eax / return -1
1954: / pop %esi
1955: / ret
1956:
1957: /putq:
1958: / push %esi
1959: / sub %eax,%eax
1960: / pushf / s = sphi();
1961: / cli
1962: / mov 12(%esp),%edx / ebp = cqp
1963: / mov 4(%edx),%esi / ip = cqp->cq_ip [%esi]
1964: / mov 8(%edx),%ecx / ix = cqp->cq_ix [%ecx]
1965: / cmp %eax,%ecx / if (ix==0) {
1966: / jne loc26
1967: / mov cltfree,%esi / ip = cltfree
1968: / cmp %eax,%esi / if (ip==0)
1969: / je loc27 / goto bad;
1970: / mov (%esi),%ecx
1971: / mov %ecx,cltfree / cltfree = cltfree->cl_fp
1972: / mov %eax,(%esi) / ip->cl_fp = 0
1973: / mov 4(%edx),%ecx / np = cqp->cq_ip
1974: / cmp %eax,%ecx / if (np==0)
1975: / jne loc29
1976: / mov %esi,12(%edx) / cqp->cq_op = ip
1977: / jmp loc30
1978: / / else
1979: /loc29: mov %esi,(%ecx) / np->cl_fp = ip
1980:
1981: /loc30: mov %esi,4(%edx) / cqp->cq_ip = ip
1982: / mov %eax,%ecx / ix = 0
1983: / / }
1984:
1985: /loc26:
1986: / movb 16(%esp),%al / ip->cl_ch[ix] = c
1987: / movb %al, 4(%esi,%ecx)
1988: / inc %ecx / ix++
1989: / cmp $NCPCL,%ecx / if (ix==NCPCL)
1990: / jne loc31
1991: / sub %ecx,%ecx / ix = 0
1992:
1993: /loc31: mov %ecx,8(%edx) / cqp->cq_ix = ix
1994: / incl (%edx) / cqp->cq_cc++
1995: / call spl / spl(s)
1996: / add $4,%esp
1997: / mov 12(%esp),%eax / return (c)
1998: /loc28:
1999: / pop %esi
2000: / ret
2001: /loc27:
2002: / call spl / spl(s)
2003: / add $4,%esp
2004: / mov $-1,%eax / return -1
2005: / jmp loc28
2006:
2007: /clrq:
2008: / mov 4(%esp),%edx
2009: / pushf
2010: / cli
2011:
2012: /loc34: push %edx
2013: / call getq
2014: / pop %edx
2015: / or %eax,%eax
2016: / jge loc34
2017:
2018: / call spl
2019: / pop %eax
2020: / ret
2021:
2022: /loc35: movl $0x01,cltwant
2023: / push %eax
2024: / push %eax
2025: / push $0x0100
2026: / push $cltwant
2027: / call sleep
2028: / add $16,%esp
2029: /waitq:
2030: / sub %eax,%eax
2031: / cmp %eax,cltfree
2032: / jne loc35
2033: / ret
2034:
2035: ///////
2036:
2037: / atbsyw() -- wait for AT disk controller to become not busy
2038:
2039: / Return: 0 = timeout
2040: / * = not busy
2041:
2042: ///////
2043: /atbsyw:
2044: / mov $0x3FFFF, %ecx
2045: / mov ATSREG, %edx
2046: /loc16: inb (%dx)
2047: / testb $BSY_ST, %al
2048: / loopne loc16
2049: / mov %ecx, %eax
2050: / ret
2051:
2052: ///////
2053:
2054: / AT Hard Disk Assembler Support
2055: / atbsyw() - wait while controller is busy
2056: / atdrqw() - wait for controller to request data transfer
2057:
2058: ///////
2059: ///////
2060:
2061: / atdrqw() -- wait for AT disk controller to initiate data request
2062:
2063: / Return: 0 = timeout
2064: / * = data requested
2065:
2066: ///////
2067:
2068: /atdrqw:
2069: / mov $0x3FFFF, %ecx
2070: / mov ATSREG, %edx
2071: /loc17: inb (%dx)
2072: / testb $DRQ_ST, %al
2073: / loope loc17
2074: / mov %ecx, %eax
2075: / ret
2076:
2077: / Read a byte from the CMOS. Takes one argument--the
2078: / CMOS address to read from as an int; returns the
2079: / value read as a char.
2080: /
2081: / int read_cmos(int addr);
2082:
2083: read_cmos:
2084: push %esi
2085: push %edi
2086: movb 12(%esp), %al / Fetch address from stack.
2087: outb $CMOSA / Send address to CMOS.
2088: IODELAY
2089: sub %eax, %eax / Zero out everything we don't want.
2090: inb $CMOSD / Get Value from CMOS into al.
2091: pop %edi
2092: pop %esi
2093: ret / Return from read_cmos().
2094:
2095: / Write a byte to the CMOS.
2096: /
2097: / void write_cmos(int addr, int data)
2098:
2099: write_cmos:
2100: push %esi
2101: push %edi
2102: movb 12(%esp), %al / Fetch address from stack.
2103: outb $CMOSA / Send address to CMOS.
2104: IODELAY
2105: movb 16(%esp), %al / Fetch address from stack.
2106: outb $CMOSD / Get Value from CMOS into al.
2107: IODELAY
2108: pop %edi
2109: pop %esi
2110: ret / Return from read_cmos().
2111:
2112: / Read timer channel 0 into int value.
2113: / Clock counts down from 11932 to 0 with each clock tick.
2114: .globl read_t0
2115: read_t0:
2116: pushfl
2117: cli
2118: xorl %eax,%eax / Counter latch timer 0 and clear return val
2119: outb $PIT+3
2120: IODELAY
2121: inb $PIT / low byte of counter latch
2122: IODELAY
2123: movb %al,%ah
2124: inb $PIT / high byte of counter latch
2125: IODELAY
2126: xchgb %al,%ah
2127: popfl
2128: ret
2129:
2130: / return current contents of psw
2131: .globl read_psw
2132: read_psw:
2133: pushfl
2134: popl %eax
2135: ret
2136:
2137: / Read master PIC state
2138: / return 00:xx:yy:zz 4-byte int value
2139: / xx: interrupt mask
2140: / yy: isr
2141: / zz: irr
2142:
2143: / .globl mchirp
2144: /FOO .macro ch
2145: / push ch
2146: / call mchirp
2147: / add $4,%esp
2148: / .endm
2149:
2150: / .globl rd_m_pic
2151: /rd_m_pic:
2152: / pushfl
2153: / cli
2154: / sub %eax,%eax
2155: / inb $PICM / interrupt mask to %eax:16..23
2156: / shl $8,%eax
2157: / movb $0x0B,%al / OCW3 - read isr
2158: / outb $PIC
2159: / IODELAY
2160: / inb $PIC / in-service register to %eax:8..15
2161: / shl $8,%eax
2162: / movb $0x0A,%al / OCW3 - read irr
2163: / outb $PIC
2164: / IODELAY
2165: / inb $PIC / irpt request register to %eax:0..7
2166: / popfl
2167: / ret
2168:
2169: / Read slave PIC state
2170: / return 00:xx:yy:zz 4-byte int value
2171: / xx: interrupt mask
2172: / yy: isr
2173: / zz: irr
2174:
2175: / .globl rd_s_pic
2176: /rd_s_pic:
2177: / pushfl
2178: / cli
2179: / sub %eax,%eax
2180: / inb $SPICM / interrupt mask to %eax:16..23
2181: / shl $8,%eax
2182: / movb $0x0B,%al / OCW3 - read isr
2183: / outb $SPIC
2184: / IODELAY
2185: / inb $SPIC / in-service register to %eax:8..15
2186: / shl $8,%eax
2187: / movb $0x0A,%al / OCW3 - read irr
2188: / outb $SPIC
2189: / IODELAY
2190: / inb $SPIC / irpt request register to %eax:0..7
2191: / popfl
2192: / ret
2193:
2194: / return current contents of cr0
2195: .globl read_cr0
2196: read_cr0:
2197: movl %cr0,%eax
2198: ret
2199:
2200: / return current contents of cr2
2201: .globl read_cr2
2202: read_cr2:
2203: movl %cr2,%eax
2204: ret
2205:
2206: / return current contents of cr3
2207: .globl read_cr3
2208: read_cr3:
2209: movl %cr3,%eax
2210: ret
2211:
2212: /////////
2213: /
2214: / Debugging support.
2215: /
2216: /////////
2217: .globl write_dr0
2218: .globl write_dr1
2219: .globl write_dr2
2220: .globl write_dr3
2221: .globl write_dr6
2222: .globl write_dr7
2223:
2224: .globl read_dr0
2225: .globl read_dr1
2226: .globl read_dr2
2227: .globl read_dr3
2228: .globl read_dr6
2229: .globl read_dr7
2230:
2231: / write arg to dr0
2232: write_dr0:
2233: movl 4(%esp),%eax
2234: movl %eax,%dr0
2235: ret
2236:
2237: / write arg to dr1
2238: write_dr1:
2239: movl 4(%esp),%eax
2240: movl %eax,%dr1
2241: ret
2242:
2243: / write arg to dr2
2244: write_dr2:
2245: movl 4(%esp),%eax
2246: movl %eax,%dr2
2247: ret
2248:
2249: / write arg to dr3
2250: write_dr3:
2251: movl 4(%esp),%eax
2252: movl %eax,%dr3
2253: ret
2254:
2255: / write arg to dr6
2256: write_dr6:
2257: movl 4(%esp),%eax
2258: movl %eax,%dr6
2259: ret
2260:
2261: / write arg to dr7
2262: write_dr7:
2263: movl 4(%esp),%eax
2264: movl %eax,%dr7
2265: ret
2266:
2267: read_dr0:
2268: movl %dr0,%eax
2269: ret
2270:
2271: read_dr1:
2272: movl %dr1,%eax
2273: ret
2274:
2275: read_dr2:
2276: movl %dr2,%eax
2277: ret
2278:
2279: read_dr3:
2280: movl %dr3,%eax
2281: ret
2282:
2283: read_dr6:
2284: movl %dr6,%eax
2285: ret
2286:
2287: read_dr7:
2288: movl %dr7,%eax
2289: ret
2290:
2291: / write to the EM bit of CR0
2292: / this routine is a stub for the ring 0 code
2293: / argument is 0 or 1
2294: /
2295: / void setEm(int bit)
2296: .globl setEm
2297: setEm:
2298: movl 4(%esp),%eax / fetch argument
2299: pushf
2300: cli
2301: pushl %eax
2302: lcall $SEG_SET_EM,$0 / gate to setEmfR0
2303: / setEmfR0 will delete 4 bytes worth of args
2304: popf
2305: ret
2306:
2307: / Ring 0 write to CR0 EM bit. Called via a gate.
2308: / Want interrupts off when we arrive since the interrupt gates
2309: / lead into Ring 1.
2310: setEmfR0:
2311: movb 8(%esp),%cl / fetch argument
2312:
2313: cmpb $0,%cl
2314: movl %cr0,%eax
2315: jz se00
2316: orb $4,%al / set EM bit
2317: andb $0xDF,%al / clear NE bit
2318: jmp se01
2319: se00:
2320: andb $0xFB,%al / clear EM bit
2321: orb $0x20,%al / set NE bit
2322: se01:
2323: mov %eax,%cr0
2324: / make 4-byte arg list disappear
2325: lret $4
2326:
2327: / return nonzero if paging is turned on
2328: .globl paging
2329: paging:
2330: movl (%esp),%eax / fetch return address
2331: cmpl $[SBASE<<BPCSHIFT],%eax / is it >= unsigned FFC0_0000?
2332: jae pagingMaybe
2333: xorl %eax,%eax / if not, no paging
2334: ret
2335: pagingMaybe:
2336: movw %cs,%ax / if return addr high, cs is a selector
2337: cmpw $0x58,%ax / selectors 58-6F are nonpaging
2338: jb pagingYes
2339: cmpw $0x6F,%ax / selectors 58-6F are nonpaging
2340: ja pagingYes
2341: xorl %eax,%eax / no paging
2342: ret
2343: pagingYes:
2344: movl $1,%eax
2345: ret
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.