Page 1 of 2
Question about libx86emu
Posted: Sun Feb 26, 2017 11:20 am
by Agola
Sorry for that silly question.
Hi, I was making an emulator to use BIOS functions in long / protected mode. After all of my attempts fail (code was unstable and really very very messy) I decided to use libx86emu or x86emu.
The sad part is I can't find any download links for it. All links I've found from the Google are broken.
Then I found libx86emu from opensuse repo and
https://github.com/wfeldt/libx86emu, but it compiles as a shared library. My OS doesn't support dynamically linked libraries, and I don't know how to patch makefile to build it as a static library, simply an .a archive. Then I found x86emu from archive.org, part of Exclaim project, by Adam Smith. But it looks really old and some part of code is missing.
Where can I found the x86emu / x86emu or how can I patch libx86emu Makefile to build as a static library?
Makefile:
Code: Select all
ARCH := $(shell uname -m)
ifneq ($(filter i386 i486 i586 i686, $(ARCH)),)
ARCH := i386
endif
GIT2LOG := $(shell if [ -x ./git2log ] ; then echo ./git2log --update ; else echo true ; fi)
GITDEPS := $(shell [ -d .git ] && echo .git/HEAD .git/refs/heads .git/refs/tags)
VERSION := $(shell $(GIT2LOG) --version VERSION ; cat VERSION)
BRANCH := $(shell [ -d .git ] && git branch | perl -ne 'print $$_ if s/^\*\s*//')
PREFIX := libx86emu-$(VERSION)
MAJOR_VERSION := $(shell $(GIT2LOG) --version VERSION ; cut -d . -f 1 VERSION)
CC = gcc
CFLAGS = -g -O2 -fPIC -fomit-frame-pointer -Wall
ifneq ($(filter x86_64, $(ARCH)),)
LIBDIR = /usr/lib64
else
LIBDIR = /usr/lib
endif
LIBX86 = libx86emu
CFILES = $(wildcard *.c)
OBJS = $(CFILES:.c=.o)
LIB_NAME = $(LIBX86).so.$(VERSION)
LIB_SONAME = $(LIBX86).so.$(MAJOR_VERSION)
.PHONY: all shared install test clean
%.o: %.c
$(CC) -c $(CFLAGS) $<
all: changelog shared
changelog: $(GITDEPS)
$(GIT2LOG) --changelog changelog
shared: $(LIB_NAME)
install: shared
install -D $(LIB_NAME) $(DESTDIR)$(LIBDIR)/$(LIB_NAME)
ln -snf $(LIB_NAME) $(DESTDIR)$(LIBDIR)/$(LIB_SONAME)
ln -snf $(LIB_SONAME) $(DESTDIR)$(LIBDIR)/$(LIBX86).so
install -m 644 -D include/x86emu.h $(DESTDIR)/usr/include/x86emu.h
$(LIB_NAME): .depend $(OBJS)
$(CC) -shared -Wl,-soname,$(LIB_SONAME) $(OBJS) -o $(LIB_NAME)
test:
make -C test
archive: changelog
@if [ ! -d .git ] ; then echo no git repo ; false ; fi
mkdir -p package
git archive --prefix=$(PREFIX)/ $(BRANCH) > package/$(PREFIX).tar
tar -r -f package/$(PREFIX).tar --mode=0664 --owner=root --group=root --mtime="`git show -s --format=%ci`" --transform='s:^:$(PREFIX)/:' VERSION changelog
xz -f package/$(PREFIX).tar
clean:
make -C test clean
rm -f *.o *~ include/*~ *.so.* .depend
rm -rf package
ifneq "$(MAKECMDGOALS)" "clean"
.depend: $(CFILES)
@$(CC) -MG -MM $(CFLAGS) $(CFILES) >$@
-include .depend
endif
Thanks in advance.
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 11:31 am
by Ch4ozz
No need to compile this at all beforehand, just copy all the code into your os tree and include the headers and link it with the rest of the os.
Anyways, if you still want to build this externally use -static.
It will tell the linker to link it as static library (.a) instead of a shared one (.so)
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 12:56 pm
by Agola
Thanks, I fixed by compiling until the part of dynamic library creation, then created the static library manually with i686-agola-ar rcs ...
Except, a new problem. I couldn't find a way to redirect virtual port / memory io to real port / memory io. BIOS code works in VM and returns with a success code, but it doesn't affect the real system.
How can I redirect the port and mem io to real mem and ports?
The nearest thing for it:
Code: Select all
x86emu_memio_handler_t x86emu_set_memio_handler(x86emu_t *emu, x86emu_memio_handler_t handler);
typedef unsigned (* x86emu_memio_handler_t)(x86emu_t *emu, u32 addr, u32 *val, unsigned type);
Thanks in advance.
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 2:17 pm
by onlyonemac
x86emu is an x86 emulator. It's designed to simulate an x86 system, like a virtual machine. It's not intended for executing BIOS functions on your real CPU.
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 2:25 pm
by Agola
Yes, x86emu is an emulator. And I want to use it to execute BIOS' code. I simply copy the lowest 1 MB of memory to virtual machine's memory, then make cs:ip point to 0:7C00 where I simply put the opcode of execute int 0x10. It should work, isn't it?
This is how I done it:
Code: Select all
x86emu_t *emu = x86emu_new(X86EMU_PERM_RWX, X86EMU_PERM_RWX);
x86emu_set_log(emu, 0xFFFFFF, flush_log);
vm_write_nbytes(emu, 4, 4, 0x100000 - 4, X86EMU_PERM_RWX | X86EMU_PERM_VALID);
x86emu_set_perm(emu, 4, 0xFFFFFF, X86EMU_PERM_RWX | X86EMU_PERM_VALID);
x86emu_set_io_perm(emu, 4, 0xFFFFFF, X86EMU_PERM_RWX | X86EMU_PERM_VALID);
x86emu_set_seg_register(emu, emu->x86.R_CS_SEL, 0);
emu->x86.R_EIP = 0x7c00;
vm_write_byte(emu, 0x7c00, 0xfb, X86EMU_PERM_RWX | X86EMU_PERM_VALID); //sti
vm_write_word(emu, 0x7c01, 0x10cd, X86EMU_PERM_RWX | X86EMU_PERM_VALID); //int 0x10
vm_write_byte(emu, 0x7c03, 0xf4, X86EMU_PERM_RWX | X86EMU_PERM_VALID); //hlt
emu->x86.R_AX = 0x4F02;
emu->x86.R_BX = 0x4117;
x86emu_run(emu, X86EMU_RUN_LOOP);
printf("ax: 0x%X", emu->x86.R_AX);
Output is ax: 0x4F, so it really does the mode switching in its virtual memory and port io. Then I want to redirect it to real memory and ports to make it "really" happened.
It should be possible, as there are many people used that way.
Thanks in advance.
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 4:16 pm
by Ch4ozz
Well, it will only emulate everything you put in, it will never switch the resolution for example using VESA functions, I doubt you will be able to redirect everything perfectly though.
What your looking for is either Virtual 8086 Mode (
http://wiki.osdev.org/Virtual_8086_Mode) which I wouldnt use or a switch to realmode and back to protected mode like this:
http://www.rohitab.com/discuss/topic/35 ... cted-mode/
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 4:55 pm
by Octocontrabass
I'm not sure why everyone keeps saying you can't use x86emu to change the screen resolution. That's exactly what X.Org Server does with its copy of x86emu.
...Unfortunately, I couldn't figure out how it sets up the I/O callbacks to allow the emulated code to communicate with hardware. All I could find was the code to emulate things the video card ROM might try to access that it shouldn't be able to, like the PIT and the PCI configuration registers.
Re: I can't find libx86emu or x86emu
Posted: Sun Feb 26, 2017 7:22 pm
by dchapiesky
Octocontrabass wrote:I'm not sure why everyone keeps saying you can't use x86emu to change the screen resolution. That's exactly what X.Org Server does with its copy of x86emu.
...Unfortunately, I couldn't figure out how it sets up the I/O callbacks to allow the emulated code to communicate with hardware. All I could find was the code to emulate things the video card ROM might try to access that it shouldn't be able to, like the PIT and the PCI configuration registers.
https://github.com/XQuartz/xorg-server/ ... NT10.HOWTO
and the whole int10 directory....
particularly MapCurrentInt10() in helper_exec.c....
which links to (in linux)
https://github.com/XQuartz/xorg-server/ ... 10/linux.c
which shows how realmode memory of the emulator is mapped via mmap to the proper addresses of the physical hardware....
I would use the stub code in
https://github.com/XQuartz/xorg-server/ ... pport/stub
cheers
Re: I can't find libx86emu or x86emu
Posted: Mon Feb 27, 2017 9:16 am
by Agola
I found x86emu from X.org, copyrighted to SciTech Software.
And it worked!
After memory and port io hooks, it has successfully set the mode. I also tried other BIOS interrupts, all worked.
I think that is the best way for BIOS interrupts, it works both on protected and long mode, fast and portable.
That is code:
Code: Select all
portfuncs.outb = (void*) outb;
portfuncs.outw = (void*) outw;
portfuncs.outl = (void*) outl;
portfuncs.inb = (void*) inb;
portfuncs.inw = (void*) inw;
portfuncs.inl = (void*) inl;
memfuncs.rdb = (void*) mem_read_byte;
memfuncs.rdw = (void*) mem_read_word;
memfuncs.rdl = (void*) mem_read_long;
memfuncs.wrb = (void*) mem_write_byte;
memfuncs.wrw = (void*) mem_write_word;
memfuncs.wrl = (void*) mem_write_long;
memset(&M, 0, sizeof(M));
X86EMU_setupMemFuncs(&memfuncs);
X86EMU_setupPioFuncs(&portfuncs);
M.x86.gen.A.I16_reg.x_reg = 0x4F02;
M.x86.gen.B.I16_reg.x_reg = 0x4107;
X86EMU_prepareForInt(0x10);
X86EMU_exec();
And that is the screenshot
But, it is really old. Modern version of x86emu is libx86emu, used by openSUSE and hwinfo. And I want to use it instead of x86emu.
And, it is hard to set up its memory and port io hook.
https://github.com/wfeldt/libx86emu#x86 ... _handler_t is way to do it, and I've almost finished it.
X86EMU_MEMIO_R is read from memory,
X86EMU_MEMIO_W is write to memory,
X86EMU_MEMIO_I is read from port,
X86EMU_MEMIO_O is write to port.
But what is X86EMU_MEMIO_X? Everything works except that.
I couldn't understand what is X86EMU_MEMIO_X for, and it gets called many times, so I need to implement it, too.
Thanks in advance.
Re: I can't find libx86emu or x86emu
Posted: Mon Feb 27, 2017 10:04 am
by Korona
A quick search in the GitHub repository reveals that X86EMU_MEMIO_X is an instruction fetch, that means it has the same semantics as X86EMU_MEMIO_R. (But be aware that I did not actually try that library)
Note that the BIOS was never meant to be used alongside a real OS and I'm sure that things will break spectacularly if you're not very careful. For example I would ensure that only a single instance of this emulator runs at a time and that no ports and MMIO regions that the emulator accesses are read/written by real drivers at the same time. You probably also have to be careful not to change PCI configuration space concurrently and ensure that all expansion ROM mappings are in the same state as they where when BIOS ran.
Re: I can't find libx86emu or x86emu
Posted: Mon Feb 27, 2017 11:05 am
by Agola
Korona wrote:A quick search in the GitHub repository reveals that X86EMU_MEMIO_X is an instruction fetch, that means it has the same semantics as X86EMU_MEMIO_R. (But be aware that I did not actually try that library)
Note that the BIOS was never meant to be used alongside a real OS and I'm sure that things will break spectacularly if you're not very careful. For example I would ensure that only a single instance of this emulator runs at a time and that no ports and MMIO regions that the emulator accesses are read/written by real drivers at the same time. You probably also have to be careful not to change PCI configuration space concurrently and ensure that all expansion ROM mappings are in the same state as they where when BIOS ran.
Thanks, I changed X86EMU_MEMIO_X to same as X86EMU_MEMIO_R, but it is not working.
Maybe I'm mishandling inputs / outputs, as libx86emu has a different, paged memory system in mem.c that I don't fully understand.
How can I handle the input / outputs with
x86emu_set_memio_handler?
And is it the correct way to handle IO and redirect IO to real machine?
Thanks in advance.
Re: I can't find libx86emu or x86emu
Posted: Mon Feb 27, 2017 11:43 am
by dchapiesky
Agola wrote:
How can I handle the input / outputs with x86emu_set_memio_handler?
And is it the correct way to handle IO and redirect IO to real machine?
The handler you pass to
x86emu_set_memio_handler takes an argument called "type"
you do a switch/case statement against the following possible values:
Code: Select all
X86EMU_MEMIO_8 + X86EMU_MEMIO_R
X86EMU_MEMIO_16 + X86EMU_MEMIO_R
X86EMU_MEMIO_32 + X86EMU_MEMIO_R
X86EMU_MEMIO_8_NOPERM + X86EMU_MEMIO_R
X86EMU_MEMIO_8 + X86EMU_MEMIO_W
X86EMU_MEMIO_16 + X86EMU_MEMIO_W
X86EMU_MEMIO_32 + X86EMU_MEMIO_W
X86EMU_MEMIO_8_NOPERM + X86EMU_MEMIO_W
X86EMU_MEMIO_8 + X86EMU_MEMIO_X
X86EMU_MEMIO_16 + X86EMU_MEMIO_X
X86EMU_MEMIO_32 + X86EMU_MEMIO_X
X86EMU_MEMIO_8_NOPERM + X86EMU_MEMIO_X
X86EMU_MEMIO_8 + X86EMU_MEMIO_I
X86EMU_MEMIO_16 + X86EMU_MEMIO_I
X86EMU_MEMIO_32 + X86EMU_MEMIO_I
X86EMU_MEMIO_8_NOPERM + X86EMU_MEMIO_I
X86EMU_MEMIO_8 + X86EMU_MEMIO_O
X86EMU_MEMIO_16 + X86EMU_MEMIO_O
X86EMU_MEMIO_32 + X86EMU_MEMIO_O
X86EMU_MEMIO_8_NOPERM + X86EMU_MEMIO_O
if you look at decode.c you see that it uses X86EMU_MEMIO_* to determine how to cast a particular address.... I would definitely turn on logging so decode.c shows you what is happening...
Re: I can't find libx86emu or x86emu
Posted: Mon Feb 27, 2017 1:35 pm
by Agola
Yay!
Finally, it works with new version, libx86emu also.
All interrupts I tried worked, but not important for me as I will just use some int 0x10 functions
That is the code:
Code: Select all
unsigned alternate_vm_memio(x86emu_t *emu, uint32_t addr, uint32_t *val, uint32_t type)
{
x86emu_mem_t *mem = emu->mem;
uint32_t bits = type & 0xFF;
type &= ~0xFF;
mem->invalid = 0;
switch(type)
{
case X86EMU_MEMIO_R:
switch(bits)
{
case X86EMU_MEMIO_8:
*val = mem_read_byte(addr);
break;
case X86EMU_MEMIO_16:
*val = mem_read_word(addr);
break;
case X86EMU_MEMIO_32:
*val = mem_read_long(addr);
break;
case X86EMU_MEMIO_8_NOPERM:
*val = mem_read_byte(addr);
break;
}
break;
case X86EMU_MEMIO_W:
switch(bits)
{
case X86EMU_MEMIO_8:
mem_write_byte(addr, *val);
break;
case X86EMU_MEMIO_16:
mem_write_word(addr, *val);
break;
case X86EMU_MEMIO_32:
mem_write_long(addr, *val);
break;
case X86EMU_MEMIO_8_NOPERM:
mem_write_byte(addr, *val);
break;
}
break;
case X86EMU_MEMIO_X:
switch(bits)
{
case X86EMU_MEMIO_8:
*val = mem_read_byte(addr);
break;
case X86EMU_MEMIO_16:
*val = mem_read_word(addr);
break;
case X86EMU_MEMIO_32:
*val = mem_read_long(addr);
break;
}
break;
case X86EMU_MEMIO_I:
switch(bits)
{
case X86EMU_MEMIO_8:
*val = inb(addr);
break;
case X86EMU_MEMIO_16:
*val = inw(addr);
break;
case X86EMU_MEMIO_32:
*val = inl(addr);
break;
}
break;
case X86EMU_MEMIO_O:
switch(bits)
{
case X86EMU_MEMIO_8:
outb(addr, *val);
break;
case X86EMU_MEMIO_16:
outw(addr, *val);
break;
case X86EMU_MEMIO_32:
outl(addr, *val);
break;
}
break;
}
return 0;
}
Code: Select all
x86emu_t* emu = x86emu_new(X86EMU_PERM_RWX, X86EMU_PERM_RWX);
x86emu_set_memio_handler(emu, (x86emu_memio_handler_t*) alternate_vm_memio);
x86emu_set_seg_register(emu, emu->x86.R_CS_SEL, 0);
emu->x86.R_IP = 0x7C00;
mem_write_word(0x7C00, 0x10CD);
mem_write_byte(0x7C02, 0xF4);
emu->x86.R_AX = 0x4F02;
emu->x86.R_BX = 0x117;
x86emu_run(emu, X86EMU_RUN_LOOP);
dprintf(3, "AX: %x\n", emu->x86.R_AX);
Thanks, everything is great now!
Re: Question about libx86emu
Posted: Fri Mar 03, 2017 1:01 pm
by Agola
Yes, I was marked thread as 'Solved', but I had a new question and I didn't want to open a new thread for it.
Does libx86emu has PIC emulation? If not, as I remapped PICs, interrupts uses PICs will be confused.
I couldn't find anything about PIC in source.
Can I reset the PIC before the interrupt, and restore its state after interrupt? But then it's going to be a hacky code, and it is going to look like "Napalm's Protected Mode BIOS Functionality" which I didn't want to use before because that also resets PICs.
Thanks in advance.
Re: Question about libx86emu
Posted: Fri Mar 03, 2017 3:37 pm
by Korona
As far as I understand the library only emulates the instruction set. You have to handle (e.g. save/restore or emulate) the PIC yourself using the I/O handler.