// Misc utility functions. // // Copyright (C) 2008 Kevin O'Connor // // This file may be distributed under the terms of the GNU LGPLv3 license. #include "util.h" // usleep #include "bregs.h" // struct bregs #include "config.h" // SEG_BIOS #include "farptr.h" // GET_FLATPTR #include "biosvar.h" // get_ebda_seg // Call a function with a specified register state. Note that on // return, the interrupt enable/disable flag may be altered. inline void call16(struct bregs *callregs) { asm volatile( #if MODE16 == 1 "calll __call16\n" #else "calll __call16_from32\n" #endif : "+a" (callregs), "+m" (*callregs) : : "ebx", "ecx", "edx", "esi", "edi", "ebp", "cc", "memory"); } inline void call16big(struct bregs *callregs) { extern void __force_link_error__call16big_only_in_32bit_mode(); if (MODE16) __force_link_error__call16big_only_in_32bit_mode(); asm volatile( "calll __call16big_from32\n" : "+a" (callregs), "+m" (*callregs) : : "ebx", "ecx", "edx", "esi", "edi", "ebp", "cc", "memory"); } inline void __call16_int(struct bregs *callregs, u16 offset) { callregs->cs = SEG_BIOS; callregs->ip = offset; call16(callregs); } inline void call16_simpint(int nr, u32 *eax, u32 *flags) { extern void __force_link_error__call16_simpint_only_in_16bit_mode(); if (!MODE16) __force_link_error__call16_simpint_only_in_16bit_mode(); asm volatile( "stc\n" "int %2\n" "pushfl\n" "popl %1\n" "cld\n" "cli\n" : "+a"(*eax), "=r"(*flags) : "i"(nr) : "cc", "memory"); } // Switch to the extra stack in ebda and call a function. inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func) { extern void __force_link_error__stack_hop_only_in_16bit_mode(); if (!MODE16) __force_link_error__stack_hop_only_in_16bit_mode(); u16 ebda_seg = get_ebda_seg(), bkup_ss; u32 bkup_esp; asm volatile( // Backup current %ss/%esp values. "movw %%ss, %w3\n" "movl %%esp, %4\n" // Copy ebda seg to %ds/%ss and set %esp "movw %w6, %%ds\n" "movw %w6, %%ss\n" "movl %5, %%esp\n" // Call func "calll %7\n" // Restore segments and stack "movw %w3, %%ds\n" "movw %w3, %%ss\n" "movl %4, %%esp\n" : "+a" (eax), "+d" (edx), "+c" (ecx), "=&r" (bkup_ss), "=&r" (bkup_esp) : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg), "m" (*(u8*)func) : "cc", "memory"); return eax; } // Sum the bytes in the specified area. u8 checksum_far(u16 buf_seg, u8 *buf_far, u32 len) { SET_SEG(ES, buf_seg); u32 i; u8 sum = 0; for (i=0; i= d) return memcpy(d, s, len); d += len-1; s += len-1; while (len--) { *(char*)d = *(char*)s; d--; s--; } return d; }