source: trunk/minix/kernel/klib386.s@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 15.6 KB
Line 
1#
2! sections
3
4.sect .text; .sect .rom; .sect .data; .sect .bss
5
6#include <minix/config.h>
7#include <minix/const.h>
8#include "const.h"
9#include "sconst.h"
10#include "protect.h"
11
12! This file contains a number of assembly code utility routines needed by the
13! kernel. They are:
14
15.define _monitor ! exit Minix and return to the monitor
16.define _int86 ! let the monitor make an 8086 interrupt call
17.define _cp_mess ! copies messages from source to destination
18.define _exit ! dummy for library routines
19.define __exit ! dummy for library routines
20.define ___exit ! dummy for library routines
21.define ___main ! dummy for GCC
22.define _phys_insw ! transfer data from (disk controller) port to memory
23.define _phys_insb ! likewise byte by byte
24.define _phys_outsw ! transfer data from memory to (disk controller) port
25.define _phys_outsb ! likewise byte by byte
26.define _enable_irq ! enable an irq at the 8259 controller
27.define _disable_irq ! disable an irq
28.define _phys_copy ! copy data from anywhere to anywhere in memory
29.define _phys_memset ! write pattern anywhere in memory
30.define _mem_rdw ! copy one word from [segment:offset]
31.define _reset ! reset the system
32.define _idle_task ! task executed when there is no work
33.define _level0 ! call a function at level 0
34.define _read_tsc ! read the cycle counter (Pentium and up)
35.define _read_cpu_flags ! read the cpu flags
36.define _read_cr0 ! read cr0
37.define _write_cr0 ! write a value in cr0
38.define _write_cr3 ! write a value in cr3 (root of the page table)
39
40! The routines only guarantee to preserve the registers the C compiler
41! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
42! direction bit in the flags).
43
44.sect .text
45!*===========================================================================*
46!* monitor *
47!*===========================================================================*
48! PUBLIC void monitor();
49! Return to the monitor.
50
51_monitor:
52 mov esp, (_mon_sp) ! restore monitor stack pointer
53 o16 mov dx, SS_SELECTOR ! monitor data segment
54 mov ds, dx
55 mov es, dx
56 mov fs, dx
57 mov gs, dx
58 mov ss, dx
59 pop edi
60 pop esi
61 pop ebp
62 o16 retf ! return to the monitor
63
64
65!*===========================================================================*
66!* int86 *
67!*===========================================================================*
68! PUBLIC void int86();
69_int86:
70 cmpb (_mon_return), 0 ! is the monitor there?
71 jnz 0f
72 movb ah, 0x01 ! an int 13 error seems appropriate
73 movb (_reg86+ 0), ah ! reg86.w.f = 1 (set carry flag)
74 movb (_reg86+13), ah ! reg86.b.ah = 0x01 = "invalid command"
75 ret
760: push ebp ! save C registers
77 push esi
78 push edi
79 push ebx
80 pushf ! save flags
81 cli ! no interruptions
82
83 inb INT2_CTLMASK
84 movb ah, al
85 inb INT_CTLMASK
86 push eax ! save interrupt masks
87 mov eax, (_irq_use) ! map of in-use IRQ's
88 and eax, ~[1<<CLOCK_IRQ] ! keep the clock ticking
89 outb INT_CTLMASK ! enable all unused IRQ's and vv.
90 movb al, ah
91 outb INT2_CTLMASK
92
93 mov eax, SS_SELECTOR ! monitor data segment
94 mov ss, ax
95 xchg esp, (_mon_sp) ! switch stacks
96 push (_reg86+36) ! parameters used in INT call
97 push (_reg86+32)
98 push (_reg86+28)
99 push (_reg86+24)
100 push (_reg86+20)
101 push (_reg86+16)
102 push (_reg86+12)
103 push (_reg86+ 8)
104 push (_reg86+ 4)
105 push (_reg86+ 0)
106 mov ds, ax ! remaining data selectors
107 mov es, ax
108 mov fs, ax
109 mov gs, ax
110 push cs
111 push return ! kernel return address and selector
112 o16 jmpf 20+2*4+10*4+2*4(esp) ! make the call
113return:
114 pop (_reg86+ 0)
115 pop (_reg86+ 4)
116 pop (_reg86+ 8)
117 pop (_reg86+12)
118 pop (_reg86+16)
119 pop (_reg86+20)
120 pop (_reg86+24)
121 pop (_reg86+28)
122 pop (_reg86+32)
123 pop (_reg86+36)
124 lgdt (_gdt+GDT_SELECTOR) ! reload global descriptor table
125 jmpf CS_SELECTOR:csinit ! restore everything
126csinit: mov eax, DS_SELECTOR
127 mov ds, ax
128 mov es, ax
129 mov fs, ax
130 mov gs, ax
131 mov ss, ax
132 xchg esp, (_mon_sp) ! unswitch stacks
133 lidt (_gdt+IDT_SELECTOR) ! reload interrupt descriptor table
134 andb (_gdt+TSS_SELECTOR+DESC_ACCESS), ~0x02 ! clear TSS busy bit
135 mov eax, TSS_SELECTOR
136 ltr ax ! set TSS register
137
138 pop eax
139 outb INT_CTLMASK ! restore interrupt masks
140 movb al, ah
141 outb INT2_CTLMASK
142
143 add (_lost_ticks), ecx ! record lost clock ticks
144
145 popf ! restore flags
146 pop ebx ! restore C registers
147 pop edi
148 pop esi
149 pop ebp
150 ret
151
152
153!*===========================================================================*
154!* cp_mess *
155!*===========================================================================*
156! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
157! phys_clicks dst_clicks, vir_bytes dst_offset);
158! This routine makes a fast copy of a message from anywhere in the address
159! space to anywhere else. It also copies the source address provided as a
160! parameter to the call into the first word of the destination message.
161!
162! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
163! correctly. Changing the definition of message in the type file and not
164! changing it here will lead to total disaster.
165
166CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
167! es ds edi esi eip proc scl sof dcl dof
168
169 .align 16
170_cp_mess:
171 cld
172 push esi
173 push edi
174 push ds
175 push es
176
177 mov eax, FLAT_DS_SELECTOR
178 mov ds, ax
179 mov es, ax
180
181 mov esi, CM_ARGS+4(esp) ! src clicks
182 shl esi, CLICK_SHIFT
183 add esi, CM_ARGS+4+4(esp) ! src offset
184 mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
185 shl edi, CLICK_SHIFT
186 add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
187
188 mov eax, CM_ARGS(esp) ! process number of sender
189 stos ! copy number of sender to dest message
190 add esi, 4 ! do not copy first word
191 mov ecx, Msize - 1 ! remember, first word does not count
192 rep
193 movs ! copy the message
194
195 pop es
196 pop ds
197 pop edi
198 pop esi
199 ret ! that is all folks!
200
201
202!*===========================================================================*
203!* exit *
204!*===========================================================================*
205! PUBLIC void exit();
206! Some library routines use exit, so provide a dummy version.
207! Actual calls to exit cannot occur in the kernel.
208! GNU CC likes to call ___main from main() for nonobvious reasons.
209
210_exit:
211__exit:
212___exit:
213 sti
214 jmp ___exit
215
216___main:
217 ret
218
219
220!*===========================================================================*
221!* phys_insw *
222!*===========================================================================*
223! PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count);
224! Input an array from an I/O port. Absolute address version of insw().
225
226_phys_insw:
227 push ebp
228 mov ebp, esp
229 cld
230 push edi
231 push es
232 mov ecx, FLAT_DS_SELECTOR
233 mov es, cx
234 mov edx, 8(ebp) ! port to read from
235 mov edi, 12(ebp) ! destination addr
236 mov ecx, 16(ebp) ! byte count
237 shr ecx, 1 ! word count
238rep o16 ins ! input many words
239 pop es
240 pop edi
241 pop ebp
242 ret
243
244
245!*===========================================================================*
246!* phys_insb *
247!*===========================================================================*
248! PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count);
249! Input an array from an I/O port. Absolute address version of insb().
250
251_phys_insb:
252 push ebp
253 mov ebp, esp
254 cld
255 push edi
256 push es
257 mov ecx, FLAT_DS_SELECTOR
258 mov es, cx
259 mov edx, 8(ebp) ! port to read from
260 mov edi, 12(ebp) ! destination addr
261 mov ecx, 16(ebp) ! byte count
262! shr ecx, 1 ! word count
263 rep insb ! input many bytes
264 pop es
265 pop edi
266 pop ebp
267 ret
268
269
270!*===========================================================================*
271!* phys_outsw *
272!*===========================================================================*
273! PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count);
274! Output an array to an I/O port. Absolute address version of outsw().
275
276 .align 16
277_phys_outsw:
278 push ebp
279 mov ebp, esp
280 cld
281 push esi
282 push ds
283 mov ecx, FLAT_DS_SELECTOR
284 mov ds, cx
285 mov edx, 8(ebp) ! port to write to
286 mov esi, 12(ebp) ! source addr
287 mov ecx, 16(ebp) ! byte count
288 shr ecx, 1 ! word count
289rep o16 outs ! output many words
290 pop ds
291 pop esi
292 pop ebp
293 ret
294
295
296!*===========================================================================*
297!* phys_outsb *
298!*===========================================================================*
299! PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
300! Output an array to an I/O port. Absolute address version of outsb().
301
302 .align 16
303_phys_outsb:
304 push ebp
305 mov ebp, esp
306 cld
307 push esi
308 push ds
309 mov ecx, FLAT_DS_SELECTOR
310 mov ds, cx
311 mov edx, 8(ebp) ! port to write to
312 mov esi, 12(ebp) ! source addr
313 mov ecx, 16(ebp) ! byte count
314 rep outsb ! output many bytes
315 pop ds
316 pop esi
317 pop ebp
318 ret
319
320
321!*==========================================================================*
322!* enable_irq *
323!*==========================================================================*/
324! PUBLIC void enable_irq(irq_hook_t *hook)
325! Enable an interrupt request line by clearing an 8259 bit.
326! Equivalent C code for hook->irq < 8:
327! if ((irq_actids[hook->irq] &= ~hook->id) == 0)
328! outb(INT_CTLMASK, inb(INT_CTLMASK) & ~(1 << irq));
329
330 .align 16
331_enable_irq:
332 push ebp
333 mov ebp, esp
334 pushf
335 cli
336 mov eax, 8(ebp) ! hook
337 mov ecx, 8(eax) ! irq
338 mov eax, 12(eax) ! id bit
339 not eax
340 and _irq_actids(ecx*4), eax ! clear this id bit
341 jnz en_done ! still masked by other handlers?
342 movb ah, ~1
343 rolb ah, cl ! ah = ~(1 << (irq % 8))
344 mov edx, INT_CTLMASK ! enable irq < 8 at the master 8259
345 cmpb cl, 8
346 jb 0f
347 mov edx, INT2_CTLMASK ! enable irq >= 8 at the slave 8259
3480: inb dx
349 andb al, ah
350 outb dx ! clear bit at the 8259
351en_done:popf
352 leave
353 ret
354
355
356!*==========================================================================*
357!* disable_irq *
358!*==========================================================================*/
359! PUBLIC int disable_irq(irq_hook_t *hook)
360! Disable an interrupt request line by setting an 8259 bit.
361! Equivalent C code for irq < 8:
362! irq_actids[hook->irq] |= hook->id;
363! outb(INT_CTLMASK, inb(INT_CTLMASK) | (1 << irq));
364! Returns true iff the interrupt was not already disabled.
365
366 .align 16
367_disable_irq:
368 push ebp
369 mov ebp, esp
370 pushf
371 cli
372 mov eax, 8(ebp) ! hook
373 mov ecx, 8(eax) ! irq
374 mov eax, 12(eax) ! id bit
375 or _irq_actids(ecx*4), eax ! set this id bit
376 movb ah, 1
377 rolb ah, cl ! ah = (1 << (irq % 8))
378 mov edx, INT_CTLMASK ! disable irq < 8 at the master 8259
379 cmpb cl, 8
380 jb 0f
381 mov edx, INT2_CTLMASK ! disable irq >= 8 at the slave 8259
3820: inb dx
383 testb al, ah
384 jnz dis_already ! already disabled?
385 orb al, ah
386 outb dx ! set bit at the 8259
387 mov eax, 1 ! disabled by this function
388 popf
389 leave
390 ret
391dis_already:
392 xor eax, eax ! already disabled
393 popf
394 leave
395 ret
396
397
398!*===========================================================================*
399!* phys_copy *
400!*===========================================================================*
401! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
402! phys_bytes bytecount);
403! Copy a block of physical memory.
404
405PC_ARGS = 4 + 4 + 4 + 4 ! 4 + 4 + 4
406! es edi esi eip src dst len
407
408 .align 16
409_phys_copy:
410 cld
411 push esi
412 push edi
413 push es
414
415 mov eax, FLAT_DS_SELECTOR
416 mov es, ax
417
418 mov esi, PC_ARGS(esp)
419 mov edi, PC_ARGS+4(esp)
420 mov eax, PC_ARGS+4+4(esp)
421
422 cmp eax, 10 ! avoid align overhead for small counts
423 jb pc_small
424 mov ecx, esi ! align source, hope target is too
425 neg ecx
426 and ecx, 3 ! count for alignment
427 sub eax, ecx
428 rep
429 eseg movsb
430 mov ecx, eax
431 shr ecx, 2 ! count of dwords
432 rep
433 eseg movs
434 and eax, 3
435pc_small:
436 xchg ecx, eax ! remainder
437 rep
438 eseg movsb
439
440 pop es
441 pop edi
442 pop esi
443 ret
444
445!*===========================================================================*
446!* phys_memset *
447!*===========================================================================*
448! PUBLIC void phys_memset(phys_bytes source, unsigned long pattern,
449! phys_bytes bytecount);
450! Fill a block of physical memory with pattern.
451
452 .align 16
453_phys_memset:
454 push ebp
455 mov ebp, esp
456 push esi
457 push ebx
458 push ds
459 mov esi, 8(ebp)
460 mov eax, 16(ebp)
461 mov ebx, FLAT_DS_SELECTOR
462 mov ds, bx
463 mov ebx, 12(ebp)
464 shr eax, 2
465fill_start:
466 mov (esi), ebx
467 add esi, 4
468 dec eax
469 jnz fill_start
470 ! Any remaining bytes?
471 mov eax, 16(ebp)
472 and eax, 3
473remain_fill:
474 cmp eax, 0
475 jz fill_done
476 movb bl, 12(ebp)
477 movb (esi), bl
478 add esi, 1
479 inc ebp
480 dec eax
481 jmp remain_fill
482fill_done:
483 pop ds
484 pop ebx
485 pop esi
486 pop ebp
487 ret
488
489!*===========================================================================*
490!* mem_rdw *
491!*===========================================================================*
492! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
493! Load and return word at far pointer segment:offset.
494
495 .align 16
496_mem_rdw:
497 mov cx, ds
498 mov ds, 4(esp) ! segment
499 mov eax, 4+4(esp) ! offset
500 movzx eax, (eax) ! word to return
501 mov ds, cx
502 ret
503
504
505!*===========================================================================*
506!* reset *
507!*===========================================================================*
508! PUBLIC void reset();
509! Reset the system by loading IDT with offset 0 and interrupting.
510
511_reset:
512 lidt (idt_zero)
513 int 3 ! anything goes, the 386 will not like it
514.sect .data
515idt_zero: .data4 0, 0
516.sect .text
517
518
519!*===========================================================================*
520!* idle_task *
521!*===========================================================================*
522_idle_task:
523! This task is called when the system has nothing else to do. The HLT
524! instruction puts the processor in a state where it draws minimum power.
525 push halt
526 call _level0 ! level0(halt)
527 pop eax
528 jmp _idle_task
529halt:
530 sti
531 hlt
532 cli
533 ret
534
535!*===========================================================================*
536!* level0 *
537!*===========================================================================*
538! PUBLIC void level0(void (*func)(void))
539! Call a function at permission level 0. This allows kernel tasks to do
540! things that are only possible at the most privileged CPU level.
541!
542_level0:
543 mov eax, 4(esp)
544 mov (_level0_func), eax
545 int LEVEL0_VECTOR
546 ret
547
548
549!*===========================================================================*
550!* read_tsc *
551!*===========================================================================*
552! PUBLIC void read_tsc(unsigned long *high, unsigned long *low);
553! Read the cycle counter of the CPU. Pentium and up.
554.align 16
555_read_tsc:
556.data1 0x0f ! this is the RDTSC instruction
557.data1 0x31 ! it places the TSC in EDX:EAX
558 push ebp
559 mov ebp, 8(esp)
560 mov (ebp), edx
561 mov ebp, 12(esp)
562 mov (ebp), eax
563 pop ebp
564 ret
565
566!*===========================================================================*
567!* read_flags *
568!*===========================================================================*
569! PUBLIC unsigned long read_cpu_flags(void);
570! Read CPU status flags from C.
571.align 16
572_read_cpu_flags:
573 pushf
574 mov eax, (esp)
575 popf
576 ret
577
578
579!*===========================================================================*
580!* read_cr0 *
581!*===========================================================================*
582! PUBLIC unsigned long read_cr0(void);
583_read_cr0:
584 push ebp
585 mov ebp, esp
586 mov eax, cr0
587 pop ebp
588 ret
589
590!*===========================================================================*
591!* write_cr0 *
592!*===========================================================================*
593! PUBLIC void write_cr0(unsigned long value);
594_write_cr0:
595 push ebp
596 mov ebp, esp
597 mov eax, 8(ebp)
598 mov cr0, eax
599 jmp 0f ! A jump is required for some flags
6000:
601 pop ebp
602 ret
603
604!*===========================================================================*
605!* write_cr3 *
606!*===========================================================================*
607! PUBLIC void write_cr3(unsigned long value);
608_write_cr3:
609 push ebp
610 mov ebp, esp
611 mov eax, 8(ebp)
612 mov cr3, eax
613 pop ebp
614 ret
615
Note: See TracBrowser for help on using the repository browser.