+// Misc utility functions.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // call16
+#include "bregs.h" // struct bregs
+#include "config.h" // BUILD_STACK_ADDR
+
+void
+cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ // Check for cpu id
+ u32 origflags = save_flags();
+ restore_flags(origflags ^ F_ID);
+ u32 newflags = save_flags();
+ restore_flags(origflags);
+
+ if (((origflags ^ newflags) & F_ID) != F_ID)
+ // no cpuid
+ *eax = *ebx = *ecx = *edx = 0;
+ else
+ __cpuid(index, eax, ebx, ecx, edx);
+}
+
+
+/****************************************************************
+ * 16bit calls
+ ****************************************************************/
+
+// 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)
+{
+ if (!MODESEGMENT && getesp() > BUILD_STACK_ADDR)
+ panic("call16 with invalid stack\n");
+ asm volatile(
+#if MODE16 == 1
+ "calll __call16\n"
+ "cli\n"
+ "cld"
+#else
+ "calll __call16_from32"
+#endif
+ : "+a" (callregs), "+m" (*callregs)
+ :
+ : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+call16big(struct bregs *callregs)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16 with invalid stack\n");
+ asm volatile(
+ "calll __call16big_from32"
+ : "+a" (callregs), "+m" (*callregs)
+ :
+ : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+__call16_int(struct bregs *callregs, u16 offset)
+{
+ if (MODESEGMENT)
+ callregs->code.seg = GET_SEG(CS);
+ else
+ callregs->code.seg = SEG_BIOS;
+ callregs->code.offset = offset;
+ call16(callregs);
+}
+
+
+/****************************************************************
+ * String ops
+ ****************************************************************/