/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Copyright (C) 2012-2013 Ian Preston This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: jpc.sourceforge.net or the developer website sourceforge.net/projects/jpc/ End of licence header */ package tools; import java.io.*; import java.util.*; public class Bochs extends EmulatorControl { public static final String EXE = "/home/ian/jpc/bochs/bochs-2.6.1/bochs"; public static final boolean PRINT = false; private static int lineCount = 0; public static String[] names2 = new String[] { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi","eip", "flags", /*10*/"es", "cs", "ss", "ds", "fs", "gs", "ticks", /*17*/"es-lim", "cs-lim", "ss-lim", "ds-lim", "fs-lim", "gs-lim", "cs-prop", /*24*/"gdtrbase", "gdtr-lim", "idtrbase", "idtr-lim", "ldtrbase", "ldtr-lim", /*30*/"es-base", "cs-base", "ss-base", "ds-base", "fs-base", "gs-base", /*36*/"cr0", /*37*/"ST0H", "ST0L","ST1H", "ST1L","ST2H", "ST2L","ST3H", "ST3L", /*45*/"ST4H", "ST4L","ST5H", "ST5L","ST6H", "ST6L","ST7H", "ST7L", //"expiry" }; final Process p; final BufferedReader in; final BufferedWriter out; public Bochs() throws IOException { this("prince.cfg"); } public Bochs(String config) throws IOException { ProcessBuilder pb = new ProcessBuilder(EXE, "-q", "-f", config); Map<String, String> env = pb.environment(); // force path to /home/ian/java/jni/bochs pb.directory(new File("/home/ian/jpc/bochs")); pb.redirectErrorStream(true); p = pb.start(); in = new BufferedReader(new InputStreamReader(p.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(p.getOutputStream())); // read startup String end = readLine(); while (!end.contains("e05b") && !end.contains("2000")) // my hacked BIOS jumps to 0000:2000 end = readLine(); readLine(); // last line } public String executeInstruction() throws IOException { writeCommand("s"); String pream = readLine(); String next = readLine(); // normally cs:eip, disam of next instruction, raw bytes (very useful) String end = readLine(); if (next.contains("Next at")) next = end + next; while (!end.contains("Mouse capture off")) { next += end; end = readLine(); } return next + pream; } public int[] getState() throws IOException { writeCommand("r"); int[] regs = new int[names2.length]; for (int i=0; i < 10; i++) regs[i] = parseReg(readLine(), 8); readLine(); // segment registers writeCommand("sreg"); for (int i=0; i < 6; i++) { String line1 = readLine(); regs[10+i] = parseReg(line1, 4); // selector if (i == 1) // cs, extract size { regs[23] = (parseReg(line1.substring(line1.indexOf("dh")), 8) & 0x00400000) >> 22; } if (!line1.contains("valid=0")) { String line2 = readLine(); if (!line2.contains("limit")) throw new IllegalStateException(line2 + ",i="+i+" doesn't contain limit, prev line="+line1); regs[17+i] = parseReg(line2.substring(line2.indexOf("limit")), 8); // limit regs[30+i] = parseReg(line2, 8); // base } else { regs[17+i] = 0xffff; // limit (technically meaningless here) regs[30+i] = 0x0; // base (technically meaningless here) } } String lline = readLine(); // ldtr int lhigh = parseReg(lline.substring(lline.indexOf("dh")), 8); int llow = parseReg(lline.substring(lline.indexOf("dl")), 8); regs[28] = getBase(lhigh, llow); // base regs[29] = getLimit(lhigh, llow); readLine(); // tr String gline = readLine(); // gdtr regs[24] = parseReg(gline, 8); // base regs[25] = parseReg(gline.substring(gline.indexOf("limit")), 4); String iline = readLine(); // idtr regs[26] = parseReg(iline, 8); // base regs[27] = parseReg(iline.substring(iline.indexOf("limit")), 4); readLine(); // control regs writeCommand("creg"); regs[36] = parseReg(readLine(), 8); String last = readLine(); // CR2, CR3, CR3, CR3, CR4, EFER while (!last.contains("Mouse capture off")) last = readLine(); // ticks writeCommand("ptime"); String time = readLine(); regs[16] = Integer.parseInt(time.substring(time.indexOf("ptime:")+7)); String end = readLine(); while (!end.contains("Mouse capture off")) end = readLine(); // get FPU stack writeCommand("fpu"); String fline; fline = readLine(); int status=0; if (fline.contains("status")) { int start = fline.indexOf("0x") + 2; status = Integer.parseInt(fline.substring(start, fline.indexOf(":", start)), 16); } while (!(fline = readLine()).contains("fds")); for (int i=0; i < 8; i++) { int findex = (i - ((status >> 11) & 7)) & 7; fline = readLine(); long val = parseFPUReg(fline); regs[37+2*findex] = (int)(val >> 32); regs[37+2*findex+1] = (int)val; } readLine(); // Mouse capture off //print(regs); return regs; } public void setPhysicalMemory(int addr, byte[] data) throws IOException { for (int i=0; i < data.length; i++) { writeCommand(String.format("setpmem 0x%x 1 0x%x", addr+i, data[i])); String line = readLine(); while (!line.contains("Mouse capture")) line = readLine(); } } public byte[] getCMOS() throws IOException { writeCommand("info device \"cmos\""); String line; while (!(line=readLine()).contains("Index register")); readLine(); byte[] res = new byte[128]; for (int i=0; i < 8; i++) { line = readLine(); for (int j=0; j < 16; j++) { res[i*16+j] = (byte) Integer.parseInt(line.substring(6+j*3, 8+j*3), 16); } } String end = readLine(); while (!end.contains("Mouse capture off")) end = readLine(); return res; } public int[] getPit() throws IOException { int[] state = new int[3*4]; getPit(state, 0); getPit(state, 1); getPit(state, 2); return state; } @Override public int getPITIntTargetEIP() throws IOException { writeCommand("info ivt 8"); String line =readLine(); try { while (!line.contains("INT# 08")) { if (line.contains("protected")) { //need to lookup idt return 0; } line = readLine(); } } finally { String end = readLine(); while (!end.contains("Mouse capture off")) end = readLine(); } int start = line.indexOf(":", line.indexOf("INT"))+1; int last = line.indexOf(" ", start); return Integer.parseInt(line.substring(start, last), 16); } private void getPit(int[] state, int channel) throws IOException { writeCommand("info device 'pit' 'counter="+channel+"'"); String line; while (!(line=readLine()).contains("counter")); line = readLine(); int count = Integer.parseInt(line.substring(7)); readLine(); int gate = Integer.parseInt(readLine().substring(14)); int out = Integer.parseInt(readLine().substring(13)); int nextChangeTime = Integer.parseInt(readLine().substring(18)); String end = readLine(); while (!end.contains("Mouse capture off")) end = readLine(); state[4*channel] = count; state[4*channel+1] = gate; state[4*channel+2] = out; state[4*channel+3] = nextChangeTime; } public void keysDown(String keys) { throw new IllegalStateException("Unimplemented keysDown"); } public void keysUp(String keys) { throw new IllegalStateException("Unimplemented keysUp"); } public void sendMouse(Integer dx, Integer dy, Integer dz, Integer buttons) { throw new IllegalStateException("Unimplemented sendMouse"); } public String disam(byte[] code, Integer ops, Boolean mode) { throw new IllegalStateException("Unimplemented sendMouse"); } public int x86Length(byte[] code, Boolean mode) { throw new IllegalStateException("Unimplemented sendMouse"); } public Integer getPhysicalPage(Integer page, byte[] data) throws IOException { return getPage("xp/4096bx ", page, data); } public Integer getLinearPage(Integer page, byte[] data) throws IOException { return getPage("x/4096bx ", page, data); } public Integer getPage(String command, Integer page, byte[] data) throws IOException { writeCommand(command + page); String line = readLine(); while (!line.contains("bogus")) line = readLine(); for (int i=0; i < 512; i++) { while (line.contains("MEM")) line = readLine(); if (line.contains("read error")) return 0; if (line.contains("physical address not available")) { System.out.printf("Error reading from linear address: %x\n", page); return 0; } String[] bytes = line.substring(line.indexOf(":")+1).trim().split("\t"); for (int j=0; j < 8; j++) data[8*i+j] = (byte)Integer.parseInt(bytes[j].substring(2), 16); line = readLine(); } while (!line.contains("Mouse capture off")) line = readLine(); return 4096; } private String readLine() throws IOException { String line = in.readLine(); if (PRINT) System.out.println((lineCount++) + " " + line); return line; } private void writeCommand(String c) throws IOException { out.write(c); out.newLine(); out.flush(); } public static int getBase(int high, int low) { return ((low >> 16) & 0xffff) | ((high & 0xff) << 16) | (high & 0xff000000); } public static int getLimit(int high, int low) { return (low & 0xffff) | (high & 0xf0000); } public static void print(int[] r) { for (int i=0; i < r.length; i++) System.out.printf("%s %08x\n", names2[i], r[i]); } public static long parseFPUReg(String line) { int start = line.indexOf(":", line.indexOf("raw")) + 1; long sign = Integer.parseInt(line.substring(start-5, start-4), 16) >= 8 ? 1 : 0; long exponent = Long.parseLong(line.substring(start - 5, start - 1), 16); exponent -= (0x3fff - 0x3ff); exponent &= 0x7ff; long fraction = Long.parseLong(line.substring(start, start + 14), 16); fraction >>= 3; return (sign << 63) | (exponent << 52) | (fraction & 0xfffffffffffffL); } public static int parseReg(String line, int size) { int start = line.indexOf("0x"); int end = start+2+size; if (end > line.length()) end = line.length(); try { return (int)Long.parseLong(line.substring(start+2, end), 16); } catch (StringIndexOutOfBoundsException e) { System.out.println("Input string for bochs reg parse: "+line+"*"); throw e; } } public void destroy() { try { writeCommand("q"); in.close(); out.close(); p.getInputStream().close(); p.destroy(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws IOException { Bochs b = new Bochs(); print(b.getState()); while (true) b.executeInstruction(); } }