?? monitor.c
字號(hào):
/* * This source code is a part of coLinux source package. * * Dan Aloni <da-x@colinux.org>, 2003-2004 (c) * * The code is licensed under the GPL. See the COPYING file at * the root directory. *//* * Monitor * * FIXME: It should be architecture independant, but I am not sure if it * currently achieves that goal. Maybe with a few fixes... */#include <colinux/common/debug.h>#include <colinux/common/libc.h>#include <colinux/os/kernel/alloc.h>#include <colinux/os/kernel/misc.h>#include <colinux/os/kernel/monitor.h>#include <colinux/os/kernel/time.h>#include <colinux/os/kernel/wait.h>#include <colinux/os/timer.h>#include <colinux/arch/passage.h>#include <colinux/arch/interrupt.h>#include <colinux/arch/mmu.h>#include "monitor.h"#include "manager.h"#include "block.h"#include "fileblock.h"#include "transfer.h"#include "filesystem.h"#include "pages.h"co_rc_t co_monitor_malloc(co_monitor_t *cmon, unsigned long bytes, void **ptr){ void *block = co_os_malloc(bytes); if (block == NULL) return CO_RC(OUT_OF_MEMORY); *ptr = block; cmon->blocks_allocated++; return CO_RC(OK);}co_rc_t co_monitor_free(co_monitor_t *cmon, void *ptr){ co_os_free(ptr); cmon->blocks_allocated--; return CO_RC(OK);}static co_rc_t guest_address_space_init(co_monitor_t *cmon){ co_rc_t rc = CO_RC(OK); co_pfn_t *pfns = NULL, self_map_pfn, passage_page_pfn, swapper_pg_dir_pfn; unsigned long pp_pagetables_pgd, self_map_page_offset, passage_page_offset; unsigned long reversed_physical_mapping_offset; rc = co_monitor_get_pfn(cmon, cmon->import.kernel_swapper_pg_dir, &swapper_pg_dir_pfn); if (!CO_OK(rc)) { co_debug_error("error %08x getting swapper_pg_dir pfn", (int)rc); goto out_error; } cmon->pgd = swapper_pg_dir_pfn << CO_ARCH_PAGE_SHIFT; rc = co_monitor_arch_passage_page_alloc(cmon); if (!CO_OK(rc)) { co_debug_error("error %08x allocating passage page", (int)rc); goto out_error; } rc = co_monitor_arch_passage_page_init(cmon); if (!CO_OK(rc)) { co_debug_error("error %08x initializing the passage page", (int)rc); goto out_error; } pp_pagetables_pgd = CO_VPTR_PSEUDO_RAM_PAGE_TABLES >> PGDIR_SHIFT; pfns = cmon->pp_pfns[pp_pagetables_pgd]; if (pfns == NULL) { co_debug_error("CO_VPTR_PSEUDO_RAM_PAGE_TABLES is not mapped, huh?"); goto out_error; } rc = co_monitor_create_ptes(cmon, cmon->import.kernel_swapper_pg_dir, CO_ARCH_PAGE_SIZE, pfns); if (!CO_OK(rc)) { co_debug_error("error %08x initializing swapper_pg_dir", (int)rc); goto out_error; } reversed_physical_mapping_offset = (CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP >> PGDIR_SHIFT)*sizeof(linux_pgd_t); rc = co_monitor_copy_and_create_pfns(cmon, cmon->import.kernel_swapper_pg_dir + reversed_physical_mapping_offset, sizeof(linux_pgd_t)*cmon->manager->reversed_map_pgds_count, (void *)cmon->manager->reversed_map_pgds); if (!CO_OK(rc)) { co_debug_error("error %08x adding reversed physical mapping", (int)rc); goto out_error; } rc = co_monitor_create_ptes(cmon, CO_VPTR_SELF_MAP, CO_ARCH_PAGE_SIZE, pfns); if (!CO_OK(rc)) { co_debug_error("error %08x initializing self_map", (int)rc); goto out_error; } rc = co_monitor_get_pfn(cmon, CO_VPTR_SELF_MAP, &self_map_pfn); if (!CO_OK(rc)) { co_debug_error("error %08x getting self_map pfn", (int)rc); goto out_error; } self_map_page_offset = ((CO_VPTR_SELF_MAP >> PGDIR_SHIFT) * sizeof(linux_pte_t)); co_debug_ulong(self_map_page_offset); rc = co_monitor_create_ptes( cmon, cmon->import.kernel_swapper_pg_dir + self_map_page_offset, sizeof(linux_pte_t), &self_map_pfn); if (!CO_OK(rc)) { co_debug_error("error %08x getting self_map pfn", (int)rc); goto out_error; } passage_page_offset = ((CO_VPTR_PASSAGE_PAGE & ((1 << PGDIR_SHIFT) - 1)) >> CO_ARCH_PAGE_SHIFT) * sizeof(linux_pte_t); passage_page_pfn = co_os_virt_to_phys(cmon->passage_page) >> CO_ARCH_PAGE_SHIFT; rc = co_monitor_create_ptes( cmon, CO_VPTR_SELF_MAP + passage_page_offset, sizeof(linux_pte_t), &passage_page_pfn); if (!CO_OK(rc)) { co_debug_error("error %08x mapping passage page into the self map", (int)rc); goto out_error; } rc = co_monitor_create_ptes( cmon, CO_VPTR_SELF_MAP, sizeof(linux_pte_t), &self_map_pfn); if (!CO_OK(rc)) { co_debug_error("error %08x initializing self_map", (int)rc); goto out_error; } { long io_buffer_page; long io_buffer_num_pages = CO_VPTR_IO_AREA_SIZE >> CO_ARCH_PAGE_SHIFT; long io_buffer_offset = ((CO_VPTR_IO_AREA_START & ((1 << PGDIR_SHIFT) - 1)) >> CO_ARCH_PAGE_SHIFT) * sizeof(linux_pte_t); unsigned long io_buffer_host_address = (unsigned long)(cmon->io_buffer); for (io_buffer_page=0; io_buffer_page < io_buffer_num_pages; io_buffer_page++) { unsigned long io_buffer_pfn = co_os_virt_to_phys((void *)io_buffer_host_address) >> CO_ARCH_PAGE_SHIFT; rc = co_monitor_create_ptes(cmon, CO_VPTR_SELF_MAP + io_buffer_offset, sizeof(linux_pte_t), &io_buffer_pfn); if (!CO_OK(rc)) { co_debug_error("error %08x initializing io buffer (%ld)", (int)rc, io_buffer_page); goto out_error; } io_buffer_offset += sizeof(linux_pte_t); io_buffer_host_address += CO_ARCH_PAGE_SIZE; } } co_debug("initialization finished");out_error: return rc;}static bool_t device_request(co_monitor_t *cmon, co_device_t device, unsigned long *params){ switch (device) { case CO_DEVICE_BLOCK: { co_block_request_t *request; unsigned int unit = params[0]; co_rc_t rc; co_debug_lvl(blockdev, 13, "blockdev requested (unit %d)", unit); request = (co_block_request_t *)(¶ms[1]); rc = co_monitor_block_request(cmon, unit, request); if (CO_OK(rc)) request->rc = 0; else request->rc = -1; return PTRUE; } case CO_DEVICE_NETWORK: { co_network_request_t *network = NULL; co_debug_lvl(network, 13, "network requested"); network = (co_network_request_t *)(params); network->result = 0; if (network->unit < 0 || network->unit >= CO_MODULE_MAX_CONET) { co_debug_lvl(network, 12, "invalid network unit %d", network->unit); break; } co_debug_lvl(network, 12, "network unit %d requested", network->unit); switch (network->type) { case CO_NETWORK_GET_MAC: { co_netdev_desc_t *dev = &cmon->config.net_devs[network->unit]; co_debug_lvl(network, 10, "CO_NETWORK_GET_MAC requested"); network->result = dev->enabled; if (dev->enabled == PFALSE) break; co_memcpy(network->mac_address, dev->mac_address, sizeof(network->mac_address)); break; } default: break; } return PTRUE; } case CO_DEVICE_FILESYSTEM: { co_monitor_file_system(cmon, params[0], params[1], ¶ms[2]); return PTRUE; } default: break; } return PTRUE;}static co_rc_t callback_return_messages(co_monitor_t *cmon){ co_rc_t rc; unsigned char *io_buffer, *io_buffer_end; co_queue_t *queue; co_passage_page->params[0] = 0; if (!cmon->io_buffer) return CO_RC(ERROR); if (cmon->io_buffer->messages_waiting) return CO_RC(OK); io_buffer = cmon->io_buffer->buffer; io_buffer_end = io_buffer + CO_VPTR_IO_AREA_SIZE - sizeof(co_io_buffer_t); co_os_mutex_acquire(cmon->linux_message_queue_mutex); cmon->io_buffer->messages_waiting = 0; queue = &cmon->linux_message_queue; while (co_queue_size(queue) != 0) { co_message_queue_item_t *message_item; co_message_t *message; unsigned long size; co_linux_message_t *linux_message; rc = co_queue_peek_tail(queue, (void **)&message_item); if (!CO_OK(rc)) return rc; message = message_item->message; size = message->size + sizeof(*message); if (message->from == CO_MODULE_CONET0) co_debug_lvl(network, 14, "message sent to linux: %p", message); if (io_buffer + size > io_buffer_end) { break; } rc = co_queue_pop_tail(queue, (void **)&message_item); if (!CO_OK(rc)) return rc; if ((unsigned long)message->from >= (unsigned long)CO_MODULES_MAX) { co_debug_system("BUG! %s:%d", __FILE__, __LINE__); co_queue_free(queue, message_item); co_os_free(message); break; } if ((unsigned long)message->to >= (unsigned long)CO_MODULES_MAX){ co_debug_system("BUG! %s:%d", __FILE__, __LINE__); co_queue_free(queue, message_item); co_os_free(message); break; } linux_message = (co_linux_message_t *)message->data; if ((unsigned long)linux_message->device >= (unsigned long)CO_DEVICES_TOTAL){ co_debug_system("BUG! %s:%d %d %d", __FILE__, __LINE__, message->to, message->from); co_queue_free(queue, message_item); co_os_free(message); break; } cmon->io_buffer->messages_waiting += 1; co_queue_free(queue, message_item); co_memcpy(io_buffer, message, size); io_buffer += size; co_os_free(message); } co_os_mutex_release(cmon->linux_message_queue_mutex); co_passage_page->params[0] = io_buffer - (unsigned char *)&cmon->io_buffer->buffer; co_debug_lvl(messages, 12, "sending messages to linux (%ld bytes)", co_passage_page->params[0]); return CO_RC(OK);}static void callback_return_jiffies(co_monitor_t *cmon){ co_timestamp_t timestamp; long long timestamp_diff; unsigned long jiffies = 0; co_os_get_timestamp(×tamp); timestamp_diff = cmon->timestamp_reminder; timestamp_diff += 100 * (((long long)timestamp.quad) - ((long long)cmon->timestamp.quad)); /* HZ value */ jiffies = co_div64(timestamp_diff, cmon->timestamp_freq.quad); cmon->timestamp_reminder = timestamp_diff - (jiffies * cmon->timestamp_freq.quad); cmon->timestamp = timestamp; co_passage_page->params[1] = jiffies;}static void callback_return(co_monitor_t *cmon){ co_passage_page->operation = CO_OPERATION_MESSAGE_FROM_MONITOR; callback_return_messages(cmon); callback_return_jiffies(cmon);}static bool_t co_terminate(co_monitor_t *cmon){ co_os_timer_deactivate(cmon->timer); cmon->termination_reason = co_passage_page->params[0]; if (cmon->termination_reason == CO_TERMINATE_BUG) { int len; char *str = (char *)&co_passage_page->params[4]; cmon->bug_info.code = co_passage_page->params[1]; cmon->bug_info.line = co_passage_page->params[2]; len = co_strlen(str); if (len < sizeof(cmon->bug_info.file)-1) co_snprintf(cmon->bug_info.file, sizeof(cmon->bug_info.file), "%s", str); else /* show the end of filename */ co_snprintf(cmon->bug_info.file, sizeof(cmon->bug_info.file), "...%s", str + len - sizeof(cmon->bug_info.file) + 4); co_debug_system("BUG%ld at %s:%ld", cmon->bug_info.code, cmon->bug_info.file, cmon->bug_info.line); } cmon->state = CO_MONITOR_STATE_TERMINATED; return PFALSE;}static bool_t co_idle(co_monitor_t *cmon){ bool_t next_iter = PTRUE; co_queue_t *queue; co_os_wait_sleep(cmon->idle_wait); queue = &cmon->linux_message_queue; if (co_queue_size(queue) == 0) next_iter = PFALSE; return next_iter;}static void co_free_pages(co_monitor_t *cmon, vm_ptr_t address, int num_pages){ unsigned long scan_address; int j; scan_address = address; for (j=0; j < num_pages; j++) { co_monitor_free_and_unmap_page(cmon, scan_address); scan_address += CO_ARCH_PAGE_SIZE; }}static co_rc_t co_alloc_pages(co_monitor_t *cmon, vm_ptr_t address, int num_pages){ unsigned long scan_address; co_rc_t rc = CO_RC(OK); int i; scan_address = address; for (i=0; i < num_pages; i++) { rc = co_monitor_alloc_and_map_page(cmon, scan_address); if (!CO_OK(rc)) break; scan_address += CO_ARCH_PAGE_SIZE; }
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -