#include "insignia.h" #include "host_def.h" /* * SoftPC Revision 3.0 * * Title : ROM init functions * * Author : Ade Brownlow * * NB : These functions are used by BOTH the c and assembler cpus. * also note that host_read_resource now returns a long. * * SCCS ID: @(#)rom.c 1.53 06/16/95 * * (C) Copyright Insignia Solutions Ltd, 1994. */ #include #if defined(NTVDM) && defined(MONITOR) #include #endif #include TypesH #include MemoryH /* * SoftPC include files */ #include "xt.h" #include "sas.h" #include CpuH #include "error.h" #include "config.h" #include "rom.h" #include "debug.h" #include "ckmalloc.h" #include "yoda.h" #include "gispsvga.h" #ifdef CPU_40_STYLE #ifdef CCPU #include "ccpusas4.h" #else /* ! CCPU */ #include "Cpu_c.h" #endif /* ! CCPU */ #endif /* CPU_40_STYLE */ #ifndef BIOS1ROM_FILENAME #define BIOS1ROM_FILENAME "bios1.rom" #endif /* BIOS1ROM_FILENAME */ #ifndef BIOS2ROM_FILENAME #ifdef CPU_40_STYLE #define BIOS2ROM_FILENAME "bios4.rom" #else /* CPU_40_STYLE */ #define BIOS2ROM_FILENAME "bios2.rom" #endif /* CPU_40_STYLE */ #endif /* BIOS2ROM_FILENAME */ #ifndef EGAROM_FILENAME #define EGAROM_FILENAME "ega.rom" #endif /* EGAROM_FILENAME */ #ifndef VGAROM_FILENAME #define VGAROM_FILENAME "vga.rom" #endif /* VGAROM_FILENAME */ #ifndef V7VGAROM_FILENAME #define V7VGAROM_FILENAME "v7vga.rom" #endif /* V7VGAROM_FILENAME */ #ifdef GISP_SVGA #define GISP_VGAROM_FILENAME "hwvga.rom" #define GISP_BIOS1ROM_FILENAME "hwbios1.rom" #define GISP_BIOS2ROM_FILENAME BIOS2ROM_FILENAME #endif #ifndef ADAPTOR_ROM_START #define ADAPTOR_ROM_START 0xc8000 #endif /* ADAPTOR_ROM_START */ #ifndef ADAPTOR_ROM_END #define ADAPTOR_ROM_END 0xe0000 #endif /* ADAPTOR_ROM_END */ #define ADAPTOR_ROM_INCREMENT 0x800 #ifndef EXPANSION_ROM_START #define EXPANSION_ROM_START 0xe0000 #endif /* EXPANSION_ROM_START */ #ifndef EXPANSION_ROM_END #define EXPANSION_ROM_END 0xf0000 #endif /* EXPANSION_ROM_END */ #define EXPANSION_ROM_INCREMENT 0x10000 #define ROM_SIGNATURE 0xaa55 /* Current SoftPC verion number */ #define MAJOR_VER 0x03 #define MINOR_VER 0x00 #if defined(macintosh) && defined(A2CPU) /* Buffer is temporarily allocted - no bigger than needed. */ #define ROM_BUFFER_SIZE 1024*25 #else /* Using sas_scratch_buffer - will get 64K anyway. */ #define ROM_BUFFER_SIZE 1024*64 #endif LOCAL LONG read_rom IPT2(char *, name, sys_addr, address); LOCAL half_word do_rom_checksum IPT1(sys_addr, addr); #ifdef ANSI extern long host_read_resource (int, char *, host_addr, int ,int); #else extern long host_read_resource (); #endif /*( *=========================== patchCheckSum ================================ * patchCheckSum * * Purpose * This function calculates the check-sum for the indicated ROM, * and patches it in at the indicated offset into the ROM. * * It also checks that the ROM has the correct signature, and length, * and rounds the size up to a multiple of 512 bytes. * * Note this routine should not be called once paging is turned on. * * Input * start Physical address of start of ROM * length length of ROM in bytes * offset Checksum byte offset from start. * * Outputs * None. * * Description * We round the size-up to a multiple of 512 bytes, check the * signature, then patch-in the checksum. )*/ LOCAL void patchCheckSum IFN3(PHY_ADDR, start, PHY_ADDR, length, PHY_ADDR, offset) { PHY_ADDR roundedLength; IU16 signature; IU8 checksum; IU8 *buffer; PHY_ADDR currByte; PHY_ADDR indicatedLength; roundedLength = (length + 511) & (~511); sas_connect_memory(start, start + roundedLength - 1, SAS_RAM); #ifndef PROD if (roundedLength != length) { always_trace3("ROM at 0x%.5lx length rounded up from 0x%.8lx to 0x%.8lx", start, length, roundedLength); } if (roundedLength > (128 * 1024)) { always_trace2("ROM at 0x%.5lx has a length of 0x%.8lx which is more than 128K", start, roundedLength); force_yoda(); return; } if ((roundedLength <= offset) || (roundedLength < 4)) { always_trace1("ROM at 0x%.5lx is too short!", start); force_yoda(); return; } #endif signature = sas_PR16(start); if (signature != 0xaa55) { always_trace2("ROM at 0x%.5lx has an invalid signature 0x%.4x (should be aa55)", start, signature); sas_PW16(start, 0xaa55); } indicatedLength = sas_PR8(start + 2) * 512; if (indicatedLength != roundedLength) { always_trace3("ROM at 0x%.5lx has incorrect length 0x%.8lx (actually 0x%.8lx)", start, indicatedLength, roundedLength); sas_PW8(start + 2, roundedLength / 512); } check_malloc(buffer, roundedLength, IU8); sas_loads((LIN_ADDR)start, buffer, roundedLength); checksum = 0; for (currByte = 0; currByte < roundedLength; currByte++) { checksum += buffer[currByte]; } host_free(buffer); if (checksum != 0) { always_trace2("ROM at 0x%.8lx has incorrect checksum 0x%.2x", start, checksum); sas_PW8(start + offset, (IU8)((IS8)sas_PR8(start + offset) - checksum)); } sas_connect_memory(start, start + roundedLength - 1, SAS_ROM); } /*( =============================== read_video_rom ============================ PURPOSE: Load the appropriate video rom file. INPUT: None. OUTPUT: None. =========================================================================== )*/ GLOBAL void read_video_rom IFN0() { #ifdef REAL_VGA read_rom (VGAROM_FILENAME, EGA_ROM_START); #else /* REAL_VGA */ PHY_ADDR romLength = 0; switch ((ULONG) config_inquire(C_GFX_ADAPTER, NULL)) { #ifndef GISP_SVGA #ifdef VGG case VGA: #ifdef V7VGA romLength = read_rom (V7VGAROM_FILENAME, EGA_ROM_START); #else /* V7VGA */ romLength = read_rom (VGAROM_FILENAME, EGA_ROM_START); #endif /* V7VGA */ break; #endif /* VGG */ #ifdef EGG case EGA: romLength = read_rom (EGAROM_FILENAME, EGA_ROM_START); break; #endif /* EGG */ default: /* No rom required */ break; #else /* GISP_SVGA */ /* GISP_SVGA - only have the gisp vga roms or, none for CGA boot */ case VGA: romLength = read_rom (GISP_VGAROM_FILENAME, EGA_ROM_START); default: break; #endif /* GISP_SVGA */ } if (romLength != 0) { /* There is a problem with emm386 and Windows start up, which * is cured by setting the video bios rom internal length * to 32Kb. * Is seems that the V86 manager (or emm386) incorrectly * maps C6000..C7FFF during initialisation. * We round up the video ROM to 32Kb to avoid this problem, * which reduces the amount of "upper memory" RAM available to * dos extenders by 12K. */ if (romLength < (32*1024)) romLength = (32*1024); patchCheckSum(EGA_ROM_START, romLength, 5); } #endif /* not REAL_VGA */ } GLOBAL void rom_init IFN0() { #if !defined(NTVDM) || ( defined(NTVDM) && !defined(X86GFX) ) /* * Fill up all of ROM (Intel C0000 upwards) with bad op-codes. * This is the Expansion ROM and the BIOS ROM. * This will enable the CPU to trap any calls to ROM that are not made at a * valid entry point. */ #ifdef GISP_SVGA mapHostROMs( ); #else /* GISP_SVGA */ #if defined(macintosh) && defined(A2CPU) /* not macintosh 2.0 cpus - they have sparse M */ #else sas_fills( ROM_START, BAD_OP, PC_MEM_SIZE - ROM_START); #endif /* macintosh && A2CPU */ #endif /* GISP_SVGA */ /* * emm386 needs a hole to put it's page frame in. */ #if defined(SPC386) && !defined(GISP_CPU) sas_connect_memory(0xc0000, 0xfffff, SAS_ROM); #endif /* Load the video rom. */ read_video_rom(); /* load the rom bios */ #ifdef GISP_SVGA if ((ULONG) config_inquire(C_GFX_ADAPTER, NULL) == CGA ) { read_rom (BIOS1ROM_FILENAME, BIOS_START); read_rom (BIOS2ROM_FILENAME, BIOS2_START); } else { read_rom (GISP_BIOS1ROM_FILENAME, BIOS_START); read_rom (GISP_BIOS2ROM_FILENAME, BIOS2_START); } #else /* GISP_SVGA */ read_rom (BIOS1ROM_FILENAME, BIOS_START); read_rom (BIOS2ROM_FILENAME, BIOS2_START); #endif /* GISP_SVGA */ #else /* !NTVDM | (NTVDM & !X86GFX) */ /* * Now tell the CPU what it's not allowed to write over... * * These used to be done for everyone, but now they're only done for NT * as everyone else should have done it inside read_rom. */ sas_connect_memory (BIOS_START, 0xFFFFFL, SAS_ROM); #ifdef EGG sas_connect_memory (EGA_ROM_START, EGA_ROM_END-1, SAS_ROM); #endif #endif /* !NTVDM | (NTVDM & !X86GFX) */ host_rom_init(); } LOCAL LONG read_rom IFN2(char *, name, sys_addr, address) { #if !(defined(NTVDM) && defined(MONITOR)) host_addr tmp; long size = 0; /* do a rom load - use the sas_io buffer to get it the right way round */ /* BIOS rom first. */ /* Mac on 2.0 cpu doesn't want to use sas scratch buffer. */ #if defined(macintosh) && defined(A2CPU) tmp = (host_addr)host_malloc(ROM_BUFFER_SIZE); #else tmp = (host_addr)sas_scratch_address(ROM_BUFFER_SIZE); #endif if (!tmp) { host_error(EG_MALLOC_FAILURE, ERR_CONT | ERR_QUIT, NULL); return(0); } if (size = host_read_resource(ROMS_REZ_ID, name, tmp, ROM_BUFFER_SIZE, TRUE)) { sas_connect_memory( address, address+size, SAS_RAM); sas_stores (address, tmp, size); sas_connect_memory( address, address+size, SAS_ROM); } #if defined(macintosh) && defined(A2CPU) host_free((char *)tmp); #endif return( size ); #else return ( 0L ); #endif /* !(NTVDM && MONITOR) */ } LOCAL half_word do_rom_checksum IFN1(sys_addr, addr) { LONG sum = 0; sys_addr last_byte_addr; last_byte_addr = addr + (sas_hw_at(addr+2)*512); for (; addr> 4); setIP((addr & 0xffff)); host_simulate(); setCS(savedCS); setIP(savedIP); assert1(NO, "Additional ROM located and initialised at 0x%x ", addr-3); } else { assert2(NO, "Bad additonal ROM located at 0x%x, checksum = 0x%x\n", addr, checksum); } } } } GLOBAL void search_for_roms IFN0() { #if !defined(NTVDM) || (defined(NTVDM) && !defined(X86GFX)) #ifndef GISP_SVGA /* First search for adaptor ROM modules */ do_search_for_roms(ADAPTOR_ROM_START, ADAPTOR_ROM_END, ADAPTOR_ROM_INCREMENT); /* Now search for expansion ROM modules */ do_search_for_roms(EXPANSION_ROM_START, EXPANSION_ROM_END, EXPANSION_ROM_INCREMENT); #endif /* GISP_SVGA */ #endif /* !NTVDM | (NTVDM & !X86GFX) */ } GLOBAL void rom_checksum IFN0() { #if !defined(NTVDM) || (defined(NTVDM) && !defined(X86GFX) ) patchCheckSum(BIOS_START, PC_MEM_SIZE - BIOS_START, 0xfffff - BIOS_START); #endif /* !NTVDM | (NTVDM & !X86GFX) */ } GLOBAL VOID patch_rom IFN2(sys_addr, addr, half_word, val) { #if !defined(NTVDM) || (defined(NTVDM) && !defined(X86GFX) ) UTINY old_val; /* * 4.0 style CPUs don't export this variable, and if sas hasn't been * inited, then the sas_connect will drop out to yoda. */ #ifdef CPU_40_STYLE IU8 *hostPtr; /* TMM 14/2/95 * ----------- * What we are doing here is replacing the sas_connect() method of writing to ROM * with the new approach of poking the values directly in there. See display_string() * below for a more detiled discussion of the why's and wherefores. */ #ifdef macintosh /* The Mac config system wants to call this routine before the * CPU exists, so we'd better invent a Mac-specific IBOOL to * make the symptom non-fatal - finding and fixing the cause * is too hard. */ { extern IBOOL SafeToCallSas; if (!SafeToCallSas) return; } #endif /* macintosh */ /* The page might not be present (Arrggghhhh!!!!!) ** so we can't do anything sensible and must give ** up. We print an error though. */ hostPtr = getPtrToPhysAddrByte (addr); if (hostPtr == 0) { host_error(EG_OWNUP, ERR_QUIT, NULL); return; } old_val = *hostPtr; /* Optimisation - don't upset the world if the value is unchanged. */ if (old_val == val) return; *hostPtr = val; /* * Adjust the checksum value by new - old. * val is now difference between new and old value. * We don't do this for GISP_SVGA because the checksums are already * screwed, and attempting to write to the real host system ROM would * only make things worse! */ #ifndef GISP_SVGA /* Now get the checksum at the end of the ROM */ hostPtr = getPtrToPhysAddrByte (0xFFFFFL); if (hostPtr == 0) { host_error(EG_OWNUP, ERR_QUIT, NULL); return; } /* Now set the checksum to the difference between the old and new values */ *hostPtr -= (val - old_val); #endif /* GISP_SVGA */ #else /* CPU_40_STYLE */ /* * 4.0 style CPUs don't export this variable, and if sas hasn't been * inited, then the sas_connect will drop out to yoda. */ if (Length_of_M_area == 0) return; old_val = sas_hw_at( addr ); /* Optimisation - don't upset the world if the value is unchanged. */ if (old_val == val) return; sas_connect_memory (addr, addr, SAS_RAM); sas_store (addr,val); sas_connect_memory (addr, addr, SAS_ROM); /* * Adjust the checksum value by new - old. * val is now difference between new and old value. * We don't do this for GISP_SVGA because the checksums are already * screwed, and attempting to write to the real host system ROM would * only make things worse! */ #ifndef GISP_SVGA val -= old_val; old_val = sas_hw_at( 0xFFFFFL ); old_val -= val; sas_connect_memory (0xFFFFFL, 0xFFFFFL, SAS_RAM); sas_store (0xFFFFFL, old_val); sas_connect_memory (0xFFFFFL, 0xFFFFFL, SAS_ROM); #endif /* GISP_SVGA */ #endif /* CPU_40_STYLE */ #endif /* !NTVDM | (NTVDM & !X86GFX) */ } #ifndef GISP_SVGA /* * These routines were used by 2.0 CPUs which performed * post-write checks. Since all 3.0 and later CPUs do * pre-write checks they're no longer needed. */ #if !(defined(NTVDM) & defined(MONITOR)) void update_romcopy IFN1(long, addr) { UNUSED( addr ); } #endif GLOBAL void copyROM IFN0() { } #endif /* GISP_SVGA */ /* * To enable our drivers to output messages generated from * our bops we use a scratch area inside our rom. */ #ifndef GISP_SVGA LOCAL sys_addr cur_loc = DOS_SCRATCH_PAD; #else /* GISP_SVGA */ /* For GISP svga builds, we initialise from gispROMInit() */ sys_addr cur_loc; #endif /* GISP_SVGA */ GLOBAL void display_string IFN1(char *, string_ptr) { #if !defined(NTVDM) || (defined(NTVDM) && !defined(X86GFX) ) /* * Put the message "*string_ptr" in the ROM * scratch area where the drivers know where * to output it from. */ #ifdef CPU_40_STYLE IU8 *hostPtr; IU16 count; IU32 endLinAddr; /* In a paging environment, we must be careful as a ** the ROM area could have been copied and/or mapped ** as read only. We must alter the memory which is ** currently at the linear address of the ROM (whether ** that is actually our rom or a RAM copy of it). We ** must force this alteration despite any protection ** placed on the page by the Intel page tables. */ /* get a host pointer to the memory behind the required ** linear address. */ hostPtr = getPtrToLinAddrByte(cur_loc); /* The page might not be present (Arrggghhhh!!!!!) ** so we can't do anything sensible and must give ** up. We print an error though. */ if (hostPtr == 0) { host_error(EG_OWNUP, ERR_QUIT, NULL); return; } /* the area to be patched must lie entirely in one intel page for ** this method to be sure to work. So check it. */ endLinAddr = (cur_loc + strlen(string_ptr) + 2); if (((endLinAddr ^ DOS_SCRATCH_PAD) > 0xfff) || (endLinAddr > DOS_SCRATCH_PAD_END)) { #ifndef PROD fprintf(trace_file, "*** Warning ***: patch string into ROM too long; tuncating string '%s'", string_ptr); #endif if ((DOS_SCRATCH_PAD_END ^ DOS_SCRATCH_PAD) > 0xfff) { /* The defined DOS scratch pad crosses a page ** boundary. must truncate to the page boundary, ** allowing for the '$' and terminating zero */ string_ptr[0xffd - (DOS_SCRATCH_PAD & 0xfff)] = '\0'; } else { /* The string overflows the DOS scratch pad. We ** must truncate to the scrtach pad boundary, ** allowing for the '$' and terminating zero */ string_ptr[cur_loc - DOS_SCRATCH_PAD - 2] = '\0'; } } for (count = 0; count < strlen(string_ptr); count++) { *IncCpuPtrLS8(hostPtr) = string_ptr[count]; } /* Terminate the string */ *IncCpuPtrLS8(hostPtr) = '$'; *IncCpuPtrLS8(hostPtr) = '\0'; #else /* CPU_40_STYLE */ sas_connect_memory(DOS_SCRATCH_PAD, DOS_SCRATCH_PAD_END, SAS_RAM); sas_stores(cur_loc, (host_addr)string_ptr, strlen(string_ptr)); cur_loc += strlen(string_ptr); /* Terminate the string */ sas_store(cur_loc, '$'); sas_store(cur_loc + 1, '\0'); sas_disconnect_memory(DOS_SCRATCH_PAD, DOS_SCRATCH_PAD_END); cur_loc -= strlen(string_ptr); #endif /* CPU_40_STYLE */ #endif /* !NTVDM | !MONITOR */ cur_loc+=strlen(string_ptr); } GLOBAL void clear_string IFN0() { cur_loc = DOS_SCRATCH_PAD; /* Need to reset this pointer to start of ** ** scratch area to prevent messages being ** ** repeatedly displayed. */ display_string (""); } /* Returns the SoftPC version to our device drivers */ GLOBAL void softpc_version IFN0() { setAH(MAJOR_VER); setAL(MINOR_VER); }