QEMU i486 port is code complete
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3342 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
2f5a41f8c7
commit
aa147f7c1d
@ -62,19 +62,25 @@
|
||||
#define REG_EDI (1) /* Saved by pusha */
|
||||
#define REG_ESI (2) /* " " "" " " */
|
||||
#define REG_EBP (3) /* " " "" " " */
|
||||
#define REG_ESP (4) /* " " "" " " */
|
||||
#define REG_ESP (4) /* " " "" " " (NOTE 1)*/
|
||||
#define REG_EBX (5) /* " " "" " " */
|
||||
#define REG_EDX (6) /* " " "" " " */
|
||||
#define REG_ECX (7) /* " " "" " " */
|
||||
#define REG_EAX (8) /* " " "" " " */
|
||||
#define REG_IRQNO (9) /* Interrupt number */
|
||||
#define REG_ERRCODE (10) /* Error code */
|
||||
#define REG_IRQNO (9) /* Interrupt number (NOTE 2) */
|
||||
#define REG_ERRCODE (10) /* Error code (NOTE 2) */
|
||||
#define REG_EIP (11) /* Pushed by process on interrupt processing */
|
||||
#define REG_CS (12) /* " " "" " " "" " " " " */
|
||||
#define REG_EFLAGS (13) /* " " "" " " "" " " " " */
|
||||
#define REG_SP (14) /* " " "" " " "" " " " " */
|
||||
#define REG_SS (15) /* " " "" " " "" " " " " */
|
||||
|
||||
/* NOTE 1: Two versions of the ESP are saved: One from the interrupt
|
||||
* processing and one from pusha. Only the interrupt ESP (REG_SP) is used.
|
||||
* NOTE 2: This is not really state data. Rather, this is just a convenient
|
||||
* way to pass parameters from the interrupt handler to C cod.
|
||||
*/
|
||||
|
||||
#define XCPTCONTEXT_REGS (16)
|
||||
#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS)
|
||||
|
||||
|
@ -100,7 +100,7 @@ SYMBOL(gdt_flush):
|
||||
|
||||
SYMBOL(idt_flush):
|
||||
mov eax, [esp+4] /* Get the pointer to the IDT, passed as a parameter */
|
||||
lidt [eax] /* Load the IDT pointer */
|
||||
lidt [eax] /* Load the IDT pointer */
|
||||
ret
|
||||
|
||||
#else /* !CONFIG_X86_NASM (GAS) */
|
||||
@ -141,7 +141,7 @@ SYMBOL(gdt_flush):
|
||||
mov %fs, %ax
|
||||
mov %gs, %ax
|
||||
mov %ss, %ax
|
||||
ljmp *.Lgflush /* 0x08 is the offset to our code segment: Far jump! */
|
||||
jmp $0x08, $.Lgflush /* 0x08 is the offset to our code segment: Far jump! */
|
||||
.Lgflush:
|
||||
ret
|
||||
#ifndef __CYGWIN__
|
||||
|
@ -97,35 +97,55 @@
|
||||
.type SYMBOL(up_fullcontextrestore), @function
|
||||
#endif
|
||||
SYMBOL(up_fullcontextrestore):
|
||||
movl 4(%esp), %ecx /* Register save area in %ecx. */
|
||||
/* Fetch the pointer to the register save array in EAX. */
|
||||
|
||||
/* Disable interrupts now (the will be conditionally re-enabled below) */
|
||||
movl 4(%esp), %eax
|
||||
|
||||
/* Disable interrupts now (the correct EFLAGS will be restored before we
|
||||
* return
|
||||
*/
|
||||
|
||||
cli
|
||||
|
||||
/* Save the return address. */
|
||||
/* We now have everything we need from the old stack. Now get the new
|
||||
* stack pointer.
|
||||
*/
|
||||
|
||||
movl (REG_EIP)(%ecx), %edx
|
||||
movl (REG_SP)(%eax), %esp
|
||||
|
||||
/* Restore registers. */
|
||||
/* Save the return address, EFLAGS, and the values as well the
|
||||
* values of EBX and EAC on the new stack.
|
||||
*/
|
||||
|
||||
movl (REG_EBX)(%ecx), %ebx
|
||||
movl (REG_ESI)(%ecx), %esi
|
||||
movl (REG_EDI)(%ecx), %edi
|
||||
movl (REG_EBP)(%ecx), %ebp
|
||||
movl (REG_SP)(%ecx), %esp
|
||||
movl (REG_EIP)(%eax), %ebx
|
||||
push %ebx
|
||||
movl (REG_EFLAGS)(%eax), %ebx
|
||||
push %ebx
|
||||
movl (REG_EAX)(%eax), %ebx
|
||||
push %ebx
|
||||
movl (REG_EBX)(%eax), %ebx
|
||||
push %ebx
|
||||
|
||||
/* Conditionally restore interrupts */
|
||||
/* Now restore the remaining registers */
|
||||
|
||||
testl $512, (REG_EFLAGS)(%ecx)
|
||||
je .Ldisabled
|
||||
sti
|
||||
.Ldisabled:
|
||||
movl (REG_EDI)(%ebx), %edi
|
||||
movl (REG_ESI)(%ebx), %esi
|
||||
movl (REG_EBP)(%ebx), %ebp
|
||||
movl (REG_EDX)(%ebx), %edx
|
||||
movl (REG_ECX)(%ebx), %ecx
|
||||
|
||||
/* Jump to saved PC with non-zero return value in %eax. */
|
||||
/* Restore the segment registers */
|
||||
|
||||
movl $1, %eax
|
||||
jmp *%edx
|
||||
mov (REG_DS)(%ebx), %ds
|
||||
mov (REG_CS)(%ebx), %cs
|
||||
mov (REG_SS)(%ebx), %ss
|
||||
|
||||
/* Restore the correct value of EAX, EBX, and the EFLAGS then return */
|
||||
|
||||
popl %ebx
|
||||
popl %eax
|
||||
popf
|
||||
ret
|
||||
#ifndef __CYGWIN__
|
||||
.size SYMBOL(up_fullcontextrestore), . - SYMBOL(up_fullcontextrestore)
|
||||
#endif
|
||||
|
@ -225,7 +225,7 @@ hang:
|
||||
.type SYMBOL(g_heapbase), @object
|
||||
#endif
|
||||
SYMBOL(g_heapbase):
|
||||
.word _ebss
|
||||
.long _ebss
|
||||
#ifndef __CYGWIN__
|
||||
.size SYMBOL(g_heapbase), . - SYMBOL(g_heapbase)
|
||||
#endif
|
||||
|
@ -85,6 +85,20 @@
|
||||
* Full C prototype:
|
||||
* int up_saveusercontext(uint32_t *regs);
|
||||
*
|
||||
* Description:
|
||||
* Save the "user" context. It is not necessary to save all of the
|
||||
* registers because it is acceptable for certain registers to be
|
||||
* modified upon return from a subroutine call. On a context switch
|
||||
* back to user mode, it will appear as a return from this function.
|
||||
*
|
||||
* According to the Intel ABI, the EAX, EDX, and ECX are to be free for
|
||||
* use within a procedure or function, and need not be preserved. These
|
||||
* are the so-called caller-saved registers are EAX, ECX, EDX.
|
||||
*
|
||||
* On entry,
|
||||
* sp points to the return address
|
||||
* sp+4 points to register save array
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifdef CONFIG_X86_NASM
|
||||
@ -97,21 +111,34 @@
|
||||
.type SYMBOL(up_saveusercontext), @function
|
||||
#endif
|
||||
SYMBOL(up_saveusercontext):
|
||||
|
||||
/* %ebx, %esi, %edi, and %ebp must be preserved.
|
||||
* save %ebx, $esi, and %edi now... */
|
||||
/* Fetch the pointer to the register save array. %eax is a available
|
||||
* because it must be modified later to provide the return value.
|
||||
*/
|
||||
|
||||
movl 4(%esp), %eax
|
||||
|
||||
/* %ebx, %esi, %edi, and %ebp must be preserved. We can freely used %eax
|
||||
* because it will be the return value from this function.
|
||||
*/
|
||||
|
||||
movl %ebx, (REG_EBX)(%eax)
|
||||
movl %esi, (REG_ESI)(%eax)
|
||||
movl %edi, (REG_EDI)(%eax)
|
||||
|
||||
/* Save the value of SP as will be after we return */
|
||||
/* Save the segment registers */
|
||||
|
||||
mov %ss, (REG_SS)(%eax)
|
||||
mov %cs, (REG_CS)(%eax)
|
||||
mov %ds, (REG_DS)(%eax)
|
||||
|
||||
/* Save the value of SP as will be after we return (don't bother to save
|
||||
* REG_ESP).
|
||||
*/
|
||||
|
||||
leal 4(%esp), %ecx
|
||||
movl %ecx, (REG_SP)(%eax)
|
||||
|
||||
/* Save the return PC */
|
||||
/* Fetch the PC from the stack and save it in the save block */
|
||||
|
||||
movl 0(%esp), %ecx
|
||||
movl %ecx, (REG_EIP)(%eax)
|
||||
@ -120,13 +147,13 @@ SYMBOL(up_saveusercontext):
|
||||
|
||||
movl %ebp, (REG_EBP)(%eax)
|
||||
|
||||
/* Save the interrupt state */
|
||||
/* Get and save the interrupt state */
|
||||
|
||||
pushf
|
||||
pop %ecx
|
||||
movl %ecx, (REG_EFLAGS)(%eax)
|
||||
|
||||
/* And return 0 */
|
||||
/* And return 0. 'ret' will remove the EIP from the top of the stack. */
|
||||
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
|
@ -200,18 +200,14 @@ isr_common:
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
/* The current value of the SP points to the beginning of the state save
|
||||
* structure. Save that on the stack as the input parameter to isr_handler.
|
||||
*/
|
||||
|
||||
mov esp, eax
|
||||
push eax
|
||||
call SYMBOL(isr_handler)
|
||||
|
||||
pop ebx /* Reload the original data segment descriptor */
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov fs, bx
|
||||
mov gs, bx
|
||||
|
||||
popa /* Pops edi,esi,ebp... */
|
||||
add esp, 8 /* Cleans up the pushed error code and pushed ISR number */
|
||||
sti
|
||||
iret /* Pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP */
|
||||
jmp .Lreturn
|
||||
|
||||
/****************************************************************************
|
||||
* Name: irq_common
|
||||
@ -236,8 +232,38 @@ irq_common:
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
/* The current value of the SP points to the beginning of the state save
|
||||
* structure. Save that on the stack as the input parameter to irq_handler.
|
||||
*/
|
||||
|
||||
mov esp, eax
|
||||
push eax
|
||||
call SYMBOL(irq_handler)
|
||||
|
||||
/* The common return point for both isr_handler and irq_handler */
|
||||
|
||||
.Lreturn:
|
||||
add 4, esp
|
||||
|
||||
/* EAX may possibly hold a pointer to a different regiser save area on
|
||||
* return. Are we switching to a new context?
|
||||
*/
|
||||
|
||||
cmp eax, esp
|
||||
je .Lnoswitch
|
||||
|
||||
/* A context swith will be performed. EAX holds the address of the new
|
||||
* register save structure.
|
||||
*
|
||||
* 'Jump' to up_fullcontextrestore(). We perform a call here, but that function
|
||||
* never returns. The address of the new register save block is the argument
|
||||
* to the up_fullcontextrestore().
|
||||
*/
|
||||
|
||||
push eax
|
||||
jmp SYMBOL(up_fullcontext)
|
||||
|
||||
.Lnoswitch:
|
||||
pop ebx /* Reload the original data segment descriptor */
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
@ -395,21 +421,17 @@ isr_common:
|
||||
mov %fs, %ax
|
||||
mov %gs, %ax
|
||||
|
||||
/* The current value of the SP points to the beginning of the state save
|
||||
* structure. Save that on the stack as the input parameter to isr_handler.
|
||||
*/
|
||||
|
||||
mov %esp, %eax
|
||||
push %eax
|
||||
call SYMBOL(isr_handler)
|
||||
|
||||
pop %ebx /* Reload the original data segment descriptor */
|
||||
mov %ds, %bx
|
||||
mov %es, %bx
|
||||
mov %fs, %bx
|
||||
mov %gs, %bx
|
||||
|
||||
popa /* Pops edi,esi,ebp... */
|
||||
add %esp, 8 /* Cleans up the pushed error code and pushed ISR number */
|
||||
sti
|
||||
jmp .Lreturn
|
||||
#ifndef __CYGWIN__
|
||||
.size isr_common, . - isr_common
|
||||
#endif
|
||||
iret /* Pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: irq_common
|
||||
@ -437,8 +459,38 @@ irq_common:
|
||||
mov %fs, %ax
|
||||
mov %gs, %ax
|
||||
|
||||
/* The current value of the SP points to the beginning of the state save
|
||||
* structure. Save that on the stack as the input parameter to irq_handler.
|
||||
*/
|
||||
|
||||
mov %esp, %eax
|
||||
push %eax
|
||||
call SYMBOL(irq_handler)
|
||||
|
||||
/* The common return point for both isr_handler and irq_handler */
|
||||
|
||||
.Lreturn:
|
||||
add $4, %esp
|
||||
|
||||
/* EAX may possibly hold a pointer to a different regiser save area on
|
||||
* return. Are we switching to a new context?
|
||||
*/
|
||||
|
||||
cmp %eax, %esp
|
||||
je .Lnoswitch
|
||||
|
||||
/* A context swith will be performed. EAX holds the address of the new
|
||||
* register save structure.
|
||||
*
|
||||
* Jump to up_fullcontextrestore(). We perform a call here, but that function
|
||||
* never returns. The address of the new register save block is the argument
|
||||
* to the up_fullcontextrestore().
|
||||
*/
|
||||
|
||||
push %eax
|
||||
call SYMBOL(up_fullcontextrestore)
|
||||
|
||||
.Lnoswitch:
|
||||
pop %ebx /* Reload the original data segment descriptor */
|
||||
mov %ds, %bx
|
||||
mov %es, %bx
|
||||
|
Loading…
Reference in New Issue
Block a user