# ! This file, mpx386.s, is included by mpx.s when Minix is compiled for ! 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs. ! This file is part of the lowest layer of the MINIX kernel. (The other part ! is "proc.c".) The lowest layer does process switching and message handling. ! Furthermore it contains the assembler startup code for Minix and the 32-bit ! interrupt handlers. It cooperates with the code in "start.c" to set up a ! good environment for main(). ! Every transition to the kernel goes through this file. Transitions to the ! kernel may be nested. The initial entry may be with a system call (i.e., ! send or receive a message), an exception or a hardware interrupt; kernel ! reentries may only be made by hardware interrupts. The count of reentries ! is kept in "k_reenter". It is important for deciding whether to switch to ! the kernel stack and for protecting the message passing code in "proc.c". ! For the message passing trap, most of the machine state is saved in the ! proc table. (Some of the registers need not be saved.) Then the stack is ! switched to "k_stack", and interrupts are reenabled. Finally, the system ! call handler (in C) is called. When it returns, interrupts are disabled ! again and the code falls into the restart routine, to finish off held-up ! interrupts and run the process or task whose pointer is in "proc_ptr". ! Hardware interrupt handlers do the same, except (1) The entire state must ! be saved. (2) There are too many handlers to do this inline, so the save ! routine is called. A few cycles are saved by pushing the address of the ! appropiate restart routine for a return later. (3) A stack switch is ! avoided when the stack is already switched. (4) The (master) 8259 interrupt ! controller is reenabled centrally in save(). (5) Each interrupt handler ! masks its interrupt line using the 8259 before enabling (other unmasked) ! interrupts, and unmasks it after servicing the interrupt. This limits the ! nest level to the number of lines and protects the handler from itself. ! For communication with the boot monitor at startup time some constant ! data are compiled into the beginning of the text segment. This facilitates ! reading the data at the start of the boot process, since only the first ! sector of the file needs to be read. ! Some data storage is also allocated at the end of this file. This data ! will be at the start of the data segment of the kernel and will be read ! and modified by the boot monitor before the kernel starts. ! sections .sect .text begtext: .sect .rom begrom: .sect .data begdata: .sect .bss begbss: #include #include #include #include #include "const.h" #include "protect.h" #include "sconst.h" /* Selected 386 tss offsets. */ #define TSS3_S_SP0 4 ! Exported functions ! Note: in assembly language the .define statement applied to a function name ! is loosely equivalent to a prototype in C code -- it makes it possible to ! link to an entity declared in the assembly code but does not create ! the entity. .define _restart .define save .define _divide_error .define _single_step_exception .define _nmi .define _breakpoint_exception .define _overflow .define _bounds_check .define _inval_opcode .define _copr_not_available .define _double_fault .define _copr_seg_overrun .define _inval_tss .define _segment_not_present .define _stack_exception .define _general_protection .define _page_fault .define _copr_error .define _hwint00 ! handlers for hardware interrupts .define _hwint01 .define _hwint02 .define _hwint03 .define _hwint04 .define _hwint05 .define _hwint06 .define _hwint07 .define _hwint08 .define _hwint09 .define _hwint10 .define _hwint11 .define _hwint12 .define _hwint13 .define _hwint14 .define _hwint15 .define _s_call .define _p_s_call .define _level0_call ! Exported variables. .define begbss .define begdata .sect .text !*===========================================================================* !* MINIX * !*===========================================================================* MINIX: ! this is the entry point for the MINIX kernel jmp over_flags ! skip over the next few bytes .data2 CLICK_SHIFT ! for the monitor: memory granularity flags: .data2 0x01FD ! boot monitor flags: ! call in 386 mode, make bss, make stack, ! load high, don't patch, will return, ! uses generic INT, memory vector, ! new boot code return nop ! extra byte to sync up disassembler over_flags: ! Set up a C stack frame on the monitor stack. (The monitor sets cs and ds ! right. The ss descriptor still references the monitor data segment.) movzx esp, sp ! monitor stack is a 16 bit stack push ebp mov ebp, esp push esi push edi cmp 4(ebp), 0 ! monitor return vector is jz noret ! nonzero if return possible inc (_mon_return) noret: mov (_mon_sp), esp ! save stack pointer for later return ! Copy the monitor global descriptor table to the address space of kernel and ! switch over to it. Prot_init() can then update it with immediate effect. sgdt (_gdt+GDT_SELECTOR) ! get the monitor gdtr mov esi, (_gdt+GDT_SELECTOR+2) ! absolute address of GDT mov ebx, _gdt ! address of kernel GDT mov ecx, 8*8 ! copying eight descriptors copygdt: eseg movb al, (esi) movb (ebx), al inc esi inc ebx loop copygdt mov eax, (_gdt+DS_SELECTOR+2) ! base of kernel data and eax, 0x00FFFFFF ! only 24 bits add eax, _gdt ! eax = vir2phys(gdt) mov (_gdt+GDT_SELECTOR+2), eax ! set base of GDT lgdt (_gdt+GDT_SELECTOR) ! switch over to kernel GDT ! Locate boot parameters, set up kernel segment registers and stack. mov ebx, 8(ebp) ! boot parameters offset mov edx, 12(ebp) ! boot parameters length mov eax, 16(ebp) ! address of a.out headers mov (_aout), eax mov ax, ds ! kernel data mov es, ax mov fs, ax mov gs, ax mov ss, ax mov esp, k_stktop ! set sp to point to the top of kernel stack ! Call C startup code to set up a proper environment to run main(). push edx push ebx push SS_SELECTOR push DS_SELECTOR push CS_SELECTOR call _cstart ! cstart(cs, ds, mds, parmoff, parmlen) add esp, 5*4 ! Reload gdtr, idtr and the segment registers to global descriptor table set ! up by prot_init(). lgdt (_gdt+GDT_SELECTOR) lidt (_gdt+IDT_SELECTOR) jmpf CS_SELECTOR:csinit csinit: o16 mov ax, DS_SELECTOR mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax o16 mov ax, TSS_SELECTOR ! no other TSS is used ltr ax push 0 ! set flags to known good state popf ! esp, clear nested task and int enable jmp _main ! main() !*===========================================================================* !* interrupt handlers * !* interrupt handlers for 386 32-bit protected mode * !*===========================================================================* !*===========================================================================* !* hwint00 - 07 * !*===========================================================================* ! Note this is a macro, it just looks like a subroutine. #define hwint_master(irq) \ call save /* save interrupted process state */;\ push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\ call _intr_handle /* intr_handle(irq_handlers[irq]) */;\ pop ecx ;\ cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\ jz 0f ;\ inb INT_CTLMASK /* get current mask */ ;\ orb al, [1<