Skip to content

Instantly share code, notes, and snippets.

@Myriachan
Created March 4, 2016 07:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Myriachan/4faecfaf0959ee0dc83c to your computer and use it in GitHub Desktop.
Save Myriachan/4faecfaf0959ee0dc83c to your computer and use it in GitHub Desktop.
ARM code support on Windows RT/IoT detection and example.
// ARM code support on Windows RT/IoT detection and example.
// By Myria, 2016/03/03.
#ifndef _M_ARM_NT
#error "This code is for ARMv7-Thumb2 only."
#endif
#define _WIN32_WINNT 0x0602
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include <process.h>
#pragma warning(suppress:4325)
#pragma section(".text", read, execute)
static DWORD WINAPI DummyThreadProc(void *context)
{
(void) context;
return 0;
}
bool DetectKernelARMSupport(void)
{
HANDLE thread = (HANDLE) CreateThread(NULL, 4096, DummyThreadProc, NULL, CREATE_SUSPENDED, NULL);
if (!thread)
{
fprintf(stderr, "DetectKernelARMSupport: Unable to create helper thread: %d\n", errno);
return false;
}
CONTEXT context;
memset(&context, 0xCC, sizeof(context));
context.ContextFlags = CONTEXT_CONTROL;
if (!GetThreadContext(thread, &context))
{
fprintf(stderr, "DetectKernelARMSupport: GetThreadContext[1] on helper thread failed: %lu\n", GetLastError());
TerminateThread(thread, 0);
CloseHandle(thread);
return false;
}
printf("Before: PC = %08lX, CPSR = %08lX, T = %lu\n", context.Pc, context.Cpsr, (context.Cpsr >> 5) & 1);
// Attempt to put the thread into ARM mode.
context.Pc &= ~(DWORD) 3;
context.Cpsr &= ~(DWORD) (1 << 5);
if (!SetThreadContext(thread, &context))
{
fprintf(stderr, "DetectKernelARMSupport: SetThreadContext on helper thread failed: %lu\n", GetLastError());
TerminateThread(thread, 0);
CloseHandle(thread);
return false;
}
// Check whether we succeeded.
memset(&context, 0xFF, sizeof(context));
context.ContextFlags = CONTEXT_CONTROL;
if (!GetThreadContext(thread, &context))
{
fprintf(stderr, "DetectKernelARMSupport: GetThreadContext[1] on helper thread failed: %lu\n", GetLastError());
TerminateThread(thread, 0);
CloseHandle(thread);
return false;
}
printf("After: PC = %08lX, CPSR = %08lX, T = %lu\n", context.Pc, context.Cpsr, (context.Cpsr >> 5) & 1);
TerminateThread(thread, 0);
CloseHandle(thread);
// If the kernel doesn't support ARM, it will not allow us to clear the T bit via SetThreadContext.
return !(context.Pc & 3) && !(context.Cpsr & (1 << 5));
}
// Test ARM execution for a short time.
__declspec(allocate(".text")) const uint32_t s_countTo5[] =
{
0xE3A00000, // _00: mov r0, #0
0xE2800001, // _04: add r0, r0, #r1
0xE3500005, // _08: cmp r0, #5
0x1AFFFFFC, // _0C: bne _04
0xE12FFF1E, // _10: bx lr
};
// Test ARM code for a long time.
__declspec(allocate(".text")) const uint32_t s_countToFourBillion[] =
{
0xE3A00001, // _00: mov r0, #1
0xE2800001, // _04: add r0, r0, #r1
0xE3500000, // _08: cmp r0, #0
0x1AFFFFFC, // _0C: bne _04
0xE12FFF1E, // _10: bx lr
};
union FunctionPointer
{
unsigned (*m_function)(void);
uintptr_t m_pointer;
};
C_ASSERT(RTL_FIELD_SIZE(union FunctionPointer, m_function) == RTL_FIELD_SIZE(union FunctionPointer, m_pointer));
int main(void)
{
printf("Kernel supports user-mode programs in ARM mode: %s\n", DetectKernelARMSupport() ? "YES" : "NO");
// Call the sample functions.
union FunctionPointer countTo5;
union FunctionPointer countToFourBillion;
// Mask off the low bit because the compiler likes to add 1 if the object is in a code section.
countTo5.m_pointer = ((uintptr_t) s_countTo5) & ~(uintptr_t) 1;
countToFourBillion.m_pointer = ((uintptr_t) s_countToFourBillion) & ~(uintptr_t) 1;
printf("countTo5: %08IX, %08X\n", countTo5.m_pointer, (*countTo5.m_function)());
fflush(stdout);
printf("countToFourBillion: %08IX %08X\n", countToFourBillion.m_pointer, (*countToFourBillion.m_function)());
fflush(stdout);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment