/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
#include <libc/stubs.h>
#include <crt0.h>
#include <string.h>
#include <libc/internal.h>
#include <stdlib.h>
#include <go32.h>
#include <stubinfo.h>
#include <dpmi.h>
#include <libc/farptrgs.h>
#include <pc.h>
#include <libc/bss.h>
/* Global variables */
#define ds _my_ds()
int __bss_count = 1;
char **environ;
int _crt0_startup_flags; /* default to zero unless app overrides them */
int __crt0_argc;
char **__crt0_argv;
/* Local variables */
static void
setup_core_selector(void)
{
int c = __dpmi_allocate_ldt_descriptors(1);
if (c == -1)
{
_dos_ds = 0;
return;
}
_dos_ds = c;
__dpmi_set_segment_limit(_dos_ds, 16 * 1024 * 1024 - 1);
}
static void
setup_screens(void)
{
if(_farpeekw(_dos_ds, 0xffff3) == 0xfd80) /* NEC PC98 ? */
{
ScreenPrimary = ScreenSecondary = 0xa0000;
}
else if (_farpeekb(_dos_ds, 0x449) == 7)
{
ScreenPrimary = 0xb0000;
ScreenSecondary = 0xb8000;
}
else
{
ScreenPrimary = 0xb8000;
ScreenSecondary = 0xb0000;
}
}
static void
setup_go32_info_block(void)
{
__dpmi_version_ret ver;
__dpmi_get_version(&ver);
_go32_info_block.size_of_this_structure_in_bytes = sizeof(_go32_info_block);
__tb = _stubinfo->ds_segment * 16;
_go32_info_block.size_of_transfer_buffer = _stubinfo->minkeep;
_go32_info_block.pid = _stubinfo->psp_selector;
_go32_info_block.master_interrupt_controller_base = ver.master_pic;
_go32_info_block.slave_interrupt_controller_base = ver.slave_pic;
_go32_info_block.linear_address_of_stub_info_structure = 0xffffffffU; /* force error */
__dpmi_get_segment_base_address(_stubinfo->psp_selector, &_go32_info_block.linear_address_of_original_psp);
_go32_info_block.run_mode = _GO32_RUN_MODE_DPMI;
_go32_info_block.run_mode_info = (ver.major << 8) | (ver.minor);
}
char *__dos_argv0;
static void
setup_environment(void)
{
char *dos_environ = alloca(_stubinfo->env_size), *cp;
short env_selector;
int env_count=0;
movedata(_stubinfo->psp_selector, 0x2c, ds, (int)&env_selector, 2);
movedata(env_selector, 0, ds, (int)dos_environ, _stubinfo->env_size);
cp = dos_environ;
do {
env_count++;
while (*cp) cp++; /* skip to NUL */
cp++; /* skip to next character */
} while (*cp); /* repeat until two NULs */
environ = (char **)malloc((env_count+1) * sizeof(char *));
if (environ == 0)
return;
cp = dos_environ;
env_count = 0;
do {
/* putenv assumes each string is malloc'd */
environ[env_count] = (char *)malloc(strlen(cp)+1);
strcpy(environ[env_count], cp);
env_count++;
while (*cp) cp++; /* skip to NUL */
cp++; /* skip to next character */
} while (*cp); /* repeat until two NULs */
environ[env_count] = 0;
__dos_argv0 = (char *)malloc(strlen(cp + 3)+1);
if (__dos_argv0 == 0)
abort();
strcpy(__dos_argv0, cp+3);
}
extern void __main(void);
extern int main(int, char **, char **);
extern void _crt0_init_mcount(void); /* For profiling */
void
__crt1_startup(void)
{
char *pn;
__bss_count ++;
__crt0_argv = 0;
setup_core_selector();
setup_screens();
setup_go32_info_block();
__djgpp_exception_setup();
setup_environment();
__crt0_setup_arguments();
pn = __crt0_argv ? __crt0_argv[0] : __dos_argv0;
__crt0_load_environment_file(pn);
_npxsetup(pn);
_crt0_init_mcount();
__main();
exit(main(__crt0_argc, __crt0_argv, environ));
}