diff options
Diffstat (limited to 'dostsr.h')
-rw-r--r-- | dostsr.h | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/dostsr.h b/dostsr.h new file mode 100644 index 0000000..726ef3a --- /dev/null +++ b/dostsr.h @@ -0,0 +1,116 @@ +/* + * VBMouse - utility functions for DOS TSRs + * Copyright (C) 2022 Javier S. Pedro + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DOSTSR_H +#define DOSTSR_H + +#include <stdint.h> + +#include "int21dos.h" + +/** Deallocates the environment block from the passed PSP segment. */ +static void deallocate_environment(segment_t 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_free(*envblockP); + *envblockP = 0; +} + +/** 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_t new_seg, segment_t 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_t 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 __segment reallocate_to_umb(segment_t __far * cur_seg, unsigned segment_size) +{ + segment_t old_psp_segment = *cur_seg - (DOS_PSP_SIZE/16); + segment_t new_psp_segment; + + deallocate_environment(_psp); + + // If we are already in UMA, don't bother + if (old_psp_segment >= 0xA000) { + return 0; + } + + new_psp_segment = allocate_umb(segment_size); + + if (new_psp_segment && new_psp_segment >= 0xA000) { + segment_t 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, segment_size); + + // Tell DOS to "switch" to the new program + dos_set_psp(new_psp_segment); + + // Return the new segment + return new_segment; + } 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 0; + } +} + +#endif // DOSTSR_H |