Petr Stehlik dixit:

>Thorsten Glaser píše v Ne 13. 01. 2013 v 21:37 +0000:
>> >Could you show me the source code of nfimvirt, please? Seems like it
>>
>> I attached it.
>
>Thanks

Actually, the attached version is v2, which doesn’t endlessly
loop in the SIGILL handler on “real hardware” any more… but I
guess it’s obsolete anyway, if the spec is “incorrect” ☹

bye,
//mirabilos
-- 
I want one of these. They cost 720 € though… good they don’t have the HD hole,
which indicates 3½″ floppies with double capacity… still. A tad too much, atm.
‣ http://www.floppytable.com/floppytable-images-1.html
#include <sys/types.h>
#include <sys/mman.h>
#include <err.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <ucontext.h>
#include <unistd.h>

#ifndef __GNUC__
#error This file makes use of GNU C extensions.
#endif

extern long nf_get_id_asm(const char *feature_name)
        asm("nf_get_id_asm")
        __attribute__((__cdecl__, __regparm__(0)));
extern long nf_call_asm(unsigned long feature_id, ...)
        asm("nf_call_asm")
        __attribute__((__cdecl__, __regparm__(0)));

volatile sig_atomic_t got_sigill;

void sigill_handler(int sigraised, siginfo_t *info, void *context);
long nf_get_id(const char *feature_name);

#define nf_call2(id, subid, ...) __extension__({                        \
        long nf_call2_res;                                              \
        unsigned long nf_call2_fid;                                     \
                                                                        \
        if (got_sigill)                                                 \
                errx(2, "nf_call2: previous unhandled SIGILL");         \
        nf_call2_fid = (unsigned long)(id) | (unsigned long)(subid);    \
        nf_call2_res = nf_call_asm(nf_call2_fid, ## __VA_ARGS__);       \
        if (got_sigill)                                                 \
                errx(2, "nf_call2: SIGILL for %08lX", nf_call2_fid);    \
        (nf_call2_res);                                                 \
})

#ifdef __KLIBC__
void err(int, const char *, ...)
        __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
void errx(int, const char *, ...)
        __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
#endif

int
main(void)
{
        long NF_NAME, NF_VERSION, sres;
        char *buf;
        unsigned long bufsz = 0, ures;
        int pgsz;
        struct sigaction sact;

        if ((pgsz = getpagesize()) <= 0 || pgsz > 0x10000000)
                err(2, "getpagesize() returned %d", pgsz);
        while (bufsz < 4096)
                bufsz += pgsz;
        if ((buf = mmap(NULL, (size_t)bufsz, PROT_READ | PROT_WRITE,
            MAP_ANON | MAP_PRIVATE, 0, (off_t)0)) == MAP_FAILED)
                err(2, "mmap() %lu bytes failed", bufsz);
        if (mlock(buf, bufsz))
                err(2, "mlock() failed");

        sigemptyset(&sact.sa_mask);
        sact.sa_flags = SA_SIGINFO;
        sact.sa_sigaction = sigill_handler;
        got_sigill = 0;
        if (sigaction(SIGILL, &sact, NULL))
                err(2, "cannot install SIGILL handler");

        if ((NF_NAME = nf_get_id("NF_NAME")) == -1L) {
                printf("Physical (no NatFeat)\n");
                return (0);
        }
        if ((NF_VERSION = nf_get_id("NF_VERSION")) == -1L) {
                printf("Ambiguous (broken NatFeat)\n");
                return (1);
        }

        sres = nf_call2(NF_VERSION, 0);
        ures = nf_call2(NF_NAME, 0, buf, bufsz);
        buf[bufsz - 1] = 0;
        printf("NatFeat v%d.%d (Emulator%s: %s)", (int)((sres >> 16) & 0xFFFF),
            (int)(sres & 0xFFFF), ures >= bufsz ? " (truncated)" : "", buf);
        ures = nf_call2(NF_NAME, 1, buf, bufsz);
        buf[bufsz - 1] = 0;
        printf(" on%s: %s\n", ures >= bufsz ? " (truncated)" : "", buf);

        /* munlock, munmap, signal */

        return (0);
}

long
nf_get_id(const char *feature_name)
{
        long res;

        if (got_sigill)
                errx(2, "nf_get_id: previous unhandled SIGILL");
        res = nf_get_id_asm(feature_name);
        if (got_sigill) {
                got_sigill = 0;
                return (-1L);
        }
        return (res & 0xFFF00000);
}

void
sigill_handler(int sigraised __attribute__((__unused__)),
    siginfo_t *info __attribute__((__unused__)), void *context)
{
        ucontext_t *ctx = context;
        unsigned char *cp;

        cp = (void *)(ctx->uc_mcontext.gregs[R_PC]);

        /*
         * 0x4AFC is a regular undefined opcode (for testing);
         * 0x7300 and 0x7301 are our NatFeat call opcodes
         */
        if (cp[0] == 0x73 && (cp[1] == 0x00 || cp[1] == 0x01)) {
                ctx->uc_mcontext.gregs[R_PC] += 2;
        } else {
                /* SIGILL from something else */
                /* bail out (longjmp) to error handler is right to do */
                write(2, "E: SIGILL from something else\n", 30);
                _exit(2);
        }

        got_sigill = 1;
}

Reply via email to