void g_system::addProcessor(uint32_t apicId) { // Check if ID is in use g_processor* n = processor_list; while (n) { if (n->apic == apicId) { g_log_warn("%! ignoring core with irregular, duplicate id %i", "system", apicId); return; } n = n->next; } // Create core g_processor* core = new g_processor(); core->apic = apicId; core->next = processor_list; // This function is called by the BSP only, therefore we can do: if (apicId == g_lapic::read_id()) { core->bsp = true; } processor_list = core; ++processors_available; }
g_fs_transaction_handler_start_status g_fs_transaction_handler_write::start_transaction(g_thread* thread) { // create a context-bound wrapper for the data buffer g_contextual<uint8_t*> bound_buffer(data()->buffer, thread->process->pageDirectory); // check for the driver delegate g_fs_delegate* delegate = node->get_delegate(); if (delegate == 0) { g_log_warn("%! writing of '%i' failed due to missing delegate on underlying node %i", "filesystem", fd->id, node->id); return G_FS_TRANSACTION_START_FAILED; } // check if the transaction is repeated only if (wants_repeat_transaction()) { // when a transaction is repeated, the waiter is still on the requesters task delegate->request_write(thread, node, data()->length, bound_buffer, fd, this); return G_FS_TRANSACTION_START_WITH_WAITER; } // start transaction by requesting the delegate g_fs_transaction_id transaction = delegate->request_write(thread, node, data()->length, bound_buffer, fd, this); // initially check status if (g_waiter_fs_transaction::is_transaction_waiting(thread, this, transaction, delegate)) { thread->wait(new g_waiter_fs_transaction(this, transaction, delegate)); return G_FS_TRANSACTION_START_WITH_WAITER; } return G_FS_TRANSACTION_START_IMMEDIATE_FINISH; }
void g_scheduler::deleteCurrent() { g_task_entry* entry_to_remove = current_entry; g_thread* thread = entry_to_remove->value; // remove from run queue g_task_entry* entry_from_run_queue = removeFromQueue(&run_queue, thread); // remove from wait queue if (entry_from_run_queue == 0) { g_task_entry* entry_from_wait_queue = removeFromQueue(&wait_queue, thread); if (entry_from_wait_queue == 0) { g_log_warn("%! failed to properly delete thread %i, was not assigned to a queue", "scheduler", thread->id); return; } } // delete the task g_thread_manager::deleteTask(thread); delete entry_to_remove; // let scheduling choose new one next time current_entry = 0; }
g_fs_transaction_handler_start_status g_filesystem::write(g_thread* thread, g_fs_node* node, g_file_descriptor_content* fd, int64_t length, g_contextual<uint8_t*> buffer, g_fs_transaction_handler_write* handler) { // ask driver delegate to perform operation g_fs_delegate* delegate = node->get_delegate(); if (delegate == 0) { g_log_warn("%! writing of '%i' failed due to missing delegate on underlying node %i", "filesystem", fd->id, node->id); return G_FS_TRANSACTION_START_FAILED; } // check if the transaction is repeated only if (handler->wants_repeat_transaction()) { // when a transaction is repeated, the waiter is still on the requesters task delegate->request_write(thread, node, length, buffer, fd, handler); return G_FS_TRANSACTION_STARTED_WITH_WAITER; } // start transaction by requesting the delegate g_fs_transaction_id transaction = delegate->request_write(thread, node, length, buffer, fd, handler); // initially check status bool keep_waiting = g_waiter_fs_transaction::check_transaction_status(thread, handler, transaction, delegate); if (keep_waiting) { thread->wait(new g_waiter_fs_transaction(handler, transaction, delegate)); return G_FS_TRANSACTION_STARTED_WITH_WAITER; } return G_FS_TRANSACTION_STARTED_AND_FINISHED; }
void g_filesystem::read_directory(g_thread* thread, g_fs_virt_id node_id, int position, g_contextual<g_syscall_fs_read_directory*> data) { // find the folder to operate on auto folder_entry = nodes->get(node_id); if (folder_entry == 0) { data()->status = G_FS_READ_DIRECTORY_ERROR; return; } g_fs_node* folder = folder_entry->value; // handler that actually puts the next node into the iterator g_fs_transaction_handler_read_directory* read_handler = new g_fs_transaction_handler_read_directory(folder, position, data); // if directory is already refreshed, finish immediately if (folder->contents_valid) { read_handler->finish_transaction(thread, 0); delete read_handler; return; } // take the delegate g_fs_delegate* delegate = folder->get_delegate(); if (delegate == nullptr) { data()->status = G_FS_READ_DIRECTORY_ERROR; g_log_warn("%! reading directory failed due to missing delegate on node %i", "filesystem", folder->id); return; } // schedule a refresh g_fs_transaction_handler_directory_refresh* refresh_handler = new g_fs_transaction_handler_directory_refresh(folder, read_handler); read_handler->causing_handler = refresh_handler; g_fs_transaction_id transaction = delegate->request_directory_refresh(thread, folder, refresh_handler); thread->wait(new g_waiter_fs_transaction(refresh_handler, transaction, delegate)); }
void g_filesystem::get_real_path_to_node(g_fs_node* node, char* out) { g_fs_node* current = node; int abs_len = 0; while (current != 0) { // on root we can stop if (current->type == G_FS_NODE_TYPE_ROOT) { break; } // check if (current->name == 0) { g_log_warn("%! problem: tried to add name of nameless node %i", "filesystem", current->id); break; } // get & check length + slash int name_len = g_string::length(current->name); if (abs_len + name_len + 1 > G_PATH_MAX) { g_log_warn("%! problem: tried to create a path thats longer than G_PATH_MAX from a node", "filesystem"); break; } // copy so that out contains: current->name "/" out for (int i = abs_len; i >= 0; i--) { out[i + name_len + 1] = out[i]; } out[name_len] = '/'; g_memory::copy(out, current->name, name_len); abs_len += name_len + 1; current = current->parent; } // add final slash & null termination for (int i = abs_len; i >= 0; i--) { out[i + 1] = out[i]; } out[0] = '/'; out[abs_len + 1] = 0; }
g_fs_transaction_id g_fs_delegate_mount::request_close(g_thread* requester, g_fs_transaction_handler_close* handler, g_file_descriptor_content* fd, g_fs_node* node) { g_fs_transaction_id id = g_fs_transaction_store::next_transaction(); // mount can't be opened g_log_warn("%! mountpoints can not be closed", "filesystem"); handler->status = G_FS_CLOSE_ERROR; g_fs_transaction_store::set_status(id, G_FS_TRANSACTION_FINISHED); return id; }
g_fs_transaction_id g_fs_delegate_mount::request_open(g_thread* requester, g_fs_node* node, char* filename, int32_t flags, int32_t mode, g_fs_transaction_handler_open* handler) { g_fs_transaction_id id = g_fs_transaction_store::next_transaction(); // mount can't be opened g_log_warn("%! mountpoints can not be opened", "filesystem"); handler->status = G_FS_OPEN_ERROR; g_fs_transaction_store::set_status(id, G_FS_TRANSACTION_FINISHED); return id; }
/** * Spawns a ramdisk file as a process. */ g_elf32_spawn_status g_elf32_loader::spawnFromRamdisk(g_ramdisk_entry* entry, g_security_level securityLevel, g_thread** target, const char* arguments, bool enforceCurrentCore) { // Check file if (entry == 0 || entry->type != G_RAMDISK_ENTRY_TYPE_FILE) { return ELF32_SPAWN_STATUS_FILE_NOT_FOUND; } // Get and validate ELF header elf32_ehdr* header = (elf32_ehdr*) entry->data; g_elf32_validation_status status = validate(header); if (status == ELF32_VALIDATION_SUCCESSFUL) { // Create the process g_thread* mainThread = g_thread_manager::createProcess(securityLevel); if (mainThread == 0) { g_log_warn("%! failed to create main thread to spawn ELF binary from ramdisk", "elf32"); return ELF32_SPAWN_STATUS_PROCESS_CREATION_FAILED; } g_process* process = mainThread->process; // Temporarily switch to the new processes page directory to load the binary to it g_page_directory thisPageDirectory = g_address_space::get_current_space(); g_address_space::switch_to_space(process->pageDirectory); loadBinaryToCurrentAddressSpace(header, process); g_thread_manager::prepare_thread_local_storage(mainThread); g_address_space::switch_to_space(thisPageDirectory); // Set the tasks entry point mainThread->cpuState->eip = header->e_entry; // Give CLI if (arguments) { process->cliArguments = new char[G_CLIARGS_BUFFER_LENGTH]; uint32_t argsLen = g_string::length(arguments); g_memory::copy(process->cliArguments, arguments, argsLen); process->cliArguments[argsLen] = 0; g_log_debug("%! kernel stored cli arguments for task %i", "elf32", process->main->id); } // Add to scheduling list g_tasking::addTask(mainThread, enforceCurrentCore); // Set out parameter *target = mainThread; return ELF32_SPAWN_STATUS_SUCCESSFUL; } return ELF32_SPAWN_STATUS_VALIDATION_ERROR; }
g_fd g_filesystem::open(g_pid pid, g_fs_node* node, int32_t flags, g_fd fd) { if (node->type == G_FS_NODE_TYPE_FILE) { return g_file_descriptors::map(pid, node->id, fd); } else if (node->type == G_FS_NODE_TYPE_PIPE) { g_pipes::add_reference(node->phys_fs_id, pid); return g_file_descriptors::map(pid, node->id, fd); } g_log_warn("%! tried to open a node of non-file type %i", "filesystem", node->type); return -1; }
void g_lapic::prepare(g_physical_address lapicAddress) { physicalBase = lapicAddress; prepared = true; // Warn if APIC not at expected location if (physicalBase != G_EXPECTED_APIC_PHYSICAL_ADDRESS) { g_log_warn("%! is at %h, not %h as expected", "lapic", physicalBase, G_EXPECTED_APIC_PHYSICAL_ADDRESS); } g_log_debug("%! base is %h", "lapic", physicalBase); // Map it to virtual space createMapping(); }
bool g_filesystem::discover_absolute_path(g_thread* requester, char* absolute_path, g_fs_transaction_handler_discovery* handler, bool follow_symlinks) { // check if this node is already discovered g_fs_node* parent = 0; g_fs_node* child = 0; g_local<char> last_name(new char[G_PATH_MAX]); g_filesystem::find_existing(absolute_path, &parent, &child, last_name(), follow_symlinks); // if the node already exists, tell the handler that discovery was successful if (child) { handler->status = G_FS_DISCOVERY_SUCCESSFUL; handler->node = child; handler->all_nodes_discovered = true; handler->finish_transaction(requester, child->get_delegate()); } else { // otherwise, request the driver delegate to discover it and set to sleep g_fs_delegate* delegate = parent->get_delegate(); if (delegate) { g_fs_transaction_id transaction = delegate->request_discovery(requester, parent, last_name(), handler); requester->wait(new g_waiter_fs_transaction(handler, transaction, delegate)); return false; } // if no driver delegate, error if (parent == root) { g_log_warn("%! mountpoint for '%s' does not exist", "filesystem", absolute_path); } else { g_log_warn("%! discovery of '%s' failed due to missing delegate on node %i", "filesystem", absolute_path, parent->id); } handler->status = G_FS_DISCOVERY_ERROR; handler->all_nodes_discovered = true; handler->finish_transaction(requester, 0); } return true; }
g_fs_transaction_handler_start_status g_fs_transaction_handler_directory_refresh::start_transaction(g_thread* thread) { // take the delegate g_fs_delegate* delegate = folder->get_delegate(); if (delegate == nullptr) { data()->status = G_FS_READ_DIRECTORY_ERROR; g_log_warn("%! reading directory failed due to missing delegate on node %i", "filesystem", folder->id); return G_FS_TRANSACTION_START_FAILED; } // request the refresh g_fs_transaction_id transaction = delegate->request_directory_refresh(thread, folder, this); thread->wait(new g_waiter_fs_transaction(this, transaction, delegate)); return G_FS_TRANSACTION_START_WITH_WAITER; }
g_fs_transaction_handler_finish_status g_fs_transaction_handler_close::finish_transaction(g_thread* thread, g_fs_delegate* delegate) { delegate->finish_close(thread, this); data()->status = status; // once delegate says closing was successful, unmap it if (status == G_FS_CLOSE_SUCCESSFUL) { if (!g_filesystem::unmap_file(thread->process->main->id, node, fd)) { g_log_warn("%! delegate failed to close file descriptor %i in process %i", "filesystem", fd->id, thread->process->main->id); status = G_FS_CLOSE_ERROR; } } return G_FS_TRANSACTION_HANDLING_DONE; }
g_fs_transaction_id g_fs_delegate_ramdisk::request_open(g_thread* requester, g_fs_node* node, char* filename, int32_t flags, int32_t mode, g_fs_transaction_handler_open* handler) { g_fs_transaction_id id = g_fs_transaction_store::next_transaction(); g_ramdisk_entry* ramdisk_node = g_kernel_ramdisk->findById(node->phys_fs_id); if (handler->discovery_status == G_FS_DISCOVERY_SUCCESSFUL) { if (ramdisk_node->type != G_RAMDISK_ENTRY_TYPE_FILE) { g_log_warn("%! only files can be opened, given node was a %i", "filesystem", ramdisk_node->type); handler->status = G_FS_OPEN_ERROR; } else { // truncate file if requested if (flags & G_FILE_FLAG_MODE_TRUNCATE) { // only applies when data no more used from ramdisk memory if (!ramdisk_node->data_on_ramdisk) { // completely remove the buffer ramdisk_node->datalength = 0; ramdisk_node->not_on_rd_buffer_length = 0; delete ramdisk_node->data; ramdisk_node->data = 0; } } handler->status = G_FS_OPEN_SUCCESSFUL; } } else if (handler->discovery_status == G_FS_DISCOVERY_NOT_FOUND) { if (flags & G_FILE_FLAG_MODE_CREATE) { // create the filesystem file g_ramdisk_entry* new_ramdisk_entry = g_kernel_ramdisk->createChild(ramdisk_node, filename); handler->node = create_vfs_node(new_ramdisk_entry, node); handler->status = G_FS_OPEN_SUCCESSFUL; } else { // return with failure handler->status = G_FS_OPEN_NOT_FOUND; } } g_fs_transaction_store::set_status(id, G_FS_TRANSACTION_FINISHED); return id; }
bool g_filesystem::close(g_pid pid, g_fs_node* node, g_file_descriptor_content* fd, g_fs_close_status* out_status) { if (node->type == G_FS_NODE_TYPE_FILE) { g_file_descriptors::unmap(pid, fd->id); *out_status = G_FS_CLOSE_SUCCESSFUL; return 0; } else if (node->type == G_FS_NODE_TYPE_PIPE) { g_pipes::remove_reference(node->phys_fs_id, pid); g_file_descriptors::unmap(pid, fd->id); *out_status = G_FS_CLOSE_SUCCESSFUL; return 0; } g_log_warn("%! tried to close a node of non-file type %i", "filesystem", node->type); *out_status = G_FS_CLOSE_ERROR; return -1; }
g_fs_transaction_handler_start_status g_fs_transaction_handler_close::start_transaction(g_thread* thread) { // check for the driver delegate g_fs_delegate* delegate = node->get_delegate(); if (delegate == 0) { g_log_warn("%! failed to close descriptor %i due to missing delegate", "filesystem", fd); return G_FS_TRANSACTION_START_FAILED; } // start transaction by requesting the delegate g_fs_transaction_id transaction = delegate->request_close(thread, this, fd, node); // check status for possible immediate finish if (g_waiter_fs_transaction::is_transaction_waiting(thread, this, transaction, delegate)) { thread->wait(new g_waiter_fs_transaction(this, transaction, delegate)); return G_FS_TRANSACTION_START_WITH_WAITER; } return G_FS_TRANSACTION_START_IMMEDIATE_FINISH; }
g_fs_transaction_id g_fs_delegate_ramdisk::request_read(g_thread* requester, g_fs_node* node, int64_t length, g_contextual<uint8_t*> buffer, g_file_descriptor_content* fd, g_fs_transaction_handler_read* handler) { // start/repeat transaction g_fs_transaction_id id; if (handler->wants_repeat_transaction()) { id = handler->get_repeated_transaction(); } else { id = g_fs_transaction_store::next_transaction(); } g_ramdisk_entry* ramdisk_node = g_kernel_ramdisk->findById(node->phys_fs_id); if (ramdisk_node == 0) { handler->status = G_FS_READ_INVALID_FD; g_fs_transaction_store::set_status(id, G_FS_TRANSACTION_FINISHED); return id; } // check if node is valid if (ramdisk_node->data == nullptr) { g_log_warn("%! tried to read from a node %i that has no buffer", "ramdisk", node->phys_fs_id); handler->status = G_FS_READ_ERROR; g_fs_transaction_store::set_status(id, G_FS_TRANSACTION_FINISHED); return id; } // read data into buffer int64_t copy_amount = ((fd->offset + length) >= ramdisk_node->datalength) ? (ramdisk_node->datalength - fd->offset) : length; if (copy_amount > 0) { g_memory::copy(buffer(), &ramdisk_node->data[fd->offset], copy_amount); fd->offset += copy_amount; } handler->result = copy_amount; handler->status = G_FS_READ_SUCCESSFUL; g_fs_transaction_store::set_status(id, G_FS_TRANSACTION_FINISHED); return id; }
void g_system::initializeBsp(g_physical_address initialPageDirectoryPhysical) { // Check if the required CPU features are available if (g_processor::supportsCpuid()) { g_log_debug("%! supports CPUID", "cpu"); } else { g_kernel::panic("%! no CPUID support", "cpu"); } // Do some CPU info output g_processor::printInformation(); // Enable SSE if available if (g_processor::hasFeature(g_cpuid_standard_edx_feature::SSE)) { g_log_info("%! support enabled", "sse"); g_processor::enableSSE(); } else { g_log_warn("%! no support detected", "sse"); } // APIC must be available if (g_processor::hasFeature(g_cpuid_standard_edx_feature::APIC)) { g_log_debug("%! APIC available", "cpu"); } else { g_kernel::panic("%! no APIC available", "cpu"); } // Gather ACPI information g_acpi::gatherInformation(); if (g_acpi::hasEntries()) { g_log_debug("%! is available", "acpi"); // Parse the MADT g_acpi_entry* cur = g_acpi::getEntryWithSignature("APIC"); if (cur) { // This creates the list of CPU's g_madt::parse(cur->header); } } else { g_kernel::panic("%! ACPI info not available", "system"); } // Initialize the interrupt controllers if (g_lapic::isPrepared() && g_ioapic_manager::areAvailable() && processor_list) { // Initialize the interrupt descriptor table g_idt::prepare(); g_idt::load(); // Disable PIC properly g_pic::remapIrqs(); g_pic::maskAll(); // Initialize local APIC g_lapic::initialize(); // Initialize each IO APIC g_ioapic* ioapic = g_ioapic_manager::getEntries(); while (ioapic) { ioapic->initialize(); ioapic = ioapic->getNext(); } // Print available CPUs g_log_info("%! %i available core%s", "system", processors_available, (processors_available > 1 ? "s" : "")); // Initialize multiprocessing g_smp::initialize(initialPageDirectoryPhysical); // Create keyboard and mouse redirection entries g_ioapic_manager::createIsaRedirectionEntry(1, 1, 0); g_ioapic_manager::createIsaRedirectionEntry(12, 12, 0); } else { g_kernel::panic("%! pic compatibility mode not implemented. apic/ioapic required!", "system"); /* PIC::remapIrqs(); PIC::unmaskAll(); */ } }
g_virtual_monitor_handling_result g_virtual_8086_monitor::handleGpf(g_processor_state_vm86* ctx) { uint8_t* ip = (uint8_t*) G_SEGOFF_TO_LINEAR(ctx->defaultFrame.cs, ctx->defaultFrame.eip); uint16_t* sp = (uint16_t*) G_SEGOFF_TO_LINEAR(ctx->defaultFrame.ss, ctx->defaultFrame.esp); uint32_t* esp = (uint32_t*) sp; bool operands32 = false; bool address32 = false; g_thread* current = g_tasking::getCurrentThread(); while (true) { switch (ip[0]) { /** * Enables 32bit operands for the next instructions */ case 0x66: { operands32 = true; ++ip; ++ctx->defaultFrame.eip; break; } /** * Enables 32bit addresses for the next instruction */ case 0x67: { address32 = true; ++ip; ++ctx->defaultFrame.eip; break; } /** * Instruction 0x9C: * PUSHF * * Pushes the CPU's eflags */ case 0x9C: { if (operands32) { ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) - 4) & 0xffff; esp--; esp[0] = ctx->defaultFrame.eflags & G_VALID_FLAGS; if (current->getVm86Information()->cpuIf) { esp[0] |= G_EFLAG_IF; } else { esp[0] &= ~G_EFLAG_IF; } } else { ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) - 2) & 0xffff; sp--; sp[0] = (uint16_t) ctx->defaultFrame.eflags; if (current->getVm86Information()->cpuIf) { sp[0] |= G_EFLAG_IF; } else { sp[0] &= ~G_EFLAG_IF; } } ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0x9D: * POPF * * Pops the CPU's eflags */ case 0x9D: { if (operands32) { ctx->defaultFrame.eflags = G_EFLAG_IF | G_EFLAG_VM | (esp[0] & G_VALID_FLAGS); current->getVm86Information()->cpuIf = (esp[0] & G_EFLAG_IF) != 0; ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) + 4) & 0xffff; } else { ctx->defaultFrame.eflags = G_EFLAG_IF | G_EFLAG_VM | sp[0]; current->getVm86Information()->cpuIf = (sp[0] & G_EFLAG_IF) != 0; ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) + 2) & 0xffff; } ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0xCD: * INT x * * Calls an interrupt */ case 0xCD: { sp -= 3; ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) - 6) & 0xffff; sp[0] = (uint16_t) (ctx->defaultFrame.eip + 2); sp[1] = ctx->defaultFrame.cs; sp[2] = (uint16_t) ctx->defaultFrame.eflags; if (current->getVm86Information()->cpuIf) { sp[2] |= G_EFLAG_IF; } else { sp[2] &= ~G_EFLAG_IF; } ctx->defaultFrame.cs = G_FP_SEG(ivt->entry[ip[1]]); ctx->defaultFrame.eip = G_FP_OFF(ivt->entry[ip[1]]); ++current->getVm86Information()->interruptRecursionLevel; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0xCF: * IRET * * Returns from an interrupt */ case 0xCF: { ctx->defaultFrame.eip = sp[0]; ctx->defaultFrame.cs = sp[1]; ctx->defaultFrame.eflags = G_EFLAG_IF | G_EFLAG_VM | sp[2]; current->getVm86Information()->cpuIf = ((sp[2] & G_EFLAG_IF) != 0); ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) + 6) & 0xffff; if (current->getVm86Information()->interruptRecursionLevel == 0) { current->getVm86Information()->out->ax = ctx->defaultFrame.eax; current->getVm86Information()->out->bx = ctx->defaultFrame.ebx; current->getVm86Information()->out->cx = ctx->defaultFrame.ecx; current->getVm86Information()->out->dx = ctx->defaultFrame.edx; current->getVm86Information()->out->di = ctx->defaultFrame.edi; current->getVm86Information()->out->si = ctx->defaultFrame.esi; current->getVm86Information()->out->ds = ctx->ds; current->getVm86Information()->out->es = ctx->es; return VIRTUAL_MONITOR_HANDLING_RESULT_FINISHED; } --current->getVm86Information()->interruptRecursionLevel; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0xFA: * CLI * * Disables interrupts */ case 0xFA: { current->getVm86Information()->cpuIf = false; ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0xFB: * STI * * Enables interrupts */ case 0xFB: { current->getVm86Information()->cpuIf = true; ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /* Instruction 0xEE: * OUT dx, al * * Output byte in AL to I/O port address in DX. */ case 0xEE: { io_ports::writeByte((uint16_t) ctx->defaultFrame.edx, (uint8_t) ctx->defaultFrame.eax); ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /* Instruction 0xEF: * OUT dx, ax * * Output word in AX to I/O port address in DX. */ case 0xEF: { io_ports::writeShort((uint16_t) ctx->defaultFrame.edx, (uint16_t) ctx->defaultFrame.eax); ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0xEC: * IN al, dx * * Input byte from I/O port in DX into AL. */ case 0xEC: { uint8_t res = io_ports::readByte((uint16_t) ctx->defaultFrame.edx); ctx->defaultFrame.eax &= ~(0xFF); ctx->defaultFrame.eax |= res; ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Instruction 0xED: * IN al, dx * * Input word from I/O port in DX into AX. */ case 0xED: { uint16_t res = io_ports::readShort((uint16_t) ctx->defaultFrame.edx); ctx->defaultFrame.eax &= ~(0xFFFF); ctx->defaultFrame.eax |= res; ++ctx->defaultFrame.eip; return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; } /** * Unhandled operation */ default: { g_log_warn("%! unhandled opcode %h at linear location %h", "vm86", (uint32_t) ip[0], ip); return VIRTUAL_MONITOR_HANDLING_RESULT_UNHANDLED_OPCODE; } } } // Not reached return VIRTUAL_MONITOR_HANDLING_RESULT_UNHANDLED_OPCODE; }