/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Helpers for calling DPMI functions. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "allegro.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintdos.h" #ifndef ALLEGRO_DOS #error something is wrong with the makefile #endif /* _create_physical_mapping: * Maps a physical address range into linear memory, and allocates a * selector to access it. */ int _create_physical_mapping(unsigned long *linear, int *segment, unsigned long physaddr, int size) { if (_create_linear_mapping(linear, physaddr, size) != 0) return -1; if (_create_selector(segment, *linear, size) != 0) { _remove_linear_mapping(linear); return -1; } return 0; } /* _remove_physical_mapping: * Frees the DPMI resources being used to map a physical address range. */ void _remove_physical_mapping(unsigned long *linear, int *segment) { _remove_linear_mapping(linear); _remove_selector(segment); } /* _create_linear_mapping: * Maps a physical address range into linear memory. */ int _create_linear_mapping(unsigned long *linear, unsigned long physaddr, int size) { __dpmi_meminfo meminfo; if (physaddr >= 0x100000) { /* map into linear memory */ meminfo.address = physaddr; meminfo.size = size; if (__dpmi_physical_address_mapping(&meminfo) != 0) return -1; *linear = meminfo.address; /* lock the linear memory range */ __dpmi_lock_linear_region(&meminfo); } else /* exploit 1 -> 1 physical to linear mapping in low megabyte */ *linear = physaddr; return 0; } /* _remove_linear_mapping: * Frees the DPMI resources being used to map a linear address range. */ void _remove_linear_mapping(unsigned long *linear) { __dpmi_meminfo meminfo; if (*linear) { if (*linear >= 0x100000) { meminfo.address = *linear; __dpmi_free_physical_address_mapping(&meminfo); } *linear = 0; } } /* _create_selector: * Allocates a selector to access a region of linear memory. */ int _create_selector(int *segment, unsigned long linear, int size) { /* allocate an ldt descriptor */ *segment = __dpmi_allocate_ldt_descriptors(1); if (*segment < 0) { *segment = 0; return -1; } /* set the descriptor base and limit */ __dpmi_set_segment_base_address(*segment, linear); __dpmi_set_segment_limit(*segment, MAX(size-1, 0xFFFF)); return 0; } /* _remove_selector: * Frees a DPMI segment selector. */ void _remove_selector(int *segment) { if (*segment) { __dpmi_free_ldt_descriptor(*segment); *segment = 0; } } /* _unlock_dpmi_data: * Unlocks a memory region (this is needed when repeatedly allocating and * freeing large samples, to prevent all of memory ending up in a locked * state). */ void _unlock_dpmi_data(void *addr, int size) { unsigned long baseaddr; __dpmi_meminfo mem; __dpmi_get_segment_base_address(_default_ds(), &baseaddr); mem.address = baseaddr + (unsigned long)addr; mem.size = size; __dpmi_unlock_linear_region(&mem); }