/** Install I/O Permission bitmap. * * Current task's I/O permission bitmap, if any, is installed * in the current CPU's TSS. * * Interrupts must be disabled prior this call. * */ void io_perm_bitmap_install(void) { /* First, copy the I/O Permission Bitmap. */ irq_spinlock_lock(&TASK->lock, false); size_t ver = TASK->arch.iomapver; size_t elements = TASK->arch.iomap.elements; if (elements > 0) { ASSERT(TASK->arch.iomap.bits); bitmap_t iomap; bitmap_initialize(&iomap, TSS_IOMAP_SIZE * 8, CPU->arch.tss->iomap); bitmap_copy(&iomap, &TASK->arch.iomap, elements); /* * Set the trailing bits in the last byte of the map to disable * I/O access. */ bitmap_set_range(&iomap, elements, ALIGN_UP(elements, 8) - elements); /* * It is safe to set the trailing eight bits because of the * extra convenience byte in TSS_IOMAP_SIZE. */ bitmap_set_range(&iomap, ALIGN_UP(elements, 8), 8); } irq_spinlock_unlock(&TASK->lock, false); /* * Second, adjust TSS segment limit. * Take the extra ending byte with all bits set into account. */ ptr_16_64_t cpugdtr; gdtr_store(&cpugdtr); descriptor_t *gdt_p = (descriptor_t *) cpugdtr.base; size_t size = bitmap_size(elements); gdt_tss_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE + size); gdtr_load(&cpugdtr); /* * Before we load new TSS limit, the current TSS descriptor * type must be changed to describe inactive TSS. */ tss_descriptor_t *tss_desc = (tss_descriptor_t *) &gdt_p[TSS_DES]; tss_desc->type = AR_TSS; tr_load(GDT_SELECTOR(TSS_DES)); /* * Update the generation count so that faults caused by * early accesses can be serviced. */ CPU->arch.iomapver_copy = ver; }
/** Enable I/O space range for task. * * Interrupts are disabled and task is locked. * * @param task Task. * @param ioaddr Starting I/O space address. * @param size Size of the enabled I/O range. * * @return EOK on success or an error code from errno.h. * */ int ddi_iospace_enable_arch(task_t *task, uintptr_t ioaddr, size_t size) { size_t elements = ioaddr + size; if (elements > IO_PORTS) return ENOENT; if (task->arch.iomap.elements < elements) { /* * The I/O permission bitmap is too small and needs to be grown. */ void *store = malloc(bitmap_size(elements), FRAME_ATOMIC); if (!store) return ENOMEM; bitmap_t oldiomap; bitmap_initialize(&oldiomap, task->arch.iomap.elements, task->arch.iomap.bits); bitmap_initialize(&task->arch.iomap, elements, store); /* * Mark the new range inaccessible. */ bitmap_set_range(&task->arch.iomap, oldiomap.elements, elements - oldiomap.elements); /* * In case there really existed smaller iomap, * copy its contents and deallocate it. */ if (oldiomap.bits) { bitmap_copy(&task->arch.iomap, &oldiomap, oldiomap.elements); free(oldiomap.bits); } } /* * Enable the range and we are done. */ bitmap_clear_range(&task->arch.iomap, (size_t) ioaddr, size); /* * Increment I/O Permission bitmap generation counter. */ task->arch.iomapver++; return EOK; }
/** Mark frame in zone unavailable to allocation. */ NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t index) { ASSERT(zone->flags & ZONE_AVAILABLE); frame_t *frame = zone_get_frame(zone, index); if (frame->refcount > 0) return; frame->refcount = 1; bitmap_set_range(&zone->bitmap, index, 1); zone->free_count--; reserve_force_alloc(1); }
/* Allocate and initialize data needed for global pseudo live analysis. */ static void initiate_live_solver (void) { bitmap_initialize (&all_hard_regs_bitmap, ®_obstack); bitmap_set_range (&all_hard_regs_bitmap, 0, FIRST_PSEUDO_REGISTER); bb_data = XNEWVEC (struct bb_data_pseudos, last_basic_block_for_fn (cfun)); bitmap_initialize (&all_blocks, ®_obstack); basic_block bb; FOR_ALL_BB_FN (bb, cfun) { bb_data_t bb_info = get_bb_data (bb); bb_info->bb = bb; bitmap_initialize (&bb_info->killed_pseudos, ®_obstack); bitmap_initialize (&bb_info->gen_pseudos, ®_obstack); bitmap_set_bit (&all_blocks, bb->index); }
/** Enable I/O space range for task. * * Interrupts are disabled and task is locked. * * @param task Task. * @param ioaddr Starting I/O space address. * @param size Size of the enabled I/O range. * * @return EOK on success or an error code from errno.h. */ int ddi_iospace_enable_arch(task_t *task, uintptr_t ioaddr, size_t size) { if (!task->arch.iomap) { task->arch.iomap = malloc(sizeof(bitmap_t), 0); if (task->arch.iomap == NULL) return ENOMEM; void *store = malloc(bitmap_size(IO_MEMMAP_PAGES), 0); if (store == NULL) return ENOMEM; bitmap_initialize(task->arch.iomap, IO_MEMMAP_PAGES, store); bitmap_clear_range(task->arch.iomap, 0, IO_MEMMAP_PAGES); } uintptr_t iopage = ioaddr / PORTS_PER_PAGE; size = ALIGN_UP(size + ioaddr - 4 * iopage, PORTS_PER_PAGE); bitmap_set_range(task->arch.iomap, iopage, size / 4); return EOK; }
/** Disable I/O space range for task. * * Interrupts are disabled and task is locked. * * @param task Task. * @param ioaddr Starting I/O space address. * @param size Size of the enabled I/O range. * * @return EOK on success or an error code from errno.h. * */ int ddi_iospace_disable_arch(task_t *task, uintptr_t ioaddr, size_t size) { size_t elements = ioaddr + size; if (elements > IO_PORTS) return ENOENT; if (ioaddr >= task->arch.iomap.elements) return EINVAL; if (task->arch.iomap.elements < elements) size -= elements - task->arch.iomap.elements; /* * Disable the range. */ bitmap_set_range(&task->arch.iomap, (size_t) ioaddr, size); /* * Increment I/O Permission bitmap generation counter. */ task->arch.iomapver++; return 0; }