⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lowlevel.asm

📁 The main purpose of this project is to add a new scheduling algorithm to GeekOS and to implement a s
💻 ASM
字号:
; Low level interrupt/thread handling code for GeekOS.; Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>; Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>; $Revision: 1.15 $; This is free software.  You are permitted to use,; redistribute, and modify it as specified in the file "COPYING".; This is 32 bit code to be linked into the kernel.; It defines low level interrupt handler entry points that we'll use; to populate the IDT.  It also contains the interrupt handling; and thread context switch code.%include "defs.asm"%include "symbol.asm"[BITS 32]; ----------------------------------------------------------------------; Definitions; ----------------------------------------------------------------------; This is the size of the Interrupt_State struct in int.hINTERRUPT_STATE_SIZE equ 64; Save registers prior to calling a handler function.; This must be kept up to date with:;   - Interrupt_State struct in int.h;   - Setup_Initial_Thread_Context() in kthread.c%macro Save_Registers 0	push	eax	push	ebx	push	ecx	push	edx	push	esi	push	edi	push	ebp	push	ds	push	es	push	fs	push	gs%endmacro; Restore registers and clean up the stack after calling a handler function; (i.e., just before we return from the interrupt via an iret instruction).%macro Restore_Registers 0	pop	gs	pop	fs	pop	es	pop	ds	pop	ebp	pop	edi	pop	esi	pop	edx	pop	ecx	pop	ebx	pop	eax	add	esp, 8	; skip int num and error code%endmacro; Code to activate a new user context (if necessary), before returning; to executing a thread.  Should be called just before restoring; registers (because the interrupt context is used).%macro Activate_User_Context 0	; If the new thread has a user context which is not the current	; one, activate it.	push    esp                     ; Interrupt_State pointer	push    dword [g_currentThread] ; Kernel_Thread pointer	call    Switch_To_User_Context	add     esp, 8                  ; clear 2 arguments%endmacro; Number of bytes between the top of the stack and; the interrupt number after the general-purpose and segment; registers have been saved.REG_SKIP equ (11*4); Template for entry point code for interrupts that have; an explicit processor-generated error code.; The argument is the interrupt number.%macro Int_With_Err 1align 8	push	dword %1	; push interrupt number	jmp	Handle_Interrupt ; jump to common handler%endmacro; Template for entry point code for interrupts that do not; generate an explicit error code.  We push a dummy error; code on the stack, so the stack layout is the same; for all interrupts.%macro Int_No_Err 1align 8	push	dword 0		; fake error code	push	dword %1	; push interrupt number	jmp	Handle_Interrupt ; jump to common handler%endmacro; ----------------------------------------------------------------------; Symbol imports and exports; ----------------------------------------------------------------------; This symbol is defined in idt.c, and is a table of addresses; of C handler functions for interrupts.IMPORT g_interruptTable; Global variable pointing to context struct for current thread.IMPORT g_currentThread; Set to non-zero when we need to choose a new thread; in the interrupt return code.IMPORT g_needReschedule; Set to non-zero when preemption is disabled.IMPORT g_preemptionDisabled; This is the function that returns the next runnable thread.IMPORT Get_Next_Runnable; Function to put a thread on the run queue.IMPORT Make_Runnable; Function to activate a new user context (if needed).IMPORT Switch_To_User_Context; Sizes of interrupt handler entry points for interrupts with; and without error codes.  The code in idt.c uses this; information to infer the layout of the table of interrupt; handler entry points, without needing a separate linker; symbol for each one (which is quite tedious to type :-)EXPORT g_handlerSizeNoErrEXPORT g_handlerSizeErr; Simple functions to load the IDTR, GDTR, and LDTR.EXPORT Load_IDTREXPORT Load_GDTREXPORT Load_LDTR; Beginning and end of the table of interrupt entry points.EXPORT g_entryPointTableStartEXPORT g_entryPointTableEnd; Thread context switch function.EXPORT Switch_To_Thread; Return current value of eflags register.EXPORT Get_Current_EFLAGS; ----------------------------------------------------------------------; Code; ----------------------------------------------------------------------[SECTION .text]; Load IDTR with 6-byte pointer whose address is passed as; the parameter.align 8Load_IDTR:	mov	eax, [esp+4]	lidt	[eax]	ret;  Load the GDTR with 6-byte pointer whose address is; passed as the parameter.  Assumes that interrupts; are disabled.align 8Load_GDTR:	mov	eax, [esp+4]	lgdt	[eax]	; Reload segment registers	mov	ax, KERNEL_DS	mov	ds, ax	mov	es, ax	mov	fs, ax	mov	gs, ax	mov	ss, ax	jmp	KERNEL_CS:.here.here:	ret; Load the LDT whose selector is passed as a parameter.align 8Load_LDTR:	mov	eax, [esp+4]	lldt	ax	ret; Common interrupt handling code.; Save registers, call C handler function,; possibly choose a new thread to run, restore; registers, return from the interrupt.align 8Handle_Interrupt:	; Save registers (general purpose and segment)	Save_Registers	; Ensure that we're using the kernel data segment	mov	ax, KERNEL_DS	mov	ds, ax	mov	es, ax	; Get the address of the C handler function from the	; table of handler functions.	mov	eax, g_interruptTable	; get address of handler table	mov	esi, [esp+REG_SKIP]	; get interrupt number	mov	ebx, [eax+esi*4]	; get address of handler function	; Call the handler.	; The argument passed is a pointer to an Interrupt_State struct,	; which describes the stack layout for all interrupts.	push	esp	call	ebx	add	esp, 4			; clear 1 argument	; If preemption is disabled, then the current thread	; keeps running.	cmp	[g_preemptionDisabled], dword 0	jne	.restore	; See if we need to choose a new thread to run.	cmp	[g_needReschedule], dword 0	je	.restore	; Put current thread back on the run queue	push	dword [g_currentThread]	call	Make_Runnable	add	esp, 4			; clear 1 argument	; Save stack pointer in current thread context, and	; clear numTicks field.	mov	eax, [g_currentThread]	mov	[eax+0], esp		; esp field	mov	[eax+4], dword 0	; numTicks field	; Pick a new thread to run, and switch to its stack	call	Get_Next_Runnable	mov	[g_currentThread], eax	mov	esp, [eax+0]		; esp field	; Clear "need reschedule" flag	mov	[g_needReschedule], dword 0.restore:	; Activate the user context, if necessary.	Activate_User_Context	; Restore registers	Restore_Registers	; Return from the interrupt.	iret; ----------------------------------------------------------------------; Switch_To_Thread();   Save context of currently executing thread, and activate;   the thread whose context object is passed as a parameter.; ; Parameter: ;   - ptr to Kernel_Thread whose state should be restored and made active;; Notes:; Called with interrupts disabled.; This must be kept up to date with definition of Kernel_Thread; struct, in kthread.h.; ----------------------------------------------------------------------align 16Switch_To_Thread:	; Modify the stack to allow a later return via an iret instruction.	; We start with a stack that looks like this:	;	;            thread_ptr	;    esp --> return addr	;	; We change it to look like this:	;	;            thread_ptr	;            eflags	;            cs	;    esp --> return addr	push	eax		; save eax	mov	eax, [esp+4]	; get return address	mov	[esp-4], eax	; move return addr down 8 bytes from orig loc	add	esp, 8		; move stack ptr up	pushfd			; put eflags where return address was	mov	eax, [esp-4]	; restore saved value of eax	push	dword KERNEL_CS	; push cs selector	sub	esp, 4		; point stack ptr at return address	; Push fake error code and interrupt number	push	dword 0	push	dword 0	; Save general purpose registers.	Save_Registers	; Save stack pointer in the thread context struct (at offset 0).	mov	eax, [g_currentThread]	mov	[eax+0], esp	; Clear numTicks field in thread context, since this	; thread is being suspended.	mov	[eax+4], dword 0	; Load the pointer to the new thread context into eax.	; We skip over the Interrupt_State struct on the stack to	; get the parameter.	mov	eax, [esp+INTERRUPT_STATE_SIZE]	; Make the new thread current, and switch to its stack.	mov	[g_currentThread], eax	mov	esp, [eax+0]	; Activate the user context, if necessary.	Activate_User_Context	; Restore general purpose and segment registers, and clear interrupt	; number and error code.	Restore_Registers	; We'll return to the place where the thread was	; executing last.	iret; Return current contents of eflags register.align 16Get_Current_EFLAGS:	pushfd			; push eflags	pop	eax		; pop contents into eax	ret; ----------------------------------------------------------------------; Generate interrupt-specific entry points for all interrupts.; We also define symbols to indicate the extend of the table; of entry points, and the size of individual entry points.; ----------------------------------------------------------------------align 8g_entryPointTableStart:; Handlers for processor-generated exceptions, as defined by; Intel 486 manual.Int_No_Err 0align 8Before_No_Err:Int_No_Err 1align 8After_No_Err:Int_No_Err 2	; FIXME: not described in 486 manualInt_No_Err 3Int_No_Err 4Int_No_Err 5Int_No_Err 6Int_No_Err 7align 8Before_Err:Int_With_Err 8align 8After_Err:Int_No_Err 9	; FIXME: not described in 486 manualInt_With_Err 10Int_With_Err 11Int_With_Err 12Int_With_Err 13Int_With_Err 14Int_No_Err 15	; FIXME: not described in 486 manualInt_No_Err 16Int_With_Err 17; The remaining interrupts (18 - 255) do not have error codes.; We can generate them all in one go with nasm's %rep construct.%assign intNum 18%rep (256 - 18)Int_No_Err intNum%assign intNum intNum+1%endrepalign 8g_entryPointTableEnd:[SECTION .data]; Exported symbols defining the size of handler entry points; (both with and without error codes).align 4g_handlerSizeNoErr: dd (After_No_Err - Before_No_Err)align 4g_handlerSizeErr: dd (After_Err - Before_Err)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -