2017-05-30 03:38:38 +02:00
/*
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
*
* This file is part of the 86 Box distribution .
*
* Implementation of the Intel 2 Mbit 8 - bit flash devices .
*
2017-10-07 00:46:54 -04:00
* Version : @ ( # ) intel_flash . c 1.0 .5 2017 / 10 / 04
2017-05-30 03:38:38 +02:00
*
2017-08-24 01:14:39 -04:00
* Authors : Sarah Walker , < http : //pcem-emulator.co.uk/>
2017-05-30 03:38:38 +02:00
* Miran Grca , < mgrca8 @ gmail . com >
* Copyright 2008 - 2017 Sarah Walker .
2017-09-25 04:31:20 -04:00
* Copyright 2016 , 2017 Miran Grca .
2017-05-30 03:38:38 +02:00
*/
2017-09-25 04:31:20 -04:00
# include <stdio.h>
# include <stdint.h>
# include <string.h>
2016-06-26 00:34:39 +02:00
# include <stdlib.h>
2017-09-25 04:31:20 -04:00
# include <wchar.h>
2016-06-26 00:34:39 +02:00
# include "ibm.h"
2017-08-27 04:33:47 +01:00
# include "cpu/cpu.h"
2016-06-26 00:34:39 +02:00
# include "device.h"
# include "mem.h"
2017-09-02 20:39:57 +02:00
# include "machine/machine.h"
2017-09-23 21:12:26 -04:00
# include "nvr.h"
2016-06-26 00:34:39 +02:00
2016-07-05 19:29:31 +02:00
# define FLASH_IS_BXB 2
# define FLASH_INVERT 1
# define BLOCK_MAIN 0
2016-11-04 22:32:23 +01:00
# define BLOCK_DATA1 1
# define BLOCK_DATA2 2
2016-07-05 19:29:31 +02:00
# define BLOCK_BOOT 3
2016-06-26 00:34:39 +02:00
enum
{
CMD_READ_ARRAY = 0xff ,
CMD_IID = 0x90 ,
CMD_READ_STATUS = 0x70 ,
CMD_CLEAR_STATUS = 0x50 ,
CMD_ERASE_SETUP = 0x20 ,
CMD_ERASE_CONFIRM = 0xd0 ,
CMD_ERASE_SUSPEND = 0xb0 ,
2017-05-05 01:49:42 +02:00
CMD_PROGRAM_SETUP = 0x40 ,
CMD_PROGRAM_SETUP_ALT = 0x10
2016-06-26 00:34:39 +02:00
} ;
typedef struct flash_t
{
2016-11-04 22:32:23 +01:00
uint8_t command , status ;
uint8_t flash_id ;
int invert_high_pin ;
2016-07-05 19:29:31 +02:00
mem_mapping_t mapping [ 8 ] , mapping_h [ 8 ] ;
uint32_t block_start [ 4 ] , block_end [ 4 ] , block_len [ 4 ] ;
uint8_t array [ 131072 ] ;
2016-06-26 00:34:39 +02:00
} flash_t ;
2017-05-06 04:02:03 +02:00
static wchar_t flash_path [ 1024 ] ;
2016-06-26 00:34:39 +02:00
static uint8_t flash_read ( uint32_t addr , void * p )
{
flash_t * flash = ( flash_t * ) p ;
2016-07-05 19:29:31 +02:00
if ( flash - > invert_high_pin )
{
addr ^ = 0x10000 ;
if ( addr & 0xfff00000 ) return flash - > array [ addr & 0x1ffff ] ;
}
addr & = 0x1ffff ;
2016-06-26 00:34:39 +02:00
switch ( flash - > command )
{
2016-07-05 19:29:31 +02:00
case CMD_READ_ARRAY :
default :
return flash - > array [ addr ] ;
2016-06-26 00:34:39 +02:00
case CMD_IID :
if ( addr & 1 )
return flash - > flash_id ;
return 0x89 ;
2016-07-05 19:29:31 +02:00
case CMD_READ_STATUS :
return flash - > status ;
2016-06-26 00:34:39 +02:00
}
}
2016-07-05 19:29:31 +02:00
static uint16_t flash_readw ( uint32_t addr , void * p )
{
flash_t * flash = ( flash_t * ) p ;
2017-06-16 06:44:11 +02:00
uint16_t * q ;
2016-07-05 19:29:31 +02:00
addr & = 0x1ffff ;
2016-11-04 22:32:23 +01:00
if ( flash - > invert_high_pin ) addr ^ = 0x10000 ;
2017-06-16 06:44:11 +02:00
q = ( uint16_t * ) & ( flash - > array [ addr ] ) ;
return * q ;
2016-07-05 19:29:31 +02:00
}
static uint32_t flash_readl ( uint32_t addr , void * p )
{
flash_t * flash = ( flash_t * ) p ;
2017-06-16 06:44:11 +02:00
uint32_t * q ;
2016-07-05 19:29:31 +02:00
addr & = 0x1ffff ;
if ( flash - > invert_high_pin ) addr ^ = 0x10000 ;
2017-06-16 06:44:11 +02:00
q = ( uint32_t * ) & ( flash - > array [ addr ] ) ;
return * q ;
2016-07-05 19:29:31 +02:00
}
2016-06-26 00:34:39 +02:00
static void flash_write ( uint32_t addr , uint8_t val , void * p )
{
flash_t * flash = ( flash_t * ) p ;
int i ;
2016-07-05 19:29:31 +02:00
if ( flash - > invert_high_pin )
{
addr ^ = 0x10000 ;
if ( addr & 0xfff00000 ) return ;
}
addr & = 0x1ffff ;
2016-06-26 00:34:39 +02:00
switch ( flash - > command )
{
case CMD_ERASE_SETUP :
if ( val = = CMD_ERASE_CONFIRM )
{
2016-07-05 19:29:31 +02:00
for ( i = 0 ; i < 3 ; i + + )
{
if ( ( addr > = flash - > block_start [ i ] ) & & ( addr < = flash - > block_end [ i ] ) )
memset ( & ( flash - > array [ flash - > block_start [ i ] ] ) , 0xff , flash - > block_len [ i ] ) ;
}
2016-06-26 00:34:39 +02:00
flash - > status = 0x80 ;
}
flash - > command = CMD_READ_STATUS ;
break ;
case CMD_PROGRAM_SETUP :
2017-05-05 01:49:42 +02:00
case CMD_PROGRAM_SETUP_ALT :
2016-07-05 19:29:31 +02:00
if ( ( addr & 0x1e000 ) ! = ( flash - > block_start [ 3 ] & 0x1e000 ) )
flash - > array [ addr ] = val ;
2016-06-26 00:34:39 +02:00
flash - > command = CMD_READ_STATUS ;
flash - > status = 0x80 ;
break ;
default :
flash - > command = val ;
switch ( val )
{
case CMD_CLEAR_STATUS :
flash - > status = 0 ;
2016-07-05 19:29:31 +02:00
break ;
2016-06-26 00:34:39 +02:00
}
}
}
2016-11-04 22:32:23 +01:00
static void intel_flash_add_mappings ( flash_t * flash )
2016-07-05 19:29:31 +02:00
{
int i = 0 ;
for ( i = 0 ; i < = 7 ; i + + )
{
2016-11-04 22:32:23 +01:00
mem_mapping_add ( & ( flash - > mapping [ i ] ) , 0xe0000 + ( i < < 14 ) , 0x04000 , flash_read , flash_readw , flash_readl , flash_write , mem_write_nullw , mem_write_nulll , flash - > array + ( ( i < < 14 ) & 0x1ffff ) , MEM_MAPPING_EXTERNAL , ( void * ) flash ) ;
mem_mapping_add ( & ( flash - > mapping_h [ i ] ) , 0xfffe0000 + ( i < < 14 ) , 0x04000 , flash_read , flash_readw , flash_readl , flash_write , mem_write_nullw , mem_write_nulll , flash - > array + ( ( i < < 14 ) & 0x1ffff ) , 0 , ( void * ) flash ) ;
2016-07-05 19:29:31 +02:00
}
}
/* This is for boards which invert the high pin - the flash->array pointers need to pointer invertedly in order for INTERNAL writes to go to the right part of the array. */
2016-11-04 22:32:23 +01:00
static void intel_flash_add_mappings_inverted ( flash_t * flash )
2016-07-05 19:29:31 +02:00
{
int i = 0 ;
for ( i = 0 ; i < = 7 ; i + + )
{
2016-11-04 22:32:23 +01:00
mem_mapping_add ( & ( flash - > mapping [ i ] ) , 0xe0000 + ( i < < 14 ) , 0x04000 , flash_read , flash_readw , flash_readl , flash_write , mem_write_nullw , mem_write_nulll , flash - > array + ( ( ( i < < 14 ) ^ 0x10000 ) & 0x1ffff ) , MEM_MAPPING_EXTERNAL , ( void * ) flash ) ;
mem_mapping_add ( & ( flash - > mapping_h [ i ] ) , 0xfffe0000 + ( i < < 14 ) , 0x04000 , flash_read , flash_readw , flash_readl , flash_write , mem_write_nullw , mem_write_nulll , flash - > array + ( ( ( i < < 14 ) ^ 0x10000 ) & 0x1ffff ) , 0 , ( void * ) flash ) ;
2016-07-05 19:29:31 +02:00
}
}
void * intel_flash_init ( uint8_t type )
2016-06-26 00:34:39 +02:00
{
FILE * f ;
2016-07-05 19:29:31 +02:00
int i ;
2017-05-05 01:49:42 +02:00
flash_t * flash ;
2017-09-02 20:39:57 +02:00
wchar_t * machine_name ;
2017-06-08 00:58:47 +02:00
wchar_t * flash_name ;
2017-05-05 01:49:42 +02:00
flash = malloc ( sizeof ( flash_t ) ) ;
memset ( flash , 0 , sizeof ( flash_t ) ) ;
2016-06-26 00:34:39 +02:00
2017-09-02 20:39:57 +02:00
machine_name = ( wchar_t * ) malloc ( ( strlen ( machine_get_internal_name_ex ( machine ) ) < < 1 ) + 2 ) ;
mbstowcs ( machine_name , machine_get_internal_name_ex ( machine ) , strlen ( machine_get_internal_name_ex ( machine ) ) + 1 ) ;
flash_name = ( wchar_t * ) malloc ( ( wcslen ( machine_name ) < < 1 ) + 2 + 8 ) ;
_swprintf ( flash_name , L " %s.bin " , machine_name ) ;
2017-06-08 00:58:47 +02:00
wcscpy ( flash_path , flash_name ) ;
2017-10-03 16:26:55 -04:00
pclog ( " Flash path: %ws \n " , flash_name ) ;
2016-06-26 00:34:39 +02:00
2016-11-04 22:32:23 +01:00
flash - > flash_id = ( type & FLASH_IS_BXB ) ? 0x95 : 0x94 ;
flash - > invert_high_pin = ( type & FLASH_INVERT ) ;
2016-07-05 19:29:31 +02:00
/* The block lengths are the same both flash types. */
2016-11-04 22:32:23 +01:00
flash - > block_len [ BLOCK_MAIN ] = 0x1c000 ;
flash - > block_len [ BLOCK_DATA1 ] = 0x01000 ;
flash - > block_len [ BLOCK_DATA2 ] = 0x01000 ;
flash - > block_len [ BLOCK_BOOT ] = 0x02000 ;
2016-07-05 19:29:31 +02:00
2016-11-04 22:32:23 +01:00
if ( type & FLASH_IS_BXB ) /* 28F001BX-B */
2016-06-26 00:34:39 +02:00
{
2016-11-04 22:32:23 +01:00
flash - > block_start [ BLOCK_MAIN ] = 0x04000 ; /* MAIN BLOCK */
flash - > block_end [ BLOCK_MAIN ] = 0x1ffff ;
flash - > block_start [ BLOCK_DATA1 ] = 0x03000 ; /* DATA AREA 1 BLOCK */
flash - > block_end [ BLOCK_DATA1 ] = 0x03fff ;
flash - > block_start [ BLOCK_DATA2 ] = 0x04000 ; /* DATA AREA 2 BLOCK */
flash - > block_end [ BLOCK_DATA2 ] = 0x04fff ;
flash - > block_start [ BLOCK_BOOT ] = 0x00000 ; /* BOOT BLOCK */
flash - > block_end [ BLOCK_BOOT ] = 0x01fff ;
2016-07-05 19:29:31 +02:00
}
else /* 28F001BX-T */
{
2016-11-04 22:32:23 +01:00
flash - > block_start [ BLOCK_MAIN ] = 0x00000 ; /* MAIN BLOCK */
flash - > block_end [ BLOCK_MAIN ] = 0x1bfff ;
flash - > block_start [ BLOCK_DATA1 ] = 0x1c000 ; /* DATA AREA 1 BLOCK */
flash - > block_end [ BLOCK_DATA1 ] = 0x1cfff ;
flash - > block_start [ BLOCK_DATA2 ] = 0x1d000 ; /* DATA AREA 2 BLOCK */
flash - > block_end [ BLOCK_DATA2 ] = 0x1dfff ;
flash - > block_start [ BLOCK_BOOT ] = 0x1e000 ; /* BOOT BLOCK */
flash - > block_end [ BLOCK_BOOT ] = 0x1ffff ;
2016-06-26 00:34:39 +02:00
}
2016-07-05 19:29:31 +02:00
for ( i = 0 ; i < 8 ; i + + )
2016-06-26 00:34:39 +02:00
{
2016-07-05 19:29:31 +02:00
mem_mapping_disable ( & bios_mapping [ i ] ) ;
mem_mapping_disable ( & bios_high_mapping [ i ] ) ;
2016-06-26 00:34:39 +02:00
}
2016-07-05 19:29:31 +02:00
if ( flash - > invert_high_pin )
2016-06-26 00:34:39 +02:00
{
2016-07-05 19:29:31 +02:00
memcpy ( flash - > array , rom + 65536 , 65536 ) ;
memcpy ( flash - > array + 65536 , rom , 65536 ) ;
2016-06-26 00:34:39 +02:00
}
else
{
2016-07-05 19:29:31 +02:00
memcpy ( flash - > array , rom , 131072 ) ;
2016-06-26 00:34:39 +02:00
}
2016-07-05 19:29:31 +02:00
if ( flash - > invert_high_pin )
2016-06-26 00:34:39 +02:00
{
2016-07-05 19:29:31 +02:00
intel_flash_add_mappings_inverted ( flash ) ;
2016-06-26 00:34:39 +02:00
}
2016-07-05 19:29:31 +02:00
else
{
intel_flash_add_mappings ( flash ) ;
}
flash - > command = CMD_READ_ARRAY ;
flash - > status = 0 ;
2017-10-03 16:26:55 -04:00
f = nvr_fopen ( flash_path , L " rb " ) ;
2016-07-05 19:29:31 +02:00
if ( f )
{
fread ( & ( flash - > array [ flash - > block_start [ BLOCK_MAIN ] ] ) , flash - > block_len [ BLOCK_MAIN ] , 1 , f ) ;
2016-11-04 22:32:23 +01:00
fread ( & ( flash - > array [ flash - > block_start [ BLOCK_DATA1 ] ] ) , flash - > block_len [ BLOCK_DATA1 ] , 1 , f ) ;
fread ( & ( flash - > array [ flash - > block_start [ BLOCK_DATA2 ] ] ) , flash - > block_len [ BLOCK_DATA2 ] , 1 , f ) ;
2016-06-26 00:34:39 +02:00
fclose ( f ) ;
}
2017-06-22 18:38:36 +02:00
free ( flash_name ) ;
2017-09-02 20:39:57 +02:00
free ( machine_name ) ;
2017-06-22 18:38:36 +02:00
2016-06-26 00:34:39 +02:00
return flash ;
}
2017-05-05 01:49:42 +02:00
void * intel_flash_bxb_ami_init ( )
{
return intel_flash_init ( FLASH_IS_BXB | FLASH_INVERT ) ;
}
2016-06-26 00:34:39 +02:00
/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */
void * intel_flash_bxt_ami_init ( )
{
2016-07-05 19:29:31 +02:00
return intel_flash_init ( FLASH_INVERT ) ;
2016-06-26 00:34:39 +02:00
}
/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */
void * intel_flash_bxt_init ( )
{
2016-07-05 19:29:31 +02:00
return intel_flash_init ( 0 ) ;
2016-06-26 00:34:39 +02:00
}
2016-07-05 19:29:31 +02:00
/* For Acer BIOS'es - Intel 28F001BXB. */
2016-06-26 00:34:39 +02:00
void * intel_flash_bxb_init ( )
{
2016-07-05 19:29:31 +02:00
return intel_flash_init ( FLASH_IS_BXB ) ;
2016-06-26 00:34:39 +02:00
}
void intel_flash_close ( void * p )
{
FILE * f ;
flash_t * flash = ( flash_t * ) p ;
2017-10-03 16:26:55 -04:00
f = nvr_fopen ( flash_path , L " wb " ) ;
2016-07-05 19:29:31 +02:00
fwrite ( & ( flash - > array [ flash - > block_start [ BLOCK_MAIN ] ] ) , flash - > block_len [ BLOCK_MAIN ] , 1 , f ) ;
2016-11-04 22:32:23 +01:00
fwrite ( & ( flash - > array [ flash - > block_start [ BLOCK_DATA1 ] ] ) , flash - > block_len [ BLOCK_DATA1 ] , 1 , f ) ;
fwrite ( & ( flash - > array [ flash - > block_start [ BLOCK_DATA2 ] ] ) , flash - > block_len [ BLOCK_DATA2 ] , 1 , f ) ;
2016-07-05 19:29:31 +02:00
fclose ( f ) ;
2016-11-04 22:32:23 +01:00
2016-06-26 00:34:39 +02:00
free ( flash ) ;
}
2017-10-07 00:46:54 -04:00
2016-06-26 00:34:39 +02:00
device_t intel_flash_bxt_ami_device =
{
" Intel 28F001BXT Flash BIOS " ,
2017-10-07 00:46:54 -04:00
0 , 0 ,
2016-06-26 00:34:39 +02:00
intel_flash_bxt_ami_init ,
intel_flash_close ,
2017-10-07 00:46:54 -04:00
NULL ,
NULL , NULL , NULL , NULL , NULL
2016-06-26 00:34:39 +02:00
} ;
2017-05-05 01:49:42 +02:00
device_t intel_flash_bxb_ami_device =
{
" Intel 28F001BXB Flash BIOS " ,
2017-10-07 00:46:54 -04:00
0 , 0 ,
2017-05-05 01:49:42 +02:00
intel_flash_bxb_ami_init ,
intel_flash_close ,
2017-10-07 00:46:54 -04:00
NULL ,
NULL , NULL , NULL , NULL , NULL
2017-05-05 01:49:42 +02:00
} ;
2016-06-26 00:34:39 +02:00
device_t intel_flash_bxt_device =
{
" Intel 28F001BXT Flash BIOS " ,
2017-10-07 00:46:54 -04:00
0 , 0 ,
2016-06-26 00:34:39 +02:00
intel_flash_bxt_init ,
intel_flash_close ,
2017-10-07 00:46:54 -04:00
NULL ,
NULL , NULL , NULL , NULL , NULL
2016-06-26 00:34:39 +02:00
} ;
device_t intel_flash_bxb_device =
{
2016-11-04 22:32:23 +01:00
" Intel 28F001BXB Flash BIOS " ,
2017-10-07 00:46:54 -04:00
0 , 0 ,
2016-06-26 00:34:39 +02:00
intel_flash_bxb_init ,
intel_flash_close ,
2017-10-07 00:46:54 -04:00
NULL ,
NULL , NULL , NULL , NULL , NULL
2016-06-26 00:34:39 +02:00
} ;