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

📄 longjmp.c

📁 gerneral os development
💻 C
字号:
#include <setjmp.h> /* jmp_buf *//*****************************************************************************To use setjmp() and longjmp() for asynchronous (interrupt-driven;pre-emptive) task-switching, we want to enable interrupts simultaneouswith jumping to the task. In other words, we want the EFLAGS and EIPregisters loaded at the same time.The only instruction that can do this is IRET, which also loads the CSregister. Changing CS is done in code that uses far pointers, and it'salso done when changing address spaces, and when changing privilege levels.We're not interested in any of those, so just push the current CS valueon the stack and let IRET use that.Three distinct stack pointer (ESP) values are used in this routine:- 'Old' or 'current' stack pointer value, which is discarded by  this routine (use setjmp() to save it)- ESP is made to point, briefly, to the jmp_buf struct itself- 'New' ESP value; stored in jmp_buf.espRegister values are restored from the jmp_buf as follows:1. Push jmp_buf.eflags, the current CS value, and jmp_buf.eip   onto the 'new' stack2. Make ESP point to the jmp_buf struct itself, then use the POPA   instruction to pop the 7 general purpose registers (ESP is not   loaded by POPA). The use of POPA means that registers in the   jmp_buf MUST be stored in the order that POPA expects.   (Maybe use MOVs instead, to eliminate this restriction?   Might have to rewrite entire function in asm, instead of C.)3. Load ESP with the 'new' stack pointer, from jmp_buf.esp4. Use IRET to pop EIP, CS, and EFLAGS from the 'new' stack5. ???6. Profit!	<--- obligatory Slashdot jokeThis code does NOT save the floating-point state of the CPU. Either:1. Don't use floating point, or2. Don't use floating point in more than one thread, or3. Rewrite this code so it DOES save the floating-point state, or4. Save/restore the floating-point state when entering/leaving   the kernel (protected OS only)*****************************************************************************/void longjmp(jmp_buf buf, int ret_val){	unsigned *esp;/* make sure return value is not 0 */	if(ret_val == 0)		ret_val++;/* EAX is used for return values, so store it in jmp_buf.EAX */	buf->eax = ret_val;/* get ESP for new stack */	esp = (unsigned *)buf->esp;/* push EFLAGS on the new stack */	esp--;	*esp = buf->eflags;/* push current CS on the new stack */	esp--;	__asm__ __volatile__(		"mov %%cs,%0\n"		: "=m"(*esp));/* push EIP on the new stack */	esp--;	*esp = buf->eip;/* new ESP is 12 bytes lower; update jmp_buf.ESP */	buf->esp = (unsigned)esp;/* now, briefly, make the jmp_buf struct our stack */	__asm__ __volatile__(		"movl %0,%%esp\n"/* ESP now points to 8 general-purpose registers stored in jmp_bufPop them */		"popa\n"/* load new stack pointer from jmp_buf */		"movl -20(%%esp),%%esp\n"/* ESP now points to new stack, with the IRET frame (EIP, CS, EFLAGS)we created just above. Pop these registers: */		"iret\n"		:		: "m"(buf));}

⌨️ 快捷键说明

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