/* * SYSCALL.java * * (c) 2006 EduMips64 project - Andrea Spadaccini * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.edumips64.core.is; import org.edumips64.core.*; import org.edumips64.utils.*; import org.edumips64.utils.io.*; import java.util.logging.Logger; /** SYSCALL instruction, used to issue system calls. * * @author Andrea Spadaccini */ public class SYSCALL extends Instruction { private static final Logger logger = Logger.getLogger(SYSCALL.class.getName()); String OPCODE_VALUE = "000000"; String FINAL_VALUE = "001100"; private int syscall_n; private int return_value; private long address; private Dinero din; private IOManager iom; private Memory memory; SYSCALL(Memory memory, IOManager iom) { this.syntax = "%U"; this.paramCount = 1; this.name = "SYSCALL"; this.iom = iom; this.memory = memory; } public void IF() { syscall_n = params.get(0); logger.info("SYSCALL " + syscall_n + " (" + this.hashCode() + ") is in IF"); try { dinero.IF(Converter.binToHex(Converter.intToBin(64, cpu.getLastPC().getValue()))); } catch (IrregularStringOfBitsException e) { e.printStackTrace(); } } public void ID() throws RAWException, IrregularWriteOperationException, IrregularStringOfBitsException { if (syscall_n == 0) { logger.info("Stopping CPU due to SYSCALL (" + this.hashCode() + ")"); cpu.setStatus(CPU.CPUStatus.STOPPING); } else if ((syscall_n > 0) && (syscall_n <= 5)) { Register r14 = cpu.getRegister(14); if (r14.getWriteSemaphore() > 0) { throw new RAWException(); } Register r1 = cpu.getRegister(1); // In WB, R1 <- Return value r1.incrWriteSemaphore(); address = r14.getValue(); logger.info("SYSCALL (" + this.hashCode() + "): locked register R14. Value = " + address); } else { // TODO: invalid syscall logger.info("INVALID SYSCALL (" + this.hashCode() + ")"); } } public void EX() throws IrregularStringOfBitsException, IntegerOverflowException, TwosComplementSumException, IrregularWriteOperationException { logger.info("SYSCALL (" + this.hashCode() + ") -> EX"); } public void MEM() throws IrregularStringOfBitsException, MemoryElementNotFoundException { logger.info("SYSCALL (" + this.hashCode() + ") -> MEM"); if (syscall_n == 1) { // int open(const char* filename, int flags) String filename = fetchString(address); int flags_address = (int) address + filename.length(); flags_address += 8 - (flags_address % 8); MemoryElement flags_m = memory.getCellByAddress(flags_address); int flags = (int) flags_m.getValue(); // Memory access for the string and the flags (note the <=) for (int i = (int) address; i <= flags_address; i += 8) { dinero.Load(Converter.binToHex(Converter.positiveIntToBin(64, i)), 8); } logger.info("We must open " + filename + " with flags " + flags); return_value = -1; try { return_value = iom.open(filename, flags); } catch (Exception e) { logger.info("Error in executing the open(), the syscall will fail."); logger.info(e.toString()); } } else if (syscall_n == 2) { // int close(int fd) MemoryElement fd_cell = memory.getCellByAddress(address); int fd = (int) fd_cell.getValue(); logger.info("Closing fd " + fd); return_value = iom.close(fd); } else if ((syscall_n == 3) || (syscall_n == 4)) { // int read(int fd, void* buf, int count) // int write(int fd, void* buf, int count) int fd, count; long buf_addr; MemoryElement temp = memory.getCellByAddress(address); fd = (int) temp.getValue(); address += 8; temp = memory.getCellByAddress(address); buf_addr = temp.getValue(); address += 8; temp = memory.getCellByAddress(address); count = (int) temp.getValue(); address += 8; return_value = -1; try { if (syscall_n == 3) { logger.info("SYSCALL (" + this.hashCode() + "): trying to read from fd " + fd + " " + count + " bytes, writing them to address " + buf_addr); return_value = iom.read(fd, buf_addr, count); } else { logger.info("SYSCALL (" + this.hashCode() + "): trying to write to fd " + fd + " " + count + " bytes, reading them from address " + buf_addr); return_value = iom.write(fd, buf_addr, count); } } catch (Exception e) { logger.info("Error in executing the read(), the syscall will fail."); logger.info(e.toString()); } } else if (syscall_n == 5) { StringBuilder temp = new StringBuilder(); // In the address variable (content of R14) we have the address of // the format string, that we get and put in the format_string_address variable logger.info("Reading memory cell at address " + address + ", searching for the address of the format string"); MemoryElement tempMemCell = memory.getCellByAddress(address); int format_string_address = (int) tempMemCell.getValue(); // Recording in the tracefile the last memory access dinero.Load(Converter.binToHex(Converter.positiveIntToBin(64, address)), 8); // Fetching the format string String format_string = fetchString(format_string_address); logger.info("Read " + format_string); // Going to the next memory cell to start fetching parameters. int next_param_address = (int) address + 8; // Let's record in the tracefile the format string's memory access // t1 will hold the address of the last memory cell accessed // while we were reading format_string. int t1 = format_string_address + format_string.length(); t1 += 8 - (t1 % 8); for (int i = format_string_address; i < t1; i += 8) { dinero.Load(Converter.binToHex(Converter.positiveIntToBin(64, i)), 8); } int oldIndex = 0; int newIndex = 0; while ((newIndex = format_string.indexOf('%', oldIndex)) >= 0) { char type = format_string.charAt(newIndex + 1); logger.info("Found a placeholder... type " + type); temp.append(format_string.substring(oldIndex, newIndex)); switch (type) { case 's': // %s tempMemCell = memory.getCellByAddress(next_param_address); int str_address = (int) tempMemCell.getValue(); logger.info("Retrieving the string @ " + str_address + "..."); String param = fetchString(str_address); next_param_address += 8; /* Old, buggy behavior int old_param_address = next_param_address; next_param_address += param.length(); next_param_address += 8 - (next_param_address % 8); */ // Tracefile entry for this string int t2 = str_address + param.length(); t2 += 8 - (t2 % 8); for (int i = str_address; i < t2; i += 8) { dinero.Load(Converter.binToHex(Converter.positiveIntToBin(64, i)), 8); } logger.info("Got " + param); temp.append(param); break; case 'i': // %i case 'd': // %d logger.info("Retrieving the integer @ " + next_param_address + "..."); MemoryElement memCell = memory.getCellByAddress(next_param_address); // Tracefile entry for this memory access dinero.Load(Converter.binToHex(Converter.positiveIntToBin(64, next_param_address)), 8); Long val = memCell.getValue(); next_param_address += 8; temp.append(val.toString()); logger.info("Got " + val); break; case '%': // %% logger.info("Literal %..."); temp.append('%'); break; default: logger.info("Unknown placeholder"); break; } oldIndex = newIndex + 2; } temp.append(format_string.substring(oldIndex)); logger.info("That became " + temp.toString()); //This prints to StdOutput. try { iom.write(1, temp.toString()); } catch (WriteException e) { logger.info("Error in executing the printf(), the syscall will fail."); logger.info(e.toString()); } return_value = temp.length(); } } private String fetchString(long address) throws MemoryElementNotFoundException { StringBuilder temp = new StringBuilder(); boolean end_of_string = false; while (!end_of_string) { MemoryElement memEl = memory.getCellByAddress(address); for (int i = 0; i < 8; ++i) { int tempInt = memEl.readByte(i); if (tempInt == 0) { end_of_string = true; break; } char c = (char)(tempInt); temp.append(c); } address += 8; } return temp.toString(); } public void WB() throws IrregularStringOfBitsException, HaltException { logger.info("SYSCALL (" + this.hashCode() + ") -> WB. n = " + syscall_n); if (syscall_n == 0) { logger.info("Stopped CPU due to SYSCALL (" + this.hashCode() + ")"); cpu.setStatus(CPU.CPUStatus.HALTED); throw new HaltException(); } else if (syscall_n > 0 && syscall_n <= 5) { logger.info("SYSCALL (" + this.hashCode() + "): setting R1 to " + return_value); Register r1 = cpu.getRegister(1); logger.info("SYSCALL (" + this.hashCode() + "): got R1"); r1.setBits(Converter.intToBin(64, return_value), 0); logger.info("SYSCALL (" + this.hashCode() + "): set R1 to " + return_value); r1.decrWriteSemaphore(); logger.info("SYSCALL (" + this.hashCode() + "): decremented write semaphore"); } logger.info("SYSCALL (" + this.hashCode() + ") exiting from WB. n = " + syscall_n); } public void pack() throws IrregularStringOfBitsException { /* First 6 bits -> 000000 (SPECIAL) */ repr.setBits(OPCODE_VALUE, 0); /* Next 20 bits -> binary value of the immediate parameter. */ repr.setBits(Converter.intToBin(20, params.get(0)), 6); /* Last 6 bits -> 001100 (SYSCALL) */ repr.setBits(FINAL_VALUE, 26); } }