aboutsummaryrefslogtreecommitdiff
path: root/dosmain.c
diff options
context:
space:
mode:
Diffstat (limited to 'dosmain.c')
-rw-r--r--dosmain.c183
1 files changed, 158 insertions, 25 deletions
diff --git a/dosmain.c b/dosmain.c
index 0ac5f75..5e789a9 100644
--- a/dosmain.c
+++ b/dosmain.c
@@ -25,6 +25,7 @@
#include "dlog.h"
#include "int33.h"
+#include "int21dos.h"
#include "ps2.h"
#include "vbox.h"
#include "vmware.h"
@@ -241,34 +242,142 @@ static int configure_driver(LPTSRDATA data)
return 0;
}
-static void deallocate_environment(uint16_t psp)
+/** Converts bytes to MS-DOS "paragraphs" (16 bytes), rounding up. */
+static inline unsigned get_paragraphs(unsigned bytes)
+{
+ return (bytes + 15) / 16;
+}
+
+/** Gets the size of the resident part of this program, including the PSP. */
+static inline unsigned get_resident_program_size()
+{
+ return get_resident_size() + DOS_PSP_SIZE;
+}
+
+/** Deallocates the environment block from the passed PSP segment. */
+static void deallocate_environment(__segment psp)
{
// TODO : Too lazy to make PSP struct;
// 0x2C is offsetof the environment block field on the PSP
uint16_t __far *envblockP = (uint16_t __far *) MK_FP(psp, 0x2C);
- _dos_freemem(*envblockP);
+ dos_free(*envblockP);
*envblockP = 0;
}
-static int install_driver(LPTSRDATA data)
+/** Copies a program to another location.
+ * @param new_seg PSP segment for the new location
+ * @param old_seg PSP segment for the old location
+ * @param size size of the program to copy including PSP size. */
+static void copy_program(__segment new_seg, __segment old_seg, unsigned size)
+{
+ // The MCB is always 1 segment before.
+ uint8_t __far *new_mcb = MK_FP(new_seg - 1, 0);
+ uint8_t __far *old_mcb = MK_FP(old_seg - 1, 0);
+ uint16_t __far *new_mcb_owner = (uint16_t __far *) &new_mcb[1];
+ char __far *new_mcb_owner_name = &new_mcb[8];
+ char __far *old_mcb_owner_name = &old_mcb[8];
+
+ // Copy entire resident segment including PSP
+ _fmemcpy(MK_FP(new_seg, 0), MK_FP(old_seg, 0), size);
+
+ // Make the new MCB point to itself as owner
+ *new_mcb_owner = new_seg;
+
+ // Copy the program name, too.
+ _fmemcpy(new_mcb_owner_name, old_mcb_owner_name, 8);
+}
+
+/** Allocates a UMB of the given size.
+ * If no UMBs are available, this may still return a block in conventional memory. */
+static __segment allocate_umb(unsigned size)
+{
+ bool old_umb_link = dos_query_umb_link_state();
+ unsigned int old_strategy = dos_query_allocation_strategy();
+ __segment new_segment;
+
+ dos_set_umb_link_state(true);
+ dos_set_allocation_strategy(DOS_FIT_BEST | DOS_FIT_HIGHONLY);
+
+ new_segment = dos_alloc(get_paragraphs(size));
+
+ dos_set_umb_link_state(old_umb_link);
+ dos_set_allocation_strategy(old_strategy);
+
+ return new_segment;
+}
+
+static int reallocate_to_umb(LPTSRDATA __far * data)
{
- unsigned int resident_size = get_resident_size();
+ const unsigned int resident_size = get_resident_program_size();
+ LPTSRDATA old_data = *data;
+ __segment old_psp_segment = FP_SEG(old_data) - (DOS_PSP_SIZE/16);
+ __segment new_psp_segment;
- // Not that this will do anything other than fragment memory, but why not...
deallocate_environment(_psp);
+ // If we are already in UMA, don't bother
+ if (old_psp_segment >= 0xA000) {
+ return -1;
+ }
+
+ new_psp_segment = allocate_umb(resident_size);
+
+ if (new_psp_segment && new_psp_segment >= 0xA000) {
+ __segment new_segment = new_psp_segment + (DOS_PSP_SIZE/16);
+ printf("Moving to upper memory\n");
+
+ // Create a new program instance including PSP at the new_segment
+ copy_program(new_psp_segment, old_psp_segment, resident_size);
+
+ // Tell DOS to "switch" to the new program
+ dos_set_psp(new_psp_segment);
+
+ // Now update the data pointer to the new segment
+ *data = MK_FP(new_segment, FP_OFF(old_data));
+
+ return 0;
+ } else {
+ printf("No upper memory available\n");
+ if (new_psp_segment) {
+ // In case we got another low-memory segment...
+ dos_free(new_psp_segment);
+ }
+
+ return -1;
+ }
+}
+
+static __declspec(aborts) int install_driver(LPTSRDATA data, bool high)
+{
+ const unsigned int resident_size = DOS_PSP_SIZE + get_resident_size();
+
+ // No more interruptions from now on and until we TSR.
+ // Inserting ourselves in the interrupt chain should be atomic.
+ _disable();
+
data->prev_int33_handler = _dos_getvect(0x33);
- _dos_setvect(0x33, int33_isr);
+ _dos_setvect(0x33, data:>int33_isr);
#if USE_WIN386
data->prev_int2f_handler = _dos_getvect(0x2f);
- _dos_setvect(0x2f, int2f_isr);
+ _dos_setvect(0x2f, data:>int2f_isr);
#endif
printf("Driver installed\n");
- _dos_keep(EXIT_SUCCESS, (256 + resident_size + 15) / 16);
- return 0;
+ // If we reallocated ourselves to UMB,
+ // it's time to free our initial conventional memory allocation
+ if (high) {
+ // We are about to free() our own code segment.
+ // Nothing should try to allocate memory between this and the TSR call
+ // below, since it could overwrite our code...
+ dos_free(_psp);
+ }
+
+ _dos_keep(EXIT_SUCCESS, get_paragraphs(resident_size));
+
+ // Shouldn't reach this part
+ return EXIT_FAILURE;
}
static bool check_if_driver_uninstallable(LPTSRDATA data)
@@ -298,10 +407,8 @@ static bool check_if_driver_uninstallable(LPTSRDATA data)
static int unconfigure_driver(LPTSRDATA data)
{
-#if USE_VIRTUALBOX
- if (data->vbavail) {
- set_integration(data, false);
- }
+#if USE_INTEGRATION
+ set_integration(data, false);
#endif
ps2m_enable(false);
@@ -320,7 +427,7 @@ static int uninstall_driver(LPTSRDATA data)
// Find and deallocate the PSP (including the entire program),
// it is always 256 bytes (16 paragraphs) before the TSR segment
- _dos_freemem(FP_SEG(data) - 16);
+ dos_free(FP_SEG(data) - (DOS_PSP_SIZE/16));
printf("Driver uninstalled\n");
@@ -343,21 +450,29 @@ static void print_help(void)
{
printf("\n"
"Usage: \n"
- "\tVBMOUSE <ACTION>\n\n"
+ " VBMOUSE <ACTION> <ARGS..>\n\n"
"Supported actions:\n"
- "\tinstall install the driver (default)\n"
- "\tuninstall uninstall the driver from memory\n"
+ " install install the driver (default)\n"
+ " low install in conventional memory (otherwise UMB)\n"
+ " uninstall uninstall the driver from memory\n"
#if USE_WHEEL
- "\twheel <ON|OFF> enable/disable wheel API support\n"
+ " wheel <ON|OFF> enable/disable wheel API support\n"
#endif
#if USE_INTEGRATION
- "\tinteg <ON|OFF> enable/disable virtualbox integration\n"
- "\thostcur <ON|OFF> enable/disable mouse cursor rendering in host\n"
+ " integ <ON|OFF> enable/disable virtualbox integration\n"
+ " hostcur <ON|OFF> enable/disable mouse cursor rendering in host\n"
#endif
- "\treset reset mouse driver settings\n"
+ " reset reset mouse driver settings\n"
);
}
+static int invalid_arg(const char *s)
+{
+ fprintf(stderr, "Invalid argument '%s'", s);
+ print_help();
+ return EXIT_FAILURE;
+}
+
static bool is_true(const char *s)
{
return stricmp(s, "yes") == 0
@@ -388,15 +503,34 @@ int main(int argc, const char *argv[])
printf("\nVBMouse %x.%x (like MSMOUSE %x.%x)\n", VERSION_MAJOR, VERSION_MINOR, REPORTED_VERSION_MAJOR, REPORTED_VERSION_MINOR);
if (argi >= argc || stricmp(argv[argi], "install") == 0) {
+ bool high = true;
+
+ argi++;
+ for (; argi < argc; argi++) {
+ if (stricmp(argv[argi], "low") == 0) {
+ high = false;
+ } else if (stricmp(argv[argi], "high") == 0) {
+ high = true;
+ } else {
+ return invalid_arg(argv[argi]);
+ }
+ }
+
if (data) {
printf("VBMouse already installed\n");
return EXIT_SUCCESS;
}
data = get_tsr_data(false);
+ if (high) {
+ err = reallocate_to_umb(&data);
+ if (err) high = false; // Not fatal
+ } else {
+ deallocate_environment(_psp);
+ }
err = configure_driver(data);
if (err) return EXIT_FAILURE;
- return install_driver(data);
+ return install_driver(data, high);
} else if (stricmp(argv[argi], "uninstall") == 0) {
if (!data) return driver_not_found();
if (!check_if_driver_uninstallable(data)) {
@@ -449,8 +583,7 @@ int main(int argc, const char *argv[])
#endif
} else if (stricmp(argv[argi], "reset") == 0) {
return driver_reset();
+ } else {
+ return invalid_arg(argv[argi]);
}
-
- print_help();
- return EXIT_FAILURE;
}