Index: branches/ErmaC/Enoch/i386/libsaio/cpu.c =================================================================== --- branches/ErmaC/Enoch/i386/libsaio/cpu.c (revision 2824) +++ branches/ErmaC/Enoch/i386/libsaio/cpu.c (revision 2825) @@ -251,7 +251,7 @@ } // Bronya C1E fix -void post_startup_cpu_fixups(void) +static void post_startup_cpu_fixups(void) { /* * Some AMD processors support C1E state. Entering this state will @@ -272,6 +272,90 @@ } /* + * Large memcpy() into MMIO space can take longer than 1 clock tick (55ms). + * The timer interrupt must remain responsive when updating VRAM so + * as not to miss timer interrupts during countdown(). + * + * If interrupts are enabled, use normal memcpy. + * + * If interrupts are disabled, breaks memcpy down + * into 128K chunks, times itself and makes a bios + * real-mode call every 25 msec in order to service + * pending interrupts. + * + * -- zenith432, May 22nd, 2016 + */ +void* memcpy_interruptible(void* dst, const void* src, size_t len) +{ + uint64_t tscFreq, lastTsc; + uint32_t eflags, threshold; + ptrdiff_t offset; + const size_t chunk = 131072U; // 128K + + if (len <= chunk) + { + /* + * Short memcpy - use normal. + */ + return memcpy(dst, src, len); + } + + __asm__ volatile("pushfl; popl %0" : "=r"(eflags)); + if (eflags & 0x200U) + { + /* + * Interrupts are enabled - use normal memcpy. + */ + return memcpy(dst, src, len); + } + + tscFreq = Platform.CPU.TSCFrequency; + if ((uint32_t) (tscFreq >> 32)) + { + /* + * If TSC Frequency >= 2 ** 32, use a default time threshold. + */ + threshold = (~0U) / 40U; + } + else if (!(uint32_t) tscFreq) + { + /* + * If early on and TSC Frequency hasn't been estimated yet, + * use normal memcpy. + */ + return memcpy(dst, src, len); + } + else + { + threshold = ((uint32_t) tscFreq) / 40U; + } + + /* + * Do the work + */ + offset = 0; + lastTsc = rdtsc64(); + do + { + (void) memcpy((char*) dst + offset, (const char*) src + offset, chunk); + offset += (ptrdiff_t) chunk; + len -= chunk; + if ((rdtsc64() - lastTsc) < threshold) + { + continue; + } + (void) readKeyboardStatus(); // visit real-mode + lastTsc = rdtsc64(); + } + while (len > chunk); + if (len) + { + (void) memcpy((char*) dst + offset, (const char*) src + offset, len); + } + return dst; +} + +/* * Calculates the FSB and CPU frequencies using specific MSRs for each CPU * - multi. is read from a specific MSR. In the case of Intel, there is: * a max multi. (used to calculate the FSB freq.), @@ -529,6 +613,9 @@ p->CPU.NoThreads = (uint32_t)bitfield((uint32_t)msr, 15, 0); break; case CPUID_MODEL_ATOM_3700: + p->CPU.NoCores = 4; + p->CPU.NoThreads = 4; + break; case CPUID_MODEL_ATOM: p->CPU.NoCores = 2; p->CPU.NoThreads = 2; Index: branches/ErmaC/Enoch/i386/libsaio/biosfn.c =================================================================== --- branches/ErmaC/Enoch/i386/libsaio/biosfn.c (revision 2824) +++ branches/ErmaC/Enoch/i386/libsaio/biosfn.c (revision 2825) @@ -1078,5 +1078,6 @@ bb.intno = 0x15; bb.eax.rr = 0x2401; bios(&bb); +// return !bb.flags.cf; } */ Index: branches/ErmaC/Enoch/i386/boot2/drivers.c =================================================================== --- branches/ErmaC/Enoch/i386/boot2/drivers.c (revision 2824) +++ branches/ErmaC/Enoch/i386/boot2/drivers.c (revision 2825) @@ -256,7 +256,7 @@ { verbose("Attempting to loading drivers from standard repositories:\n"); - if ( (gMacOSVersion[3] == '9') || ((gMacOSVersion[3] == '1') && ((gMacOSVersion[4] == '0') || gMacOSVersion[4] == '1' ) )) // issue 352 + if ( (gMacOSVersion[3] == '9') || ((gMacOSVersion[3] == '1') && ((gMacOSVersion[4] == '0') || (gMacOSVersion[4] == '1') || (gMacOSVersion[4] == '2') ) )) // issue 352 { verbose("\t- Third party extensions search path: /Library/Extensions\n"); strlcpy(gExtensionsSpec, dirSpec, 4087); /* 4096 - sizeof("Library/") mean 4096 - 9 = 4087 */ Index: branches/ErmaC/Enoch/i386/boot2/boot.c =================================================================== --- branches/ErmaC/Enoch/i386/boot2/boot.c (revision 2824) +++ branches/ErmaC/Enoch/i386/boot2/boot.c (revision 2825) @@ -863,12 +863,13 @@ // bootFile must start with a / if it not start with a device name if (!bootFileWithDevice && (bootInfo->bootFile)[0] != '/') { - if ( MacOSVerCurrent < MacOSVer2Int("10.10") ) // Micky1979 - Is prior to Yosemite 10.10 + if ( MacOSVerCurrent < MacOSVer2Int("10.10") ) // Mavericks and older { snprintf(bootFile, sizeof(bootFile), "/%s", bootInfo->bootFile); // append a leading / } else { + // Yosemite and newer snprintf(bootFile, sizeof(bootFile), kDefaultKernelPathForYos"%s", bootInfo->bootFile); // Yosemite or El Capitan } } Index: branches/ErmaC/Enoch/i386/boot2/gui.c =================================================================== --- branches/ErmaC/Enoch/i386/boot2/gui.c (revision 2824) +++ branches/ErmaC/Enoch/i386/boot2/gui.c (revision 2825) @@ -1341,9 +1341,10 @@ static inline void vramwrite (void *data, int width, int height) { + extern void* memcpy_interruptible(void*, const void*, size_t); if (VIDEO (depth) == 32 && VIDEO (rowBytes) == gui.backbuffer->width * 4) { - memcpy((uint8_t *)vram, gui.backbuffer->pixels, VIDEO (rowBytes)*VIDEO (height)); + memcpy_interruptible((uint8_t *)vram, gui.backbuffer->pixels, VIDEO (rowBytes)*VIDEO (height)); } else { Index: branches/ErmaC/Enoch/i386/libsa/prf.c =================================================================== --- branches/ErmaC/Enoch/i386/libsa/prf.c (revision 2824) +++ branches/ErmaC/Enoch/i386/libsa/prf.c (revision 2825) @@ -38,11 +38,12 @@ * @(#)prf.c 7.1 (Berkeley) 6/5/86 */ -#include +#include #define SPACE 1 #define ZERO 2 -#define UCASE 16 +#define UCASE 16 +#define SIGNED 32 /* * Scaled down version of C Library printf. @@ -52,57 +53,144 @@ * */ +#define DIVIDEND_LOW *(unsigned int*) dividend +#define DIVIDEND_HIGH ((unsigned int*) dividend)[1] + /* + * Divides 64-bit dividend by 32-bit divisor. + * Quotient stored in dividend, remainder returned. + * Assumes little-endian byte order. + * Assumes divisor is non-zero. + */ +unsigned int i386_unsigned_div( + unsigned long long* dividend, + unsigned int divisor + ) +{ + unsigned int high = DIVIDEND_HIGH; + + if (high >= divisor) + { + __asm__ volatile ("xorl %%edx, %%edx; divl %2" : "=a"(DIVIDEND_HIGH), "=d"(high) : "r"(divisor), "a"(high)); + } + else + { + DIVIDEND_HIGH = 0; + } + __asm__ volatile("divl %2" : "+a"(DIVIDEND_LOW), "+d"(high) : "r"(divisor)); + return high; +} + +#undef DIVIDEND_HIGH +#undef DIVIDEND_LOW + +/* * Printn prints a number n in base b. * We don't use recursion to avoid deep kernel stacks. */ -static void printn(n, b, flag, minwidth, putfn_p, putfn_arg) - u_long n; - int b, flag, minwidth; - void (*putfn_p)(); - void *putfn_arg; +static int printn( + unsigned long long n, + int b, + int flag, + int minwidth, + int (*putfn_p)(), + void* putfn_arg + ) { - char prbuf[11]; + char prbuf[22]; register char *cp; int width = 0, neg = 0; + static const char hexdig[] = "0123456789abcdef0123456789ABCDEF"; - if (b == 10 && (int)n < 0) { + if ((flag & SIGNED) && (long long)n < 0) + { neg = 1; - n = (unsigned)(-(int)n); + n = (unsigned long long)(-(long long)n); } cp = prbuf; - do { - *cp++ = "0123456789abcdef0123456789ABCDEF"[(flag & UCASE) + n%b]; - n /= b; + if ((b & -b) == b) // b is a power of 2 + { + unsigned int log2b = (unsigned int) (__builtin_ctz((unsigned int) b) & 31); + unsigned int mask = (unsigned int) (b - 1); + do + { + *cp++ = hexdig[(flag & UCASE) + (int) (n & mask)]; + n >>= log2b; + width++; + } + while (n); + } + else // b is not a power of 2 + { + do + { + *cp++ = hexdig[(flag & UCASE) + (int) i386_unsigned_div(&n, (unsigned int) b)]; + width++; + } + while (n); + } + + if (neg) + { + if (putfn_p) + { + (void)(*putfn_p)('-', putfn_arg); + } width++; - } while (n); - - if (neg) { - (*putfn_p)('-', putfn_arg); - width++; } - while (width++ < minwidth) - (*putfn_p)( (flag & ZERO) ? '0' : ' ', putfn_arg); - + if (!putfn_p) + { + return (width < minwidth) ? minwidth : width; + } + for (;width < minwidth; width++) + (void)(*putfn_p)( (flag & ZERO) ? '0' : ' ', putfn_arg); + do - (*putfn_p)(*--cp, putfn_arg); + (void)(*putfn_p)(*--cp, putfn_arg); while (cp > prbuf); + return width; } +/* + * Printp prints a pointer. + */ +static int printp( + const void* p, + int minwidth, + int (*putfn_p)(), + void* putfn_arg + ) +{ + int width = 0; + + if (p) + { + if (putfn_p) + { + (void)(*putfn_p)('0', putfn_arg); + (void)(*putfn_p)('x', putfn_arg); + } + width = 2; + minwidth = ((minwidth >= 2) ? (minwidth - 2) : 0); + } + return width + printn((unsigned long long) p, 16, ZERO, minwidth, putfn_p, putfn_arg); +} + int prf( - char *fmt, - unsigned int *adx, - void (*putfn_p)(), + const char *fmt, + va_list ap, + int (*putfn_p)(), void *putfn_arg -) + ) { - int b, c, len =0; - char *s; - int flag = 0, width = 0; + int b, c, len = 0; + const char *s; + int flag, width, ells; int minwidth; loop: - while ((c = *fmt++) != '%') { + while ((c = *fmt++) != '%') + { if(c == '\0') { return len; @@ -110,15 +198,22 @@ if (putfn_p) { - (*putfn_p)(c, putfn_arg); + (void)(*putfn_p)(c, putfn_arg); } len++; } minwidth = 0; + flag = 0; + ells = 0; again: c = *fmt++; - switch (c) { + switch (c) + { case 'l': + if (ells < 2) + { + ++ells; + } goto again; case ' ': flag |= SPACE; @@ -149,46 +244,82 @@ b = 16; goto number; case 'd': + case 'i': + flag |= SIGNED; + /* fall through */ + case 'u': b = 10; goto number; case 'o': case 'O': b = 8; number: - if (putfn_p) + switch (ells) { - printn((u_long)*adx, b, flag, minwidth, putfn_p, putfn_arg); + case 2: + len += printn(va_arg(ap, unsigned long long), b, flag, minwidth, putfn_p, putfn_arg); + break; + case 1: + len += printn(va_arg(ap, unsigned long), b, flag, minwidth, putfn_p, putfn_arg); + break; + default: + len += printn(va_arg(ap, unsigned int), b, flag, minwidth, putfn_p, putfn_arg); + break; } - len++; break; case 's': - s = (char *)*adx; - while ((c = *s++)) { - if (putfn_p) + s = va_arg(ap, const char*); + if (!s) + { + s = "(null)"; + } + width = 0; + if (!putfn_p) + { + while ((c = *s++)) { - (*putfn_p)(c, putfn_arg); + width++; } + len += ((width < minwidth) ? minwidth : width); + break; + } + while ((c = *s++)) + { + (void)(*putfn_p)(c, putfn_arg); len++; width++; } while (width++ < minwidth) { - if (putfn_p) - { - (*putfn_p)(' ', putfn_arg); - } + (void)(*putfn_p)(' ', putfn_arg); len++; } break; case 'c': if (putfn_p) { - (*putfn_p)((char)*adx, putfn_arg); + (void)(*putfn_p)((char) va_arg(ap, int), putfn_arg); } len++; break; + case '%': + if (putfn_p) + { + (void)(*putfn_p)('%', putfn_arg); + } + len++; + break; + case 'p': + len += printp(va_arg(ap, const void*), minwidth, putfn_p, putfn_arg); + break; + case 'n': + s = va_arg(ap, const char*); + if (s) + { + *(int*) s = len; + } + break; default: break; } - adx++; goto loop; } Index: branches/ErmaC/Enoch/i386/libsa/strtol.c =================================================================== --- branches/ErmaC/Enoch/i386/libsa/strtol.c (revision 2824) +++ branches/ErmaC/Enoch/i386/libsa/strtol.c (revision 2825) @@ -324,8 +324,9 @@ register const char *s = nptr; register unsigned long long acc; register int c; - register unsigned long long qbase, cutoff; + /* register */ unsigned long long qbase, cutoff; register int neg, any, cutlim; + extern unsigned int i386_unsigned_div(unsigned long long*, unsigned int); /* * See strtoq for comments as to the logic used. @@ -365,8 +366,8 @@ } qbase = (unsigned)base; - cutoff = (unsigned long long)UQUAD_MAX / qbase; - cutlim = (unsigned long long)UQUAD_MAX % qbase; + cutoff = (unsigned long long)UQUAD_MAX; + cutlim = (int) i386_unsigned_div(&cutoff, (unsigned int) base); for (acc = 0, any = 0;; c = *s++) {