source: branches/minix3-book/kernel/klib386.s@ 4

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

Importazione sorgenti libro

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