2008-08-29 00:52:19 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-07-20 20:55:45 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301, USA.
|
2008-08-29 00:52:19 +02:00
|
|
|
*/
|
|
|
|
|
2009-05-01 16:41:06 +02:00
|
|
|
FILE_LICENCE ( GPL2_OR_LATER )
|
|
|
|
|
2008-08-29 00:52:19 +02:00
|
|
|
.text
|
|
|
|
.arch i386
|
|
|
|
.code32
|
|
|
|
|
[comboot] Run com32 programs with a valid IDT
COM32 binaries generally expect to run with interrupts
enabled. Syslinux does so, and COM32 programs will execute cli/sti
pairs when running a critical section, to provide mutual exclusion
against BIOS interrupt handlers. Previously, under iPXE, the IDT was
not valid, so any interrupt (e.g. a timer tick) would generally cause
the machine to triple fault.
This change introduces code to:
- Create a valid IDT at the same location that syslinux uses
- Create an "interrupt jump buffer", which contains small pieces of
code that simply record the vector number and jump to a common
handler
- Thunk down to real mode and execute the BIOS's interrupt handler
whenever an interrupt is received in a COM32 program
- Switch IDTs and enable/disable interrupts when context switching to
and from COM32 binaries
Testing done:
- Booted VMware ESX using a COM32 multiboot loader (mboot.c32)
- Built with GDBSERIAL enabled, and tested breakpoints on int22 and
com32_irq
- Put the following code in a COM32 program:
asm volatile ( "sti" );
while ( 1 );
Before this change, the machine would triple fault
immediately. After this change, it hangs as expected. Under Bochs,
it is possible to see the interrupt handler run, and the current
time in the BIOS data area gets incremented.
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-07-08 00:35:01 +02:00
|
|
|
/*
|
|
|
|
* This code is entered after running the following sequence out of
|
|
|
|
* the interrupt jump buffer:
|
|
|
|
*
|
|
|
|
* pushal
|
|
|
|
* movb $vector, %al
|
|
|
|
* jmp com32_irq_wrapper
|
|
|
|
*/
|
|
|
|
|
|
|
|
.globl com32_irq_wrapper
|
|
|
|
com32_irq_wrapper:
|
|
|
|
|
|
|
|
movzbl %al,%eax
|
|
|
|
pushl %eax
|
|
|
|
movl $com32_irq, %eax
|
|
|
|
call com32_wrapper
|
|
|
|
popl %eax
|
|
|
|
popal
|
|
|
|
iret
|
|
|
|
|
2008-08-29 00:52:19 +02:00
|
|
|
.globl com32_farcall_wrapper
|
|
|
|
com32_farcall_wrapper:
|
|
|
|
|
|
|
|
movl $com32_farcall, %eax
|
|
|
|
jmp com32_wrapper
|
|
|
|
|
|
|
|
|
|
|
|
.globl com32_cfarcall_wrapper
|
|
|
|
com32_cfarcall_wrapper:
|
|
|
|
|
|
|
|
movl $com32_cfarcall, %eax
|
|
|
|
jmp com32_wrapper
|
|
|
|
|
|
|
|
|
|
|
|
.globl com32_intcall_wrapper
|
|
|
|
com32_intcall_wrapper:
|
|
|
|
|
|
|
|
movl $com32_intcall, %eax
|
|
|
|
/*jmp com32_wrapper*/ /* fall through */
|
|
|
|
|
|
|
|
com32_wrapper:
|
[comboot] Run com32 programs with a valid IDT
COM32 binaries generally expect to run with interrupts
enabled. Syslinux does so, and COM32 programs will execute cli/sti
pairs when running a critical section, to provide mutual exclusion
against BIOS interrupt handlers. Previously, under iPXE, the IDT was
not valid, so any interrupt (e.g. a timer tick) would generally cause
the machine to triple fault.
This change introduces code to:
- Create a valid IDT at the same location that syslinux uses
- Create an "interrupt jump buffer", which contains small pieces of
code that simply record the vector number and jump to a common
handler
- Thunk down to real mode and execute the BIOS's interrupt handler
whenever an interrupt is received in a COM32 program
- Switch IDTs and enable/disable interrupts when context switching to
and from COM32 binaries
Testing done:
- Booted VMware ESX using a COM32 multiboot loader (mboot.c32)
- Built with GDBSERIAL enabled, and tested breakpoints on int22 and
com32_irq
- Put the following code in a COM32 program:
asm volatile ( "sti" );
while ( 1 );
Before this change, the machine would triple fault
immediately. After this change, it hangs as expected. Under Bochs,
it is possible to see the interrupt handler run, and the current
time in the BIOS data area gets incremented.
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-07-08 00:35:01 +02:00
|
|
|
cli
|
2008-08-29 00:52:19 +02:00
|
|
|
|
|
|
|
/* Switch to internal virtual address space */
|
|
|
|
call _phys_to_virt
|
|
|
|
|
[comboot] Run com32 programs with a valid IDT
COM32 binaries generally expect to run with interrupts
enabled. Syslinux does so, and COM32 programs will execute cli/sti
pairs when running a critical section, to provide mutual exclusion
against BIOS interrupt handlers. Previously, under iPXE, the IDT was
not valid, so any interrupt (e.g. a timer tick) would generally cause
the machine to triple fault.
This change introduces code to:
- Create a valid IDT at the same location that syslinux uses
- Create an "interrupt jump buffer", which contains small pieces of
code that simply record the vector number and jump to a common
handler
- Thunk down to real mode and execute the BIOS's interrupt handler
whenever an interrupt is received in a COM32 program
- Switch IDTs and enable/disable interrupts when context switching to
and from COM32 binaries
Testing done:
- Booted VMware ESX using a COM32 multiboot loader (mboot.c32)
- Built with GDBSERIAL enabled, and tested breakpoints on int22 and
com32_irq
- Put the following code in a COM32 program:
asm volatile ( "sti" );
while ( 1 );
Before this change, the machine would triple fault
immediately. After this change, it hangs as expected. Under Bochs,
it is possible to see the interrupt handler run, and the current
time in the BIOS data area gets incremented.
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-07-08 00:35:01 +02:00
|
|
|
/* Switch to internal IDT (if we have one for debugging) */
|
|
|
|
lidt com32_internal_idtr
|
|
|
|
|
2008-08-29 00:52:19 +02:00
|
|
|
mov %eax, (com32_helper_function)
|
|
|
|
|
|
|
|
/* Save external COM32 stack pointer */
|
|
|
|
movl %esp, (com32_external_esp)
|
|
|
|
|
|
|
|
/* Copy arguments to caller-save registers */
|
|
|
|
movl 12(%esp), %eax
|
|
|
|
movl 8(%esp), %ecx
|
|
|
|
movl 4(%esp), %edx
|
|
|
|
|
|
|
|
/* Switch to internal stack */
|
|
|
|
movl (com32_internal_esp), %esp
|
|
|
|
|
|
|
|
/* Copy arguments to internal stack */
|
|
|
|
pushl %eax
|
|
|
|
pushl %ecx
|
|
|
|
pushl %edx
|
|
|
|
|
|
|
|
call *(com32_helper_function)
|
|
|
|
|
|
|
|
/* Clean up stack */
|
|
|
|
addl $12, %esp
|
|
|
|
|
|
|
|
/* Save internal stack pointer and restore external stack pointer */
|
|
|
|
movl %esp, (com32_internal_esp)
|
|
|
|
movl (com32_external_esp), %esp
|
|
|
|
|
[comboot] Run com32 programs with a valid IDT
COM32 binaries generally expect to run with interrupts
enabled. Syslinux does so, and COM32 programs will execute cli/sti
pairs when running a critical section, to provide mutual exclusion
against BIOS interrupt handlers. Previously, under iPXE, the IDT was
not valid, so any interrupt (e.g. a timer tick) would generally cause
the machine to triple fault.
This change introduces code to:
- Create a valid IDT at the same location that syslinux uses
- Create an "interrupt jump buffer", which contains small pieces of
code that simply record the vector number and jump to a common
handler
- Thunk down to real mode and execute the BIOS's interrupt handler
whenever an interrupt is received in a COM32 program
- Switch IDTs and enable/disable interrupts when context switching to
and from COM32 binaries
Testing done:
- Booted VMware ESX using a COM32 multiboot loader (mboot.c32)
- Built with GDBSERIAL enabled, and tested breakpoints on int22 and
com32_irq
- Put the following code in a COM32 program:
asm volatile ( "sti" );
while ( 1 );
Before this change, the machine would triple fault
immediately. After this change, it hangs as expected. Under Bochs,
it is possible to see the interrupt handler run, and the current
time in the BIOS data area gets incremented.
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-07-08 00:35:01 +02:00
|
|
|
/* Switch to com32 IDT */
|
|
|
|
lidt com32_external_idtr
|
|
|
|
|
2008-08-29 00:52:19 +02:00
|
|
|
/* Switch to external flat physical address space */
|
|
|
|
call _virt_to_phys
|
|
|
|
|
[comboot] Run com32 programs with a valid IDT
COM32 binaries generally expect to run with interrupts
enabled. Syslinux does so, and COM32 programs will execute cli/sti
pairs when running a critical section, to provide mutual exclusion
against BIOS interrupt handlers. Previously, under iPXE, the IDT was
not valid, so any interrupt (e.g. a timer tick) would generally cause
the machine to triple fault.
This change introduces code to:
- Create a valid IDT at the same location that syslinux uses
- Create an "interrupt jump buffer", which contains small pieces of
code that simply record the vector number and jump to a common
handler
- Thunk down to real mode and execute the BIOS's interrupt handler
whenever an interrupt is received in a COM32 program
- Switch IDTs and enable/disable interrupts when context switching to
and from COM32 binaries
Testing done:
- Booted VMware ESX using a COM32 multiboot loader (mboot.c32)
- Built with GDBSERIAL enabled, and tested breakpoints on int22 and
com32_irq
- Put the following code in a COM32 program:
asm volatile ( "sti" );
while ( 1 );
Before this change, the machine would triple fault
immediately. After this change, it hangs as expected. Under Bochs,
it is possible to see the interrupt handler run, and the current
time in the BIOS data area gets incremented.
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-07-08 00:35:01 +02:00
|
|
|
sti
|
2008-08-29 00:52:19 +02:00
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
.data
|
|
|
|
|
2010-04-19 21:16:01 +02:00
|
|
|
/* Internal iPXE virtual address space %esp */
|
2008-08-29 00:52:19 +02:00
|
|
|
.globl com32_internal_esp
|
|
|
|
.lcomm com32_internal_esp, 4
|
|
|
|
|
|
|
|
/* External flat physical address space %esp */
|
|
|
|
.globl com32_external_esp
|
|
|
|
.lcomm com32_external_esp, 4
|
|
|
|
|
|
|
|
/* Function pointer of helper to call */
|
|
|
|
.lcomm com32_helper_function, 4
|