ntloader/callback.S
A1ive 4512426e9a
V3 (#9)
* import wimboot v28

* remove -Wno-array-bounds

* addd

* reg

* cmline

* charset

* update bcd.bat

* reg prefix

* fix

* bcd

* rootfs

* fsuuid

* vdisk

* partmap

* biosdisk

* efidisk

* efi

* fix

* fix

* fix reg

* fix bcd

* bcd

* initrd

* payload
2025-02-10 22:26:20 +09:00

234 lines
5.2 KiB
ArmAsm

/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 (at your option) 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Real-mode callbacks
*
*/
#include "ntloader.h"
/* Offsets within parameter block */
#define PARAM_VECTOR 0x00
#define PARAM_EAX 0x04
#define PARAM_EBX 0x08
#define PARAM_ECX 0x0c
#define PARAM_EDX 0x10
#define PARAM_ESI 0x1c
#define PARAM_EDI 0x20
#define PARAM_DS 0x28
#define PARAM_ES 0x30
#define PARAM_FS 0x34
#define PARAM_GS 0x38
#define PARAM_EFLAGS 0x3c
#define PARAM_LEN 0x40
/** Protected-mode bit in CR0 */
#define CR0_PE 0x00000001
/** Paging bit in CR0 */
#define CR0_PG 0x80000000
.section ".note.GNU-stack", "", @progbits
#if defined(__i386__) || defined(__x86_64__)
.code32
.arch i386
/* Call an arbitrary real-mode function */
.section ".text", "ax", @progbits
.globl call_real
call_real:
/* Preserve registers */
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
/* Switch to real-mode stack, store original stack pointer,
* copy parameter block to stack, store original parameter block
* address.
*/
movl 20(%esp), %esi
movl %esp, %ebp
movl $_ermstack, %esp
pushl %ebp
subl $PARAM_LEN, %esp
movl %esp, %edi
movl $( PARAM_LEN / 4 ), %ecx
cld
rep movsl
movl %esp, %ebp /* %ebp points to parameter block copy */
subl $PARAM_LEN, %esi
pushl %esi
/* Set up 16-bit segment registers and stack */
ljmp $REAL_CS, $( 1f - BASE_ADDRESS )
1: .code16
movw $REAL_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
subl $BASE_ADDRESS, %esp
subl $BASE_ADDRESS, %ebp
/* Switch to real mode */
movl %cr0, %eax
pushl %eax
andl $~( CR0_PG | CR0_PE ), %eax
movl %eax, %cr0
data32 ljmp $BASE_SEG, $( 1f - BASE_ADDRESS )
1: movw $BASE_SEG, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
addr32 data32 lidt %cs:( rm_idtr - BASE_ADDRESS )
/* Load registers from parameter block copy */
movl PARAM_EAX(%bp), %eax
movl PARAM_EBX(%bp), %ebx
movl PARAM_ECX(%bp), %ecx
movl PARAM_EDX(%bp), %edx
movl PARAM_ESI(%bp), %esi
movl PARAM_EDI(%bp), %edi
movw PARAM_DS(%bp), %ds
movw PARAM_ES(%bp), %es
movw PARAM_FS(%bp), %fs
movw PARAM_GS(%bp), %gs
/* Call real-mode function with interrupts enabled */
pushw %bp
sti
lcall *PARAM_VECTOR(%bp)
cli
popw %bp
/* Save registers and flags to parameter block copy */
pushfl
popl PARAM_EFLAGS(%bp)
movl %eax, PARAM_EAX(%bp)
movl %ebx, PARAM_EBX(%bp)
movl %ecx, PARAM_ECX(%bp)
movl %edx, PARAM_EDX(%bp)
movl %esi, PARAM_ESI(%bp)
movl %edi, PARAM_EDI(%bp)
movw %ds, PARAM_DS(%bp)
movw %es, PARAM_ES(%bp)
movw %fs, PARAM_FS(%bp)
movw %gs, PARAM_GS(%bp)
/* Switch back to protected mode */
addr32 data32 lgdt %cs:( gdtr - BASE_ADDRESS )
addr32 data32 lidt %cs:( idtr - BASE_ADDRESS )
popl %eax
movl %eax, %cr0
data32 ljmp $FLAT_CS, $1f
1: .code32
movw $FLAT_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
addl $BASE_ADDRESS, %esp
/* Copy modified parameter block back to original location and
* return to original stack
*/
popl %edi
movl %esp, %esi
movl $( PARAM_LEN / 4 ), %ecx
cld
rep movsl
movl 0(%esi), %esp
/* Restore registers and return */
popl %edi
popl %esi
popl %ebx
popl %ebp
ret
.size call_real, . - call_real
/* Call an arbitrary real-mode interrupt */
.section ".text", "ax", @progbits
.globl call_interrupt
call_interrupt:
/* Enter function */
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
/* Extract INT number from parameter block and update INT instruction */
movl 8(%ebp), %esi /* %esi points to parameter block */
movl PARAM_VECTOR(%esi), %ebx
movb %bl, ( dynamic_int + 1 )
/* Overwrite vector with dynamic INT code fragment */
movw $BASE_SEG, (PARAM_VECTOR + 2)(%esi)
movl $( dynamic_int - BASE_ADDRESS ), %eax
movw %ax, PARAM_VECTOR(%esi)
/* Call dynamic INT code fragment */
pushl %esi
call call_real
popl %esi
/* Restore INT number in parameter block */
movl %ebx, PARAM_VECTOR(%esi)
/* Restore registers and return */
popl %esi
popl %ebx
popl %ebp
ret
.size call_interrupt, . - call_interrupt
/* Dynamic interrupt code fragment */
.section ".text16", "ax", @progbits
dynamic_int:
int $0x00
lret
.size dynamic_int, . - dynamic_int
/* Real-mode interrupt descriptor table */
.section ".data16", "ax", @progbits
rm_idtr:
.word ( ( 256 * 4 ) - 1 ) /* Limit (256 segment:offset pairs) */
.long 0 /* Base */
.size rm_idtr, . - rm_idtr
/* Real-mode stack */
.section ".stack16", "aw", @nobits
.balign 8
_rmstack:
.space 8192
.size _rmstack, . - _rmstack
_ermstack:
#endif /* defined(__i386__) || defined(__x86_64__) */