// Misc utility functions. // // Copyright (C) 2008,2009 Kevin O'Connor // // 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 ****************************************************************/ // Sum the bytes in the specified area. u8 checksum_far(u16 buf_seg, void *buf_far, u32 len) { SET_SEG(ES, buf_seg); u32 i; u8 sum = 0; for (i=0; i 3) { u32 copylen = len; if (copylen > 2048) copylen = 2048; copylen /= 4; len -= copylen * 4; asm volatile( "rep movsl (%%esi),%%es:(%%edi)" : "+c"(copylen), "+S"(s), "+D"(d) : : "cc", "memory"); yield(); } if (len) // Copy any remaining bytes. memcpy(d, s, len); } void * memmove(void *d, const void *s, size_t len) { if (s >= d) return memcpy(d, s, len); d += len-1; s += len-1; while (len--) { *(char*)d = *(char*)s; d--; s--; } return d; } // Copy a string - truncating it if necessary. char * strtcpy(char *dest, const char *src, size_t len) { char *d = dest; while (--len && *src != '\0') *d++ = *src++; *d = '\0'; return dest; } // locate first occurance of character c in the string s char * strchr(const char *s, int c) { for (; *s; s++) if (*s == c) return (char*)s; return NULL; } // Remove any trailing blank characters (spaces, new lines, carriage returns) void nullTrailingSpace(char *buf) { int len = strlen(buf); char *end = &buf[len-1]; while (end >= buf && *end <= ' ') *(end--) = '\0'; } /**************************************************************** * Keyboard calls ****************************************************************/ // See if a keystroke is pending in the keyboard buffer. static int check_for_keystroke(void) { struct bregs br; memset(&br, 0, sizeof(br)); br.flags = F_IF; br.ah = 1; call16_int(0x16, &br); return !(br.flags & F_ZF); } // Return a keystroke - waiting forever if necessary. static int get_raw_keystroke(void) { struct bregs br; memset(&br, 0, sizeof(br)); br.flags = F_IF; call16_int(0x16, &br); return br.ah; } // Read a keystroke - waiting up to 'msec' milliseconds. int get_keystroke(int msec) { u32 end = calc_future_timer(msec); for (;;) { if (check_for_keystroke()) return get_raw_keystroke(); if (check_timer(end)) return -1; wait_irq(); } }