Example #1
0
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;
}
Example #3
0
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;
}
Example #4
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;
}
Example #5
0
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));
}
Example #6
0
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;
}
Example #7
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;
}
Example #8
0
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;
}
Example #9
0
/**
 * 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;
}
Example #10
0
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;
}
Example #11
0
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();
}
Example #12
0
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;
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #18
0
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;
}
Example #19
0
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();
		 */
	}
}
Example #20
0
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;
}