📄 lrmi.c
字号:
/*Linux Real Mode Interface - A library of DPMI-like functions for Linux.Copyright (C) 1998 by Josh VanderhoofYou are free to distribute and modify this file, as long as youdo not remove this copyright notice and clearly label modifiedversions as being modified.This software has NO WARRANTY. Use it at your own risk.*/#include <stdio.h>#include <string.h>#include <asm/vm86.h>#ifdef USE_LIBC_VM86#include <sys/vm86.h>#endif#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <unistd.h>#include <fcntl.h>#include "lrmi.h"#define REAL_MEM_BASE ((void *)0x10000)#define REAL_MEM_SIZE 0x10000#define REAL_MEM_BLOCKS 0x100struct mem_block { unsigned int size : 20; unsigned int free : 1; };static struct { int ready; int count; struct mem_block blocks[REAL_MEM_BLOCKS]; } mem_info = { 0 };static intreal_mem_init(void) { void *m; int fd_zero; if (mem_info.ready) return 1; fd_zero = open("/dev/zero", O_RDONLY); if (fd_zero == -1) { perror("open /dev/zero"); return 0; } m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd_zero, 0); if (m == (void *)-1) { perror("mmap /dev/zero"); close(fd_zero); return 0; } mem_info.ready = 1; mem_info.count = 1; mem_info.blocks[0].size = REAL_MEM_SIZE; mem_info.blocks[0].free = 1; return 1; }static voidinsert_block(int i) { memmove( mem_info.blocks + i + 1, mem_info.blocks + i, (mem_info.count - i) * sizeof(struct mem_block)); mem_info.count++; }static voiddelete_block(int i) { mem_info.count--; memmove( mem_info.blocks + i, mem_info.blocks + i + 1, (mem_info.count - i) * sizeof(struct mem_block)); }void *LRMI_alloc_real(int size) { int i; char *r = (char *)REAL_MEM_BASE; if (!mem_info.ready) return NULL; if (mem_info.count == REAL_MEM_BLOCKS) return NULL; size = (size + 15) & ~15; for (i = 0; i < mem_info.count; i++) { if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) { insert_block(i); mem_info.blocks[i].size = size; mem_info.blocks[i].free = 0; mem_info.blocks[i + 1].size -= size; return (void *)r; } r += mem_info.blocks[i].size; } return NULL; }voidLRMI_free_real(void *m) { int i; char *r = (char *)REAL_MEM_BASE; if (!mem_info.ready) return; i = 0; while (m != (void *)r) { r += mem_info.blocks[i].size; i++; if (i == mem_info.count) return; } mem_info.blocks[i].free = 1; if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) { mem_info.blocks[i].size += mem_info.blocks[i + 1].size; delete_block(i + 1); } if (i - 1 >= 0 && mem_info.blocks[i - 1].free) { mem_info.blocks[i - 1].size += mem_info.blocks[i].size; delete_block(i); } }#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)#define DEFAULT_STACK_SIZE 0x1000#define RETURN_TO_32_INT 255static struct { int ready; unsigned short ret_seg, ret_off; unsigned short stack_seg, stack_off; struct vm86_struct vm; } context = { 0 };static inline voidset_bit(unsigned int bit, void *array) { unsigned char *a = array; a[bit / 8] |= (1 << (bit % 8)); }static inline unsigned intget_int_seg(int i) { return *(unsigned short *)(i * 4 + 2); }static inline unsigned intget_int_off(int i) { return *(unsigned short *)(i * 4); }static inline voidpushw(unsigned short i) { struct vm86_regs *r = &context.vm.regs; r->esp -= 2; *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i; }intLRMI_init(void) { void *m; int fd_mem; if (context.ready) return 1; if (!real_mem_init()) return 0; /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502) and the ROM (0xa0000 - 0x100000) */ fd_mem = open("/dev/mem", O_RDWR); if (fd_mem == -1) { perror("open /dev/mem"); return 0; } m = mmap((void *)0, 0x502, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd_mem, 0); if (m == (void *)-1) { perror("mmap /dev/mem"); return 0; } m = mmap((void *)0xa0000, 0x100000 - 0xa0000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000); if (m == (void *)-1) { perror("mmap /dev/mem"); return 0; } /* Allocate a stack */ m = LRMI_alloc_real(DEFAULT_STACK_SIZE); context.stack_seg = (unsigned int)m >> 4; context.stack_off = DEFAULT_STACK_SIZE; /* Allocate the return to 32 bit routine */ m = LRMI_alloc_real(2); context.ret_seg = (unsigned int)m >> 4; context.ret_off = (unsigned int)m & 0xf; ((unsigned char *)m)[0] = 0xcd; /* int opcode */ ((unsigned char *)m)[1] = RETURN_TO_32_INT; memset(&context.vm, 0, sizeof(context.vm)); context.vm.cpu_type =CPU_386; /* Enable kernel emulation of all ints except RETURN_TO_32_INT */ memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored)); set_bit(RETURN_TO_32_INT, &context.vm.int_revectored); context.ready = 1; return 1; }static voidset_regs(struct LRMI_regs *r) { context.vm.regs.edi = r->edi; context.vm.regs.esi = r->esi; context.vm.regs.ebp = r->ebp; context.vm.regs.ebx = r->ebx; context.vm.regs.edx = r->edx; context.vm.regs.ecx = r->ecx; context.vm.regs.eax = r->eax; context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.es = r->es; context.vm.regs.ds = r->ds; context.vm.regs.fs = r->fs; context.vm.regs.gs = r->gs; }static voidget_regs(struct LRMI_regs *r) { r->edi = context.vm.regs.edi; r->esi = context.vm.regs.esi; r->ebp = context.vm.regs.ebp; r->ebx = context.vm.regs.ebx; r->edx = context.vm.regs.edx; r->ecx = context.vm.regs.ecx; r->eax = context.vm.regs.eax; r->flags = context.vm.regs.eflags; r->es = context.vm.regs.es; r->ds = context.vm.regs.ds; r->fs = context.vm.regs.fs; r->gs = context.vm.regs.gs; }#define DIRECTION_FLAG (1 << 10)static voidem_ins(int size) { unsigned int edx, edi; edx = context.vm.regs.edx & 0xffff; edi = context.vm.regs.edi & 0xffff; edi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; insl; cld" : "=D" (edi) : "d" (edx), "0" (edi)); else if (size == 2) asm volatile ("std; insw; cld" : "=D" (edi) : "d" (edx), "0" (edi)); else asm volatile ("std; insb; cld" : "=D" (edi) : "d" (edx), "0" (edi)); } else { if (size == 4) asm volatile ("cld; insl" : "=D" (edi) : "d" (edx), "0" (edi)); else if (size == 2) asm volatile ("cld; insw" : "=D" (edi) : "d" (edx), "0" (edi)); else asm volatile ("cld; insb" : "=D" (edi) : "d" (edx), "0" (edi)); } edi -= (unsigned int)context.vm.regs.ds << 4; context.vm.regs.edi &= 0xffff0000; context.vm.regs.edi |= edi & 0xffff; }static voidem_rep_ins(int size) { unsigned int ecx, edx, edi; ecx = context.vm.regs.ecx & 0xffff; edx = context.vm.regs.edx & 0xffff; edi = context.vm.regs.edi & 0xffff; edi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; rep; insl; cld" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else if (size == 2) asm volatile ("std; rep; insw; cld" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else asm volatile ("std; rep; insb; cld" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); } else { if (size == 4) asm volatile ("cld; rep; insl" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else if (size == 2) asm volatile ("cld; rep; insw" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else asm volatile ("cld; rep; insb" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); } edi -= (unsigned int)context.vm.regs.ds << 4; context.vm.regs.edi &= 0xffff0000; context.vm.regs.edi |= edi & 0xffff; context.vm.regs.ecx &= 0xffff0000; context.vm.regs.ecx |= ecx & 0xffff; }static voidem_outs(int size) { unsigned int edx, esi; edx = context.vm.regs.edx & 0xffff; esi = context.vm.regs.esi & 0xffff; esi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; outsl; cld" : "=S" (esi) : "d" (edx), "0" (esi)); else if (size == 2) asm volatile ("std; outsw; cld" : "=S" (esi) : "d" (edx), "0" (esi)); else asm volatile ("std; outsb; cld" : "=S" (esi) : "d" (edx), "0" (esi));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -