Chameleon

Chameleon Commit Details

Date:2016-05-22 18:42:14 (4 years 4 days ago)
Author:zenith432
Commit:2824
Parents: 2823
Message:Add memcpy_interruptible() for smooth countdown()
Changes:
M/branches/zenith432/i386/boot2/gui.c
M/branches/zenith432/i386/libsaio/cpu.c
M/branches/zenith432/i386/libsaio/fake_efi.c
M/trunk/i386/boot2/gui.c
M/trunk/i386/libsaio/cpu.c
M/trunk/i386/libsaio/fake_efi.c
M/branches/zenith432/i386/libsaio/biosfn.c
M/trunk/i386/libsaio/biosfn.c

File differences

trunk/i386/libsaio/cpu.c
251251
252252
253253
254
254
255255
256256
257257
......
272272
273273
274274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
275359
276360
277361
}
// 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
}
/*
* 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.),
trunk/i386/libsaio/biosfn.c
10781078
10791079
10801080
1081
10811082
10821083
bb.intno = 0x15;
bb.eax.rr = 0x2401;
bios(&bb);
// return !bb.flags.cf;
}
*/
trunk/i386/libsaio/fake_efi.c
759759
760760
761761
762
763
762
763
764764
765765
766766
767
767768
769
768770
769771
770772
*/
if (PMRepeatCount)
{
--PMRepeatCount;
continue;// jb0x17e55(retry)
--PMRepeatCount;
continue;// jb0x17e55(retry)
}
}
else
{
PMRepeatCount = 0xffff;
}
cpuTick = (EFI_UINT32) getCPUTick();// callq0x121a7
//printf("value: 0x%x\n", getCPUTick());
trunk/i386/boot2/gui.c
13081308
13091309
13101310
1311
13111312
13121313
1313
1314
13141315
13151316
13161317
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
{
branches/zenith432/i386/libsaio/cpu.c
251251
252252
253253
254
254
255255
256256
257257
......
272272
273273
274274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
275359
276360
277361
}
// 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
}
/*
* 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.),
branches/zenith432/i386/libsaio/biosfn.c
10781078
10791079
10801080
1081
10811082
10821083
bb.intno = 0x15;
bb.eax.rr = 0x2401;
bios(&bb);
// return !bb.flags.cf;
}
*/
branches/zenith432/i386/libsaio/fake_efi.c
759759
760760
761761
762
763
762
763
764764
765765
766766
767
767768
769
768770
769771
770772
*/
if (PMRepeatCount)
{
--PMRepeatCount;
continue;// jb0x17e55(retry)
--PMRepeatCount;
continue;// jb0x17e55(retry)
}
}
else
{
PMRepeatCount = 0xffff;
}
cpuTick = (EFI_UINT32) getCPUTick();// callq0x121a7
//printf("value: 0x%x\n", getCPUTick());
branches/zenith432/i386/boot2/gui.c
13081308
13091309
13101310
1311
13111312
13121313
1313
1314
13141315
13151316
13161317
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
{

Archive Download the corresponding diff file

Revision: 2824