Files
86Box/src/intel_flash.c

332 lines
9.7 KiB
C
Raw Normal View History

/*
* 86Box 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 86Box distribution.
*
* Implementation of the Intel 1 Mbit 8-bit flash devices.
*
* Version: @(#)intel_flash.c 1.0.18 2018/10/30
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2018 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
2017-10-17 01:59:09 -04:00
#include "86box.h"
#include "device.h"
#include "mem.h"
#include "machine/machine.h"
#include "nvr.h"
#include "plat.h"
#define FLASH_IS_BXB 2
#define FLASH_INVERT 1
#define BLOCK_MAIN 0
#define BLOCK_DATA1 1
#define BLOCK_DATA2 2
#define BLOCK_BOOT 3
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,
CMD_PROGRAM_SETUP = 0x40,
CMD_PROGRAM_SETUP_ALT = 0x10
};
typedef struct flash_t
{
uint8_t command, status;
uint8_t flash_id;
int invert_high_pin;
uint32_t program_addr;
mem_mapping_t mapping[8], mapping_h[8];
uint32_t block_start[4], block_end[4], block_len[4];
uint8_t array[131072];
} flash_t;
static wchar_t flash_path[1024];
static uint8_t flash_read(uint32_t addr, void *p)
{
flash_t *flash = (flash_t *)p;
if (flash->invert_high_pin)
addr ^= 0x10000;
addr &= 0x1ffff;
switch (flash->command) {
case CMD_READ_ARRAY:
default:
return flash->array[addr];
case CMD_IID:
if (addr & 1)
return flash->flash_id;
return 0x89;
case CMD_READ_STATUS:
return flash->status;
}
}
static uint16_t flash_readw(uint32_t addr, void *p)
{
flash_t *flash = (flash_t *)p;
uint16_t *q;
addr &= 0x1ffff;
if (flash->invert_high_pin) addr ^= 0x10000;
q = (uint16_t *)&(flash->array[addr]);
return *q;
}
static uint32_t flash_readl(uint32_t addr, void *p)
{
flash_t *flash = (flash_t *)p;
uint32_t *q;
addr &= 0x1ffff;
if (flash->invert_high_pin) addr ^= 0x10000;
q = (uint32_t *)&(flash->array[addr]);
return *q;
}
static void flash_write(uint32_t addr, uint8_t val, void *p)
{
flash_t *flash = (flash_t *)p;
int i;
if (flash->invert_high_pin)
addr ^= 0x10000;
addr &= 0x1ffff;
switch (flash->command) {
case CMD_ERASE_SETUP:
if (val == CMD_ERASE_CONFIRM) {
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]);
}
flash->status = 0x80;
}
flash->command = CMD_READ_STATUS;
break;
case CMD_PROGRAM_SETUP:
case CMD_PROGRAM_SETUP_ALT:
if (((addr & 0x1e000) != (flash->block_start[3] & 0x1e000)) && (addr == flash->program_addr))
flash->array[addr] = val;
flash->command = CMD_READ_STATUS;
flash->status = 0x80;
break;
default:
flash->command = val;
switch (val) {
case CMD_CLEAR_STATUS:
flash->status = 0;
break;
case CMD_PROGRAM_SETUP:
case CMD_PROGRAM_SETUP_ALT:
flash->program_addr = addr;
break;
}
}
}
static void intel_flash_add_mappings(flash_t *flash)
{
int i = 0;
for (i = 0; i <= 7; i++) {
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);
}
}
/* 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. */
static void intel_flash_add_mappings_inverted(flash_t *flash)
{
int i = 0;
for (i = 0; i <= 7; i++) {
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);
}
}
void *intel_flash_init(uint8_t type)
{
FILE *f;
int i, l;
flash_t *flash;
wchar_t *machine_name;
wchar_t *flash_name;
flash = malloc(sizeof(flash_t));
memset(flash, 0, sizeof(flash_t));
l = strlen(machine_get_internal_name_ex(machine))+1;
machine_name = (wchar_t *) malloc(l * sizeof(wchar_t));
mbstowcs(machine_name, machine_get_internal_name_ex(machine), l);
l = wcslen(machine_name)+5;
flash_name = (wchar_t *)malloc(l*sizeof(wchar_t));
swprintf(flash_name, l, L"%ls.bin", machine_name);
wcscpy(flash_path, flash_name);
flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94;
flash->invert_high_pin = (type & FLASH_INVERT);
/* The block lengths are the same both flash types. */
flash->block_len[BLOCK_MAIN] = 0x1c000;
flash->block_len[BLOCK_DATA1] = 0x01000;
flash->block_len[BLOCK_DATA2] = 0x01000;
flash->block_len[BLOCK_BOOT] = 0x02000;
if (type & FLASH_IS_BXB) { /* 28F001BX-B */
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;
} else { /* 28F001BX-T */
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;
}
for (i = 0; i < 8; i++) {
mem_mapping_disable(&bios_mapping[i]);
mem_mapping_disable(&bios_high_mapping[i]);
}
if (flash->invert_high_pin) {
memcpy(flash->array, rom + 65536, 65536);
memcpy(flash->array + 65536, rom, 65536);
}
else
memcpy(flash->array, rom, 131072);
if (flash->invert_high_pin)
intel_flash_add_mappings_inverted(flash);
else
intel_flash_add_mappings(flash);
flash->command = CMD_READ_ARRAY;
flash->status = 0;
f = nvr_fopen(flash_path, L"rb");
if (f) {
fread(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f);
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);
fclose(f);
}
free(flash_name);
free(machine_name);
return flash;
}
void *intel_flash_bxb_ami_init()
{
return intel_flash_init(FLASH_IS_BXB | FLASH_INVERT);
}
/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */
void *intel_flash_bxt_ami_init()
{
return intel_flash_init(FLASH_INVERT);
}
/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */
void *intel_flash_bxt_init()
{
return intel_flash_init(0);
}
/* For Acer BIOS'es - Intel 28F001BXB. */
void *intel_flash_bxb_init()
{
return intel_flash_init(FLASH_IS_BXB);
}
void intel_flash_close(void *p)
{
FILE *f;
flash_t *flash = (flash_t *)p;
f = nvr_fopen(flash_path, L"wb");
fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f);
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);
fclose(f);
free(flash);
}
const device_t intel_flash_bxt_ami_device =
{
"Intel 28F001BXT Flash BIOS",
0, 0,
intel_flash_bxt_ami_init,
intel_flash_close,
NULL,
NULL, NULL, NULL, NULL
};
const device_t intel_flash_bxb_ami_device =
{
"Intel 28F001BXB Flash BIOS",
0, 0,
intel_flash_bxb_ami_init,
intel_flash_close,
NULL,
NULL, NULL, NULL, NULL
};
const device_t intel_flash_bxt_device =
{
"Intel 28F001BXT Flash BIOS",
0, 0,
intel_flash_bxt_init,
intel_flash_close,
NULL,
NULL, NULL, NULL, NULL
};
const device_t intel_flash_bxb_device =
{
"Intel 28F001BXB Flash BIOS",
0, 0,
intel_flash_bxb_init,
intel_flash_close,
NULL,
NULL, NULL, NULL, NULL
};