mirror of
https://github.com/86Box/86Box.git
synced 2026-02-21 17:15:32 -07:00
Merge branch 'master' of https://github.com/86Box/86Box
This commit is contained in:
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -25,7 +25,7 @@ If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. Windows 10]
|
||||
- 86Box version: [e.g. v2.06 build 2007]
|
||||
- 86Box version: [e.g. v2.06 build 2007, saying "Latest from Jenkins" isn't helpful]
|
||||
- Build type: [i.e. regular, optimized, or dev]
|
||||
|
||||
**Additional context**
|
||||
|
||||
2
.github/workflows/c-cpp.yml
vendored
2
.github/workflows/c-cpp.yml
vendored
@@ -34,5 +34,5 @@ jobs:
|
||||
install: 'make mingw-w64-i686-toolchain mingw-w64-i686-openal mingw-w64-i686-freetype mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-libpng mingw-w64-i686-libvncserver'
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: make -fwin/makefile.mingw DEV_BUILD=${{ matrix.dev-build }} NEW_DYNAREC=${{ matrix.new-dynarec }} VNC=n
|
||||
run: make -fwin/makefile.mingw -j DEV_BUILD=${{ matrix.dev-build }} NEW_DYNAREC=${{ matrix.new-dynarec }} VNC=n
|
||||
working-directory: ./src
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ src/*.dmp
|
||||
src/NUL
|
||||
src/nvr/
|
||||
src/roms/
|
||||
/.vs
|
||||
|
||||
68
src/acpi.c
68
src/acpi.c
@@ -39,6 +39,9 @@
|
||||
#include <86box/i2c.h>
|
||||
|
||||
|
||||
int acpi_rtc_status = 0;
|
||||
|
||||
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
int acpi_do_log = ENABLE_ACPI_LOG;
|
||||
|
||||
@@ -119,6 +122,8 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p)
|
||||
case 0x00: case 0x01:
|
||||
/* PMSTS - Power Management Status Register (IO) */
|
||||
ret = (dev->regs.pmsts >> shift16) & 0xff;
|
||||
if (addr == 0x01)
|
||||
ret |= (acpi_rtc_status << 2);
|
||||
break;
|
||||
case 0x02: case 0x03:
|
||||
/* PMEN - Power Management Resume Enable Register (IO) */
|
||||
@@ -127,6 +132,8 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p)
|
||||
case 0x04: case 0x05:
|
||||
/* PMCNTRL - Power Management Control Register (IO) */
|
||||
ret = (dev->regs.pmcntrl >> shift16) & 0xff;
|
||||
if (addr == 0x05)
|
||||
ret = (ret & 0xdf) | 0x02; /* Bit 5 is write-only. */
|
||||
break;
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
/* PMTMR - Power Management Timer Register (IO) */
|
||||
@@ -138,7 +145,10 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p)
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -211,7 +221,10 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p)
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -285,7 +298,10 @@ acpi_reg_read_via_common(int size, uint16_t addr, void *p)
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -338,7 +354,10 @@ acpi_reg_read_via(int size, uint16_t addr, void *p)
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -372,7 +391,10 @@ acpi_reg_read_via_596b(int size, uint16_t addr, void *p)
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -386,7 +408,10 @@ acpi_reg_read_smc(int size, uint16_t addr, void *p)
|
||||
|
||||
ret = acpi_reg_read_common_regs(size, addr, p);
|
||||
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -436,13 +461,18 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p)
|
||||
int shift16, sus_typ;
|
||||
|
||||
addr &= 0x3f;
|
||||
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
||||
#endif
|
||||
shift16 = (addr & 1) << 3;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: case 0x01:
|
||||
/* PMSTS - Power Management Status Register (IO) */
|
||||
dev->regs.pmsts &= ~((val << shift16) & 0x8d31);
|
||||
if ((addr == 0x01) && (val & 0x04))
|
||||
acpi_rtc_status = 0;
|
||||
acpi_update_irq(dev);
|
||||
break;
|
||||
case 0x02: case 0x03:
|
||||
@@ -452,8 +482,7 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p)
|
||||
break;
|
||||
case 0x04: case 0x05:
|
||||
/* PMCNTRL - Power Management Control Register (IO) */
|
||||
dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07;
|
||||
if (dev->regs.pmcntrl & 0x2000) {
|
||||
if ((addr == 0x05) && (dev->regs.pmcntrl & 0x2000)) {
|
||||
sus_typ = (dev->regs.pmcntrl >> 10) & 7;
|
||||
switch (sus_typ) {
|
||||
case 0:
|
||||
@@ -479,8 +508,12 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p)
|
||||
|
||||
resetx86();
|
||||
break;
|
||||
default:
|
||||
dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -493,7 +526,10 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p)
|
||||
int shift16, shift32;
|
||||
|
||||
addr &= 0x3f;
|
||||
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
||||
#ifdef ENABLE_ACPI_LOG
|
||||
if (size != 1)
|
||||
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
||||
#endif
|
||||
shift16 = (addr & 1) << 3;
|
||||
shift32 = (addr & 3) << 3;
|
||||
|
||||
@@ -876,6 +912,8 @@ acpi_reg_read(uint16_t addr, void *p)
|
||||
|
||||
ret = acpi_reg_read_common(1, addr, p);
|
||||
|
||||
acpi_log("ACPI: Read B %02X from %04X\n", ret, addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -924,6 +962,8 @@ acpi_aux_read_read(uint16_t addr, void *p)
|
||||
static void
|
||||
acpi_reg_writel(uint16_t addr, uint32_t val, void *p)
|
||||
{
|
||||
acpi_log("ACPI: Write L %08X to %04X\n", val, addr);
|
||||
|
||||
acpi_reg_write_common(4, addr, val & 0xff, p);
|
||||
acpi_reg_write_common(4, addr + 1, (val >> 8) & 0xff, p);
|
||||
acpi_reg_write_common(4, addr + 2, (val >> 16) & 0xff, p);
|
||||
@@ -934,6 +974,8 @@ acpi_reg_writel(uint16_t addr, uint32_t val, void *p)
|
||||
static void
|
||||
acpi_reg_writew(uint16_t addr, uint16_t val, void *p)
|
||||
{
|
||||
acpi_log("ACPI: Write W %04X to %04X\n", val, addr);
|
||||
|
||||
acpi_reg_write_common(2, addr, val & 0xff, p);
|
||||
acpi_reg_write_common(2, addr + 1, (val >> 8) & 0xff, p);
|
||||
}
|
||||
@@ -942,6 +984,8 @@ acpi_reg_writew(uint16_t addr, uint16_t val, void *p)
|
||||
static void
|
||||
acpi_reg_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
acpi_log("ACPI: Write B %02X to %04X\n", val, addr);
|
||||
|
||||
acpi_reg_write_common(1, addr, val, p);
|
||||
}
|
||||
|
||||
@@ -1196,6 +1240,8 @@ acpi_reset(void *priv)
|
||||
if (!strcmp(machines[machine].internal_name, "ficva503a"))
|
||||
dev->regs.gpi_val |= 0x00000004;
|
||||
}
|
||||
|
||||
acpi_rtc_status = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ sio_timer_read(uint16_t addr, void *priv)
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (!(addr & 0x0002)) {
|
||||
sub_cycles((int)(PITCONST >> 32));
|
||||
cycles -= ((int) (PITCONST >> 32));
|
||||
|
||||
sio_timer_latch = timer_get_remaining_us(&dev->timer);
|
||||
|
||||
@@ -126,7 +126,7 @@ sio_timer_readw(uint16_t addr, void *priv)
|
||||
uint16_t ret = 0xffff;
|
||||
|
||||
if (!(addr & 0x0002)) {
|
||||
sub_cycles((int)(PITCONST >> 32));
|
||||
cycles -= ((int) (PITCONST >> 32));
|
||||
|
||||
ret = timer_get_remaining_us(&dev->timer);
|
||||
}
|
||||
|
||||
@@ -1026,9 +1026,10 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemb386l);
|
||||
call_long((uintptr_t)readmembl);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -1105,8 +1106,9 @@ static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemwl);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -1190,8 +1192,9 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemll);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -1269,8 +1272,9 @@ static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemql);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -1394,10 +1398,11 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
load_param_3_reg_32(host_reg);
|
||||
call_long((uintptr_t)writememb386l);
|
||||
load_param_2_reg_32(host_reg);
|
||||
call_long((uintptr_t)writemembl);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -1485,9 +1490,10 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
load_param_3_reg_32(host_reg);
|
||||
load_param_2_reg_32(host_reg);
|
||||
call_long((uintptr_t)writememwl);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -1574,9 +1580,10 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
load_param_3_reg_32(host_reg);
|
||||
load_param_2_reg_32(host_reg);
|
||||
call_long((uintptr_t)writememll);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -1664,9 +1671,10 @@ static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12+4+6);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
load_param_3_reg_64(host_reg);
|
||||
load_param_2_reg_64(host_reg);
|
||||
call_long((uintptr_t)writememql);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -5763,9 +5771,10 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemb386l);
|
||||
call_long((uintptr_t)readmembl);
|
||||
addbyte(0x89); /*MOV ECX, EAX*/
|
||||
addbyte(0xc1);
|
||||
/*done:*/
|
||||
@@ -5841,8 +5850,9 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemwl);
|
||||
addbyte(0x89); /*MOV ECX, EAX*/
|
||||
addbyte(0xc1);
|
||||
@@ -5918,8 +5928,9 @@ static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+12);
|
||||
/*slowpath:*/
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)readmemll);
|
||||
addbyte(0x89); /*MOV ECX, EAX*/
|
||||
addbyte(0xc1);
|
||||
@@ -6023,10 +6034,11 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12);
|
||||
/*slowpath:*/
|
||||
load_param_3_reg_32(host_reg);
|
||||
load_param_1_reg_32(REG_EBX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
call_long((uintptr_t)writememb386l);
|
||||
load_param_2_reg_32(host_reg);
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
call_long((uintptr_t)writemembl);
|
||||
/*done:*/
|
||||
}
|
||||
static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg)
|
||||
@@ -6107,9 +6119,10 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12);
|
||||
/*slowpath:*/
|
||||
load_param_3_reg_32(host_reg);
|
||||
load_param_1_reg_32(REG_EBX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
load_param_2_reg_32(host_reg);
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
call_long((uintptr_t)writememwl);
|
||||
/*done:*/
|
||||
}
|
||||
@@ -6189,9 +6202,10 @@ static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg)
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(2+2+3+12);
|
||||
/*slowpath:*/
|
||||
load_param_3_reg_32(host_reg);
|
||||
load_param_1_reg_32(REG_EBX);
|
||||
load_param_2_reg_32(REG_EAX);
|
||||
load_param_2_reg_32(host_reg);
|
||||
addbyte(0x01); /*ADD ECX,EAX*/
|
||||
addbyte(0xc1);
|
||||
load_param_1_reg_32(REG_ECX);
|
||||
call_long((uintptr_t)writememll);
|
||||
/*done:*/
|
||||
}
|
||||
|
||||
@@ -148,13 +148,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B()
|
||||
addbyte(0x3a);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmembl*/
|
||||
addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addlong((uint32_t)readmembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -203,13 +204,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W()
|
||||
addbyte(0x3a);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmemwl*/
|
||||
addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -257,13 +259,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L()
|
||||
addbyte(0x3a);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmemll*/
|
||||
addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -312,13 +315,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_Q()
|
||||
addbyte(4);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmemql*/
|
||||
addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -360,13 +364,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B()
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EBX,EAX*/
|
||||
addbyte(0xC3);
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0xe8); /*CALL writememb386l*/
|
||||
addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0xe8); /*CALL writemembl*/
|
||||
addlong((uint32_t)writemembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0xc4);
|
||||
addbyte(12);
|
||||
addbyte(8);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -414,13 +419,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W()
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EBX,EAX*/
|
||||
addbyte(0xC3);
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0xe8); /*CALL writememwl*/
|
||||
addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0xc4);
|
||||
addbyte(12);
|
||||
addbyte(8);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -467,13 +473,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L()
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EBX,EAX*/
|
||||
addbyte(0xC3);
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0xe8); /*CALL writememll*/
|
||||
addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0xc4);
|
||||
addbyte(12);
|
||||
addbyte(8);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -525,13 +532,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_Q()
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EDX,EAX*/
|
||||
addbyte(0xC2);
|
||||
addbyte(0x52); /*PUSH EDX*/
|
||||
addbyte(0xe8); /*CALL writememql*/
|
||||
addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 16*/
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0xc4);
|
||||
addbyte(16);
|
||||
addbyte(12);
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
addbyte((uint8_t)cpu_state_offset(abrt));
|
||||
@@ -575,13 +583,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT()
|
||||
addbyte(0x3a);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmembl*/
|
||||
addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addlong((uint32_t)readmembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
#ifndef RELEASE_BUILD
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -644,13 +653,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT()
|
||||
addbyte(0x3a);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmemwl*/
|
||||
addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
#ifndef RELEASE_BUILD
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -712,13 +722,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT()
|
||||
addbyte(0x3a);
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x50); /*slowpath: PUSH EAX*/
|
||||
addbyte(0x01); /*slowpath: ADD ESI,EAX*/
|
||||
addbyte(0xc6);
|
||||
addbyte(0x56); /*PUSH ESI*/
|
||||
addbyte(0xe8); /*CALL readmemll*/
|
||||
addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0x83); /*ADD ESP, 4*/
|
||||
addbyte(0xc4);
|
||||
addbyte(8);
|
||||
addbyte(4);
|
||||
addbyte(0x89); /*MOV ECX, EAX*/
|
||||
addbyte(0xc1);
|
||||
#ifndef RELEASE_BUILD
|
||||
@@ -777,13 +788,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT()
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EBX,EAX*/
|
||||
addbyte(0xc3);
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0xe8); /*CALL writememb386l*/
|
||||
addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0xe8); /*CALL writemembl*/
|
||||
addlong((uint32_t)writemembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0xc4);
|
||||
addbyte(12);
|
||||
addbyte(8);
|
||||
#ifndef RELEASE_BUILD
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -843,13 +855,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT()
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EBX,EAX*/
|
||||
addbyte(0xC3);
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0xe8); /*CALL writememwl*/
|
||||
addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0xc4);
|
||||
addbyte(12);
|
||||
addbyte(8);
|
||||
#ifndef RELEASE_BUILD
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
@@ -908,13 +921,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT()
|
||||
addbyte(0xc3); /*RET*/
|
||||
|
||||
addbyte(0x51); /*slowpath: PUSH ECX*/
|
||||
addbyte(0x50); /*PUSH EAX*/
|
||||
addbyte(0x01); /*ADD EBX,EAX*/
|
||||
addbyte(0xC3);
|
||||
addbyte(0x53); /*PUSH EBX*/
|
||||
addbyte(0xe8); /*CALL writememll*/
|
||||
addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
|
||||
addbyte(0x83); /*ADD ESP, 12*/
|
||||
addbyte(0x83); /*ADD ESP, 8*/
|
||||
addbyte(0xc4);
|
||||
addbyte(12);
|
||||
addbyte(8);
|
||||
#ifndef RELEASE_BUILD
|
||||
addbyte(0x80); /*CMP abrt, 0*/
|
||||
addbyte(0x7d);
|
||||
|
||||
136
src/config.c
136
src/config.c
@@ -113,6 +113,7 @@ static list_t config_head;
|
||||
|
||||
/* TODO: Backwards compatibility, get rid of this when enough time has passed. */
|
||||
static int backwards_compat = 0;
|
||||
static int backwards_compat2 = 0;
|
||||
|
||||
|
||||
#ifdef ENABLE_CONFIG_LOG
|
||||
@@ -487,6 +488,7 @@ load_general(void)
|
||||
|
||||
confirm_reset = config_get_int(cat, "confirm_reset", 1);
|
||||
confirm_exit = config_get_int(cat, "confirm_exit", 1);
|
||||
confirm_save = config_get_int(cat, "confirm_save", 1);
|
||||
|
||||
#ifdef USE_LANGUAGE
|
||||
/*
|
||||
@@ -872,14 +874,16 @@ load_ports(void)
|
||||
}
|
||||
|
||||
|
||||
/* Load "Other Peripherals" section. */
|
||||
/* Load "Storage Controllers" section. */
|
||||
static void
|
||||
load_other_peripherals(void)
|
||||
load_storage_controllers(void)
|
||||
{
|
||||
char *cat = "Other peripherals";
|
||||
char *cat = "Storage controllers";
|
||||
char *p;
|
||||
char temp[512];
|
||||
int c, free_p = 0;
|
||||
int free_p = 0;
|
||||
|
||||
/* TODO: Backwards compatibility, get rid of this when enough time has passed. */
|
||||
backwards_compat2 = (find_section(cat) == NULL);
|
||||
|
||||
p = config_get_string(cat, "scsicard", NULL);
|
||||
if (p != NULL)
|
||||
@@ -920,19 +924,6 @@ load_other_peripherals(void)
|
||||
|
||||
ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0);
|
||||
ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0);
|
||||
|
||||
bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0);
|
||||
postcard_enabled = !!config_get_int(cat, "postcard_enabled", 0);
|
||||
|
||||
for (c = 0; c < ISAMEM_MAX; c++) {
|
||||
sprintf(temp, "isamem%d_type", c);
|
||||
|
||||
p = config_get_string(cat, temp, "none");
|
||||
isamem_type[c] = isamem_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
p = config_get_string(cat, "isartc_type", "none");
|
||||
isartc_type = isartc_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,6 +1052,11 @@ load_hard_disks(void)
|
||||
* files. We should remove this before
|
||||
* finalizing this release! --FvK
|
||||
*/
|
||||
/*
|
||||
* ANOTHER NOTE:
|
||||
* When loading differencing VHDs, the absolute path is required.
|
||||
* So we should not convert absolute paths to relative. -sards
|
||||
*/
|
||||
if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) {
|
||||
/*
|
||||
* Yep, its absolute and prefixed
|
||||
@@ -1512,7 +1508,6 @@ load_other_removable_devices(void)
|
||||
sprintf(temp, "zip_%02i_iso_path", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
|
||||
|
||||
memset(temp, 0x00, sizeof(temp));
|
||||
for (c=0; c<MO_NUM; c++) {
|
||||
@@ -1578,6 +1573,78 @@ load_other_removable_devices(void)
|
||||
}
|
||||
|
||||
|
||||
/* Load "Other Peripherals" section. */
|
||||
static void
|
||||
load_other_peripherals(void)
|
||||
{
|
||||
char *cat = "Other peripherals";
|
||||
char *p;
|
||||
char temp[512];
|
||||
int c, free_p = 0;
|
||||
|
||||
if (backwards_compat2) {
|
||||
p = config_get_string(cat, "scsicard", NULL);
|
||||
if (p != NULL)
|
||||
scsi_card_current = scsi_card_get_from_internal_name(p);
|
||||
else
|
||||
scsi_card_current = 0;
|
||||
config_delete_var(cat, "scsicard");
|
||||
|
||||
p = config_get_string(cat, "fdc", NULL);
|
||||
if (p != NULL)
|
||||
fdc_type = fdc_card_get_from_internal_name(p);
|
||||
else
|
||||
fdc_type = FDC_INTERNAL;
|
||||
config_delete_var(cat, "fdc");
|
||||
|
||||
p = config_get_string(cat, "hdc", NULL);
|
||||
if (p == NULL) {
|
||||
if (machines[machine].flags & MACHINE_HDC) {
|
||||
p = (char *)malloc((strlen("internal")+1)*sizeof(char));
|
||||
strcpy(p, "internal");
|
||||
} else {
|
||||
p = (char *)malloc((strlen("none")+1)*sizeof(char));
|
||||
strcpy(p, "none");
|
||||
}
|
||||
free_p = 1;
|
||||
}
|
||||
if (!strcmp(p, "mfm_xt"))
|
||||
hdc_current = hdc_get_from_internal_name("st506_xt");
|
||||
else if (!strcmp(p, "mfm_xt_dtc5150x"))
|
||||
hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x");
|
||||
else if (!strcmp(p, "mfm_at"))
|
||||
hdc_current = hdc_get_from_internal_name("st506_at");
|
||||
else
|
||||
hdc_current = hdc_get_from_internal_name(p);
|
||||
config_delete_var(cat, "hdc");
|
||||
|
||||
if (free_p) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0);
|
||||
config_delete_var(cat, "ide_ter");
|
||||
ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0);
|
||||
config_delete_var(cat, "ide_qua");
|
||||
}
|
||||
backwards_compat2 = 0;
|
||||
|
||||
bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0);
|
||||
postcard_enabled = !!config_get_int(cat, "postcard_enabled", 0);
|
||||
|
||||
for (c = 0; c < ISAMEM_MAX; c++) {
|
||||
sprintf(temp, "isamem%d_type", c);
|
||||
|
||||
p = config_get_string(cat, temp, "none");
|
||||
isamem_type[c] = isamem_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
p = config_get_string(cat, "isartc_type", "none");
|
||||
isartc_type = isartc_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
|
||||
/* Load the specified or a default configuration file. */
|
||||
void
|
||||
config_load(void)
|
||||
@@ -1642,12 +1709,13 @@ config_load(void)
|
||||
load_sound(); /* Sound */
|
||||
load_network(); /* Network */
|
||||
load_ports(); /* Ports (COM & LPT) */
|
||||
load_other_peripherals(); /* Other peripherals */
|
||||
load_storage_controllers(); /* Storage controllers */
|
||||
load_hard_disks(); /* Hard disks */
|
||||
load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */
|
||||
/* TODO: Backwards compatibility, get rid of this when enough time has passed. */
|
||||
load_floppy_drives(); /* Floppy drives */
|
||||
load_other_removable_devices(); /* Other removable devices */
|
||||
load_other_peripherals(); /* Other peripherals */
|
||||
|
||||
/* Mark the configuration as changed. */
|
||||
config_changed = 1;
|
||||
@@ -1756,6 +1824,11 @@ save_general(void)
|
||||
else
|
||||
config_delete_var(cat, "confirm_exit");
|
||||
|
||||
if (confirm_save != 1)
|
||||
config_set_int(cat, "confirm_save", confirm_save);
|
||||
else
|
||||
config_delete_var(cat, "confirm_save");
|
||||
|
||||
#ifdef USE_LANGUAGE
|
||||
if (plat_langid == 0x0409)
|
||||
config_delete_var(cat, "language");
|
||||
@@ -2069,13 +2142,11 @@ save_ports(void)
|
||||
}
|
||||
|
||||
|
||||
/* Save "Other Peripherals" section. */
|
||||
/* Save "Storage Controllers" section. */
|
||||
static void
|
||||
save_other_peripherals(void)
|
||||
save_storage_controllers(void)
|
||||
{
|
||||
char *cat = "Other peripherals";
|
||||
char temp[512];
|
||||
int c;
|
||||
char *cat = "Storage controllers";
|
||||
|
||||
if (scsi_card_current == 0)
|
||||
config_delete_var(cat, "scsicard");
|
||||
@@ -2102,6 +2173,18 @@ save_other_peripherals(void)
|
||||
else
|
||||
config_set_int(cat, "ide_qua", ide_qua_enabled);
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
|
||||
|
||||
/* Save "Other Peripherals" section. */
|
||||
static void
|
||||
save_other_peripherals(void)
|
||||
{
|
||||
char *cat = "Other peripherals";
|
||||
char temp[512];
|
||||
int c;
|
||||
|
||||
if (bugger_enabled == 0)
|
||||
config_delete_var(cat, "bugger_enabled");
|
||||
else
|
||||
@@ -2390,10 +2473,11 @@ config_save(void)
|
||||
save_sound(); /* Sound */
|
||||
save_network(); /* Network */
|
||||
save_ports(); /* Ports (COM & LPT) */
|
||||
save_other_peripherals(); /* Other peripherals */
|
||||
save_storage_controllers(); /* Storage controllers */
|
||||
save_hard_disks(); /* Hard disks */
|
||||
save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */
|
||||
save_other_removable_devices(); /* Other removable devices */
|
||||
save_other_peripherals(); /* Other peripherals */
|
||||
|
||||
config_write(cfg_path);
|
||||
}
|
||||
|
||||
@@ -257,6 +257,9 @@ exec386(int cycs)
|
||||
if (!use32) cpu_state.pc &= 0xffff;
|
||||
#endif
|
||||
|
||||
if (cpu_end_block_after_ins)
|
||||
cpu_end_block_after_ins--;
|
||||
|
||||
if (cpu_state.abrt) {
|
||||
flags_rebuild();
|
||||
tempi = cpu_state.abrt & ABRT_MASK;
|
||||
@@ -281,11 +284,6 @@ exec386(int cycs)
|
||||
}
|
||||
}
|
||||
|
||||
ins_cycles -= cycles;
|
||||
tsc += ins_cycles;
|
||||
|
||||
cycdiff = oldcyc - cycles;
|
||||
|
||||
if (smi_line)
|
||||
enter_smm_check(0);
|
||||
else if (trap) {
|
||||
@@ -334,7 +332,10 @@ exec386(int cycs)
|
||||
}
|
||||
}
|
||||
|
||||
cpu_end_block_after_ins = 0;
|
||||
ins_cycles -= cycles;
|
||||
tsc += ins_cycles;
|
||||
|
||||
cycdiff = oldcyc - cycles;
|
||||
|
||||
if (timetolive) {
|
||||
timetolive--;
|
||||
|
||||
@@ -1169,6 +1169,8 @@ enter_smm(int in_hlt)
|
||||
|
||||
flushmmucache();
|
||||
}
|
||||
|
||||
oldcpl = 0;
|
||||
|
||||
cpu_cur_status &= ~(CPU_STATUS_PMODE | CPU_STATUS_V86);
|
||||
CPU_BLOCK_END();
|
||||
@@ -1265,6 +1267,8 @@ leave_smm(void)
|
||||
|
||||
nmi_mask = 1;
|
||||
|
||||
oldcpl = CPL;
|
||||
|
||||
CPU_BLOCK_END();
|
||||
|
||||
x386_common_log("CS : seg = %04X, base = %08X, limit = %08X, limit_low = %08X, limit_high = %08X, access = %02X, ar_high = %02X\n",
|
||||
@@ -1465,11 +1469,7 @@ checkio(int port)
|
||||
return 1;
|
||||
|
||||
cpl_override = 1;
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
d = readmembl(tr.base + t + (port >> 3));
|
||||
#else
|
||||
d = readmemb386l(0, tr.base + t + (port >> 3));
|
||||
#endif
|
||||
cpl_override = 0;
|
||||
return d & (1 << (port & 7));
|
||||
}
|
||||
|
||||
@@ -21,50 +21,20 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))))
|
||||
#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a))))
|
||||
#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a))))
|
||||
#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a))))
|
||||
#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) )
|
||||
#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
|
||||
#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
|
||||
#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a))))
|
||||
|
||||
#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#else
|
||||
#undef readmemb
|
||||
#undef writememb
|
||||
|
||||
|
||||
#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) )
|
||||
#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a))))
|
||||
|
||||
#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
|
||||
#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#endif
|
||||
#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v
|
||||
|
||||
|
||||
int checkio(int port);
|
||||
|
||||
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
#define check_io_perm(port) if (!IOPLp || (cpu_state.eflags&VM_FLAG)) \
|
||||
{ \
|
||||
int tempi = checkio(port); \
|
||||
if (cpu_state.abrt) return 1; \
|
||||
if (tempi) \
|
||||
{ \
|
||||
if (cpu_state.eflags & VM_FLAG) \
|
||||
x86gpf_expected(NULL,0); \
|
||||
else \
|
||||
x86gpf(NULL,0); \
|
||||
return 1; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (cpu_state.eflags&VM_FLAG))) \
|
||||
{ \
|
||||
int tempi = checkio(port); \
|
||||
@@ -78,7 +48,6 @@ int checkio(int port);
|
||||
return 1; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SEG_CHECK_READ(seg) \
|
||||
do \
|
||||
@@ -347,32 +316,16 @@ static __inline void seteaq(uint64_t v)
|
||||
{
|
||||
if (seteaq_cwc())
|
||||
return;
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
writememql(easeg + cpu_state.eaaddr, v);
|
||||
#else
|
||||
writememql(easeg, cpu_state.eaaddr, v);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
|
||||
#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v
|
||||
#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v
|
||||
#else
|
||||
#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writememb386l(easeg,cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
|
||||
#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else { writememwl(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].w=v
|
||||
#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else { writememll(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].l=v
|
||||
#endif
|
||||
#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v
|
||||
#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v
|
||||
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v);
|
||||
#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v);
|
||||
#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v);
|
||||
#else
|
||||
#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v);
|
||||
#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v);
|
||||
#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v);
|
||||
#endif
|
||||
|
||||
#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++
|
||||
#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2
|
||||
|
||||
@@ -349,6 +349,12 @@ exec386_dynarec_int(void)
|
||||
if (((cs + cpu_state.pc) >> 12) != pccache)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (cpu_end_block_after_ins) {
|
||||
cpu_end_block_after_ins--;
|
||||
if (!cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
|
||||
if (cpu_state.abrt)
|
||||
CPU_BLOCK_END();
|
||||
if (smi_line)
|
||||
@@ -357,14 +363,8 @@ exec386_dynarec_int(void)
|
||||
CPU_BLOCK_END();
|
||||
else if (nmi && nmi_enable && nmi_mask)
|
||||
CPU_BLOCK_END();
|
||||
else if ((cpu_state.flags & I_FLAG) && pic.int_pending)
|
||||
else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (cpu_end_block_after_ins) {
|
||||
cpu_end_block_after_ins--;
|
||||
if (!cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
}
|
||||
|
||||
if (trap) {
|
||||
@@ -585,21 +585,21 @@ exec386_dynarec_dyn(void)
|
||||
#endif
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (cpu_end_block_after_ins) {
|
||||
cpu_end_block_after_ins--;
|
||||
if (!cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
|
||||
if (smi_line)
|
||||
CPU_BLOCK_END();
|
||||
else if (cpu_state.flags & T_FLAG)
|
||||
CPU_BLOCK_END();
|
||||
else if (nmi && nmi_enable && nmi_mask)
|
||||
CPU_BLOCK_END();
|
||||
else if ((cpu_state.flags & I_FLAG) && pic.int_pending)
|
||||
else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (cpu_end_block_after_ins) {
|
||||
cpu_end_block_after_ins--;
|
||||
if (!cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
|
||||
if (cpu_state.abrt) {
|
||||
if (!(cpu_state.abrt & ABRT_EXPECTED))
|
||||
codegen_block_remove();
|
||||
@@ -683,7 +683,7 @@ exec386_dynarec_dyn(void)
|
||||
CPU_BLOCK_END();
|
||||
else if (nmi && nmi_enable && nmi_mask)
|
||||
CPU_BLOCK_END();
|
||||
else if ((cpu_state.flags & I_FLAG) && pic.int_pending)
|
||||
else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (cpu_end_block_after_ins) {
|
||||
@@ -756,19 +756,6 @@ exec386_dynarec(int cycs)
|
||||
exec386_dynarec_dyn();
|
||||
}
|
||||
|
||||
cycdiff = oldcyc - cycles;
|
||||
delta = tsc - oldtsc;
|
||||
if (delta > 0) {
|
||||
/* TSC has changed, this means interim timer processing has happened,
|
||||
see how much we still need to add. */
|
||||
cycdiff -= delta;
|
||||
if (cycdiff > 0)
|
||||
tsc += cycdiff;
|
||||
} else {
|
||||
/* TSC has not changed. */
|
||||
tsc += cycdiff;
|
||||
}
|
||||
|
||||
if (cpu_state.abrt) {
|
||||
flags_rebuild();
|
||||
tempi = cpu_state.abrt & ABRT_MASK;
|
||||
@@ -819,6 +806,19 @@ exec386_dynarec(int cycs)
|
||||
}
|
||||
}
|
||||
|
||||
cycdiff = oldcyc - cycles;
|
||||
delta = tsc - oldtsc;
|
||||
if (delta > 0) {
|
||||
/* TSC has changed, this means interim timer processing has happened,
|
||||
see how much we still need to add. */
|
||||
cycdiff -= delta;
|
||||
if (cycdiff > 0)
|
||||
tsc += cycdiff;
|
||||
} else {
|
||||
/* TSC has not changed. */
|
||||
tsc += cycdiff;
|
||||
}
|
||||
|
||||
if (cycdiff > 0) {
|
||||
if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc))
|
||||
timer_process_inline();
|
||||
|
||||
@@ -271,6 +271,19 @@ sub_cycles(int c)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
resub_cycles(int old_cycles)
|
||||
{
|
||||
int cyc_diff = 0;
|
||||
|
||||
if (old_cycles > cycles) {
|
||||
cyc_diff = old_cycles - cycles;
|
||||
cycles = old_cycles;
|
||||
sub_cycles(cyc_diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef readmemb
|
||||
#undef readmemw
|
||||
#undef readmeml
|
||||
@@ -280,31 +293,43 @@ sub_cycles(int c)
|
||||
static void
|
||||
cpu_io(int bits, int out, uint16_t port)
|
||||
{
|
||||
int old_cycles = cycles;
|
||||
|
||||
if (out) {
|
||||
wait(4, 1);
|
||||
if (bits == 16) {
|
||||
if (is8086 && !(port & 1))
|
||||
if (is8086 && !(port & 1)) {
|
||||
old_cycles = cycles;
|
||||
outw(port, AX);
|
||||
else {
|
||||
} else {
|
||||
wait(4, 1);
|
||||
old_cycles = cycles;
|
||||
outb(port++, AL);
|
||||
outb(port, AH);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
old_cycles = cycles;
|
||||
outb(port, AL);
|
||||
}
|
||||
} else {
|
||||
wait(4, 1);
|
||||
if (bits == 16) {
|
||||
if (is8086 && !(port & 1))
|
||||
if (is8086 && !(port & 1)) {
|
||||
old_cycles = cycles;
|
||||
AX = inw(port);
|
||||
else {
|
||||
} else {
|
||||
wait(4, 1);
|
||||
old_cycles = cycles;
|
||||
AL = inb(port++);
|
||||
AH = inb(port);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
old_cycles = cycles;
|
||||
AL = inb(port);
|
||||
}
|
||||
}
|
||||
|
||||
resub_cycles(old_cycles);
|
||||
}
|
||||
|
||||
|
||||
@@ -1182,9 +1207,11 @@ check_interrupts(void)
|
||||
wait(3, 0);
|
||||
/* ACK to PIC */
|
||||
temp = pic_irq_ack();
|
||||
wait(4, 1);
|
||||
wait(1, 0);
|
||||
/* ACK to PIC */
|
||||
temp = pic_irq_ack();
|
||||
wait(4, 1);
|
||||
wait(1, 0);
|
||||
in_lock = 0;
|
||||
clear_lock = 0;
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
#endif
|
||||
#include "x87_timings.h"
|
||||
|
||||
|
||||
#define CCR1_USE_SMI (1 << 1)
|
||||
#define CCR1_SMAC (1 << 2)
|
||||
#define CCR1_SM3 (1 << 7)
|
||||
@@ -239,6 +238,7 @@ uint64_t ecx1002ff_msr = 0;
|
||||
/* Some weird long MSR's used by i686 AMI & some Phoenix BIOSes */
|
||||
uint64_t ecxf0f00250_msr = 0;
|
||||
uint64_t ecxf0f00258_msr = 0;
|
||||
uint64_t ecxf0f00259_msr = 0;
|
||||
|
||||
uint64_t star = 0; /* AMD K6-2+. */
|
||||
|
||||
@@ -3187,6 +3187,10 @@ void cpu_RDMSR()
|
||||
EAX = ecxf0f00258_msr & 0xffffffff;
|
||||
EDX = ecxf0f00258_msr >> 32;
|
||||
break;
|
||||
case 0xf0f00259:
|
||||
EAX = ecxf0f00259_msr & 0xffffffff;
|
||||
EDX = ecxf0f00259_msr >> 32;
|
||||
break;
|
||||
default:
|
||||
i686_invalid_rdmsr:
|
||||
cpu_log("RDMSR: Invalid MSR: %08X\n", ECX);
|
||||
@@ -3664,6 +3668,9 @@ void cpu_WRMSR()
|
||||
case 0xf0f00258:
|
||||
ecxf0f00258_msr = EAX | ((uint64_t)EDX << 32);
|
||||
break;
|
||||
case 0xf0f00259:
|
||||
ecxf0f00259_msr = EAX | ((uint64_t)EDX << 32);
|
||||
break;
|
||||
default:
|
||||
i686_invalid_wrmsr:
|
||||
cpu_log("WRMSR: Invalid MSR: %08X\n", ECX);
|
||||
|
||||
@@ -600,9 +600,9 @@ const cpu_family_t cpu_families[] = {
|
||||
.name = "Pentium OverDrive",
|
||||
.internal_name = "pentium_p54c_od3v",
|
||||
.cpus = {
|
||||
{"125", CPU_PENTIUM, fpus_internal, 125000000, 3.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,7,7, 16},
|
||||
{"125", CPU_PENTIUM, fpus_internal, 125000000, 3.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,7,7, 15},
|
||||
{"150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 35/2},
|
||||
{"166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 40},
|
||||
{"166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 20},
|
||||
{"", 0}
|
||||
}
|
||||
}, {
|
||||
|
||||
@@ -808,8 +808,8 @@ void
|
||||
PUSHL(uint32_t v)
|
||||
{
|
||||
if (cpu_16bitbus) {
|
||||
PUSHW(v & 0xffff);
|
||||
PUSHW(v >> 16);
|
||||
PUSHW(v & 0xffff);
|
||||
} else {
|
||||
if (stack32) {
|
||||
writememl(ss, ESP - 4, v);
|
||||
|
||||
@@ -388,7 +388,7 @@ mm67_read(uint16_t port, void *priv)
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
/* This chip is directly mapped on I/O. */
|
||||
sub_cycles(ISA_CYCLES(4));
|
||||
cycles -= ISA_CYCLES(4);
|
||||
|
||||
switch(reg) {
|
||||
case MM67_ISTAT: /* IRQ status (RO) */
|
||||
@@ -424,7 +424,7 @@ mm67_write(uint16_t port, uint8_t val, void *priv)
|
||||
#endif
|
||||
|
||||
/* This chip is directly mapped on I/O. */
|
||||
sub_cycles(ISA_CYCLES(4));
|
||||
cycles -= ISA_CYCLES(4);
|
||||
|
||||
switch(reg) {
|
||||
case MM67_ISTAT: /* intr status (RO) */
|
||||
|
||||
@@ -2047,7 +2047,7 @@ kbd_read(uint16_t port, void *priv)
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63))
|
||||
port = 0x61;
|
||||
|
||||
@@ -173,7 +173,6 @@ sermouse_callback(struct serial_s *serial, void *priv)
|
||||
dev->format = 7;
|
||||
dev->transmit_period = sermouse_transmit_period(dev, 1200, -1);
|
||||
timer_stop(&dev->command_timer);
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
sermouse_timer_on(dev, 5000.0, 0);
|
||||
#else
|
||||
|
||||
@@ -355,7 +355,7 @@ serial_write(uint16_t addr, uint8_t val, void *p)
|
||||
|
||||
serial_log("UART: Write %02X to port %02X\n", val, addr);
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
switch (addr & 7) {
|
||||
case 0:
|
||||
@@ -513,7 +513,7 @@ serial_read(uint16_t addr, void *p)
|
||||
serial_t *dev = (serial_t *)p;
|
||||
uint8_t i, ret = 0;
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
switch (addr & 7) {
|
||||
case 0:
|
||||
|
||||
@@ -276,7 +276,7 @@ const device_t xtide_acculogic_device = {
|
||||
|
||||
const device_t xtide_at_ps2_device = {
|
||||
"PS/2 AT XTIDE (1.1.5)",
|
||||
DEVICE_AT,
|
||||
DEVICE_ISA | DEVICE_AT,
|
||||
0,
|
||||
xtide_at_ps2_init, xtide_at_close, NULL,
|
||||
{ xtide_at_ps2_available }, NULL, NULL,
|
||||
|
||||
1291
src/disk/hdd_image.c
1291
src/disk/hdd_image.c
File diff suppressed because it is too large
Load Diff
12
src/disk/minivhd/CREDITS.md
Normal file
12
src/disk/minivhd/CREDITS.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Credits
|
||||
MiniVHD Copyright (c) 2019 Sherman Perry
|
||||
|
||||
MiniVHD was made possible with the help of the following projects
|
||||
|
||||
### libxml2
|
||||
**Project Home:** http://www.xmlsoft.org/
|
||||
**License:** MIT (see src/libxml2_encoding.c for details)
|
||||
|
||||
### cwalk
|
||||
**Project Home:** https://likle.github.io/cwalk/
|
||||
**Licence:** MIT (https://github.com/likle/cwalk/blob/master/LICENSE.md)
|
||||
21
src/disk/minivhd/LICENSE
Normal file
21
src/disk/minivhd/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Sherman Perry
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1424
src/disk/minivhd/cwalk.c
Normal file
1424
src/disk/minivhd/cwalk.c
Normal file
File diff suppressed because it is too large
Load Diff
457
src/disk/minivhd/cwalk.h
Normal file
457
src/disk/minivhd/cwalk.h
Normal file
@@ -0,0 +1,457 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CWK_LIBRARY_H
|
||||
#define CWK_LIBRARY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* A segment represents a single component of a path. For instance, on linux a
|
||||
* path might look like this "/var/log/", which consists of two segments "var"
|
||||
* and "log".
|
||||
*/
|
||||
struct cwk_segment
|
||||
{
|
||||
const char *path;
|
||||
const char *segments;
|
||||
const char *begin;
|
||||
const char *end;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* The segment type can be used to identify whether a segment is a special
|
||||
* segment or not.
|
||||
*
|
||||
* CWK_NORMAL - normal folder or file segment
|
||||
* CWK_CURRENT - "./" current folder segment
|
||||
* CWK_BACK - "../" relative back navigation segment
|
||||
*/
|
||||
enum cwk_segment_type
|
||||
{
|
||||
CWK_NORMAL,
|
||||
CWK_CURRENT,
|
||||
CWK_BACK
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Determines the style which is used for the path parsing and
|
||||
* generation.
|
||||
*/
|
||||
enum cwk_path_style
|
||||
{
|
||||
CWK_STYLE_WINDOWS,
|
||||
CWK_STYLE_UNIX
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generates an absolute path based on a base.
|
||||
*
|
||||
* This function generates an absolute path based on a base path and another
|
||||
* path. It is guaranteed to return an absolute path. If the second submitted
|
||||
* path is absolute, it will override the base path. The result will be written
|
||||
* to a buffer, which might be truncated if the buffer is not large enough to
|
||||
* hold the full path. However, the truncated result will always be
|
||||
* null-terminated. The returned value is the amount of characters which the
|
||||
* resulting path would take if it was not truncated (excluding the
|
||||
* null-terminating character).
|
||||
*
|
||||
* @param base The base path on which the relative path will be applied.
|
||||
* @param path The relative path which will be applied on the base path.
|
||||
* @param buffer The buffer where the result will be written to.
|
||||
* @param buffer_size The size of the result buffer.
|
||||
* @return Returns the total amount of characters of the new absolute path.
|
||||
*/
|
||||
size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Generates a relative path based on a base.
|
||||
*
|
||||
* This function generates a relative path based on a base path and another
|
||||
* path. It determines how to get to the submitted path, starting from the base
|
||||
* directory. The result will be written to a buffer, which might be truncated
|
||||
* if the buffer is not large enough to hold the full path. However, the
|
||||
* truncated result will always be null-terminated. The returned value is the
|
||||
* amount of characters which the resulting path would take if it was not
|
||||
* truncated (excluding the null-terminating character).
|
||||
*
|
||||
* @param base_directory The base path from which the relative path will start.
|
||||
* @param path The target path where the relative path will point to.
|
||||
* @param buffer The buffer where the result will be written to.
|
||||
* @param buffer_size The size of the result buffer.
|
||||
* @return Returns the total amount of characters of the full path.
|
||||
*/
|
||||
size_t cwk_path_get_relative(const char *base_directory, const char *path,
|
||||
char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Joins two paths together.
|
||||
*
|
||||
* This function generates a new path by combining the two submitted paths. It
|
||||
* will remove double separators, and unlike cwk_path_get_absolute it permits
|
||||
* the use of two relative paths to combine. The result will be written to a
|
||||
* buffer, which might be truncated if the buffer is not large enough to hold
|
||||
* the full path. However, the truncated result will always be null-terminated.
|
||||
* The returned value is the amount of characters which the resulting path would
|
||||
* take if it was not truncated (excluding the null-terminating character).
|
||||
*
|
||||
* @param path_a The first path which comes first.
|
||||
* @param path_b The second path which comes after the first.
|
||||
* @param buffer The buffer where the result will be written to.
|
||||
* @param buffer_size The size of the result buffer.
|
||||
* @return Returns the total amount of characters of the full, combined path.
|
||||
*/
|
||||
size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Joins multiple paths together.
|
||||
*
|
||||
* This function generates a new path by joining multiple paths together. It
|
||||
* will remove double separators, and unlike cwk_path_get_absolute it permits
|
||||
* the use of multiple relative paths to combine. The last path of the submitted
|
||||
* string array must be set to NULL. The result will be written to a buffer,
|
||||
* which might be truncated if the buffer is not large enough to hold the full
|
||||
* path. However, the truncated result will always be null-terminated. The
|
||||
* returned value is the amount of characters which the resulting path would
|
||||
* take if it was not truncated (excluding the null-terminating character).
|
||||
*
|
||||
* @param paths An array of paths which will be joined.
|
||||
* @param buffer The buffer where the result will be written to.
|
||||
* @param buffer_size The size of the result buffer.
|
||||
* @return Returns the total amount of characters of the full, combined path.
|
||||
*/
|
||||
size_t cwk_path_join_multiple(const char **paths, char *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Determines the root of a path.
|
||||
*
|
||||
* This function determines the root of a path by finding it's length. The root
|
||||
* always starts at the submitted path. If the path has no root, the length will
|
||||
* be set to zero.
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @param length The output of the root length.
|
||||
*/
|
||||
void cwk_path_get_root(const char *path, size_t *length);
|
||||
|
||||
/**
|
||||
* @brief Changes the root of a path.
|
||||
*
|
||||
* This function changes the root of a path. It does not normalize the result.
|
||||
* The result will be written to a buffer, which might be truncated if the
|
||||
* buffer is not large enough to hold the full path. However, the truncated
|
||||
* result will always be null-terminated. The returned value is the amount of
|
||||
* characters which the resulting path would take if it was not truncated
|
||||
* (excluding the null-terminating character).
|
||||
*
|
||||
* @param path The original path which will get a new root.
|
||||
* @param new_root The new root which will be placed in the path.
|
||||
* @param buffer The output buffer where the result is written to.
|
||||
* @param buffer_size The size of the output buffer where the result is written
|
||||
* to.
|
||||
* @return Returns the total amount of characters of the new path.
|
||||
*/
|
||||
size_t cwk_path_change_root(const char *path, const char *new_root,
|
||||
char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Determine whether the path is absolute or not.
|
||||
*
|
||||
* This function checks whether the path is an absolute path or not. A path is
|
||||
* considered to be absolute if the root ends with a separator.
|
||||
*
|
||||
* @param path The path which will be checked.
|
||||
* @return Returns true if the path is absolute or false otherwise.
|
||||
*/
|
||||
bool cwk_path_is_absolute(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Determine whether the path is relative or not.
|
||||
*
|
||||
* This function checks whether the path is a relative path or not. A path is
|
||||
* considered to be relative if the root does not end with a separator.
|
||||
*
|
||||
* @param path The path which will be checked.
|
||||
* @return Returns true if the path is relative or false otherwise.
|
||||
*/
|
||||
bool cwk_path_is_relative(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Gets the basename of a file path.
|
||||
*
|
||||
* This function gets the basename of a file path. A pointer to the beginning of
|
||||
* the basename will be returned through the basename parameter. This pointer
|
||||
* will be positioned on the first letter after the separator. The length of the
|
||||
* file path will be returned through the length parameter. The length will be
|
||||
* set to zero and the basename to NULL if there is no basename available.
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @param basename The output of the basename pointer.
|
||||
* @param length The output of the length of the basename.
|
||||
*/
|
||||
void cwk_path_get_basename(const char *path, const char **basename,
|
||||
size_t *length);
|
||||
|
||||
/**
|
||||
* @brief Changes the basename of a file path.
|
||||
*
|
||||
* This function changes the basename of a file path. This function will not
|
||||
* write out more than the specified buffer can contain. However, the generated
|
||||
* string is always null-terminated - even if not the whole path is written out.
|
||||
* The function returns the total number of characters the complete buffer would
|
||||
* have, even if it was not written out completely. The path may be the same
|
||||
* memory address as the buffer.
|
||||
*
|
||||
* @param path The original path which will be used for the modified path.
|
||||
* @param new_basename The new basename which will replace the old one.
|
||||
* @param buffer The buffer where the changed path will be written to.
|
||||
* @param buffer_size The size of the result buffer where the changed path is
|
||||
* written to.
|
||||
* @return Returns the size which the complete new path would have if it was not
|
||||
* truncated.
|
||||
*/
|
||||
size_t cwk_path_change_basename(const char *path, const char *new_basename,
|
||||
char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Gets the dirname of a file path.
|
||||
*
|
||||
* This function determines the dirname of a file path and returns the length up
|
||||
* to which character is considered to be part of it. If no dirname is found,
|
||||
* the length will be set to zero. The beginning of the dirname is always equal
|
||||
* to the submitted path pointer.
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @param length The length of the dirname.
|
||||
*/
|
||||
void cwk_path_get_dirname(const char *path, size_t *length);
|
||||
|
||||
/**
|
||||
* @brief Gets the extension of a file path.
|
||||
*
|
||||
* This function extracts the extension portion of a file path. A pointer to
|
||||
* the beginning of the extension will be returned through the extension
|
||||
* parameter if an extension is found and true is returned. This pointer will be
|
||||
* positioned on the dot. The length of the extension name will be returned
|
||||
* through the length parameter. If no extension is found both parameters won't
|
||||
* be touched and false will be returned.
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @param extension The output of the extension pointer.
|
||||
* @param length The output of the length of the extension.
|
||||
* @return Returns true if an extension is found or false otherwise.
|
||||
*/
|
||||
bool cwk_path_get_extension(const char *path, const char **extension,
|
||||
size_t *length);
|
||||
|
||||
/**
|
||||
* @brief Determines whether the file path has an extension.
|
||||
*
|
||||
* This function determines whether the submitted file path has an extension.
|
||||
* This will evaluate to true if the last segment of the path contains a dot.
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @return Returns true if the path has an extension or false otherwise.
|
||||
*/
|
||||
bool cwk_path_has_extension(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Changes the extension of a file path.
|
||||
*
|
||||
* This function changes the extension of a file name. The function will append
|
||||
* an extension if the basename does not have an extension, or use the extension
|
||||
* as a basename if the path does not have a basename. This function will not
|
||||
* write out more than the specified buffer can contain. However, the generated
|
||||
* string is always null-terminated - even if not the whole path is written out.
|
||||
* The function returns the total number of characters the complete buffer would
|
||||
* have, even if it was not written out completely. The path may be the same
|
||||
* memory address as the buffer.
|
||||
*
|
||||
* @param path The path which will be used to make the change.
|
||||
* @param new_extension The extension which will be placed within the new path.
|
||||
* @param buffer The output buffer where the result will be written to.
|
||||
* @param buffer_size The size of the output buffer where the result will be
|
||||
* written to.
|
||||
* @return Returns the total size which the output would have if it was not
|
||||
* truncated.
|
||||
*/
|
||||
size_t cwk_path_change_extension(const char *path, const char *new_extension,
|
||||
char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Creates a normalized version of the path.
|
||||
*
|
||||
* This function creates a normalized version of the path within the specified
|
||||
* buffer. This function will not write out more than the specified buffer can
|
||||
* contain. However, the generated string is always null-terminated - even if
|
||||
* not the whole path is written out. The function returns the total number of
|
||||
* characters the complete buffer would have, even if it was not written out
|
||||
* completely. The path may be the same memory address as the buffer.
|
||||
*
|
||||
* The following will be true for the normalized path:
|
||||
* 1) "../" will be resolved.
|
||||
* 2) "./" will be removed.
|
||||
* 3) double separators will be fixed with a single separator.
|
||||
* 4) separator suffixes will be removed.
|
||||
*
|
||||
* @param path The path which will be normalized.
|
||||
* @param buffer The buffer where the new path is written to.
|
||||
* @param buffer_size The size of the buffer.
|
||||
* @return The size which the complete normalized path has if it was not
|
||||
* truncated.
|
||||
*/
|
||||
size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Finds common portions in two paths.
|
||||
*
|
||||
* This function finds common portions in two paths and returns the number
|
||||
* characters from the beginning of the base path which are equal to the other
|
||||
* path.
|
||||
*
|
||||
* @param path_base The base path which will be compared with the other path.
|
||||
* @param path_other The other path which will compared with the base path.
|
||||
* @return Returns the number of characters which are common in the base path.
|
||||
*/
|
||||
size_t cwk_path_get_intersection(const char *path_base, const char *path_other);
|
||||
|
||||
/**
|
||||
* @brief Gets the first segment of a path.
|
||||
*
|
||||
* This function finds the first segment of a path. The position of the segment
|
||||
* is set to the first character after the separator, and the length counts all
|
||||
* characters until the next separator (excluding the separator).
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @param segment The segment which will be extracted.
|
||||
* @return Returns true if there is a segment or false if there is none.
|
||||
*/
|
||||
bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment);
|
||||
|
||||
/**
|
||||
* @brief Gets the last segment of the path.
|
||||
*
|
||||
* This function gets the last segment of a path. This function may return false
|
||||
* if the path doesn't contain any segments, in which case the submitted segment
|
||||
* parameter is not modified. The position of the segment is set to the first
|
||||
* character after the separator, and the length counts all characters until the
|
||||
* end of the path (excluding the separator).
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @param segment The segment which will be extracted.
|
||||
* @return Returns true if there is a segment or false if there is none.
|
||||
*/
|
||||
bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment);
|
||||
|
||||
/**
|
||||
* @brief Advances to the next segment.
|
||||
*
|
||||
* This function advances the current segment to the next segment. If there are
|
||||
* no more segments left, the submitted segment structure will stay unchanged
|
||||
* and false is returned.
|
||||
*
|
||||
* @param segment The current segment which will be advanced to the next one.
|
||||
* @return Returns true if another segment was found or false otherwise.
|
||||
*/
|
||||
bool cwk_path_get_next_segment(struct cwk_segment *segment);
|
||||
|
||||
/**
|
||||
* @brief Moves to the previous segment.
|
||||
*
|
||||
* This function moves the current segment to the previous segment. If the
|
||||
* current segment is the first one, the submitted segment structure will stay
|
||||
* unchanged and false is returned.
|
||||
*
|
||||
* @param segment The current segment which will be moved to the previous one.
|
||||
* @return Returns true if there is a segment before this one or false
|
||||
* otherwise.
|
||||
*/
|
||||
bool cwk_path_get_previous_segment(struct cwk_segment *segment);
|
||||
|
||||
/**
|
||||
* @brief Gets the type of the submitted path segment.
|
||||
*
|
||||
* This function inspects the contents of the segment and determines the type of
|
||||
* it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and CWK_BACK. A
|
||||
* CWK_NORMAL segment is a normal folder or file entry. A CWK_CURRENT is a "./"
|
||||
* and a CWK_BACK a "../" segment.
|
||||
*
|
||||
* @param segment The segment which will be inspected.
|
||||
* @return Returns the type of the segment.
|
||||
*/
|
||||
enum cwk_segment_type cwk_path_get_segment_type(
|
||||
const struct cwk_segment *segment);
|
||||
|
||||
/**
|
||||
* @brief Changes the content of a segment.
|
||||
*
|
||||
* This function overrides the content of a segment to the submitted value and
|
||||
* outputs the whole new path to the submitted buffer. The result might require
|
||||
* less or more space than before if the new value length differs from the
|
||||
* original length. The output is truncated if the new path is larger than the
|
||||
* submitted buffer size, but it is always null-terminated. The source of the
|
||||
* segment and the submitted buffer may be the same.
|
||||
*
|
||||
* @param segment The segment which will be modifier.
|
||||
* @param value The new content of the segment.
|
||||
* @param buffer The buffer where the modified path will be written to.
|
||||
* @param buffer_size The size of the output buffer.
|
||||
* @return Returns the total size which would have been written if the output
|
||||
* was not truncated.
|
||||
*/
|
||||
size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value,
|
||||
char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the submitted pointer points to a separator.
|
||||
*
|
||||
* This function simply checks whether the submitted pointer points to a
|
||||
* separator, which has to be null-terminated (but not necessarily after the
|
||||
* separator). The function will return true if it is a separator, or false
|
||||
* otherwise.
|
||||
*
|
||||
* @param symbol A pointer to a string.
|
||||
* @return Returns true if it is a separator, or false otherwise.
|
||||
*/
|
||||
bool cwk_path_is_separator(const char *str);
|
||||
|
||||
/**
|
||||
* @brief Guesses the path style.
|
||||
*
|
||||
* This function guesses the path style based on a submitted path-string. The
|
||||
* guessing will look at the root and the type of slashes contained in the path
|
||||
* and return the style which is more likely used in the path.
|
||||
*
|
||||
* @param path The path which will be inspected.
|
||||
* @return Returns the style which is most likely used for the path.
|
||||
*/
|
||||
enum cwk_path_style cwk_path_guess_style(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Configures which path style is used.
|
||||
*
|
||||
* This function configures which path style is used. The following styles are
|
||||
* currently supported.
|
||||
*
|
||||
* CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root.
|
||||
* CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root.
|
||||
*
|
||||
* @param style The style which will be used from now on.
|
||||
*/
|
||||
void cwk_path_set_style(enum cwk_path_style style);
|
||||
|
||||
/**
|
||||
* @brief Gets the path style configuration.
|
||||
*
|
||||
* This function gets the style configuration which is currently used for the
|
||||
* paths. This configuration determines how paths are parsed and generated.
|
||||
*
|
||||
* @return Returns the current path style configuration.
|
||||
*/
|
||||
enum cwk_path_style cwk_path_get_style(void);
|
||||
|
||||
#endif
|
||||
447
src/disk/minivhd/libxml2_encoding.c
Normal file
447
src/disk/minivhd/libxml2_encoding.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* encoding.c : implements the encoding conversion functions needed for XML
|
||||
*
|
||||
* Related specs:
|
||||
* rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies
|
||||
* rfc2781 UTF-16, an encoding of ISO 10646, P. Hoffman, F. Yergeau
|
||||
* [ISO-10646] UTF-8 and UTF-16 in Annexes
|
||||
* [ISO-8859-1] ISO Latin-1 characters codes.
|
||||
* [UNICODE] The Unicode Consortium, "The Unicode Standard --
|
||||
* Worldwide Character Encoding -- Version 1.0", Addison-
|
||||
* Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is
|
||||
* described in Unicode Technical Report #4.
|
||||
* [US-ASCII] Coded Character Set--7-bit American Standard Code for
|
||||
* Information Interchange, ANSI X3.4-1986.
|
||||
*
|
||||
* See Copyright for the status of this software.
|
||||
*
|
||||
* daniel@veillard.com
|
||||
*
|
||||
* Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" <duerst@w3.org>
|
||||
*
|
||||
* Adapted and abridged for MiniVHD by Sherman Perry
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
static int xmlLittleEndian = 1;
|
||||
|
||||
/* Note: extracted from original 'void xmlInitCharEncodingHandlers(void)' function */
|
||||
void xmlEncodingInit(void)
|
||||
{
|
||||
unsigned short int tst = 0x1234;
|
||||
unsigned char *ptr = (unsigned char *) &tst;
|
||||
|
||||
if (*ptr == 0x12) xmlLittleEndian = 0;
|
||||
else if (*ptr == 0x34) xmlLittleEndian = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF16LEToUTF8:
|
||||
* @out: a pointer to an array of bytes to store the result
|
||||
* @outlen: the length of @out
|
||||
* @inb: a pointer to an array of UTF-16LE passwd as a byte array
|
||||
* @inlenb: the length of @in in UTF-16LE chars
|
||||
*
|
||||
* Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8
|
||||
* block of chars out. This function assumes the endian property
|
||||
* is the same between the native type of this machine and the
|
||||
* inputed one.
|
||||
*
|
||||
* Returns the number of bytes written, or -1 if lack of space, or -2
|
||||
* if the transcoding fails (if *in is not a valid utf16 string)
|
||||
* The value of *inlen after return is the number of octets consumed
|
||||
* if the return value is positive, else unpredictable.
|
||||
*/
|
||||
int UTF16LEToUTF8(unsigned char* out, int *outlen,
|
||||
const unsigned char* inb, int *inlenb)
|
||||
{
|
||||
unsigned char* outstart = out;
|
||||
const unsigned char* processed = inb;
|
||||
unsigned char* outend = out + *outlen;
|
||||
unsigned short* in = (unsigned short*) inb;
|
||||
unsigned short* inend;
|
||||
unsigned int c, d, inlen;
|
||||
unsigned char *tmp;
|
||||
int bits;
|
||||
|
||||
if ((*inlenb % 2) == 1)
|
||||
(*inlenb)--;
|
||||
inlen = *inlenb / 2;
|
||||
inend = in + inlen;
|
||||
while ((in < inend) && (out - outstart + 5 < *outlen)) {
|
||||
if (xmlLittleEndian) {
|
||||
c= *in++;
|
||||
} else {
|
||||
tmp = (unsigned char *) in;
|
||||
c = *tmp++;
|
||||
c = c | (((unsigned int)*tmp) << 8);
|
||||
in++;
|
||||
}
|
||||
if ((c & 0xFC00) == 0xD800) { /* surrogates */
|
||||
if (in >= inend) { /* (in > inend) shouldn't happens */
|
||||
break;
|
||||
}
|
||||
if (xmlLittleEndian) {
|
||||
d = *in++;
|
||||
} else {
|
||||
tmp = (unsigned char *) in;
|
||||
d = *tmp++;
|
||||
d = d | (((unsigned int)*tmp) << 8);
|
||||
in++;
|
||||
}
|
||||
if ((d & 0xFC00) == 0xDC00) {
|
||||
c &= 0x03FF;
|
||||
c <<= 10;
|
||||
c |= d & 0x03FF;
|
||||
c += 0x10000;
|
||||
}
|
||||
else {
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
return(-2);
|
||||
}
|
||||
}
|
||||
|
||||
/* assertion: c is a single UTF-4 value */
|
||||
if (out >= outend)
|
||||
break;
|
||||
if (c < 0x80) { *out++= c; bits= -6; }
|
||||
else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; }
|
||||
else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; }
|
||||
else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; }
|
||||
|
||||
for ( ; bits >= 0; bits-= 6) {
|
||||
if (out >= outend)
|
||||
break;
|
||||
*out++= ((c >> bits) & 0x3F) | 0x80;
|
||||
}
|
||||
processed = (const unsigned char*) in;
|
||||
}
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF8ToUTF16LE:
|
||||
* @outb: a pointer to an array of bytes to store the result
|
||||
* @outlen: the length of @outb
|
||||
* @in: a pointer to an array of UTF-8 chars
|
||||
* @inlen: the length of @in
|
||||
*
|
||||
* Take a block of UTF-8 chars in and try to convert it to an UTF-16LE
|
||||
* block of chars out.
|
||||
*
|
||||
* Returns the number of bytes written, or -1 if lack of space, or -2
|
||||
* if the transcoding failed.
|
||||
*/
|
||||
int UTF8ToUTF16LE(unsigned char* outb, int *outlen,
|
||||
const unsigned char* in, int *inlen)
|
||||
{
|
||||
unsigned short* out = (unsigned short*) outb;
|
||||
const unsigned char* processed = in;
|
||||
const unsigned char *const instart = in;
|
||||
unsigned short* outstart= out;
|
||||
unsigned short* outend;
|
||||
const unsigned char* inend;
|
||||
unsigned int c, d;
|
||||
int trailing;
|
||||
unsigned char *tmp;
|
||||
unsigned short tmp1, tmp2;
|
||||
|
||||
/* UTF16LE encoding has no BOM */
|
||||
if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1);
|
||||
if (in == NULL) {
|
||||
*outlen = 0;
|
||||
*inlen = 0;
|
||||
return(0);
|
||||
}
|
||||
inend= in + *inlen;
|
||||
outend = out + (*outlen / 2);
|
||||
while (in < inend) {
|
||||
d= *in++;
|
||||
if (d < 0x80) { c= d; trailing= 0; }
|
||||
else if (d < 0xC0) {
|
||||
/* trailing byte in leading position */
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
return(-2);
|
||||
} else if (d < 0xE0) { c= d & 0x1F; trailing= 1; }
|
||||
else if (d < 0xF0) { c= d & 0x0F; trailing= 2; }
|
||||
else if (d < 0xF8) { c= d & 0x07; trailing= 3; }
|
||||
else {
|
||||
/* no chance for this in UTF-16 */
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
return(-2);
|
||||
}
|
||||
|
||||
if (inend - in < trailing) {
|
||||
break;
|
||||
}
|
||||
|
||||
for ( ; trailing; trailing--) {
|
||||
if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
|
||||
break;
|
||||
c <<= 6;
|
||||
c |= d & 0x3F;
|
||||
}
|
||||
|
||||
/* assertion: c is a single UTF-4 value */
|
||||
if (c < 0x10000) {
|
||||
if (out >= outend)
|
||||
break;
|
||||
if (xmlLittleEndian) {
|
||||
*out++ = c;
|
||||
} else {
|
||||
tmp = (unsigned char *) out;
|
||||
*tmp = c ;
|
||||
*(tmp + 1) = c >> 8 ;
|
||||
out++;
|
||||
}
|
||||
}
|
||||
else if (c < 0x110000) {
|
||||
if (out+1 >= outend)
|
||||
break;
|
||||
c -= 0x10000;
|
||||
if (xmlLittleEndian) {
|
||||
*out++ = 0xD800 | (c >> 10);
|
||||
*out++ = 0xDC00 | (c & 0x03FF);
|
||||
} else {
|
||||
tmp1 = 0xD800 | (c >> 10);
|
||||
tmp = (unsigned char *) out;
|
||||
*tmp = (unsigned char) tmp1;
|
||||
*(tmp + 1) = tmp1 >> 8;
|
||||
out++;
|
||||
|
||||
tmp2 = 0xDC00 | (c & 0x03FF);
|
||||
tmp = (unsigned char *) out;
|
||||
*tmp = (unsigned char) tmp2;
|
||||
*(tmp + 1) = tmp2 >> 8;
|
||||
out++;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
processed = in;
|
||||
}
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF16BEToUTF8:
|
||||
* @out: a pointer to an array of bytes to store the result
|
||||
* @outlen: the length of @out
|
||||
* @inb: a pointer to an array of UTF-16 passed as a byte array
|
||||
* @inlenb: the length of @in in UTF-16 chars
|
||||
*
|
||||
* Take a block of UTF-16 ushorts in and try to convert it to an UTF-8
|
||||
* block of chars out. This function assumes the endian property
|
||||
* is the same between the native type of this machine and the
|
||||
* inputed one.
|
||||
*
|
||||
* Returns the number of bytes written, or -1 if lack of space, or -2
|
||||
* if the transcoding fails (if *in is not a valid utf16 string)
|
||||
* The value of *inlen after return is the number of octets consumed
|
||||
* if the return value is positive, else unpredictable.
|
||||
*/
|
||||
int UTF16BEToUTF8(unsigned char* out, int *outlen,
|
||||
const unsigned char* inb, int *inlenb)
|
||||
{
|
||||
unsigned char* outstart = out;
|
||||
const unsigned char* processed = inb;
|
||||
unsigned char* outend = out + *outlen;
|
||||
unsigned short* in = (unsigned short*) inb;
|
||||
unsigned short* inend;
|
||||
unsigned int c, d, inlen;
|
||||
unsigned char *tmp;
|
||||
int bits;
|
||||
|
||||
if ((*inlenb % 2) == 1)
|
||||
(*inlenb)--;
|
||||
inlen = *inlenb / 2;
|
||||
inend= in + inlen;
|
||||
while (in < inend) {
|
||||
if (xmlLittleEndian) {
|
||||
tmp = (unsigned char *) in;
|
||||
c = *tmp++;
|
||||
c = c << 8;
|
||||
c = c | (unsigned int) *tmp;
|
||||
in++;
|
||||
} else {
|
||||
c= *in++;
|
||||
}
|
||||
if ((c & 0xFC00) == 0xD800) { /* surrogates */
|
||||
if (in >= inend) { /* (in > inend) shouldn't happens */
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
return(-2);
|
||||
}
|
||||
if (xmlLittleEndian) {
|
||||
tmp = (unsigned char *) in;
|
||||
d = *tmp++;
|
||||
d = d << 8;
|
||||
d = d | (unsigned int) *tmp;
|
||||
in++;
|
||||
} else {
|
||||
d= *in++;
|
||||
}
|
||||
if ((d & 0xFC00) == 0xDC00) {
|
||||
c &= 0x03FF;
|
||||
c <<= 10;
|
||||
c |= d & 0x03FF;
|
||||
c += 0x10000;
|
||||
}
|
||||
else {
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
return(-2);
|
||||
}
|
||||
}
|
||||
|
||||
/* assertion: c is a single UTF-4 value */
|
||||
if (out >= outend)
|
||||
break;
|
||||
if (c < 0x80) { *out++= c; bits= -6; }
|
||||
else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; }
|
||||
else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; }
|
||||
else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; }
|
||||
|
||||
for ( ; bits >= 0; bits-= 6) {
|
||||
if (out >= outend)
|
||||
break;
|
||||
*out++= ((c >> bits) & 0x3F) | 0x80;
|
||||
}
|
||||
processed = (const unsigned char*) in;
|
||||
}
|
||||
*outlen = out - outstart;
|
||||
*inlenb = processed - inb;
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF8ToUTF16BE:
|
||||
* @outb: a pointer to an array of bytes to store the result
|
||||
* @outlen: the length of @outb
|
||||
* @in: a pointer to an array of UTF-8 chars
|
||||
* @inlen: the length of @in
|
||||
*
|
||||
* Take a block of UTF-8 chars in and try to convert it to an UTF-16BE
|
||||
* block of chars out.
|
||||
*
|
||||
* Returns the number of byte written, or -1 by lack of space, or -2
|
||||
* if the transcoding failed.
|
||||
*/
|
||||
int UTF8ToUTF16BE(unsigned char* outb, int *outlen,
|
||||
const unsigned char* in, int *inlen)
|
||||
{
|
||||
unsigned short* out = (unsigned short*) outb;
|
||||
const unsigned char* processed = in;
|
||||
const unsigned char *const instart = in;
|
||||
unsigned short* outstart= out;
|
||||
unsigned short* outend;
|
||||
const unsigned char* inend;
|
||||
unsigned int c, d;
|
||||
int trailing;
|
||||
unsigned char *tmp;
|
||||
unsigned short tmp1, tmp2;
|
||||
|
||||
/* UTF-16BE has no BOM */
|
||||
if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1);
|
||||
if (in == NULL) {
|
||||
*outlen = 0;
|
||||
*inlen = 0;
|
||||
return(0);
|
||||
}
|
||||
inend= in + *inlen;
|
||||
outend = out + (*outlen / 2);
|
||||
while (in < inend) {
|
||||
d= *in++;
|
||||
if (d < 0x80) { c= d; trailing= 0; }
|
||||
else if (d < 0xC0) {
|
||||
/* trailing byte in leading position */
|
||||
*outlen = out - outstart;
|
||||
*inlen = processed - instart;
|
||||
return(-2);
|
||||
} else if (d < 0xE0) { c= d & 0x1F; trailing= 1; }
|
||||
else if (d < 0xF0) { c= d & 0x0F; trailing= 2; }
|
||||
else if (d < 0xF8) { c= d & 0x07; trailing= 3; }
|
||||
else {
|
||||
/* no chance for this in UTF-16 */
|
||||
*outlen = out - outstart;
|
||||
*inlen = processed - instart;
|
||||
return(-2);
|
||||
}
|
||||
|
||||
if (inend - in < trailing) {
|
||||
break;
|
||||
}
|
||||
|
||||
for ( ; trailing; trailing--) {
|
||||
if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) break;
|
||||
c <<= 6;
|
||||
c |= d & 0x3F;
|
||||
}
|
||||
|
||||
/* assertion: c is a single UTF-4 value */
|
||||
if (c < 0x10000) {
|
||||
if (out >= outend) break;
|
||||
if (xmlLittleEndian) {
|
||||
tmp = (unsigned char *) out;
|
||||
*tmp = c >> 8;
|
||||
*(tmp + 1) = c;
|
||||
out++;
|
||||
} else {
|
||||
*out++ = c;
|
||||
}
|
||||
}
|
||||
else if (c < 0x110000) {
|
||||
if (out+1 >= outend) break;
|
||||
c -= 0x10000;
|
||||
if (xmlLittleEndian) {
|
||||
tmp1 = 0xD800 | (c >> 10);
|
||||
tmp = (unsigned char *) out;
|
||||
*tmp = tmp1 >> 8;
|
||||
*(tmp + 1) = (unsigned char) tmp1;
|
||||
out++;
|
||||
|
||||
tmp2 = 0xDC00 | (c & 0x03FF);
|
||||
tmp = (unsigned char *) out;
|
||||
*tmp = tmp2 >> 8;
|
||||
*(tmp + 1) = (unsigned char) tmp2;
|
||||
out++;
|
||||
} else {
|
||||
*out++ = 0xD800 | (c >> 10);
|
||||
*out++ = 0xDC00 | (c & 0x03FF);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
processed = in;
|
||||
}
|
||||
*outlen = (out - outstart) * 2;
|
||||
*inlen = processed - instart;
|
||||
return(*outlen);
|
||||
}
|
||||
|
||||
/* This file is licenced under the MIT licence as follows:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is fur-
|
||||
nished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
|
||||
NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
12
src/disk/minivhd/libxml2_encoding.h
Normal file
12
src/disk/minivhd/libxml2_encoding.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LIBXML2_ENCODING_H
|
||||
#define LIBXML2_ENCODING_H
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint16_t mvhd_utf16;
|
||||
|
||||
void xmlEncodingInit(void);
|
||||
int UTF16LEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb);
|
||||
int UTF8ToUTF16LE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen);
|
||||
int UTF16BEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb);
|
||||
int UTF8ToUTF16BE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen);
|
||||
#endif
|
||||
269
src/disk/minivhd/minivhd.h
Normal file
269
src/disk/minivhd/minivhd.h
Normal file
@@ -0,0 +1,269 @@
|
||||
#ifndef MINIVHD_H
|
||||
#define MINIVHD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern int mvhd_errno;
|
||||
|
||||
typedef enum MVHDError {
|
||||
MVHD_ERR_MEM = -128,
|
||||
MVHD_ERR_FILE,
|
||||
MVHD_ERR_NOT_VHD,
|
||||
MVHD_ERR_TYPE,
|
||||
MVHD_ERR_FOOTER_CHECKSUM,
|
||||
MVHD_ERR_SPARSE_CHECKSUM,
|
||||
MVHD_ERR_UTF_TRANSCODING_FAILED,
|
||||
MVHD_ERR_UTF_SIZE,
|
||||
MVHD_ERR_PATH_REL,
|
||||
MVHD_ERR_PATH_LEN,
|
||||
MVHD_ERR_PAR_NOT_FOUND,
|
||||
MVHD_ERR_INVALID_PAR_UUID,
|
||||
MVHD_ERR_INVALID_GEOM,
|
||||
MVHD_ERR_INVALID_SIZE,
|
||||
MVHD_ERR_INVALID_BLOCK_SIZE,
|
||||
MVHD_ERR_INVALID_PARAMS,
|
||||
MVHD_ERR_CONV_SIZE,
|
||||
MVHD_ERR_TIMESTAMP
|
||||
} MVHDError;
|
||||
|
||||
typedef enum MVHDType {
|
||||
MVHD_TYPE_FIXED = 2,
|
||||
MVHD_TYPE_DYNAMIC = 3,
|
||||
MVHD_TYPE_DIFF = 4
|
||||
} MVHDType;
|
||||
|
||||
typedef enum MVHDBlockSize {
|
||||
MVHD_BLOCK_DEFAULT = 0, /**< 2 MB blocks */
|
||||
MVHD_BLOCK_SMALL = 1024, /**< 512 KB blocks */
|
||||
MVHD_BLOCK_LARGE = 4096 /**< 2 MB blocks */
|
||||
} MVHDBlockSize;
|
||||
|
||||
typedef struct MVHDGeom {
|
||||
uint16_t cyl;
|
||||
uint8_t heads;
|
||||
uint8_t spt;
|
||||
} MVHDGeom;
|
||||
|
||||
typedef void (*mvhd_progress_callback)(uint32_t current_sector, uint32_t total_sectors);
|
||||
|
||||
typedef struct MVHDCreationOptions {
|
||||
int type; /** MVHD_TYPE_FIXED, MVHD_TYPE_DYNAMIC, or MVHD_TYPE_DIFF */
|
||||
char* path; /** Absolute path of the new VHD file */
|
||||
char* parent_path; /** For MVHD_TYPE_DIFF, this is the absolute path of the VHD's parent. For non-diff VHDs, this should be NULL. */
|
||||
uint64_t size_in_bytes; /** Total size of the VHD's virtual disk in bytes. Must be a multiple of 512. If 0, the size is auto-calculated from the geometry field. Ignored for MVHD_TYPE_DIFF. */
|
||||
MVHDGeom geometry; /** The geometry of the VHD. If set to 0, the geometry is auto-calculated from the size_in_bytes field. */
|
||||
uint32_t block_size_in_sectors; /** MVHD_BLOCK_LARGE or MVHD_BLOCK_SMALL, or 0 for the default value. The number of sectors per block. */
|
||||
mvhd_progress_callback progress_callback; /** Optional; if not NULL, gets called to indicate progress on the creation operation. Only applies to MVHD_TYPE_FIXED. */
|
||||
} MVHDCreationOptions;
|
||||
|
||||
typedef struct MVHDMeta MVHDMeta;
|
||||
|
||||
/**
|
||||
* \brief Output a string from a MiniVHD error number
|
||||
*
|
||||
* \param [in] err is the error number to return string from
|
||||
*
|
||||
* \return Error string
|
||||
*/
|
||||
const char* mvhd_strerr(MVHDError err);
|
||||
|
||||
/**
|
||||
* \brief A simple test to see if a given file is a VHD
|
||||
*
|
||||
* \param [in] f file to test
|
||||
*
|
||||
* \retval true if f is a VHD
|
||||
* \retval false if f is not a VHD
|
||||
*/
|
||||
bool mvhd_file_is_vhd(FILE* f);
|
||||
|
||||
/**
|
||||
* \brief Open a VHD image for reading and/or writing
|
||||
*
|
||||
* The returned pointer contains all required values and structures (and files) to
|
||||
* read and write to a VHD file.
|
||||
*
|
||||
* Remember to call mvhd_close() when you are finished.
|
||||
*
|
||||
* \param [in] Absolute path to VHD file. Relative path will cause issues when opening
|
||||
* a differencing VHD file
|
||||
* \param [in] readonly set this to true to open the VHD in a read only manner
|
||||
* \param [out] err will be set if the VHD fails to open. Value could be one of
|
||||
* MVHD_ERR_MEM, MVHD_ERR_FILE, MVHD_ERR_NOT_VHD, MVHD_ERR_FOOTER_CHECKSUM, MVHD_ERR_SPARSE_CHECKSUM,
|
||||
* MVHD_ERR_TYPE, MVHD_ERR_TIMESTAMP
|
||||
* If MVHD_ERR_FILE is set, mvhd_errno will be set to the appropriate system errno value
|
||||
*
|
||||
* \return MVHDMeta pointer. If NULL, check err. err may also be set to MVHD_ERR_TIMESTAMP if
|
||||
* opening a differencing VHD.
|
||||
*/
|
||||
MVHDMeta* mvhd_open(const char* path, bool readonly, int* err);
|
||||
|
||||
/**
|
||||
* \brief Update the parent modified timestamp in the VHD file
|
||||
*
|
||||
* Differencing VHD's use a parent last modified timestamp to try and detect if the
|
||||
* parent has been modified after the child has been created. However, this is rather
|
||||
* fragile and can be broken by moving/copying the parent. Also, MS DiskPart does not
|
||||
* set this timestamp in the child :(
|
||||
*
|
||||
* Be careful when using this function that you don't update the timestamp after the
|
||||
* parent actually has been modified.
|
||||
*
|
||||
* \param [in] vhdm Differencing VHD to update.
|
||||
* \param [out] err will be set if the timestamp could not be updated
|
||||
*
|
||||
* \return non-zero on error, 0 on success
|
||||
*/
|
||||
int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err);
|
||||
|
||||
/**
|
||||
* \brief Create a fixed VHD image
|
||||
*
|
||||
* \param [in] path is the absolute path to the image to create
|
||||
* \param [in] geom is the HDD geometry of the image to create. Determines final image size
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
* \param [out] progress_callback optional; if not NULL, gets called to indicate progress on the creation operation
|
||||
*
|
||||
* \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback);
|
||||
|
||||
/**
|
||||
* \brief Create sparse (dynamic) VHD image.
|
||||
*
|
||||
* \param [in] path is the absolute path to the VHD file to create
|
||||
* \param [in] geom is the HDD geometry of the image to create. Determines final image size
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err);
|
||||
|
||||
/**
|
||||
* \brief Create differencing VHD imagee.
|
||||
*
|
||||
* \param [in] path is the absolute path to the VHD file to create
|
||||
* \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err);
|
||||
|
||||
/**
|
||||
* \brief Create a VHD using the provided options
|
||||
*
|
||||
* Use mvhd_create_ex if you want more control over the VHD's options. For quick creation, you can use mvhd_create_fixed, mvhd_create_sparse, or mvhd_create_diff.
|
||||
*
|
||||
* \param [in] options the VHD creation options.
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err);
|
||||
|
||||
/**
|
||||
* \brief Safely close a VHD image
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure to close
|
||||
*/
|
||||
void mvhd_close(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Calculate hard disk geometry from a provided size
|
||||
*
|
||||
* The VHD format uses Cylinder, Heads, Sectors per Track (CHS) when accessing the disk.
|
||||
* The size of the disk can be determined from C * H * S * sector_size.
|
||||
*
|
||||
* Note, maximum geometry size (in bytes) is 65535 * 16 * 255 * 512, which is 127GB.
|
||||
* However, the maximum VHD size is 2040GB. For VHDs larger than 127GB, the geometry size will be
|
||||
* smaller than the actual VHD size.
|
||||
*
|
||||
* This function determines the appropriate CHS geometry from a provided size in bytes.
|
||||
* The calculations used are those provided in "Appendix: CHS Calculation" from the document
|
||||
* "Virtual Hard Disk Image Format Specification" provided by Microsoft.
|
||||
*
|
||||
* \param [in] size the desired VHD image size, in bytes
|
||||
*
|
||||
* \return MVHDGeom the calculated geometry. This can be used in the appropriate create functions.
|
||||
*/
|
||||
MVHDGeom mvhd_calculate_geometry(uint64_t size);
|
||||
|
||||
/**
|
||||
* \brief Convert a raw disk image to a fixed VHD image
|
||||
*
|
||||
* \param [in] utf8_raw_path is the path of the raw image to convert
|
||||
* \param [in] utf8_vhd_path is the path of the VHD to create
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err);
|
||||
|
||||
/**
|
||||
* \brief Convert a raw disk image to a sparse VHD image
|
||||
*
|
||||
* \param [in] utf8_raw_path is the path of the raw image to convert
|
||||
* \param [in] utf8_vhd_path is the path of the VHD to create
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err);
|
||||
|
||||
/**
|
||||
* \brief Convert a VHD image to a raw disk image
|
||||
*
|
||||
* \param [in] utf8_vhd_path is the path of the VHD to convert
|
||||
* \param [in] utf8_raw_path is the path of the raw image to create
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns the raw disk image FILE pointer
|
||||
*/
|
||||
FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err);
|
||||
|
||||
/**
|
||||
* \brief Read sectors from VHD file
|
||||
*
|
||||
* Read num_sectors, beginning at offset from the VHD file into a buffer
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset the sector offset from which to start reading from
|
||||
* \param [in] num_sectors the number of sectors to read
|
||||
* \param [out] out_buff the buffer to write sector data to
|
||||
*
|
||||
* \return the number of sectors that were not read, or zero
|
||||
*/
|
||||
int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Write sectors to VHD file
|
||||
*
|
||||
* Write num_sectors, beginning at offset from a buffer VHD file into the VHD file
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset the sector offset from which to start writing to
|
||||
* \param [in] num_sectors the number of sectors to write
|
||||
* \param [in] in_buffer the buffer to write sector data to
|
||||
*
|
||||
* \return the number of sectors that were not written, or zero
|
||||
*/
|
||||
int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief Write zeroed sectors to VHD file
|
||||
*
|
||||
* Write num_sectors, beginning at offset, of zero data into the VHD file.
|
||||
* We reuse the existing write functions, with a preallocated zero buffer as
|
||||
* our source buffer.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset the sector offset from which to start writing to
|
||||
* \param [in] num_sectors the number of sectors to write
|
||||
*
|
||||
* \return the number of sectors that were not written, or zero
|
||||
*/
|
||||
int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors);
|
||||
#endif
|
||||
108
src/disk/minivhd/minivhd_convert.c
Normal file
108
src/disk/minivhd/minivhd_convert.c
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "minivhd_create.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd.h"
|
||||
|
||||
static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err);
|
||||
|
||||
static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err) {
|
||||
FILE *raw_img = mvhd_fopen(utf8_raw_path, "rb", err);
|
||||
if (raw_img == NULL) {
|
||||
*err = MVHD_ERR_FILE;
|
||||
return NULL;
|
||||
}
|
||||
if (geom == NULL) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_END);
|
||||
uint64_t size_bytes = (uint64_t)mvhd_ftello64(raw_img);
|
||||
MVHDGeom new_geom = mvhd_calculate_geometry(size_bytes);
|
||||
if (mvhd_calc_size_bytes(&new_geom) != size_bytes) {
|
||||
*err = MVHD_ERR_CONV_SIZE;
|
||||
return NULL;
|
||||
}
|
||||
geom->cyl = new_geom.cyl;
|
||||
geom->heads = new_geom.heads;
|
||||
geom->spt = new_geom.spt;
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_SET);
|
||||
return raw_img;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) {
|
||||
MVHDGeom geom;
|
||||
FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err);
|
||||
if (raw_img == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom);
|
||||
MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, size_in_bytes, &geom, err, NULL);
|
||||
if (vhdm == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return vhdm;
|
||||
}
|
||||
MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) {
|
||||
MVHDGeom geom;
|
||||
MVHDMeta *vhdm = NULL;
|
||||
FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err);
|
||||
if (raw_img == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err);
|
||||
if (vhdm == NULL) {
|
||||
goto end;
|
||||
}
|
||||
uint8_t buff[4096] = {0}; // 8 sectors
|
||||
uint8_t empty_buff[4096] = {0};
|
||||
int total_sectors = mvhd_calc_size_sectors(&geom);
|
||||
int copy_sect = 0;
|
||||
for (int i = 0; i < total_sectors; i += 8) {
|
||||
copy_sect = 8;
|
||||
if ((i + 8) >= total_sectors) {
|
||||
copy_sect = total_sectors - i;
|
||||
memset(buff, 0, sizeof buff);
|
||||
}
|
||||
fread(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img);
|
||||
/* Only write data if there's data to write, to take advantage of the sparse VHD format */
|
||||
if (memcmp(buff, empty_buff, sizeof buff) != 0) {
|
||||
mvhd_write_sectors(vhdm, i, copy_sect, buff);
|
||||
}
|
||||
}
|
||||
end:
|
||||
fclose(raw_img);
|
||||
return vhdm;
|
||||
}
|
||||
FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err) {
|
||||
FILE *raw_img = mvhd_fopen(utf8_raw_path, "wb", err);
|
||||
if (raw_img == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
MVHDMeta *vhdm = mvhd_open(utf8_vhd_path, true, err);
|
||||
if (vhdm == NULL) {
|
||||
fclose(raw_img);
|
||||
return NULL;
|
||||
}
|
||||
uint8_t buff[4096] = {0}; // 8 sectors
|
||||
int total_sectors = mvhd_calc_size_sectors((MVHDGeom*)&vhdm->footer.geom);
|
||||
int copy_sect = 0;
|
||||
for (int i = 0; i < total_sectors; i += 8) {
|
||||
copy_sect = 8;
|
||||
if ((i + 8) >= total_sectors) {
|
||||
copy_sect = total_sectors - i;
|
||||
}
|
||||
mvhd_read_sectors(vhdm, i, copy_sect, buff);
|
||||
fwrite(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img);
|
||||
}
|
||||
mvhd_close(vhdm);
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_SET);
|
||||
return raw_img;
|
||||
}
|
||||
485
src/disk/minivhd/minivhd_create.c
Normal file
485
src/disk/minivhd/minivhd_create.c
Normal file
@@ -0,0 +1,485 @@
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "cwalk.h"
|
||||
#include "libxml2_encoding.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd_struct_rw.h"
|
||||
#include "minivhd_io.h"
|
||||
#include "minivhd_create.h"
|
||||
#include "minivhd.h"
|
||||
|
||||
static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off);
|
||||
static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors);
|
||||
static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
const char* child_path,
|
||||
const char* par_path,
|
||||
uint64_t start_offset,
|
||||
mvhd_utf16* w2ku_path_buff,
|
||||
mvhd_utf16* w2ru_path_buff,
|
||||
MVHDError* err);
|
||||
static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err);
|
||||
|
||||
/**
|
||||
* \brief Populate a VHD footer
|
||||
*
|
||||
* \param [in] footer to populate
|
||||
* \param [in] size_in_bytes is the total size of the virtual hard disk in bytes
|
||||
* \param [in] geom to use
|
||||
* \param [in] type of HVD that is being created
|
||||
* \param [in] sparse_header_off, an absolute file offset to the sparse header. Not used for fixed VHD images
|
||||
*/
|
||||
static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) {
|
||||
memcpy(footer->cookie, "conectix", sizeof footer->cookie);
|
||||
footer->features = 0x00000002;
|
||||
footer->fi_fmt_vers = 0x00010000;
|
||||
footer->data_offset = (type == MVHD_TYPE_DIFF || type == MVHD_TYPE_DYNAMIC) ? sparse_header_off : 0xffffffffffffffff;
|
||||
footer->timestamp = vhd_calc_timestamp();
|
||||
memcpy(footer->cr_app, "mvhd", sizeof footer->cr_app);
|
||||
footer->cr_vers = 0x000e0000;
|
||||
memcpy(footer->cr_host_os, "Wi2k", sizeof footer->cr_host_os);
|
||||
footer->orig_sz = footer->curr_sz = size_in_bytes;
|
||||
footer->geom.cyl = geom->cyl;
|
||||
footer->geom.heads = geom->heads;
|
||||
footer->geom.spt = geom->spt;
|
||||
footer->disk_type = type;
|
||||
mvhd_generate_uuid(footer->uuid);
|
||||
footer->checksum = mvhd_gen_footer_checksum(footer);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Populate a VHD sparse header
|
||||
*
|
||||
* \param [in] header for sparse and differencing images
|
||||
* \param [in] num_blks is the number of data blocks that the image contains
|
||||
* \param [in] bat_offset is the absolute file offset for start of the Block Allocation Table
|
||||
* \param [in] block_size_in_sectors is the block size in sectors.
|
||||
*/
|
||||
static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors) {
|
||||
memcpy(header->cookie, "cxsparse", sizeof header->cookie);
|
||||
header->data_offset = 0xffffffffffffffff;
|
||||
header->bat_offset = bat_offset;
|
||||
header->head_vers = 0x00010000;
|
||||
header->max_bat_ent = num_blks;
|
||||
header->block_sz = block_size_in_sectors * (uint32_t)MVHD_SECTOR_SIZE;
|
||||
header->checksum = mvhd_gen_sparse_checksum(header);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generate parent locators for differencing VHD images
|
||||
*
|
||||
* \param [in] header the sparse header to populate with parent locator entries
|
||||
* \param [in] child_path is the full path to the VHD being created
|
||||
* \param [in] par_path is the full path to the parent image
|
||||
* \param [in] start_offset is the absolute file offset from where to start storing the entries themselves. Must be sector aligned.
|
||||
* \param [out] w2ku_path_buff is a buffer containing the full path to the parent, encoded as UTF16-LE
|
||||
* \param [out] w2ru_path_buff is a buffer containing the relative path to the parent, encoded as UTF16-LE
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \retval 0 if success
|
||||
* \retval < 0 if an error occurrs. Check value of *err for actual error
|
||||
*/
|
||||
static int mvhd_gen_par_loc(MVHDSparseHeader* header,
|
||||
const char* child_path,
|
||||
const char* par_path,
|
||||
uint64_t start_offset,
|
||||
mvhd_utf16* w2ku_path_buff,
|
||||
mvhd_utf16* w2ru_path_buff,
|
||||
MVHDError* err) {
|
||||
/* Get our paths to store in the differencing VHD. We want both the absolute path to the parent,
|
||||
as well as the relative path from the child VHD */
|
||||
int rv = 0;
|
||||
char* par_filename;
|
||||
size_t par_fn_len;
|
||||
char rel_path[MVHD_MAX_PATH_BYTES] = {0};
|
||||
char child_dir[MVHD_MAX_PATH_BYTES] = {0};
|
||||
size_t child_dir_len;
|
||||
if (strlen(child_path) < sizeof child_dir) {
|
||||
strcpy(child_dir, child_path);
|
||||
} else {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
cwk_path_get_basename(par_path, (const char**)&par_filename, &par_fn_len);
|
||||
cwk_path_get_dirname(child_dir, &child_dir_len);
|
||||
child_dir[child_dir_len] = '\0';
|
||||
size_t rel_len = cwk_path_get_relative(child_dir, par_path, rel_path, sizeof rel_path);
|
||||
if (rel_len > sizeof rel_path) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
/* We have our paths, now store the parent filename directly in the sparse header. */
|
||||
int outlen = sizeof header->par_utf16_name;
|
||||
int utf_ret;
|
||||
utf_ret = UTF8ToUTF16BE((unsigned char*)header->par_utf16_name, &outlen, (const unsigned char*)par_filename, (int*)&par_fn_len);
|
||||
if (utf_ret < 0) {
|
||||
mvhd_set_encoding_err(utf_ret, (int*)err);
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* And encode the paths to UTF16-LE */
|
||||
size_t par_path_len = strlen(par_path);
|
||||
outlen = sizeof *w2ku_path_buff * MVHD_MAX_PATH_CHARS;
|
||||
utf_ret = UTF8ToUTF16LE((unsigned char*)w2ku_path_buff, &outlen, (const unsigned char*)par_path, (int*)&par_path_len);
|
||||
if (utf_ret < 0) {
|
||||
mvhd_set_encoding_err(utf_ret, (int*)err);
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
int w2ku_len = utf_ret;
|
||||
outlen = sizeof *w2ru_path_buff * MVHD_MAX_PATH_CHARS;
|
||||
utf_ret = UTF8ToUTF16LE((unsigned char*)w2ru_path_buff, &outlen, (const unsigned char*)rel_path, (int*)&rel_len);
|
||||
if (utf_ret < 0) {
|
||||
mvhd_set_encoding_err(utf_ret, (int*)err);
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
int w2ru_len = utf_ret;
|
||||
/**
|
||||
* Finally populate the parent locaters in the sparse header.
|
||||
* This is the information needed to find the paths saved elsewhere
|
||||
* in the VHD image
|
||||
*/
|
||||
|
||||
/* Note about the plat_data_space field: The VHD spec says this field stores the number of sectors needed to store the locator path.
|
||||
* However, Hyper-V and VPC store the number of bytes, not the number of sectors, and will refuse to open VHDs which have the
|
||||
* number of sectors in this field.
|
||||
* See https://stackoverflow.com/questions/40760181/mistake-in-virtual-hard-disk-image-format-specification
|
||||
*/
|
||||
header->par_loc_entry[0].plat_code = MVHD_DIF_LOC_W2KU;
|
||||
header->par_loc_entry[0].plat_data_len = (uint32_t)w2ku_len;
|
||||
header->par_loc_entry[0].plat_data_offset = (uint64_t)start_offset;
|
||||
header->par_loc_entry[0].plat_data_space = ((header->par_loc_entry[0].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE;
|
||||
header->par_loc_entry[1].plat_code = MVHD_DIF_LOC_W2RU;
|
||||
header->par_loc_entry[1].plat_data_len = (uint32_t)w2ru_len;
|
||||
header->par_loc_entry[1].plat_data_offset = (uint64_t)start_offset + ((uint64_t)header->par_loc_entry[0].plat_data_space);
|
||||
header->par_loc_entry[1].plat_data_space = ((header->par_loc_entry[1].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE;
|
||||
goto end;
|
||||
|
||||
end:
|
||||
return rv;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback) {
|
||||
uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom);
|
||||
return mvhd_create_fixed_raw(path, NULL, size_in_bytes, &geom, err, progress_callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief internal function that implements public mvhd_create_fixed() functionality
|
||||
*
|
||||
* Contains one more parameter than the public function, to allow using an existing
|
||||
* raw disk image as the data source for the new fixed VHD.
|
||||
*
|
||||
* \param [in] raw_image file handle to a raw disk image to populate VHD
|
||||
*/
|
||||
MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) {
|
||||
uint8_t img_data[MVHD_SECTOR_SIZE] = {0};
|
||||
uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0};
|
||||
MVHDMeta* vhdm = calloc(1, sizeof *vhdm);
|
||||
if (vhdm == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
FILE* f = mvhd_fopen(path, "wb+", err);
|
||||
if (f == NULL) {
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
mvhd_fseeko64(f, 0, SEEK_SET);
|
||||
uint32_t size_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE);
|
||||
uint32_t s;
|
||||
if (progress_callback)
|
||||
progress_callback(0, size_sectors);
|
||||
if (raw_img != NULL) {
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_END);
|
||||
uint64_t raw_size = (uint64_t)mvhd_ftello64(raw_img);
|
||||
MVHDGeom raw_geom = mvhd_calculate_geometry(raw_size);
|
||||
if (mvhd_calc_size_bytes(&raw_geom) != raw_size) {
|
||||
*err = MVHD_ERR_CONV_SIZE;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
mvhd_gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0);
|
||||
mvhd_fseeko64(raw_img, 0, SEEK_SET);
|
||||
for (s = 0; s < size_sectors; s++) {
|
||||
fread(img_data, sizeof img_data, 1, raw_img);
|
||||
fwrite(img_data, sizeof img_data, 1, f);
|
||||
if (progress_callback)
|
||||
progress_callback(s + 1, size_sectors);
|
||||
}
|
||||
} else {
|
||||
mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0);
|
||||
for (s = 0; s < size_sectors; s++) {
|
||||
fwrite(img_data, sizeof img_data, 1, f);
|
||||
if (progress_callback)
|
||||
progress_callback(s + 1, size_sectors);
|
||||
}
|
||||
}
|
||||
mvhd_footer_to_buffer(&vhdm->footer, footer_buff);
|
||||
fwrite(footer_buff, sizeof footer_buff, 1, f);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
free(vhdm);
|
||||
vhdm = mvhd_open(path, false, err);
|
||||
goto end;
|
||||
|
||||
cleanup_vhdm:
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
end:
|
||||
return vhdm;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create sparse or differencing VHD image.
|
||||
*
|
||||
* \param [in] path is the absolute path to the VHD file to create
|
||||
* \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image
|
||||
* \param [in] size_in_bytes is the total size in bytes of the virtual hard disk image
|
||||
* \param [in] geom is the HDD geometry of the image to create. Determines final image size
|
||||
* \param [in] block_size_in_sectors is the block size in sectors
|
||||
* \param [out] err indicates what error occurred, if any
|
||||
*
|
||||
* \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct
|
||||
*/
|
||||
static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err) {
|
||||
uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0};
|
||||
uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0};
|
||||
uint8_t bat_sect[MVHD_SECTOR_SIZE];
|
||||
MVHDGeom par_geom = {0};
|
||||
memset(bat_sect, 0xffffffff, sizeof bat_sect);
|
||||
MVHDMeta* vhdm = NULL;
|
||||
MVHDMeta* par_vhdm = NULL;
|
||||
mvhd_utf16* w2ku_path_buff = NULL;
|
||||
mvhd_utf16* w2ru_path_buff = NULL;
|
||||
uint32_t par_mod_timestamp = 0;
|
||||
if (par_path != NULL) {
|
||||
par_mod_timestamp = mvhd_file_mod_timestamp(par_path, err);
|
||||
if (*err != 0) {
|
||||
goto end;
|
||||
}
|
||||
par_vhdm = mvhd_open(par_path, true, err);
|
||||
if (par_vhdm == NULL) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
vhdm = calloc(1, sizeof *vhdm);
|
||||
if (vhdm == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto cleanup_par_vhdm;
|
||||
}
|
||||
if (par_vhdm != NULL) {
|
||||
/* We use the geometry from the parent VHD, not what was passed in */
|
||||
par_geom.cyl = par_vhdm->footer.geom.cyl;
|
||||
par_geom.heads = par_vhdm->footer.geom.heads;
|
||||
par_geom.spt = par_vhdm->footer.geom.spt;
|
||||
geom = &par_geom;
|
||||
size_in_bytes = par_vhdm->footer.curr_sz;
|
||||
} else if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) {
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
|
||||
FILE* f = mvhd_fopen(path, "wb+", err);
|
||||
if (f == NULL) {
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
mvhd_fseeko64(f, 0, SEEK_SET);
|
||||
/* Note, the sparse header follows the footer copy at the beginning of the file */
|
||||
if (par_path == NULL) {
|
||||
mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE);
|
||||
} else {
|
||||
mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE);
|
||||
}
|
||||
mvhd_footer_to_buffer(&vhdm->footer, footer_buff);
|
||||
/* As mentioned, start with a copy of the footer */
|
||||
fwrite(footer_buff, sizeof footer_buff, 1, f);
|
||||
/**
|
||||
* Calculate the number of (2MB or 512KB) data blocks required to store the entire
|
||||
* contents of the disk image, followed by the number of sectors the
|
||||
* BAT occupies in the image. Note, the BAT is sector aligned, and is padded
|
||||
* to the next sector boundary
|
||||
* */
|
||||
uint32_t size_in_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE);
|
||||
uint32_t num_blks = size_in_sectors / block_size_in_sectors;
|
||||
if (size_in_sectors % block_size_in_sectors != 0) {
|
||||
num_blks += 1;
|
||||
}
|
||||
uint32_t num_bat_sect = num_blks / MVHD_BAT_ENT_PER_SECT;
|
||||
if (num_blks % MVHD_BAT_ENT_PER_SECT != 0) {
|
||||
num_bat_sect += 1;
|
||||
}
|
||||
/* Storing the BAT directly following the footer and header */
|
||||
uint64_t bat_offset = MVHD_FOOTER_SIZE + MVHD_SPARSE_SIZE;
|
||||
uint64_t par_loc_offset = 0;
|
||||
|
||||
/**
|
||||
* If creating a differencing VHD, populate the sparse header with additional
|
||||
* data about the parent image, and where to find it, and it's last modified timestamp
|
||||
* */
|
||||
if (par_vhdm != NULL) {
|
||||
/**
|
||||
* Create output buffers to encode paths into.
|
||||
* The paths are not stored directly in the sparse header, hence the need to
|
||||
* store them in buffers to be written to the VHD image later
|
||||
*/
|
||||
w2ku_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ku_path_buff);
|
||||
if (w2ku_path_buff == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
w2ru_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ru_path_buff);
|
||||
if (w2ru_path_buff == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
memcpy(vhdm->sparse.par_uuid, par_vhdm->footer.uuid, sizeof vhdm->sparse.par_uuid);
|
||||
par_loc_offset = bat_offset + ((uint64_t)num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE);
|
||||
if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path_buff, w2ru_path_buff, (MVHDError*)err) < 0) {
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
vhdm->sparse.par_timestamp = par_mod_timestamp;
|
||||
}
|
||||
mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors);
|
||||
mvhd_header_to_buffer(&vhdm->sparse, sparse_buff);
|
||||
fwrite(sparse_buff, sizeof sparse_buff, 1, f);
|
||||
/* The BAT sectors need to be filled with 0xffffffff */
|
||||
for (uint32_t i = 0; i < num_bat_sect; i++) {
|
||||
fwrite(bat_sect, sizeof bat_sect, 1, f);
|
||||
}
|
||||
mvhd_write_empty_sectors(f, 5);
|
||||
/**
|
||||
* If creating a differencing VHD, the paths to the parent image need to be written
|
||||
* tp the file. Both absolute and relative paths are written
|
||||
* */
|
||||
if (par_vhdm != NULL) {
|
||||
uint64_t curr_pos = (uint64_t)mvhd_ftello64(f);
|
||||
/* Double check my sums... */
|
||||
assert(curr_pos == par_loc_offset);
|
||||
/* Fill the space required for location data with zero */
|
||||
uint8_t empty_sect[MVHD_SECTOR_SIZE] = {0};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (uint32_t j = 0; j < (vhdm->sparse.par_loc_entry[i].plat_data_space / MVHD_SECTOR_SIZE); j++) {
|
||||
fwrite(empty_sect, sizeof empty_sect, 1, f);
|
||||
}
|
||||
}
|
||||
/* Now write the location entries */
|
||||
mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET);
|
||||
fwrite(w2ku_path_buff, vhdm->sparse.par_loc_entry[0].plat_data_len, 1, f);
|
||||
mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET);
|
||||
fwrite(w2ru_path_buff, vhdm->sparse.par_loc_entry[1].plat_data_len, 1, f);
|
||||
/* and reset the file position to continue */
|
||||
mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + vhdm->sparse.par_loc_entry[1].plat_data_space, SEEK_SET);
|
||||
mvhd_write_empty_sectors(f, 5);
|
||||
}
|
||||
/* And finish with the footer */
|
||||
fwrite(footer_buff, sizeof footer_buff, 1, f);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
free(vhdm);
|
||||
vhdm = mvhd_open(path, false, err);
|
||||
goto end;
|
||||
|
||||
cleanup_vhdm:
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
cleanup_par_vhdm:
|
||||
if (par_vhdm != NULL) {
|
||||
mvhd_close(par_vhdm);
|
||||
}
|
||||
end:
|
||||
free(w2ku_path_buff);
|
||||
free(w2ru_path_buff);
|
||||
return vhdm;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) {
|
||||
uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom);
|
||||
return mvhd_create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err);
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) {
|
||||
return mvhd_create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err);
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err) {
|
||||
uint32_t geom_sector_size;
|
||||
switch (options.type)
|
||||
{
|
||||
case MVHD_TYPE_FIXED:
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
geom_sector_size = mvhd_calc_size_sectors(&(options.geometry));
|
||||
if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0)
|
||||
|| (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES)
|
||||
|| (options.size_in_bytes == 0 && geom_sector_size == 0))
|
||||
{
|
||||
*err = MVHD_ERR_INVALID_SIZE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes)
|
||||
{
|
||||
*err = MVHD_ERR_INVALID_GEOM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.size_in_bytes == 0)
|
||||
options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE;
|
||||
|
||||
if (geom_sector_size == 0)
|
||||
options.geometry = mvhd_calculate_geometry(options.size_in_bytes);
|
||||
break;
|
||||
case MVHD_TYPE_DIFF:
|
||||
if (options.parent_path == NULL)
|
||||
{
|
||||
*err = MVHD_ERR_FILE;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*err = MVHD_ERR_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.path == NULL)
|
||||
{
|
||||
*err = MVHD_ERR_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (options.type != MVHD_TYPE_FIXED)
|
||||
{
|
||||
if (options.block_size_in_sectors == MVHD_BLOCK_DEFAULT)
|
||||
options.block_size_in_sectors = MVHD_BLOCK_LARGE;
|
||||
|
||||
if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL)
|
||||
{
|
||||
*err = MVHD_ERR_INVALID_BLOCK_SIZE;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (options.type)
|
||||
{
|
||||
case MVHD_TYPE_FIXED:
|
||||
return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback);
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
return mvhd_create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err);
|
||||
case MVHD_TYPE_DIFF:
|
||||
return mvhd_create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err);
|
||||
}
|
||||
|
||||
return NULL; /* Make the compiler happy */
|
||||
}
|
||||
8
src/disk/minivhd/minivhd_create.h
Normal file
8
src/disk/minivhd/minivhd_create.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef MINIVHD_CREATE_H
|
||||
#define MINIVHD_CREATE_H
|
||||
#include <stdio.h>
|
||||
#include "minivhd.h"
|
||||
|
||||
MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback);
|
||||
|
||||
#endif
|
||||
96
src/disk/minivhd/minivhd_internal.h
Normal file
96
src/disk/minivhd/minivhd_internal.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef MINIVHD_INTERNAL_H
|
||||
#define MINIVHD_INTERNAL_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MVHD_FOOTER_SIZE 512
|
||||
#define MVHD_SPARSE_SIZE 1024
|
||||
|
||||
#define MVHD_SECTOR_SIZE 512
|
||||
#define MVHD_BAT_ENT_PER_SECT 128
|
||||
|
||||
#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000
|
||||
|
||||
#define MVHD_SPARSE_BLK 0xffffffff
|
||||
/* For simplicity, we don't handle paths longer than this
|
||||
* Note, this is the max path in characters, as that is what
|
||||
* Windows uses
|
||||
*/
|
||||
#define MVHD_MAX_PATH_CHARS 260
|
||||
#define MVHD_MAX_PATH_BYTES 1040
|
||||
|
||||
#define MVHD_DIF_LOC_W2RU 0x57327275
|
||||
#define MVHD_DIF_LOC_W2KU 0x57326B75
|
||||
|
||||
typedef struct MVHDSectorBitmap {
|
||||
uint8_t* curr_bitmap;
|
||||
int sector_count;
|
||||
int curr_block;
|
||||
} MVHDSectorBitmap;
|
||||
|
||||
typedef struct MVHDFooter {
|
||||
uint8_t cookie[8];
|
||||
uint32_t features;
|
||||
uint32_t fi_fmt_vers;
|
||||
uint64_t data_offset;
|
||||
uint32_t timestamp;
|
||||
uint8_t cr_app[4];
|
||||
uint32_t cr_vers;
|
||||
uint8_t cr_host_os[4];
|
||||
uint64_t orig_sz;
|
||||
uint64_t curr_sz;
|
||||
struct {
|
||||
uint16_t cyl;
|
||||
uint8_t heads;
|
||||
uint8_t spt;
|
||||
} geom;
|
||||
uint32_t disk_type;
|
||||
uint32_t checksum;
|
||||
uint8_t uuid[16];
|
||||
uint8_t saved_st;
|
||||
uint8_t reserved[427];
|
||||
} MVHDFooter;
|
||||
|
||||
typedef struct MVHDSparseHeader {
|
||||
uint8_t cookie[8];
|
||||
uint64_t data_offset;
|
||||
uint64_t bat_offset;
|
||||
uint32_t head_vers;
|
||||
uint32_t max_bat_ent;
|
||||
uint32_t block_sz;
|
||||
uint32_t checksum;
|
||||
uint8_t par_uuid[16];
|
||||
uint32_t par_timestamp;
|
||||
uint32_t reserved_1;
|
||||
uint8_t par_utf16_name[512];
|
||||
struct {
|
||||
uint32_t plat_code;
|
||||
uint32_t plat_data_space;
|
||||
uint32_t plat_data_len;
|
||||
uint32_t reserved;
|
||||
uint64_t plat_data_offset;
|
||||
} par_loc_entry[8];
|
||||
uint8_t reserved_2[256];
|
||||
} MVHDSparseHeader;
|
||||
|
||||
typedef struct MVHDMeta MVHDMeta;
|
||||
struct MVHDMeta {
|
||||
FILE* f;
|
||||
bool readonly;
|
||||
char filename[MVHD_MAX_PATH_BYTES];
|
||||
struct MVHDMeta* parent;
|
||||
MVHDFooter footer;
|
||||
MVHDSparseHeader sparse;
|
||||
uint32_t* block_offset;
|
||||
int sect_per_block;
|
||||
MVHDSectorBitmap bitmap;
|
||||
int (*read_sectors)(MVHDMeta*, uint32_t, int, void*);
|
||||
int (*write_sectors)(MVHDMeta*, uint32_t, int, void*);
|
||||
struct {
|
||||
uint8_t* zero_data;
|
||||
int sector_count;
|
||||
} format_buffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
279
src/disk/minivhd/minivhd_io.c
Normal file
279
src/disk/minivhd/minivhd_io.c
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Sector reading and writing implementations
|
||||
*/
|
||||
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
|
||||
/* The following bit array macros adapted from
|
||||
http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html */
|
||||
|
||||
#define VHD_SETBIT(A,k) ( A[(k/8)] |= (0x80 >> (k%8)) )
|
||||
#define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) )
|
||||
#define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) )
|
||||
|
||||
static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect);
|
||||
static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk);
|
||||
static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk);
|
||||
static void mvhd_create_block(MVHDMeta* vhdm, int blk);
|
||||
static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Check that we will not be overflowing buffers
|
||||
*
|
||||
* \param [in] offset The offset from which we are beginning from
|
||||
* \param [in] num_sectors The number of sectors which we desire to read/write
|
||||
* \param [in] total_sectors The total number of sectors available
|
||||
* \param [out] transfer_sect The number of sectors to actually write.
|
||||
* This may be lower than num_sectors if offset + num_sectors >= total_sectors
|
||||
* \param [out] trunc_sectors The number of sectors truncated if transfer_sectors < num_sectors
|
||||
*/
|
||||
static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect) {
|
||||
*transfer_sect = num_sectors;
|
||||
*trunc_sect = 0;
|
||||
if ((total_sectors - offset) < (uint32_t)*transfer_sect) {
|
||||
*transfer_sect = total_sectors - offset;
|
||||
*trunc_sect = num_sectors - *transfer_sect;
|
||||
}
|
||||
}
|
||||
|
||||
void mvhd_write_empty_sectors(FILE* f, int sector_count) {
|
||||
uint8_t zero_bytes[MVHD_SECTOR_SIZE] = {0};
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
fwrite(zero_bytes, sizeof zero_bytes, 1, f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read the sector bitmap for a block.
|
||||
*
|
||||
* If the block is sparse, the sector bitmap in memory will be
|
||||
* zeroed. Otherwise, the sector bitmap is read from the VHD file.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] blk The block for which to read the sector bitmap from
|
||||
*/
|
||||
static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) {
|
||||
if (vhdm->block_offset[blk] != MVHD_SPARSE_BLK) {
|
||||
mvhd_fseeko64(vhdm->f, (uint64_t)vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET);
|
||||
fread(vhdm->bitmap.curr_bitmap, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
} else {
|
||||
memset(vhdm->bitmap.curr_bitmap, 0, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE);
|
||||
}
|
||||
vhdm->bitmap.curr_block = blk;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Write the current sector bitmap in memory to file
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) {
|
||||
if (vhdm->bitmap.curr_block >= 0) {
|
||||
int64_t abs_offset = (int64_t)vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, abs_offset, SEEK_SET);
|
||||
fwrite(vhdm->bitmap.curr_bitmap, MVHD_SECTOR_SIZE, vhdm->bitmap.sector_count, vhdm->f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Write block offset from memory into file
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] blk The block for which to write the offset for
|
||||
*/
|
||||
static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) {
|
||||
uint64_t table_offset = vhdm->sparse.bat_offset + ((uint64_t)blk * sizeof *vhdm->block_offset);
|
||||
uint32_t offset = mvhd_to_be32(vhdm->block_offset[blk]);
|
||||
mvhd_fseeko64(vhdm->f, table_offset, SEEK_SET);
|
||||
fwrite(&offset, sizeof offset, 1, vhdm->f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create an empty block in a sparse or differencing VHD image
|
||||
*
|
||||
* VHD images store data in blocks, which are typically 4096 sectors in size
|
||||
* (~2MB). These blocks may be stored on disk in any order. Blocks are created
|
||||
* on demand when required.
|
||||
*
|
||||
* This function creates new, empty blocks, by replacing the footer at the end of the file
|
||||
* and then re-inserting the footer at the new file end. The BAT table entry for the
|
||||
* new block is updated with the new offset.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] blk The block number to create
|
||||
*/
|
||||
static void mvhd_create_block(MVHDMeta* vhdm, int blk) {
|
||||
uint8_t footer[MVHD_FOOTER_SIZE];
|
||||
/* Seek to where the footer SHOULD be */
|
||||
mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
fread(footer, sizeof footer, 1, vhdm->f);
|
||||
mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
if (!mvhd_is_conectix_str(footer)) {
|
||||
/* Oh dear. We use the header instead, since something has gone wrong at the footer */
|
||||
mvhd_fseeko64(vhdm->f, 0, SEEK_SET);
|
||||
fread(footer, sizeof footer, 1, vhdm->f);
|
||||
mvhd_fseeko64(vhdm->f, 0, SEEK_END);
|
||||
}
|
||||
int64_t abs_offset = mvhd_ftello64(vhdm->f);
|
||||
if (abs_offset % MVHD_SECTOR_SIZE != 0) {
|
||||
/* Yikes! We're supposed to be on a sector boundary. Add some padding */
|
||||
int64_t padding_amount = (int64_t)MVHD_SECTOR_SIZE - (abs_offset % MVHD_SECTOR_SIZE);
|
||||
uint8_t zero_byte = 0;
|
||||
for (int i = 0; i < padding_amount; i++) {
|
||||
fwrite(&zero_byte, sizeof zero_byte, 1, vhdm->f);
|
||||
}
|
||||
abs_offset += padding_amount;
|
||||
}
|
||||
uint32_t sect_offset = (uint32_t)(abs_offset / MVHD_SECTOR_SIZE);
|
||||
int blk_size_sectors = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE;
|
||||
mvhd_write_empty_sectors(vhdm->f, vhdm->bitmap.sector_count + blk_size_sectors);
|
||||
/* Add a bit of padding. That's what Windows appears to do, although it's not strictly necessary... */
|
||||
mvhd_write_empty_sectors(vhdm->f, 5);
|
||||
/* And we finish with the footer */
|
||||
fwrite(footer, sizeof footer, 1, vhdm->f);
|
||||
/* We no longer have a sparse block. Update that BAT! */
|
||||
vhdm->block_offset[blk] = sect_offset;
|
||||
mvhd_write_bat_entry(vhdm, blk);
|
||||
}
|
||||
|
||||
int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
int64_t addr;
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
addr = (int64_t)offset * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
fread(out_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
uint8_t* buff = (uint8_t*)out_buff;
|
||||
int64_t addr;
|
||||
uint32_t s, ls;
|
||||
int blk, prev_blk, sib;
|
||||
ls = offset + transfer_sectors;
|
||||
prev_blk = -1;
|
||||
for (s = offset; s < ls; s++) {
|
||||
blk = s / vhdm->sect_per_block;
|
||||
sib = s % vhdm->sect_per_block;
|
||||
if (blk != prev_blk) {
|
||||
prev_blk = blk;
|
||||
if (vhdm->bitmap.curr_block != blk) {
|
||||
mvhd_read_sect_bitmap(vhdm, blk);
|
||||
mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR);
|
||||
} else {
|
||||
addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
}
|
||||
}
|
||||
if (VHD_TESTBIT(vhdm->bitmap.curr_bitmap, sib)) {
|
||||
fread(buff, MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
} else {
|
||||
memset(buff, 0, MVHD_SECTOR_SIZE);
|
||||
mvhd_fseeko64(vhdm->f, MVHD_SECTOR_SIZE, SEEK_CUR);
|
||||
}
|
||||
buff += MVHD_SECTOR_SIZE;
|
||||
}
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
uint8_t* buff = (uint8_t*)out_buff;
|
||||
MVHDMeta* curr_vhdm = vhdm;
|
||||
uint32_t s, ls;
|
||||
int blk, sib;
|
||||
ls = offset + transfer_sectors;
|
||||
for (s = offset; s < ls; s++) {
|
||||
while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) {
|
||||
blk = s / curr_vhdm->sect_per_block;
|
||||
sib = s % curr_vhdm->sect_per_block;
|
||||
if (curr_vhdm->bitmap.curr_block != blk) {
|
||||
mvhd_read_sect_bitmap(curr_vhdm, blk);
|
||||
}
|
||||
if (!VHD_TESTBIT(curr_vhdm->bitmap.curr_bitmap, sib)) {
|
||||
curr_vhdm = curr_vhdm->parent;
|
||||
} else { break; }
|
||||
}
|
||||
/* We handle actual sector reading using the fixed or sparse functions,
|
||||
as a differencing VHD is also a sparse VHD */
|
||||
if (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF || curr_vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) {
|
||||
mvhd_sparse_read(curr_vhdm, s, 1, buff);
|
||||
} else {
|
||||
mvhd_fixed_read(curr_vhdm, s, 1, buff);
|
||||
}
|
||||
curr_vhdm = vhdm;
|
||||
buff += MVHD_SECTOR_SIZE;
|
||||
}
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
int64_t addr;
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
addr = (int64_t)offset * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
fwrite(in_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
int transfer_sectors, truncated_sectors;
|
||||
uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE);
|
||||
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
|
||||
uint8_t* buff = (uint8_t*)in_buff;
|
||||
int64_t addr;
|
||||
uint32_t s, ls;
|
||||
int blk, prev_blk, sib;
|
||||
ls = offset + transfer_sectors;
|
||||
prev_blk = -1;
|
||||
for (s = offset; s < ls; s++) {
|
||||
blk = s / vhdm->sect_per_block;
|
||||
sib = s % vhdm->sect_per_block;
|
||||
if (vhdm->bitmap.curr_block != blk && prev_blk >= 0) {
|
||||
/* Write the sector bitmap for the previous block, before we replace it. */
|
||||
mvhd_write_curr_sect_bitmap(vhdm);
|
||||
}
|
||||
if (vhdm->block_offset[blk] == MVHD_SPARSE_BLK) {
|
||||
/* "read" the sector bitmap first, before creating a new block, as the bitmap will be
|
||||
zero either way */
|
||||
mvhd_read_sect_bitmap(vhdm, blk);
|
||||
mvhd_create_block(vhdm, blk);
|
||||
}
|
||||
if (blk != prev_blk) {
|
||||
if (vhdm->bitmap.curr_block != blk) {
|
||||
mvhd_read_sect_bitmap(vhdm, blk);
|
||||
mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR);
|
||||
} else {
|
||||
addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE;
|
||||
mvhd_fseeko64(vhdm->f, addr, SEEK_SET);
|
||||
}
|
||||
prev_blk = blk;
|
||||
}
|
||||
fwrite(buff, MVHD_SECTOR_SIZE, 1, vhdm->f);
|
||||
VHD_SETBIT(vhdm->bitmap.curr_bitmap, sib);
|
||||
buff += MVHD_SECTOR_SIZE;
|
||||
}
|
||||
/* And write the sector bitmap for the last block we visited to disk */
|
||||
mvhd_write_curr_sect_bitmap(vhdm);
|
||||
return truncated_sectors;
|
||||
}
|
||||
|
||||
int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
return 0;
|
||||
}
|
||||
132
src/disk/minivhd/minivhd_io.h
Normal file
132
src/disk/minivhd/minivhd_io.h
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef MINIVHD_IO_H
|
||||
#define MINIVHD_IO_H
|
||||
#include "minivhd.h"
|
||||
|
||||
/**
|
||||
* \brief Write zero filled sectors to file.
|
||||
*
|
||||
* Note, the caller should set the file position before calling this
|
||||
* function for correct operation.
|
||||
*
|
||||
* \param [in] f File to write sectors to
|
||||
* \param [in] sector_count The number of sectors to write
|
||||
*/
|
||||
void mvhd_write_empty_sectors(FILE* f, int sector_count);
|
||||
|
||||
/**
|
||||
* \brief Read a fixed VHD image
|
||||
*
|
||||
* Fixed VHD images are essentially raw image files with a footer tacked on
|
||||
* the end. They are therefore straightforward to write
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Read a sparse VHD image
|
||||
*
|
||||
* Sparse, or dynamic images are VHD images that grow as data is written to them.
|
||||
*
|
||||
* This function implements the logic to read sectors from the file, taking into
|
||||
* account the fact that blocks may be stored on disk in any order, and that the
|
||||
* read could cross block boundaries.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Read a differencing VHD image
|
||||
*
|
||||
* Differencing images are a variant of a sparse image. They contain the grow-on-demand
|
||||
* properties of sparse images, but also reference a parent image. Data is read from the
|
||||
* child image only if it is newer than the data stored in the parent image.
|
||||
*
|
||||
* This function implements the logic to read sectors from the child, or a parent image.
|
||||
* Differencing images may have a differencing image as a parent, creating a chain of images.
|
||||
* There is no theoretical chain length limit, although I do not consider long chains to be
|
||||
* advisable. Verifying the parent-child relationship is not very robust.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to read from
|
||||
* \param [in] num_sectors The desired number of sectors to read
|
||||
* \param [out] out_buff An output buffer to store read sectors. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were read from file
|
||||
* \retval >0 < num_sectors were read from file
|
||||
*/
|
||||
int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff);
|
||||
|
||||
/**
|
||||
* \brief Write to a fixed VHD image
|
||||
*
|
||||
* Fixed VHD images are essentially raw image files with a footer tacked on
|
||||
* the end. They are therefore straightforward to write
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief Write to a sparse or differencing VHD image
|
||||
*
|
||||
* Sparse, or dynamic images are VHD images that grow as data is written to them.
|
||||
*
|
||||
* Differencing images are a variant of a sparse image. They contain the grow-on-demand
|
||||
* properties of sparse images, but also reference a parent image. Data is always written
|
||||
* to the child image. This makes writing to differencing images essentially identical to
|
||||
* writing to sparse images, hence they use the same function.
|
||||
*
|
||||
* This function implements the logic to write sectors to the file, taking into
|
||||
* account the fact that blocks may be stored on disk in any order, and that the
|
||||
* write operation could cross block boundaries.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
/**
|
||||
* \brief A no-op function to "write" to read-only VHD images
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [in] offset Sector offset to write to
|
||||
* \param [in] num_sectors The desired number of sectors to write
|
||||
* \param [in] in_buff A source buffer to write sectors from. Must be
|
||||
* large enough to hold num_sectors worth of sectors.
|
||||
*
|
||||
* \retval 0 num_sectors were written to file
|
||||
* \retval >0 < num_sectors were written to file
|
||||
*/
|
||||
int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff);
|
||||
|
||||
#endif
|
||||
535
src/disk/minivhd/minivhd_manage.c
Normal file
535
src/disk/minivhd/minivhd_manage.c
Normal file
@@ -0,0 +1,535 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief VHD management functions (open, close, read write etc)
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "cwalk.h"
|
||||
#include "libxml2_encoding.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_io.h"
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd_struct_rw.h"
|
||||
#include "minivhd.h"
|
||||
|
||||
int mvhd_errno = 0;
|
||||
static char tmp_open_path[MVHD_MAX_PATH_BYTES] = {0};
|
||||
struct MVHDPaths {
|
||||
char dir_path[MVHD_MAX_PATH_BYTES];
|
||||
char file_name[MVHD_MAX_PATH_BYTES];
|
||||
char w2ku_path[MVHD_MAX_PATH_BYTES];
|
||||
char w2ru_path[MVHD_MAX_PATH_BYTES];
|
||||
char joined_path[MVHD_MAX_PATH_BYTES];
|
||||
uint16_t tmp_src_path[MVHD_MAX_PATH_CHARS];
|
||||
};
|
||||
|
||||
static void mvhd_read_footer(MVHDMeta* vhdm);
|
||||
static void mvhd_read_sparse_header(MVHDMeta* vhdm);
|
||||
static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm);
|
||||
static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm);
|
||||
static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err);
|
||||
static void mvhd_calc_sparse_values(MVHDMeta* vhdm);
|
||||
static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err);
|
||||
|
||||
/**
|
||||
* \brief Populate data stuctures with content from a VHD footer
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_read_footer(MVHDMeta* vhdm) {
|
||||
uint8_t buffer[MVHD_FOOTER_SIZE];
|
||||
mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
fread(buffer, sizeof buffer, 1, vhdm->f);
|
||||
mvhd_buffer_to_footer(&vhdm->footer, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Populate data stuctures with content from a VHD sparse header
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_read_sparse_header(MVHDMeta* vhdm) {
|
||||
uint8_t buffer[MVHD_SPARSE_SIZE];
|
||||
mvhd_fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET);
|
||||
fread(buffer, sizeof buffer, 1, vhdm->f);
|
||||
mvhd_buffer_to_header(&vhdm->sparse, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Validate VHD footer checksum
|
||||
*
|
||||
* This works by generating a checksum from the footer, and comparing it against the stored checksum.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm) {
|
||||
return vhdm->footer.checksum == mvhd_gen_footer_checksum(&vhdm->footer);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Validate VHD sparse header checksum
|
||||
*
|
||||
* This works by generating a checksum from the sparse header, and comparing it against the stored checksum.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm) {
|
||||
return vhdm->sparse.checksum == mvhd_gen_sparse_checksum(&vhdm->sparse);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read BAT into MiniVHD data structure
|
||||
*
|
||||
* The Block Allocation Table (BAT) is the structure in a sparse and differencing VHD which stores
|
||||
* the 4-byte sector offsets for each data block. This function allocates enough memory to contain
|
||||
* the entire BAT, and then reads the contents of the BAT into the buffer.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails
|
||||
*
|
||||
* \retval -1 if an error occurrs. Check value of err in this case
|
||||
* \retval 0 if the function call succeeds
|
||||
*/
|
||||
static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) {
|
||||
vhdm->block_offset = calloc(vhdm->sparse.max_bat_ent, sizeof *vhdm->block_offset);
|
||||
if (vhdm->block_offset == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
mvhd_fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET);
|
||||
for (uint32_t i = 0; i < vhdm->sparse.max_bat_ent; i++) {
|
||||
fread(&vhdm->block_offset[i], sizeof *vhdm->block_offset, 1, vhdm->f);
|
||||
vhdm->block_offset[i] = mvhd_from_be32(vhdm->block_offset[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Perform a one-time calculation of some sparse VHD values
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_calc_sparse_values(MVHDMeta* vhdm) {
|
||||
vhdm->sect_per_block = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE;
|
||||
int bm_bytes = vhdm->sect_per_block / 8;
|
||||
vhdm->bitmap.sector_count = bm_bytes / MVHD_SECTOR_SIZE;
|
||||
if (bm_bytes % MVHD_SECTOR_SIZE > 0) {
|
||||
vhdm->bitmap.sector_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate memory for a sector bitmap.
|
||||
*
|
||||
* Each data block is preceded by a sector bitmap. Each bit indicates whether the corresponding sector
|
||||
* is considered 'clean' or 'dirty' (for sparse VHD images), or whether to read from the parent or current
|
||||
* image (for differencing images).
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
* \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails
|
||||
*
|
||||
* \retval -1 if an error occurrs. Check value of err in this case
|
||||
* \retval 0 if the function call succeeds
|
||||
*/
|
||||
static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err) {
|
||||
vhdm->bitmap.curr_bitmap = calloc(vhdm->bitmap.sector_count, MVHD_SECTOR_SIZE);
|
||||
if (vhdm->bitmap.curr_bitmap == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
return -1;
|
||||
}
|
||||
vhdm->bitmap.curr_block = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the path for a given platform code exists
|
||||
*
|
||||
* From the available paths, both relative and absolute, construct a full path
|
||||
* and attempt to open a file at that path.
|
||||
*
|
||||
* Note, this function makes no attempt to verify that the path is the correct
|
||||
* VHD image, or even a VHD image at all.
|
||||
*
|
||||
* \param [in] paths a struct containing all available paths to work with
|
||||
* \param [in] the platform code to try and obtain a path for. Setting this to zero
|
||||
* will try using the directory of the child image
|
||||
*
|
||||
* \retval true if a file is found
|
||||
* \retval false if a file is not found
|
||||
*/
|
||||
static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) {
|
||||
memset(paths->joined_path, 0, sizeof paths->joined_path);
|
||||
FILE* f;
|
||||
int cwk_ret, ferr;
|
||||
enum cwk_path_style style = cwk_path_guess_style((const char*)paths->dir_path);
|
||||
cwk_path_set_style(style);
|
||||
cwk_ret = 1;
|
||||
if (plat_code == MVHD_DIF_LOC_W2RU && *paths->w2ru_path) {
|
||||
cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->w2ru_path, paths->joined_path, sizeof paths->joined_path);
|
||||
} else if (plat_code == MVHD_DIF_LOC_W2KU && *paths->w2ku_path) {
|
||||
memcpy(paths->joined_path, paths->w2ku_path, (sizeof paths->joined_path) - 1);
|
||||
cwk_ret = 0;
|
||||
} else if (plat_code == 0) {
|
||||
cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->file_name, paths->joined_path, sizeof paths->joined_path);
|
||||
}
|
||||
if (cwk_ret > MVHD_MAX_PATH_BYTES) {
|
||||
return false;
|
||||
}
|
||||
f = mvhd_fopen((const char*)paths->joined_path, "rb", &ferr);
|
||||
if (f != NULL) {
|
||||
/* We found a file at the requested path! */
|
||||
memcpy(tmp_open_path, paths->joined_path, (sizeof paths->joined_path) - 1);
|
||||
tmp_open_path[sizeof tmp_open_path - 1] = '\0';
|
||||
fclose(f);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief attempt to obtain a file path to a file that may be a valid VHD image
|
||||
*
|
||||
* Differential VHD images store both a UTF-16BE file name (or path), and up to
|
||||
* eight "parent locator" entries. Using this information, this function tries to
|
||||
* find a parent image.
|
||||
*
|
||||
* This function does not verify if the path returned is a valid parent image.
|
||||
*
|
||||
* \param [in] vhdm current MiniVHD data structure
|
||||
* \param [out] err any errors that may occurr. Check this if NULL is returned
|
||||
*
|
||||
* \return a pointer to the global string `tmp_open_path`, or NULL if a path could
|
||||
* not be found, or some error occurred
|
||||
*/
|
||||
static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) {
|
||||
int utf_outlen, utf_inlen, utf_ret;
|
||||
char* par_fp = NULL;
|
||||
/* We can't resolve relative paths if we don't have an absolute
|
||||
path to work with */
|
||||
if (!cwk_path_is_absolute((const char*)vhdm->filename)) {
|
||||
*err = MVHD_ERR_PATH_REL;
|
||||
goto end;
|
||||
}
|
||||
struct MVHDPaths* paths = calloc(1, sizeof *paths);
|
||||
if (paths == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
size_t dirlen;
|
||||
cwk_path_get_dirname((const char*)vhdm->filename, &dirlen);
|
||||
if (dirlen >= sizeof paths->dir_path) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
memcpy(paths->dir_path, vhdm->filename, dirlen);
|
||||
/* Get the filename field from the sparse header. */
|
||||
utf_outlen = (int)sizeof paths->file_name;
|
||||
utf_inlen = (int)sizeof vhdm->sparse.par_utf16_name;
|
||||
utf_ret = UTF16BEToUTF8((unsigned char*)paths->file_name, &utf_outlen, (const unsigned char*)vhdm->sparse.par_utf16_name, &utf_inlen);
|
||||
if (utf_ret < 0) {
|
||||
mvhd_set_encoding_err(utf_ret, err);
|
||||
goto paths_cleanup;
|
||||
}
|
||||
/* Now read the parent locator entries, both relative and absolute, if they exist */
|
||||
unsigned char* loc_path;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
utf_outlen = MVHD_MAX_PATH_BYTES - 1;
|
||||
if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2RU) {
|
||||
loc_path = (unsigned char*)paths->w2ru_path;
|
||||
} else if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2KU) {
|
||||
loc_path = (unsigned char*)paths->w2ku_path;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
utf_inlen = vhdm->sparse.par_loc_entry[i].plat_data_len;
|
||||
if (utf_inlen > MVHD_MAX_PATH_BYTES) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
mvhd_fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET);
|
||||
fread(paths->tmp_src_path, sizeof (uint8_t), utf_inlen, vhdm->f);
|
||||
/* Note, the W2*u parent locators are UTF-16LE, unlike the filename field previously obtained,
|
||||
which is UTF-16BE */
|
||||
utf_ret = UTF16LEToUTF8(loc_path, &utf_outlen, (const unsigned char*)paths->tmp_src_path, &utf_inlen);
|
||||
if (utf_ret < 0) {
|
||||
mvhd_set_encoding_err(utf_ret, err);
|
||||
goto paths_cleanup;
|
||||
}
|
||||
}
|
||||
/* We have paths in UTF-8. We should have enough info to try and find the parent VHD */
|
||||
/* Does the relative path exist? */
|
||||
if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2RU)) {
|
||||
par_fp = tmp_open_path;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
/* What about trying the child directory? */
|
||||
if (mvhd_parent_path_exists(paths, 0)) {
|
||||
par_fp = tmp_open_path;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
/* Well, all else fails, try the stored absolute path, if it exists */
|
||||
if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2KU)) {
|
||||
par_fp = tmp_open_path;
|
||||
goto paths_cleanup;
|
||||
}
|
||||
/* If we reach this point, we could not find a path with a valid file */
|
||||
par_fp = NULL;
|
||||
*err = MVHD_ERR_PAR_NOT_FOUND;
|
||||
|
||||
paths_cleanup:
|
||||
free(paths);
|
||||
paths = NULL;
|
||||
end:
|
||||
return par_fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Attach the read/write function pointers to read/write functions
|
||||
*
|
||||
* Depending on the VHD type, different sector reading and writing functions are used.
|
||||
* The functions are called via function pointers stored in the vhdm struct.
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
static void mvhd_assign_io_funcs(MVHDMeta* vhdm) {
|
||||
switch (vhdm->footer.disk_type) {
|
||||
case MVHD_TYPE_FIXED:
|
||||
vhdm->read_sectors = mvhd_fixed_read;
|
||||
vhdm->write_sectors = mvhd_fixed_write;
|
||||
break;
|
||||
case MVHD_TYPE_DYNAMIC:
|
||||
vhdm->read_sectors = mvhd_sparse_read;
|
||||
vhdm->write_sectors = mvhd_sparse_diff_write;
|
||||
break;
|
||||
case MVHD_TYPE_DIFF:
|
||||
vhdm->read_sectors = mvhd_diff_read;
|
||||
vhdm->write_sectors = mvhd_sparse_diff_write;
|
||||
break;
|
||||
}
|
||||
if (vhdm->readonly) {
|
||||
vhdm->write_sectors = mvhd_noop_write;
|
||||
}
|
||||
}
|
||||
|
||||
bool mvhd_file_is_vhd(FILE* f) {
|
||||
if (f) {
|
||||
uint8_t con_str[8];
|
||||
mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END);
|
||||
fread(con_str, sizeof con_str, 1, f);
|
||||
return mvhd_is_conectix_str(con_str);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MVHDGeom mvhd_calculate_geometry(uint64_t size) {
|
||||
MVHDGeom chs;
|
||||
uint32_t ts = (uint32_t)(size / MVHD_SECTOR_SIZE);
|
||||
uint32_t spt, heads, cyl, cth;
|
||||
if (ts > 65535 * 16 * 255) {
|
||||
ts = 65535 * 16 * 255;
|
||||
}
|
||||
if (ts >= 65535 * 16 * 63) {
|
||||
spt = 255;
|
||||
heads = 16;
|
||||
cth = ts / spt;
|
||||
} else {
|
||||
spt = 17;
|
||||
cth = ts / spt;
|
||||
heads = (cth + 1023) / 1024;
|
||||
if (heads < 4) {
|
||||
heads = 4;
|
||||
}
|
||||
if (cth >= (heads * 1024) || heads > 16) {
|
||||
spt = 31;
|
||||
heads = 16;
|
||||
cth = ts / spt;
|
||||
}
|
||||
if (cth >= (heads * 1024)) {
|
||||
spt = 63;
|
||||
heads = 16;
|
||||
cth = ts / spt;
|
||||
}
|
||||
}
|
||||
cyl = cth / heads;
|
||||
chs.heads = heads;
|
||||
chs.spt = spt;
|
||||
chs.cyl = cyl;
|
||||
return chs;
|
||||
}
|
||||
|
||||
MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) {
|
||||
MVHDError open_err;
|
||||
MVHDMeta *vhdm = calloc(sizeof *vhdm, 1);
|
||||
if (vhdm == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto end;
|
||||
}
|
||||
if (strlen(path) >= sizeof vhdm->filename) {
|
||||
*err = MVHD_ERR_PATH_LEN;
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
//This is safe, as we've just checked for potential overflow above
|
||||
strcpy(vhdm->filename, path);
|
||||
vhdm->f = readonly ? mvhd_fopen((const char*)vhdm->filename, "rb", err) : mvhd_fopen((const char*)vhdm->filename, "rb+", err);
|
||||
if (vhdm->f == NULL) {
|
||||
/* note, mvhd_fopen sets err for us */
|
||||
goto cleanup_vhdm;
|
||||
}
|
||||
vhdm->readonly = readonly;
|
||||
if (!mvhd_file_is_vhd(vhdm->f)) {
|
||||
*err = MVHD_ERR_NOT_VHD;
|
||||
goto cleanup_file;
|
||||
}
|
||||
mvhd_read_footer(vhdm);
|
||||
if (!mvhd_footer_checksum_valid(vhdm)) {
|
||||
*err = MVHD_ERR_FOOTER_CHECKSUM;
|
||||
goto cleanup_file;
|
||||
}
|
||||
if (vhdm->footer.disk_type == MVHD_TYPE_DIFF || vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) {
|
||||
mvhd_read_sparse_header(vhdm);
|
||||
if (!mvhd_sparse_checksum_valid(vhdm)) {
|
||||
*err = MVHD_ERR_SPARSE_CHECKSUM;
|
||||
goto cleanup_file;
|
||||
}
|
||||
if (mvhd_read_bat(vhdm, &open_err) == -1) {
|
||||
*err = open_err;
|
||||
goto cleanup_file;
|
||||
}
|
||||
mvhd_calc_sparse_values(vhdm);
|
||||
if (mvhd_init_sector_bitmap(vhdm, &open_err) == -1) {
|
||||
*err = open_err;
|
||||
goto cleanup_bat;
|
||||
}
|
||||
|
||||
} else if (vhdm->footer.disk_type != MVHD_TYPE_FIXED) {
|
||||
*err = MVHD_ERR_TYPE;
|
||||
goto cleanup_bitmap;
|
||||
}
|
||||
mvhd_assign_io_funcs(vhdm);
|
||||
vhdm->format_buffer.zero_data = calloc(64, MVHD_SECTOR_SIZE);
|
||||
if (vhdm->format_buffer.zero_data == NULL) {
|
||||
*err = MVHD_ERR_MEM;
|
||||
goto cleanup_bitmap;
|
||||
}
|
||||
vhdm->format_buffer.sector_count = 64;
|
||||
if (vhdm->footer.disk_type == MVHD_TYPE_DIFF) {
|
||||
char* par_path = mvhd_get_diff_parent_path(vhdm, err);
|
||||
if (par_path == NULL) {
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err);
|
||||
if (*err != 0) {
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
if (vhdm->sparse.par_timestamp != par_mod_ts) {
|
||||
/* The last-modified timestamp is to fragile to make this a fatal error.
|
||||
Instead, we inform the caller of the potential problem. */
|
||||
*err = MVHD_ERR_TIMESTAMP;
|
||||
}
|
||||
vhdm->parent = mvhd_open(par_path, true, err);
|
||||
if (vhdm->parent == NULL) {
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
if (memcmp(vhdm->sparse.par_uuid, vhdm->parent->footer.uuid, sizeof vhdm->sparse.par_uuid) != 0) {
|
||||
*err = MVHD_ERR_INVALID_PAR_UUID;
|
||||
goto cleanup_format_buff;
|
||||
}
|
||||
}
|
||||
/* If we've reached this point, we are good to go, so skip the cleanup steps */
|
||||
goto end;
|
||||
cleanup_format_buff:
|
||||
free(vhdm->format_buffer.zero_data);
|
||||
vhdm->format_buffer.zero_data = NULL;
|
||||
cleanup_bitmap:
|
||||
free(vhdm->bitmap.curr_bitmap);
|
||||
vhdm->bitmap.curr_bitmap = NULL;
|
||||
cleanup_bat:
|
||||
free(vhdm->block_offset);
|
||||
vhdm->block_offset = NULL;
|
||||
cleanup_file:
|
||||
fclose(vhdm->f);
|
||||
vhdm->f = NULL;
|
||||
cleanup_vhdm:
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
end:
|
||||
return vhdm;
|
||||
}
|
||||
|
||||
void mvhd_close(MVHDMeta* vhdm) {
|
||||
if (vhdm != NULL) {
|
||||
if (vhdm->parent != NULL) {
|
||||
mvhd_close(vhdm->parent);
|
||||
}
|
||||
fclose(vhdm->f);
|
||||
if (vhdm->block_offset != NULL) {
|
||||
free(vhdm->block_offset);
|
||||
vhdm->block_offset = NULL;
|
||||
}
|
||||
if (vhdm->bitmap.curr_bitmap != NULL) {
|
||||
free(vhdm->bitmap.curr_bitmap);
|
||||
vhdm->bitmap.curr_bitmap = NULL;
|
||||
}
|
||||
if (vhdm->format_buffer.zero_data != NULL) {
|
||||
free(vhdm->format_buffer.zero_data);
|
||||
vhdm->format_buffer.zero_data = NULL;
|
||||
}
|
||||
free(vhdm);
|
||||
vhdm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) {
|
||||
uint8_t sparse_buff[1024];
|
||||
if (vhdm == NULL || err == NULL) {
|
||||
*err = MVHD_ERR_INVALID_PARAMS;
|
||||
return -1;
|
||||
}
|
||||
if (vhdm->footer.disk_type != MVHD_TYPE_DIFF) {
|
||||
*err = MVHD_ERR_TYPE;
|
||||
return -1;
|
||||
}
|
||||
char* par_path = mvhd_get_diff_parent_path(vhdm, err);
|
||||
if (par_path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err);
|
||||
if (*err != 0) {
|
||||
return -1;
|
||||
}
|
||||
/* Update the timestamp and sparse header checksum */
|
||||
vhdm->sparse.par_timestamp = par_mod_ts;
|
||||
vhdm->sparse.checksum = mvhd_gen_sparse_checksum(&vhdm->sparse);
|
||||
/* Generate and write the updated sparse header */
|
||||
mvhd_header_to_buffer(&vhdm->sparse, sparse_buff);
|
||||
mvhd_fseeko64(vhdm->f, (int64_t)vhdm->footer.data_offset, SEEK_SET);
|
||||
fwrite(sparse_buff, sizeof sparse_buff, 1, vhdm->f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) {
|
||||
return vhdm->read_sectors(vhdm, offset, num_sectors, out_buff);
|
||||
}
|
||||
|
||||
int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) {
|
||||
return vhdm->write_sectors(vhdm, offset, num_sectors, in_buff);
|
||||
}
|
||||
|
||||
int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors) {
|
||||
int num_full = num_sectors / vhdm->format_buffer.sector_count;
|
||||
int remain = num_sectors % vhdm->format_buffer.sector_count;
|
||||
for (int i = 0; i < num_full; i++) {
|
||||
vhdm->write_sectors(vhdm, offset, vhdm->format_buffer.sector_count, vhdm->format_buffer.zero_data);
|
||||
offset += vhdm->format_buffer.sector_count;
|
||||
}
|
||||
vhdm->write_sectors(vhdm, offset, remain, vhdm->format_buffer.zero_data);
|
||||
return 0;
|
||||
}
|
||||
167
src/disk/minivhd/minivhd_struct_rw.c
Normal file
167
src/disk/minivhd/minivhd_struct_rw.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Header and footer serialize/deserialize functions
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "minivhd_util.h"
|
||||
#include "minivhd_internal.h"
|
||||
|
||||
/* Read data from footer into the struct members, swapping endian where necessary
|
||||
Note: order matters here! We must read each field in the order the struct is in.
|
||||
Doing this may be less elegant than performing a memcpy to a packed struct, but
|
||||
it avoids potential data alignment issues, and the endian swapping allows us to
|
||||
use the fields directly. */
|
||||
|
||||
static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer);
|
||||
static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer);
|
||||
|
||||
/**
|
||||
* \brief Get the next field from a buffer and store it in a struct member, converting endian if necessary
|
||||
*
|
||||
* \param [out] struct_memb struct member to save the field to
|
||||
* \param [in] memb_size the size of struct_memb, in bytes
|
||||
* \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32)
|
||||
* \param [in] buffer the buffer from which fields are read from. Will be advanced at the end of the function call
|
||||
*/
|
||||
static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) {
|
||||
memcpy(struct_memb, *buffer, memb_size);
|
||||
if (req_endian) {
|
||||
switch (memb_size) {
|
||||
case 2:
|
||||
*(uint16_t*)(struct_memb) = mvhd_from_be16(*(uint16_t*)(struct_memb));
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t*)(struct_memb) = mvhd_from_be32(*(uint32_t*)(struct_memb));
|
||||
break;
|
||||
case 8:
|
||||
*(uint64_t*)(struct_memb) = mvhd_from_be64(*(uint64_t*)(struct_memb));
|
||||
break;
|
||||
}
|
||||
}
|
||||
*buffer += memb_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Save a struct member into a buffer, converting endian if necessary
|
||||
*
|
||||
* \param [in] struct_memb struct member read from
|
||||
* \param [in] memb_size the size of struct_memb, in bytes
|
||||
* \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32)
|
||||
* \param [out] buffer the buffer from which struct member is saved to. Will be advanced at the end of the function call
|
||||
*/
|
||||
static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) {
|
||||
uint8_t *buf_ptr = *buffer;
|
||||
memcpy(buf_ptr, struct_memb, memb_size);
|
||||
if (req_endian) {
|
||||
switch (memb_size) {
|
||||
case 2:
|
||||
*((uint16_t*)buf_ptr) = mvhd_to_be16(*(uint16_t*)(struct_memb));
|
||||
break;
|
||||
case 4:
|
||||
*((uint32_t*)buf_ptr) = mvhd_to_be32(*(uint32_t*)(struct_memb));
|
||||
break;
|
||||
case 8:
|
||||
*((uint64_t*)buf_ptr) = mvhd_to_be64(*(uint64_t*)(struct_memb));
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf_ptr += memb_size;
|
||||
*buffer = buf_ptr;
|
||||
}
|
||||
|
||||
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
|
||||
}
|
||||
|
||||
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
|
||||
}
|
||||
|
||||
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
|
||||
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
|
||||
}
|
||||
mvhd_next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
|
||||
}
|
||||
|
||||
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer) {
|
||||
uint8_t* buff_ptr = buffer;
|
||||
mvhd_next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
|
||||
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
|
||||
}
|
||||
mvhd_next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
|
||||
}
|
||||
38
src/disk/minivhd/minivhd_struct_rw.h
Normal file
38
src/disk/minivhd/minivhd_struct_rw.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef MINIVHD_STRUCT_RW_H
|
||||
#define MINIVHD_STRUCT_RW_H
|
||||
|
||||
#include "minivhd_internal.h"
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD footer from a buffer to a struct
|
||||
*
|
||||
* \param [out] footer save contents of buffer into footer
|
||||
* \param [in] buffer VHD footer in raw bytes
|
||||
*/
|
||||
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD sparse header from a buffer to a struct
|
||||
*
|
||||
* \param [out] header save contents of buffer into header
|
||||
* \param [in] buffer VHD header in raw bytes
|
||||
*/
|
||||
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD footer struct to a buffer
|
||||
*
|
||||
* \param [in] footer save contents of struct into buffer
|
||||
* \param [out] buffer VHD footer in raw bytes
|
||||
*/
|
||||
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer);
|
||||
|
||||
/**
|
||||
* \brief Save the contents of a VHD sparse header struct to a buffer
|
||||
*
|
||||
* \param [in] header save contents of struct into buffer
|
||||
* \param [out] buffer VHD sparse header in raw bytes
|
||||
*/
|
||||
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer);
|
||||
|
||||
#endif
|
||||
329
src/disk/minivhd/minivhd_util.c
Normal file
329
src/disk/minivhd/minivhd_util.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Utility functions
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "libxml2_encoding.h"
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd_util.h"
|
||||
|
||||
const char MVHD_CONECTIX_COOKIE[] = "conectix";
|
||||
const char MVHD_CREATOR[] = "pcem";
|
||||
const char MVHD_CREATOR_HOST_OS[] = "Wi2k";
|
||||
const char MVHD_CXSPARSE_COOKIE[] = "cxsparse";
|
||||
|
||||
uint16_t mvhd_from_be16(uint16_t val) {
|
||||
uint8_t *tmp = (uint8_t*)&val;
|
||||
uint16_t ret = 0;
|
||||
ret |= (uint16_t)tmp[0] << 8;
|
||||
ret |= (uint16_t)tmp[1] << 0;
|
||||
return ret;
|
||||
}
|
||||
uint32_t mvhd_from_be32(uint32_t val) {
|
||||
uint8_t *tmp = (uint8_t*)&val;
|
||||
uint32_t ret = 0;
|
||||
ret = (uint32_t)tmp[0] << 24;
|
||||
ret |= (uint32_t)tmp[1] << 16;
|
||||
ret |= (uint32_t)tmp[2] << 8;
|
||||
ret |= (uint32_t)tmp[3] << 0;
|
||||
return ret;
|
||||
}
|
||||
uint64_t mvhd_from_be64(uint64_t val) {
|
||||
uint8_t *tmp = (uint8_t*)&val;
|
||||
uint64_t ret = 0;
|
||||
ret = (uint64_t)tmp[0] << 56;
|
||||
ret |= (uint64_t)tmp[1] << 48;
|
||||
ret |= (uint64_t)tmp[2] << 40;
|
||||
ret |= (uint64_t)tmp[3] << 32;
|
||||
ret |= (uint64_t)tmp[4] << 24;
|
||||
ret |= (uint64_t)tmp[5] << 16;
|
||||
ret |= (uint64_t)tmp[6] << 8;
|
||||
ret |= (uint64_t)tmp[7] << 0;
|
||||
return ret;
|
||||
}
|
||||
uint16_t mvhd_to_be16(uint16_t val) {
|
||||
uint16_t ret = 0;
|
||||
uint8_t *tmp = (uint8_t*)&ret;
|
||||
tmp[0] = (val & 0xff00) >> 8;
|
||||
tmp[1] = (val & 0x00ff) >> 0;
|
||||
return ret;
|
||||
}
|
||||
uint32_t mvhd_to_be32(uint32_t val) {
|
||||
uint32_t ret = 0;
|
||||
uint8_t *tmp = (uint8_t*)&ret;
|
||||
tmp[0] = (val & 0xff000000) >> 24;
|
||||
tmp[1] = (val & 0x00ff0000) >> 16;
|
||||
tmp[2] = (val & 0x0000ff00) >> 8;
|
||||
tmp[3] = (val & 0x000000ff) >> 0;
|
||||
return ret;
|
||||
}
|
||||
uint64_t mvhd_to_be64(uint64_t val) {
|
||||
uint64_t ret = 0;
|
||||
uint8_t *tmp = (uint8_t*)&ret;
|
||||
tmp[0] = (uint8_t)((val & 0xff00000000000000) >> 56);
|
||||
tmp[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
|
||||
tmp[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
|
||||
tmp[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
|
||||
tmp[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
|
||||
tmp[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
|
||||
tmp[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
|
||||
tmp[7] = (uint8_t)((val & 0x00000000000000ff) >> 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool mvhd_is_conectix_str(const void* buffer) {
|
||||
if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void mvhd_generate_uuid(uint8_t* uuid)
|
||||
{
|
||||
/* We aren't doing crypto here, so using system time as seed should be good enough */
|
||||
srand((unsigned int)time(0));
|
||||
for (int n = 0; n < 16; n++) {
|
||||
uuid[n] = rand();
|
||||
}
|
||||
uuid[6] &= 0x0F;
|
||||
uuid[6] |= 0x40; /* Type 4 */
|
||||
uuid[8] &= 0x3F;
|
||||
uuid[8] |= 0x80; /* Variant 1 */
|
||||
}
|
||||
|
||||
uint32_t vhd_calc_timestamp(void)
|
||||
{
|
||||
time_t start_time;
|
||||
time_t curr_time;
|
||||
double vhd_time;
|
||||
start_time = MVHD_START_TS; /* 1 Jan 2000 00:00 */
|
||||
curr_time = time(NULL);
|
||||
vhd_time = difftime(curr_time, start_time);
|
||||
return (uint32_t)vhd_time;
|
||||
}
|
||||
|
||||
uint32_t mvhd_epoch_to_vhd_ts(time_t ts) {
|
||||
time_t start_time = MVHD_START_TS;
|
||||
if (ts < start_time) {
|
||||
return start_time;
|
||||
}
|
||||
double vhd_time = difftime(ts, start_time);
|
||||
return (uint32_t)vhd_time;
|
||||
}
|
||||
|
||||
time_t vhd_get_created_time(MVHDMeta *vhdm)
|
||||
{
|
||||
time_t vhd_time = (time_t)vhdm->footer.timestamp;
|
||||
time_t vhd_time_unix = MVHD_START_TS + vhd_time;
|
||||
return vhd_time_unix;
|
||||
}
|
||||
|
||||
FILE* mvhd_fopen(const char* path, const char* mode, int* err) {
|
||||
FILE* f = NULL;
|
||||
#ifdef _WIN32
|
||||
size_t path_len = strlen(path);
|
||||
size_t mode_len = strlen(mode);
|
||||
mvhd_utf16 new_path[260] = {0};
|
||||
int new_path_len = (sizeof new_path) - 2;
|
||||
mvhd_utf16 mode_str[5] = {0};
|
||||
int new_mode_len = (sizeof mode_str) - 2;
|
||||
int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len);
|
||||
int mode_res = UTF8ToUTF16LE((unsigned char*)mode_str, &new_mode_len, (const unsigned char*)mode, (int*)&mode_len);
|
||||
if (path_res > 0 && mode_res > 0) {
|
||||
f = _wfopen(new_path, mode_str);
|
||||
if (f == NULL) {
|
||||
mvhd_errno = errno;
|
||||
*err = MVHD_ERR_FILE;
|
||||
}
|
||||
} else {
|
||||
if (path_res == -1 || mode_res == -1) {
|
||||
*err = MVHD_ERR_UTF_SIZE;
|
||||
} else if (path_res == -2 || mode_res == -2) {
|
||||
*err = MVHD_ERR_UTF_TRANSCODING_FAILED;
|
||||
}
|
||||
}
|
||||
#else
|
||||
f = fopen(path, mode);
|
||||
if (f == NULL) {
|
||||
mvhd_errno = errno;
|
||||
*err = MVHD_ERR_FILE;
|
||||
}
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
|
||||
void mvhd_set_encoding_err(int encoding_retval, int* err) {
|
||||
if (encoding_retval == -1) {
|
||||
*err = MVHD_ERR_UTF_SIZE;
|
||||
} else if (encoding_retval == -2) {
|
||||
*err = MVHD_ERR_UTF_TRANSCODING_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mvhd_calc_size_bytes(MVHDGeom *geom) {
|
||||
uint64_t img_size = (uint64_t)geom->cyl * (uint64_t)geom->heads * (uint64_t)geom->spt * (uint64_t)MVHD_SECTOR_SIZE;
|
||||
return img_size;
|
||||
}
|
||||
|
||||
uint32_t mvhd_calc_size_sectors(MVHDGeom *geom) {
|
||||
uint32_t sector_size = (uint32_t)geom->cyl * (uint32_t)geom->heads * (uint32_t)geom->spt;
|
||||
return sector_size;
|
||||
}
|
||||
|
||||
MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm) {
|
||||
MVHDGeom geometry = { .cyl = vhdm->footer.geom.cyl, .heads = vhdm->footer.geom.heads, .spt = vhdm->footer.geom.spt };
|
||||
return geometry;
|
||||
}
|
||||
|
||||
uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer) {
|
||||
uint32_t new_chk = 0;
|
||||
uint32_t orig_chk = footer->checksum;
|
||||
footer->checksum = 0;
|
||||
uint8_t* footer_bytes = (uint8_t*)footer;
|
||||
for (size_t i = 0; i < sizeof *footer; i++) {
|
||||
new_chk += footer_bytes[i];
|
||||
}
|
||||
footer->checksum = orig_chk;
|
||||
return ~new_chk;
|
||||
}
|
||||
|
||||
uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header) {
|
||||
uint32_t new_chk = 0;
|
||||
uint32_t orig_chk = header->checksum;
|
||||
header->checksum = 0;
|
||||
uint8_t* sparse_bytes = (uint8_t*)header;
|
||||
for (size_t i = 0; i < sizeof *header; i++) {
|
||||
new_chk += sparse_bytes[i];
|
||||
}
|
||||
header->checksum = orig_chk;
|
||||
return ~new_chk;
|
||||
}
|
||||
|
||||
const char* mvhd_strerr(MVHDError err) {
|
||||
switch (err) {
|
||||
case MVHD_ERR_MEM:
|
||||
return "memory allocation error";
|
||||
case MVHD_ERR_FILE:
|
||||
return "file error";
|
||||
case MVHD_ERR_NOT_VHD:
|
||||
return "file is not a VHD image";
|
||||
case MVHD_ERR_TYPE:
|
||||
return "unsupported VHD image type";
|
||||
case MVHD_ERR_FOOTER_CHECKSUM:
|
||||
return "invalid VHD footer checksum";
|
||||
case MVHD_ERR_SPARSE_CHECKSUM:
|
||||
return "invalid VHD sparse header checksum";
|
||||
case MVHD_ERR_UTF_TRANSCODING_FAILED:
|
||||
return "error converting path encoding";
|
||||
case MVHD_ERR_UTF_SIZE:
|
||||
return "buffer size mismatch when converting path encoding";
|
||||
case MVHD_ERR_PATH_REL:
|
||||
return "relative path detected where absolute path expected";
|
||||
case MVHD_ERR_PATH_LEN:
|
||||
return "path length exceeds MVHD_MAX_PATH";
|
||||
case MVHD_ERR_PAR_NOT_FOUND:
|
||||
return "parent VHD image not found";
|
||||
case MVHD_ERR_INVALID_PAR_UUID:
|
||||
return "UUID mismatch between child and parent VHD";
|
||||
case MVHD_ERR_INVALID_GEOM:
|
||||
return "invalid geometry detected";
|
||||
case MVHD_ERR_INVALID_SIZE:
|
||||
return "invalid size";
|
||||
case MVHD_ERR_INVALID_BLOCK_SIZE:
|
||||
return "invalid block size";
|
||||
case MVHD_ERR_INVALID_PARAMS:
|
||||
return "invalid parameters passed to function";
|
||||
case MVHD_ERR_CONV_SIZE:
|
||||
return "error converting image. Size mismatch detechted";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
int64_t mvhd_ftello64(FILE* stream)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _ftelli64(stream);
|
||||
#elif defined(__MINGW32__)
|
||||
return ftello64(stream);
|
||||
#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */
|
||||
return ftello(stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
int mvhd_fseeko64(FILE* stream, int64_t offset, int origin)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _fseeki64(stream, offset, origin);
|
||||
#elif defined(__MINGW32__)
|
||||
return fseeko64(stream, offset, origin);
|
||||
#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */
|
||||
return fseeko(stream, offset, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t mvhd_crc32_for_byte(uint32_t r) {
|
||||
for (int j = 0; j < 8; ++j)
|
||||
r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1;
|
||||
return r ^ (uint32_t)0xFF000000L;
|
||||
}
|
||||
|
||||
uint32_t mvhd_crc32(const void* data, size_t n_bytes) {
|
||||
static uint32_t table[0x100];
|
||||
if (!*table)
|
||||
for (size_t i = 0; i < 0x100; ++i)
|
||||
table[i] = mvhd_crc32_for_byte(i);
|
||||
|
||||
uint32_t crc = 0;
|
||||
for (size_t i = 0; i < n_bytes; ++i)
|
||||
crc = table[(uint8_t)crc ^ ((uint8_t*)data)[i]] ^ crc >> 8;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t mvhd_file_mod_timestamp(const char* path, int *err) {
|
||||
*err = 0;
|
||||
#ifdef _WIN32
|
||||
struct _stat file_stat;
|
||||
size_t path_len = strlen(path);
|
||||
mvhd_utf16 new_path[260] = {0};
|
||||
int new_path_len = (sizeof new_path) - 2;
|
||||
int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len);
|
||||
if (path_res > 0) {
|
||||
int stat_res = _wstat(new_path, &file_stat);
|
||||
if (stat_res != 0) {
|
||||
mvhd_errno = errno;
|
||||
*err = MVHD_ERR_FILE;
|
||||
return 0;
|
||||
}
|
||||
return mvhd_epoch_to_vhd_ts(file_stat.st_mtime);
|
||||
} else {
|
||||
if (path_res == -1) {
|
||||
*err = MVHD_ERR_UTF_SIZE;
|
||||
} else if (path_res == -2) {
|
||||
*err = MVHD_ERR_UTF_TRANSCODING_FAILED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
struct stat file_stat;
|
||||
int stat_res = stat(path, &file_stat);
|
||||
if (stat_res != 0) {
|
||||
mvhd_errno = errno;
|
||||
*err = MVHD_ERR_FILE;
|
||||
return 0;
|
||||
}
|
||||
return mvhd_epoch_to_vhd_ts(file_stat.st_mtime);
|
||||
#endif
|
||||
}
|
||||
136
src/disk/minivhd/minivhd_util.h
Normal file
136
src/disk/minivhd/minivhd_util.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef MINIVHD_UTIL_H
|
||||
#define MINIVHD_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "minivhd_internal.h"
|
||||
#include "minivhd.h"
|
||||
#define MVHD_START_TS 946684800
|
||||
|
||||
/**
|
||||
* Functions to deal with endian issues
|
||||
*/
|
||||
uint16_t mvhd_from_be16(uint16_t val);
|
||||
uint32_t mvhd_from_be32(uint32_t val);
|
||||
uint64_t mvhd_from_be64(uint64_t val);
|
||||
uint16_t mvhd_to_be16(uint16_t val);
|
||||
uint32_t mvhd_to_be32(uint32_t val);
|
||||
uint64_t mvhd_to_be64(uint64_t val);
|
||||
|
||||
/**
|
||||
* \brief Check if provided buffer begins with the string "conectix"
|
||||
*
|
||||
* \param [in] buffer The buffer to compare. Must be at least 8 bytes in length
|
||||
*
|
||||
* \return true if the buffer begins with "conectix"
|
||||
* \return false if the buffer does not begin with "conectix"
|
||||
*/
|
||||
bool mvhd_is_conectix_str(const void* buffer);
|
||||
|
||||
/**
|
||||
* \brief Generate a raw 16 byte UUID
|
||||
*
|
||||
* \param [out] uuid A 16 byte buffer in which the generated UUID will be stored to
|
||||
*/
|
||||
void mvhd_generate_uuid(uint8_t *uuid);
|
||||
|
||||
/**
|
||||
* \brief Calculate a VHD formatted timestamp from the current time
|
||||
*/
|
||||
uint32_t vhd_calc_timestamp(void);
|
||||
|
||||
/**
|
||||
* \brief Convert an epoch timestamp to a VHD timestamp
|
||||
*
|
||||
* \param [in] ts epoch timestamp to convert.
|
||||
*
|
||||
* \return The adjusted timestamp, or 0 if the input timestamp is
|
||||
* earlier that 1 Janurary 2000
|
||||
*/
|
||||
uint32_t mvhd_epoch_to_vhd_ts(time_t ts);
|
||||
|
||||
/**
|
||||
* \brief Return the created time from a VHD image
|
||||
*
|
||||
* \param [in] vhdm Pointer to the MiniVHD metadata structure
|
||||
*
|
||||
* \return The created time, as a Unix timestamp
|
||||
*/
|
||||
time_t vhd_get_created_time(MVHDMeta *vhdm);
|
||||
|
||||
/**
|
||||
* \brief Cross platform, unicode filepath opening
|
||||
*
|
||||
* This function accounts for the fact that fopen() handles file paths differently compared to other
|
||||
* operating systems. Windows version of fopen() will not handle multi byte encoded text like UTF-8.
|
||||
*
|
||||
* Unicode filepath support on Windows requires using the _wfopen() function, which expects UTF-16LE
|
||||
* encoded path and modestring.
|
||||
*
|
||||
* \param [in] path The filepath to open as a UTF-8 string
|
||||
* \param [in] mode The mode string to use (eg: "rb+"")
|
||||
* \param [out] err The error value, if an error occurrs
|
||||
*
|
||||
* \return a FILE pointer if successful, NULL otherwise. If NULL, check the value of err
|
||||
*/
|
||||
FILE* mvhd_fopen(const char* path, const char* mode, int* err);
|
||||
|
||||
void mvhd_set_encoding_err(int encoding_retval, int* err);
|
||||
uint64_t mvhd_calc_size_bytes(MVHDGeom *geom);
|
||||
uint32_t mvhd_calc_size_sectors(MVHDGeom *geom);
|
||||
MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm);
|
||||
|
||||
/**
|
||||
* \brief Generate VHD footer checksum
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer);
|
||||
|
||||
/**
|
||||
* \brief Generate VHD sparse header checksum
|
||||
*
|
||||
* \param [in] vhdm MiniVHD data structure
|
||||
*/
|
||||
uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header);
|
||||
|
||||
/**
|
||||
* \brief Get current position in file stream
|
||||
*
|
||||
* This is a portable version of the POSIX ftello64(). *
|
||||
*/
|
||||
int64_t mvhd_ftello64(FILE* stream);
|
||||
|
||||
/**
|
||||
* \brief Reposition the file stream's position
|
||||
*
|
||||
* This is a portable version of the POSIX fseeko64(). *
|
||||
*/
|
||||
int mvhd_fseeko64(FILE* stream, int64_t offset, int origin);
|
||||
|
||||
/**
|
||||
* \brief Calculate the CRC32 of a data buffer.
|
||||
*
|
||||
* This function can be used for verifying data integrity.
|
||||
*
|
||||
* \param [in] data The data buffer
|
||||
* \param [in] n_bytes The size of the data buffer in bytes
|
||||
*
|
||||
* \return The CRC32 of the data buffer
|
||||
*/
|
||||
uint32_t mvhd_crc32(const void* data, size_t n_bytes);
|
||||
|
||||
/**
|
||||
* \brief Calculate the file modification timestamp.
|
||||
*
|
||||
* This function is primarily to help protect differencing VHD's
|
||||
*
|
||||
* \param [in] path the UTF-8 file path
|
||||
* \param [out] err The error value, if an error occurrs
|
||||
*
|
||||
* \return The file modified timestamp, in VHD compatible timestamp.
|
||||
* 'err' will be set to non-zero on error
|
||||
*/
|
||||
uint32_t mvhd_file_mod_timestamp(const char* path, int *err);
|
||||
#endif
|
||||
@@ -735,7 +735,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
fdc_log("Write FDC %04X %02X\n", addr, val);
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
switch (addr&7) {
|
||||
case 0:
|
||||
@@ -1261,7 +1261,7 @@ fdc_read(uint16_t addr, void *priv)
|
||||
uint8_t ret;
|
||||
int drive;
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
switch (addr & 7) {
|
||||
case 0: /* STA */
|
||||
|
||||
@@ -552,7 +552,7 @@ fdd_hole(int drive)
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
static __inline uint64_t
|
||||
fdd_byteperiod(int drive)
|
||||
{
|
||||
if (!fdd_get_turbo(drive) && drives[drive].byteperiod)
|
||||
|
||||
@@ -186,7 +186,7 @@ gameport_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
p->joystick->write(p->joystick_dat);
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ gameport_read(uint16_t addr, void *priv)
|
||||
|
||||
ret = p->state | p->joystick->read(p->joystick_dat);
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,8 @@ extern int network_card; /* (C) net interface num */
|
||||
extern char network_host[522]; /* (C) host network intf */
|
||||
extern int hdd_format_type; /* (C) hard disk file format */
|
||||
extern int confirm_reset, /* (C) enable reset confirmation */
|
||||
confirm_exit; /* (C) enable exit confirmation */
|
||||
confirm_exit, /* (C) enable exit confirmation */
|
||||
confirm_save; /* (C) enable save confirmation */
|
||||
#ifdef USE_DISCORD
|
||||
extern int enable_discord; /* (C) enable Discord integration */
|
||||
#endif
|
||||
@@ -151,6 +152,7 @@ extern void pclog_toggle_suppr(void);
|
||||
extern void pclog(const char *fmt, ...);
|
||||
extern void fatal(const char *fmt, ...);
|
||||
extern void set_screen_size(int x, int y);
|
||||
extern void reset_screen_size(void);
|
||||
extern void set_screen_size_natural(void);
|
||||
#if 0
|
||||
extern void pc_reload(wchar_t *fn);
|
||||
@@ -176,6 +178,7 @@ extern uint16_t get_last_addr(void);
|
||||
should be in cpu.c but I put it here to avoid
|
||||
having to include cpu.c everywhere. */
|
||||
extern void sub_cycles(int c);
|
||||
extern void resub_cycles(int old_cycles);
|
||||
|
||||
extern double isa_timing;
|
||||
extern int io_delay;
|
||||
|
||||
@@ -89,6 +89,8 @@ typedef struct
|
||||
|
||||
|
||||
/* Global variables. */
|
||||
extern int acpi_rtc_status;
|
||||
|
||||
extern const device_t acpi_intel_device;
|
||||
extern const device_t acpi_smc_device;
|
||||
extern const device_t acpi_via_device;
|
||||
|
||||
@@ -106,32 +106,6 @@ typedef struct {
|
||||
extern hard_disk_t hdd[HDD_NUM];
|
||||
extern unsigned int hdd_table[128][3];
|
||||
|
||||
|
||||
typedef struct vhd_footer_t
|
||||
{
|
||||
uint8_t cookie[8];
|
||||
uint32_t features;
|
||||
uint32_t version;
|
||||
uint64_t offset;
|
||||
uint32_t timestamp;
|
||||
uint8_t creator[4];
|
||||
uint32_t creator_vers;
|
||||
uint8_t creator_host_os[4];
|
||||
uint64_t orig_size;
|
||||
uint64_t curr_size;
|
||||
struct {
|
||||
uint16_t cyl;
|
||||
uint8_t heads;
|
||||
uint8_t spt;
|
||||
} geom;
|
||||
uint32_t type;
|
||||
uint32_t checksum;
|
||||
uint8_t uuid[16];
|
||||
uint8_t saved_state;
|
||||
uint8_t reserved[427];
|
||||
} vhd_footer_t;
|
||||
|
||||
|
||||
extern int hdd_init(void);
|
||||
extern int hdd_string_to_bus(char *str, int cdrom);
|
||||
extern char *hdd_bus_to_string(int bus, int cdrom);
|
||||
@@ -153,11 +127,6 @@ extern void hdd_image_unload(uint8_t id, int fn_preserve);
|
||||
extern void hdd_image_close(uint8_t id);
|
||||
extern void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size);
|
||||
|
||||
extern void vhd_footer_from_bytes(vhd_footer_t *vhd, uint8_t *bytes);
|
||||
extern void vhd_footer_to_bytes(uint8_t *bytes, vhd_footer_t *vhd);
|
||||
extern void new_vhd_footer(vhd_footer_t **vhd);
|
||||
extern void generate_vhd_checksum(vhd_footer_t *vhd);
|
||||
|
||||
extern int image_is_hdi(const wchar_t *s);
|
||||
extern int image_is_hdx(const wchar_t *s, int check_signature);
|
||||
extern int image_is_vhd(const wchar_t *s, int check_signature);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#define IDS_STRINGS 2048 // "86Box"
|
||||
#define IDS_2049 2049 // "Error"
|
||||
#define IDS_2050 2050 // "Fatal error"
|
||||
#define IDS_2051 2051 // "Are you sure you want to save..."
|
||||
#define IDS_2051 2051 // "<reserved>"
|
||||
#define IDS_2052 2052 // "Press CTRL+ALT+PAGE DOWN..."
|
||||
#define IDS_2053 2053 // "Speed"
|
||||
#define IDS_2054 2054 // "ZIP %i (%03i): %ls"
|
||||
@@ -44,11 +44,11 @@
|
||||
#define IDS_2068 2068 // "Sound"
|
||||
#define IDS_2069 2069 // "Network"
|
||||
#define IDS_2070 2070 // "Ports (COM & LPT)"
|
||||
#define IDS_2071 2071 // "Other peripherals"
|
||||
#define IDS_2071 2071 // "Storage controllers"
|
||||
#define IDS_2072 2072 // "Hard disks"
|
||||
#define IDS_2073 2073 // "Floppy and CD-ROM drives"
|
||||
#define IDS_2074 2074 // "Other removable devices"
|
||||
#define IDS_2075 2075 // "CD-ROM images (*.ISO;*.CU.."
|
||||
#define IDS_2075 2075 // "Other peripherals"
|
||||
#define IDS_2076 2076 // "Surface-based images (*.8.."
|
||||
#define IDS_2077 2077 // "Click to capture mouse"
|
||||
#define IDS_2078 2078 // "Press F12-F8 to release mouse"
|
||||
@@ -94,9 +94,9 @@
|
||||
#define IDS_2118 2118 // "Internal controller"
|
||||
#define IDS_2119 2119 // "Exit"
|
||||
#define IDS_2120 2120 // "No ROMs found"
|
||||
#define IDS_2121 2121 // "Save changes\nThis will hard..."
|
||||
#define IDS_2122 2122 // "Discard changes\nAll changes..."
|
||||
#define IDS_2123 2123 // "Cancel\nGo back to the..."
|
||||
#define IDS_2121 2121 // "Do you want to save the settings?"
|
||||
#define IDS_2122 2122 // "This will hard reset the virtual..."
|
||||
#define IDS_2123 2123 // "Save"
|
||||
#define IDS_2124 2124 // "About 86Box"
|
||||
#define IDS_2125 2125 // "86Box v" EMU_VERSION
|
||||
#define IDS_2126 2126 // "An emulator of old computers..."
|
||||
@@ -109,10 +109,12 @@
|
||||
#define IDS_2133 2133 // LIB_NAME_FLUIDSYNTH " is required..."
|
||||
#define IDS_2134 2134 // "Entering fullscreen mode"
|
||||
#define IDS_2135 2135 // "Don't show this message again"
|
||||
#define IDS_2136 2136 // "Don't Exit"
|
||||
#define IDS_2136 2136 // "Don't exit"
|
||||
#define IDS_2137 2137 // "Reset"
|
||||
#define IDS_2138 2138 // "Don't Reset"
|
||||
#define IDS_2138 2138 // "Don't reset"
|
||||
#define IDS_2139 2139 // "MO images (*.IM?)\0*.IM?..."
|
||||
#define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.."
|
||||
#define IDS_2141 2141 // "%hs Device Configuration"
|
||||
|
||||
#define IDS_4096 4096 // "Hard disk (%s)"
|
||||
#define IDS_4097 4097 // "%01i:%01i"
|
||||
@@ -139,7 +141,20 @@
|
||||
#define IDS_4118 4118 // "The selected file will be..."
|
||||
#define IDS_4119 4119 // "Unsupported disk image"
|
||||
#define IDS_4120 4120 // "Overwrite"
|
||||
#define IDS_4121 4121 // "Don't Overwrite"
|
||||
#define IDS_4121 4121 // "Don't overwrite"
|
||||
#define IDS_4122 4122 // "Raw image (.img)"
|
||||
#define IDS_4123 4123 // "HDI image (.hdi)"
|
||||
#define IDS_4124 4124 // "HDX image (.hdx)"
|
||||
#define IDS_4125 4125 // "Fixed-size VHD (.vhd)"
|
||||
#define IDS_4126 4126 // "Dynamic-size VHD (.vhd)"
|
||||
#define IDS_4127 4127 // "Differencing VHD (.vhd)"
|
||||
#define IDS_4128 4128 // "Large blocks (2 MB)"
|
||||
#define IDS_4129 4129 // "Small blocks (512 KB)"
|
||||
#define IDS_4130 4130 // "VHD files (*.VHD)\0*.VHD\0All..."
|
||||
#define IDS_4131 4131 // "Select the parent VHD"
|
||||
#define IDS_4132 4132 // "This could mean that the parent..."
|
||||
#define IDS_4133 4133 // "Parent and child disk timestamps..."
|
||||
#define IDS_4134 4134 // "Could not fix VHD timestamp."
|
||||
|
||||
#define IDS_4352 4352 // "MFM/RLL"
|
||||
#define IDS_4353 4353 // "XT IDE"
|
||||
@@ -207,9 +222,9 @@
|
||||
|
||||
#define IDS_LANG_ENUS IDS_7168
|
||||
|
||||
#define STR_NUM_2048 92
|
||||
#define STR_NUM_2048 94
|
||||
#define STR_NUM_3072 11
|
||||
#define STR_NUM_4096 18
|
||||
#define STR_NUM_4096 39
|
||||
#define STR_NUM_4352 6
|
||||
#define STR_NUM_4608 6
|
||||
#define STR_NUM_5120 1
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
/* Combined flags. */
|
||||
#define MACHINE_VIDEO_FIXED 0x00003000 /* sys has fixed int video */
|
||||
/* Feature flags for internal storage controllers. */
|
||||
#define MACHINE_HDC 0x0FFC0000 /* sys has int HDC */
|
||||
#define MACHINE_HDC 0x07FC0000 /* sys has int HDC */
|
||||
#define MACHINE_MFM 0x00100000 /* sys has int MFM/RLL */
|
||||
#define MACHINE_XTA 0x00200000 /* sys has int XTA */
|
||||
#define MACHINE_ESDI 0x00400000 /* sys has int ESDI */
|
||||
|
||||
@@ -236,31 +236,16 @@ extern uint16_t read_mem_w(uint32_t addr);
|
||||
extern void write_mem_b(uint32_t addr, uint8_t val);
|
||||
extern void write_mem_w(uint32_t addr, uint16_t val);
|
||||
|
||||
#ifndef USE_NEW_DYNAREC
|
||||
#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a)))
|
||||
#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
|
||||
#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a))))
|
||||
extern uint8_t readmembl(uint32_t addr);
|
||||
extern void writemembl(uint32_t addr, uint8_t val);
|
||||
extern void rwmembl(uint32_t raddr, uint32_t waddr, uint8_t val);
|
||||
|
||||
extern uint8_t readmembl(uint32_t addr);
|
||||
extern void writemembl(uint32_t addr, uint8_t val);
|
||||
extern uint8_t readmemb386l(uint32_t seg, uint32_t addr);
|
||||
extern void writememb386l(uint32_t seg, uint32_t addr, uint8_t val);
|
||||
extern uint16_t readmemwl(uint32_t seg, uint32_t addr);
|
||||
extern void writememwl(uint32_t seg, uint32_t addr, uint16_t val);
|
||||
extern uint32_t readmemll(uint32_t seg, uint32_t addr);
|
||||
extern void writememll(uint32_t seg, uint32_t addr, uint32_t val);
|
||||
extern uint64_t readmemql(uint32_t seg, uint32_t addr);
|
||||
extern void writememql(uint32_t seg, uint32_t addr, uint64_t val);
|
||||
#else
|
||||
extern uint8_t readmembl(uint32_t addr);
|
||||
extern void writemembl(uint32_t addr, uint8_t val);
|
||||
extern uint16_t readmemwl(uint32_t addr);
|
||||
extern void writememwl(uint32_t addr, uint16_t val);
|
||||
extern uint32_t readmemll(uint32_t addr);
|
||||
extern void writememll(uint32_t addr, uint32_t val);
|
||||
extern uint64_t readmemql(uint32_t addr);
|
||||
extern void writememql(uint32_t addr, uint64_t val);
|
||||
#endif
|
||||
|
||||
extern uint8_t *getpccache(uint32_t a);
|
||||
extern uint64_t mmutranslatereal(uint32_t addr, int rw);
|
||||
|
||||
@@ -35,11 +35,12 @@
|
||||
#define DLG_CFG_SOUND 114 /* sub-dialog of config */
|
||||
#define DLG_CFG_NETWORK 115 /* sub-dialog of config */
|
||||
#define DLG_CFG_PORTS 116 /* sub-dialog of config */
|
||||
#define DLG_CFG_PERIPHERALS 117 /* sub-dialog of config */
|
||||
#define DLG_CFG_STORAGE 117 /* sub-dialog of config */
|
||||
#define DLG_CFG_HARD_DISKS 118 /* sub-dialog of config */
|
||||
#define DLG_CFG_HARD_DISKS_ADD 119 /* sub-dialog of config */
|
||||
#define DLG_CFG_FLOPPY_AND_CDROM_DRIVES 120 /* sub-dialog of config */
|
||||
#define DLG_CFG_OTHER_REMOVABLE_DEVICES 121 /* sub-dialog of config */
|
||||
#define DLG_CFG_PERIPHERALS 122 /* sub-dialog of config */
|
||||
|
||||
/* Static text label IDs. */
|
||||
#define IDT_1700 1700 /* Language: */
|
||||
@@ -100,11 +101,13 @@
|
||||
#define IDT_1766 1766 /* Board #4: */
|
||||
#define IDT_1767 1767 /* ISA RTC: */
|
||||
#define IDT_1768 1768 /* Ext FD Controller: */
|
||||
#define IDT_1769 1769 /* MO drives: */
|
||||
#define IDT_1770 1770 /* Bus: */
|
||||
#define IDT_1771 1771 /* ID: */
|
||||
#define IDT_1772 1772 /* Channel */
|
||||
#define IDT_1773 1773 /* Type: */
|
||||
#define IDT_1769 1769 /* MO drives: */
|
||||
#define IDT_1770 1770 /* Bus: */
|
||||
#define IDT_1771 1771 /* ID: */
|
||||
#define IDT_1772 1772 /* Channel */
|
||||
#define IDT_1773 1773 /* Type: */
|
||||
#define IDT_1774 1774 /* Image Format: */
|
||||
#define IDT_1775 1775 /* Block Size: */
|
||||
|
||||
|
||||
/*
|
||||
@@ -137,114 +140,117 @@
|
||||
#define IDC_MEMSPIN 1019
|
||||
#define IDC_TEXT_MB IDT_1705
|
||||
|
||||
#define IDC_VIDEO 1030 /* video config */
|
||||
#define IDC_COMBO_VIDEO 1031
|
||||
#define IDC_CHECK_VOODOO 1032
|
||||
#define IDC_BUTTON_VOODOO 1033
|
||||
#define IDC_VIDEO 1020 /* video config */
|
||||
#define IDC_COMBO_VIDEO 1021
|
||||
#define IDC_CHECK_VOODOO 1022
|
||||
#define IDC_BUTTON_VOODOO 1023
|
||||
|
||||
#define IDC_INPUT 1050 /* input config */
|
||||
#define IDC_COMBO_MOUSE 1051
|
||||
#define IDC_COMBO_JOYSTICK 1052
|
||||
#define IDC_COMBO_JOY 1053
|
||||
#define IDC_CONFIGURE_MOUSE 1054
|
||||
#define IDC_INPUT 1030 /* input config */
|
||||
#define IDC_COMBO_MOUSE 1031
|
||||
#define IDC_COMBO_JOYSTICK 1032
|
||||
#define IDC_COMBO_JOY 1033
|
||||
#define IDC_CONFIGURE_MOUSE 1034
|
||||
|
||||
#define IDC_SOUND 1070 /* sound config */
|
||||
#define IDC_COMBO_SOUND 1071
|
||||
#define IDC_CHECK_SSI 1072
|
||||
#define IDC_CHECK_CMS 1073
|
||||
#define IDC_CHECK_GUS 1074
|
||||
#define IDC_COMBO_MIDI 1075
|
||||
#define IDC_CHECK_MPU401 1076
|
||||
#define IDC_CONFIGURE_MPU401 1077
|
||||
#define IDC_CHECK_FLOAT 1078
|
||||
#define IDC_CONFIGURE_GUS 1079
|
||||
#define IDC_COMBO_MIDI_IN 1080
|
||||
#define IDC_SOUND 1040 /* sound config */
|
||||
#define IDC_COMBO_SOUND 1041
|
||||
#define IDC_CHECK_SSI 1042
|
||||
#define IDC_CHECK_CMS 1043
|
||||
#define IDC_CHECK_GUS 1044
|
||||
#define IDC_COMBO_MIDI 1045
|
||||
#define IDC_CHECK_MPU401 1046
|
||||
#define IDC_CONFIGURE_MPU401 1047
|
||||
#define IDC_CHECK_FLOAT 1048
|
||||
#define IDC_CONFIGURE_GUS 1049
|
||||
#define IDC_COMBO_MIDI_IN 1050
|
||||
|
||||
#define IDC_COMBO_NET_TYPE 1090 /* network config */
|
||||
#define IDC_COMBO_PCAP 1091
|
||||
#define IDC_COMBO_NET 1092
|
||||
#define IDC_COMBO_NET_TYPE 1060 /* network config */
|
||||
#define IDC_COMBO_PCAP 1061
|
||||
#define IDC_COMBO_NET 1062
|
||||
|
||||
#define IDC_COMBO_LPT1 1110 /* ports config */
|
||||
#define IDC_COMBO_LPT2 1111
|
||||
#define IDC_COMBO_LPT3 1112
|
||||
#define IDC_CHECK_SERIAL1 1113
|
||||
#define IDC_CHECK_SERIAL2 1114
|
||||
#define IDC_CHECK_SERIAL3 1115
|
||||
#define IDC_CHECK_SERIAL4 1116
|
||||
#define IDC_CHECK_PARALLEL1 1117
|
||||
#define IDC_CHECK_PARALLEL2 1118
|
||||
#define IDC_CHECK_PARALLEL3 1119
|
||||
#define IDC_COMBO_LPT1 1070 /* ports config */
|
||||
#define IDC_COMBO_LPT2 1071
|
||||
#define IDC_COMBO_LPT3 1072
|
||||
#define IDC_CHECK_SERIAL1 1073
|
||||
#define IDC_CHECK_SERIAL2 1074
|
||||
#define IDC_CHECK_SERIAL3 1075
|
||||
#define IDC_CHECK_SERIAL4 1076
|
||||
#define IDC_CHECK_PARALLEL1 1077
|
||||
#define IDC_CHECK_PARALLEL2 1078
|
||||
#define IDC_CHECK_PARALLEL3 1079
|
||||
|
||||
#define IDC_OTHER_PERIPH 1120 /* other periph config */
|
||||
#define IDC_COMBO_SCSI 1121
|
||||
#define IDC_CONFIGURE_SCSI 1122
|
||||
#define IDC_COMBO_HDC 1123
|
||||
#define IDC_CONFIGURE_HDC 1124
|
||||
#define IDC_CHECK_IDE_TER 1125
|
||||
#define IDC_BUTTON_IDE_TER 1126
|
||||
#define IDC_CHECK_IDE_QUA 1127
|
||||
#define IDC_BUTTON_IDE_QUA 1128
|
||||
#define IDC_CHECK_BUGGER 1129
|
||||
#define IDC_CHECK_POSTCARD 1130
|
||||
#define IDC_COMBO_ISARTC 1131
|
||||
#define IDC_CONFIGURE_ISARTC 1132
|
||||
#define IDC_COMBO_FDC 1133
|
||||
#define IDC_CONFIGURE_FDC 1134
|
||||
#define IDC_GROUP_ISAMEM 1140
|
||||
#define IDC_COMBO_ISAMEM_1 1141
|
||||
#define IDC_COMBO_ISAMEM_2 1142
|
||||
#define IDC_COMBO_ISAMEM_3 1143
|
||||
#define IDC_COMBO_ISAMEM_4 1144
|
||||
#define IDC_CONFIGURE_ISAMEM_1 1145
|
||||
#define IDC_CONFIGURE_ISAMEM_2 1146
|
||||
#define IDC_CONFIGURE_ISAMEM_3 1147
|
||||
#define IDC_CONFIGURE_ISAMEM_4 1148
|
||||
#define IDC_OTHER_PERIPH 1080 /* storage controllers config */
|
||||
#define IDC_COMBO_SCSI 1081
|
||||
#define IDC_CONFIGURE_SCSI 1082
|
||||
#define IDC_COMBO_HDC 1083
|
||||
#define IDC_CONFIGURE_HDC 1084
|
||||
#define IDC_CHECK_IDE_TER 1085
|
||||
#define IDC_BUTTON_IDE_TER 1086
|
||||
#define IDC_CHECK_IDE_QUA 1087
|
||||
#define IDC_BUTTON_IDE_QUA 1088
|
||||
|
||||
#define IDC_HARD_DISKS 1150 /* hard disks config */
|
||||
#define IDC_LIST_HARD_DISKS 1151
|
||||
#define IDC_BUTTON_HDD_ADD_NEW 1152
|
||||
#define IDC_BUTTON_HDD_ADD 1153
|
||||
#define IDC_BUTTON_HDD_REMOVE 1154
|
||||
#define IDC_COMBO_HD_BUS 1155
|
||||
#define IDC_COMBO_HD_CHANNEL 1156
|
||||
#define IDC_COMBO_HD_ID 1157
|
||||
#define IDC_COMBO_HD_LUN 1158
|
||||
#define IDC_COMBO_HD_CHANNEL_IDE 1159
|
||||
#define IDC_HARD_DISKS 1090 /* hard disks config */
|
||||
#define IDC_LIST_HARD_DISKS 1091
|
||||
#define IDC_BUTTON_HDD_ADD_NEW 1092
|
||||
#define IDC_BUTTON_HDD_ADD 1093
|
||||
#define IDC_BUTTON_HDD_REMOVE 1094
|
||||
#define IDC_COMBO_HD_BUS 1095
|
||||
#define IDC_COMBO_HD_CHANNEL 1096
|
||||
#define IDC_COMBO_HD_ID 1097
|
||||
#define IDC_COMBO_HD_LUN 1098
|
||||
#define IDC_COMBO_HD_CHANNEL_IDE 1099
|
||||
|
||||
#define IDC_EDIT_HD_FILE_NAME 1160 /* add hard disk dialog */
|
||||
#define IDC_EDIT_HD_SPT 1161
|
||||
#define IDC_EDIT_HD_HPC 1162
|
||||
#define IDC_EDIT_HD_CYL 1163
|
||||
#define IDC_EDIT_HD_SIZE 1164
|
||||
#define IDC_COMBO_HD_TYPE 1165
|
||||
#define IDC_PBAR_IMG_CREATE 1166
|
||||
#define IDC_EDIT_HD_FILE_NAME 1100 /* add hard disk dialog */
|
||||
#define IDC_EDIT_HD_SPT 1101
|
||||
#define IDC_EDIT_HD_HPC 1102
|
||||
#define IDC_EDIT_HD_CYL 1103
|
||||
#define IDC_EDIT_HD_SIZE 1104
|
||||
#define IDC_COMBO_HD_TYPE 1105
|
||||
#define IDC_PBAR_IMG_CREATE 1106
|
||||
#define IDC_COMBO_HD_IMG_FORMAT 1107
|
||||
#define IDC_COMBO_HD_BLOCK_SIZE 1108
|
||||
|
||||
#define IDC_REMOV_DEVICES 1170 /* floppy and cd-rom drives config */
|
||||
#define IDC_LIST_FLOPPY_DRIVES 1171
|
||||
#define IDC_COMBO_FD_TYPE 1172
|
||||
#define IDC_CHECKTURBO 1173
|
||||
#define IDC_CHECKBPB 1174
|
||||
#define IDC_LIST_CDROM_DRIVES 1175
|
||||
#define IDC_COMBO_CD_BUS 1176
|
||||
#define IDC_COMBO_CD_ID 1177
|
||||
#define IDC_COMBO_CD_LUN 1178
|
||||
#define IDC_COMBO_CD_CHANNEL_IDE 1179
|
||||
#define IDC_REMOV_DEVICES 1110 /* floppy and cd-rom drives config */
|
||||
#define IDC_LIST_FLOPPY_DRIVES 1111
|
||||
#define IDC_COMBO_FD_TYPE 1112
|
||||
#define IDC_CHECKTURBO 1113
|
||||
#define IDC_CHECKBPB 1114
|
||||
#define IDC_LIST_CDROM_DRIVES 1115
|
||||
#define IDC_COMBO_CD_BUS 1116
|
||||
#define IDC_COMBO_CD_ID 1117
|
||||
#define IDC_COMBO_CD_LUN 1118
|
||||
#define IDC_COMBO_CD_CHANNEL_IDE 1119
|
||||
|
||||
#define IDC_LIST_ZIP_DRIVES 1180 /* other removable devices config */
|
||||
#define IDC_COMBO_ZIP_BUS 1181
|
||||
#define IDC_COMBO_ZIP_ID 1182
|
||||
#define IDC_COMBO_ZIP_LUN 1183
|
||||
#define IDC_COMBO_ZIP_CHANNEL_IDE 1184
|
||||
#define IDC_CHECK250 1185
|
||||
#define IDC_COMBO_CD_SPEED 1186
|
||||
#define IDC_LIST_MO_DRIVES 1187
|
||||
#define IDC_COMBO_MO_BUS 1188
|
||||
#define IDC_COMBO_MO_ID 1189
|
||||
#define IDC_COMBO_MO_LUN 1190
|
||||
#define IDC_COMBO_MO_CHANNEL_IDE 1191
|
||||
#define IDC_COMBO_MO_TYPE 1192
|
||||
#define IDC_LIST_ZIP_DRIVES 1120 /* other removable devices config */
|
||||
#define IDC_COMBO_ZIP_BUS 1121
|
||||
#define IDC_COMBO_ZIP_ID 1122
|
||||
#define IDC_COMBO_ZIP_LUN 1123
|
||||
#define IDC_COMBO_ZIP_CHANNEL_IDE 1124
|
||||
#define IDC_CHECK250 1125
|
||||
#define IDC_COMBO_CD_SPEED 1126
|
||||
#define IDC_LIST_MO_DRIVES 1127
|
||||
#define IDC_COMBO_MO_BUS 1128
|
||||
#define IDC_COMBO_MO_ID 1129
|
||||
#define IDC_COMBO_MO_LUN 1130
|
||||
#define IDC_COMBO_MO_CHANNEL_IDE 1131
|
||||
#define IDC_COMBO_MO_TYPE 1132
|
||||
|
||||
#define IDC_SLIDER_GAIN 1193 /* sound gain dialog */
|
||||
#define IDC_CHECK_BUGGER 1140 /* other periph config */
|
||||
#define IDC_CHECK_POSTCARD 1141
|
||||
#define IDC_COMBO_ISARTC 1142
|
||||
#define IDC_CONFIGURE_ISARTC 1143
|
||||
#define IDC_COMBO_FDC 1144
|
||||
#define IDC_CONFIGURE_FDC 1145
|
||||
#define IDC_GROUP_ISAMEM 1146
|
||||
#define IDC_COMBO_ISAMEM_1 1147
|
||||
#define IDC_COMBO_ISAMEM_2 1148
|
||||
#define IDC_COMBO_ISAMEM_3 1149
|
||||
#define IDC_COMBO_ISAMEM_4 1150
|
||||
#define IDC_CONFIGURE_ISAMEM_1 1151
|
||||
#define IDC_CONFIGURE_ISAMEM_2 1152
|
||||
#define IDC_CONFIGURE_ISAMEM_3 1153
|
||||
#define IDC_CONFIGURE_ISAMEM_4 1154
|
||||
|
||||
#define IDC_SLIDER_GAIN 1160 /* sound gain dialog */
|
||||
|
||||
#define IDC_EDIT_FILE_NAME 1200 /* new floppy image dialog */
|
||||
#define IDC_COMBO_DISK_SIZE 1201
|
||||
@@ -289,8 +295,9 @@
|
||||
#define IDM_VID_REMEMBER 40041
|
||||
#define IDM_VID_SDL_SW 40050
|
||||
#define IDM_VID_SDL_HW 40051
|
||||
#define IDM_VID_SDL_OPENGL 40052
|
||||
#ifdef USE_VNC
|
||||
#define IDM_VID_VNC 40052
|
||||
#define IDM_VID_VNC 40053
|
||||
#endif
|
||||
#define IDM_VID_SCALE_1X 40055
|
||||
#define IDM_VID_SCALE_2X 40056
|
||||
|
||||
@@ -49,6 +49,8 @@ extern FILE *rom_fopen(wchar_t *fn, wchar_t *mode);
|
||||
extern int rom_getfile(wchar_t *fn, wchar_t *s, int size);
|
||||
extern int rom_present(wchar_t *fn);
|
||||
|
||||
extern int rom_load_linear_oddeven(wchar_t *fn, uint32_t addr, int sz,
|
||||
int off, uint8_t *ptr);
|
||||
extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz,
|
||||
int off, uint8_t *ptr);
|
||||
extern int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr,
|
||||
@@ -68,6 +70,8 @@ extern int bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2,
|
||||
|
||||
extern int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size,
|
||||
int mask, int file_offset, uint32_t flags);
|
||||
extern int rom_init_oddeven(rom_t *rom, wchar_t *fn, uint32_t address, int size,
|
||||
int mask, int file_offset, uint32_t flags);
|
||||
extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low,
|
||||
wchar_t *fn_high, uint32_t address,
|
||||
int size, int mask, int file_offset,
|
||||
|
||||
@@ -15,7 +15,7 @@ typedef struct ad1848_t
|
||||
|
||||
int16_t out_l, out_r;
|
||||
|
||||
uint32_t cd_vol_l, cd_vol_r;
|
||||
double cd_vol_l, cd_vol_r;
|
||||
|
||||
int enable;
|
||||
|
||||
|
||||
@@ -34,7 +34,10 @@ extern "C" {
|
||||
#define MBX_ERROR 2
|
||||
#define MBX_QUESTION 3
|
||||
#define MBX_QUESTION_YN 4
|
||||
#define MBX_FATAL 0x20
|
||||
#define MBX_QUESTION_OK 8
|
||||
#define MBX_QMARK 0x10
|
||||
#define MBX_WARNING 0x20
|
||||
#define MBX_FATAL 0x40
|
||||
#define MBX_ANSI 0x80
|
||||
#define MBX_LINKS 0x100
|
||||
#define MBX_DONTASK 0x200
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
|
||||
#define FLAG_EXTRA_BANKS 1
|
||||
#define FLAG_ADDR_BY8 2
|
||||
#define FLAG_LATCH8 4
|
||||
#define FLAG_EXT_WRITE 4
|
||||
#define FLAG_LATCH8 8
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -1733,10 +1733,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo
|
||||
|
||||
if ((params->fbzMode & FBZ_CHROMAKEY))
|
||||
{
|
||||
addbyte(0x66); /*MOVD EAX, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x7e);
|
||||
addbyte(0xc0);
|
||||
switch (_rgb_sel)
|
||||
{
|
||||
case CC_LOCALSELECT_ITER_RGB:
|
||||
addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x6f);
|
||||
addbyte(0x87);
|
||||
addlong(offsetof(voodoo_state_t, ib));
|
||||
addbyte(0x66); /*PSRAD XMM0, 12*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x72);
|
||||
addbyte(0xe0);
|
||||
addbyte(12);
|
||||
addbyte(0x66); /*PACKSSDW XMM0, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x6b);
|
||||
addbyte(0xc0);
|
||||
addbyte(0x66); /*PACKUSWB XMM0, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x67);
|
||||
addbyte(0xc0);
|
||||
addbyte(0x66); /*MOVD EAX, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x7e);
|
||||
addbyte(0xc0);
|
||||
break;
|
||||
case CC_LOCALSELECT_COLOR1:
|
||||
addbyte(0x8b); /*MOV EAX, params->color1[RSI]*/
|
||||
addbyte(0x86);
|
||||
addlong(offsetof(voodoo_params_t, color1));
|
||||
break;
|
||||
case CC_LOCALSELECT_TEX:
|
||||
addbyte(0x66); /*MOVD EAX, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x7e);
|
||||
addbyte(0xc0);
|
||||
break;
|
||||
}
|
||||
addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/
|
||||
addbyte(0x9e);
|
||||
addlong(offsetof(voodoo_params_t, chromaKey));
|
||||
|
||||
@@ -1668,10 +1668,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo
|
||||
|
||||
if ((params->fbzMode & FBZ_CHROMAKEY))
|
||||
{
|
||||
addbyte(0x66); /*MOVD EAX, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x7e);
|
||||
addbyte(0xc0);
|
||||
switch (_rgb_sel)
|
||||
{
|
||||
case CC_LOCALSELECT_ITER_RGB:
|
||||
addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x6f);
|
||||
addbyte(0x87);
|
||||
addlong(offsetof(voodoo_state_t, ib));
|
||||
addbyte(0x66); /*PSRAD XMM0, 12*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x72);
|
||||
addbyte(0xe0);
|
||||
addbyte(12);
|
||||
addbyte(0x66); /*PACKSSDW XMM0, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x6b);
|
||||
addbyte(0xc0);
|
||||
addbyte(0x66); /*PACKUSWB XMM0, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x67);
|
||||
addbyte(0xc0);
|
||||
addbyte(0x66); /*MOVD EAX, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x7e);
|
||||
addbyte(0xc0);
|
||||
break;
|
||||
case CC_LOCALSELECT_COLOR1:
|
||||
addbyte(0x8b); /*MOV EAX, params->color1[ESI]*/
|
||||
addbyte(0x86);
|
||||
addlong(offsetof(voodoo_params_t, color1));
|
||||
break;
|
||||
case CC_LOCALSELECT_TEX:
|
||||
addbyte(0x66); /*MOVD EAX, XMM0*/
|
||||
addbyte(0x0f);
|
||||
addbyte(0x7e);
|
||||
addbyte(0xc0);
|
||||
break;
|
||||
}
|
||||
addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/
|
||||
addbyte(0x9e);
|
||||
addlong(offsetof(voodoo_params_t, chromaKey));
|
||||
|
||||
@@ -314,7 +314,8 @@ typedef struct voodoo_t
|
||||
volatile int params_read_idx[4], params_write_idx;
|
||||
|
||||
uint32_t cmdfifo_base, cmdfifo_end, cmdfifo_size;
|
||||
int cmdfifo_rp;
|
||||
int cmdfifo_rp, cmdfifo_ret_addr;
|
||||
int cmdfifo_in_sub;
|
||||
volatile int cmdfifo_depth_rd, cmdfifo_depth_wr;
|
||||
volatile int cmdfifo_enabled;
|
||||
uint32_t cmdfifo_amin, cmdfifo_amax;
|
||||
@@ -384,6 +385,8 @@ typedef struct voodoo_t
|
||||
uint32_t dstFormat;
|
||||
uint32_t dstSize;
|
||||
uint32_t dstXY;
|
||||
uint32_t lineStipple;
|
||||
uint32_t lineStyle;
|
||||
uint32_t rop;
|
||||
uint32_t srcBaseAddr;
|
||||
uint32_t srcFormat;
|
||||
@@ -431,6 +434,9 @@ typedef struct voodoo_t
|
||||
int src_stride_src, src_stride_dest;
|
||||
|
||||
int src_bpp;
|
||||
|
||||
int line_pix_pos, line_bit_pos;
|
||||
int line_rep_cnt, line_bit_mask_size;
|
||||
} banshee_blt;
|
||||
|
||||
struct
|
||||
|
||||
@@ -214,10 +214,8 @@ extern const device_t gd5401_isa_device;
|
||||
extern const device_t gd5402_isa_device;
|
||||
extern const device_t gd5402_onboard_device;
|
||||
extern const device_t gd5420_isa_device;
|
||||
#if defined(DEV_BRANCH) && defined(USE_CL5422)
|
||||
extern const device_t gd5422_isa_device;
|
||||
extern const device_t gd5424_vlb_device;
|
||||
#endif
|
||||
extern const device_t gd5426_vlb_device;
|
||||
extern const device_t gd5426_onboard_device;
|
||||
extern const device_t gd5428_isa_device;
|
||||
|
||||
@@ -55,6 +55,8 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||
#define SB_CLASS_NAME L"86BoxStatusBar"
|
||||
#define SB_MENU_NAME L"StatusBarMenu"
|
||||
#define FS_CLASS_NAME L"86BoxFullScreen"
|
||||
#define SDL_CLASS_NAME L"86BoxSDLWnd"
|
||||
#define SDL_SUB_CLASS_NAME L"86BoxSDLSubWnd"
|
||||
|
||||
#define FLOPPY_SUBMENU_NAME L"FloppySubmenu"
|
||||
#define CDROM_SUBMENU_NAME L"CdromSubmenu"
|
||||
@@ -83,9 +85,9 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||
#define WM_HAS_SHUTDOWN 0x8897
|
||||
|
||||
#ifdef USE_VNC
|
||||
#define RENDERERS_NUM 3
|
||||
#define RENDERERS_NUM 4
|
||||
#else
|
||||
#define RENDERERS_NUM 2
|
||||
#define RENDERERS_NUM 3
|
||||
#endif
|
||||
|
||||
|
||||
@@ -100,6 +102,7 @@ extern HANDLE ghMutex;
|
||||
extern LCID lang_id;
|
||||
extern HICON hIcon[256];
|
||||
extern RECT oldclip;
|
||||
extern int sbar_height;
|
||||
|
||||
// extern int status_is_open;
|
||||
|
||||
@@ -109,6 +112,7 @@ extern WCHAR wopenfilestring[512];
|
||||
extern uint8_t filterindex;
|
||||
|
||||
|
||||
extern void ResizeWindowByClientArea(HWND hwnd, int width, int height);
|
||||
extern void InitCrashDump(void);
|
||||
|
||||
extern HICON LoadIconEx(PCTSTR pszIconName);
|
||||
@@ -155,7 +159,6 @@ extern int hard_disk_was_added(void);
|
||||
|
||||
/* Platform UI support functions. */
|
||||
extern int ui_init(int nCmdShow);
|
||||
extern void plat_set_input(HWND h);
|
||||
|
||||
|
||||
/* Functions in win_about.c: */
|
||||
@@ -177,10 +180,11 @@ extern void NewFloppyDialogCreate(HWND hwnd, int id, int part);
|
||||
#define SETTINGS_PAGE_SOUND 3
|
||||
#define SETTINGS_PAGE_NETWORK 4
|
||||
#define SETTINGS_PAGE_PORTS 5
|
||||
#define SETTINGS_PAGE_PERIPHERALS 6
|
||||
#define SETTINGS_PAGE_STORAGE 6
|
||||
#define SETTINGS_PAGE_HARD_DISKS 7
|
||||
#define SETTINGS_PAGE_FLOPPY_AND_CDROM_DRIVES 8
|
||||
#define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9
|
||||
#define SETTINGS_PAGE_PERIPHERALS 10
|
||||
|
||||
extern void win_settings_open(HWND hwnd);
|
||||
extern void win_settings_open_ex(HWND hwnd, int category);
|
||||
@@ -193,11 +197,12 @@ extern int MediaMenuHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPara
|
||||
|
||||
|
||||
/* Functions in win_dialog.c: */
|
||||
extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save);
|
||||
extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save);
|
||||
extern int file_dlg_mb(HWND hwnd, char *f, char *fn, int save);
|
||||
extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save);
|
||||
extern int file_dlg_st(HWND hwnd, int i, char *fn, int save);
|
||||
/* Pass NULL in the title param to use the default title. */
|
||||
extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, WCHAR *title, int save);
|
||||
extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, char *title, int save);
|
||||
extern int file_dlg_mb(HWND hwnd, char *f, char *fn, char *title, int save);
|
||||
extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, char *title, int save);
|
||||
extern int file_dlg_st(HWND hwnd, int i, char *fn, char *title, int save);
|
||||
|
||||
extern wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title);
|
||||
|
||||
|
||||
@@ -53,12 +53,11 @@
|
||||
extern void sdl_close(void);
|
||||
extern int sdl_inits(HWND h);
|
||||
extern int sdl_inith(HWND h);
|
||||
extern int sdl_inits_fs(HWND h);
|
||||
extern int sdl_inith_fs(HWND h);
|
||||
extern int sdl_initho(HWND h);
|
||||
extern int sdl_pause(void);
|
||||
extern void sdl_resize(int x, int y);
|
||||
extern void sdl_enable(int enable);
|
||||
extern void sdl_reinit_texture();
|
||||
extern void sdl_set_fs(int fs);
|
||||
|
||||
|
||||
#endif /*WIN_SDL_H*/
|
||||
|
||||
12
src/io.c
12
src/io.c
@@ -307,7 +307,7 @@ inb(uint16_t port)
|
||||
amstrad_latch = AMSTRAD_SW9;
|
||||
|
||||
if (!found)
|
||||
sub_cycles(io_delay);
|
||||
cycles -= io_delay;
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
|
||||
@@ -334,7 +334,7 @@ outb(uint16_t port, uint8_t val)
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
sub_cycles(io_delay);
|
||||
cycles -= io_delay;
|
||||
#ifdef USE_DYNAREC
|
||||
if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed)))
|
||||
update_tsc();
|
||||
@@ -392,7 +392,7 @@ inw(uint16_t port)
|
||||
amstrad_latch = AMSTRAD_SW9;
|
||||
|
||||
if (!found)
|
||||
sub_cycles(io_delay);
|
||||
cycles -= io_delay;
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
|
||||
@@ -433,7 +433,7 @@ outw(uint16_t port, uint16_t val)
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
sub_cycles(io_delay);
|
||||
cycles -= io_delay;
|
||||
#ifdef USE_DYNAREC
|
||||
if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed)))
|
||||
update_tsc();
|
||||
@@ -510,7 +510,7 @@ inl(uint16_t port)
|
||||
amstrad_latch = AMSTRAD_SW9;
|
||||
|
||||
if (!found)
|
||||
sub_cycles(io_delay);
|
||||
cycles -= io_delay;
|
||||
|
||||
io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret);
|
||||
|
||||
@@ -566,7 +566,7 @@ outl(uint16_t port, uint32_t val)
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
sub_cycles(io_delay);
|
||||
cycles -= io_delay;
|
||||
#ifdef USE_DYNAREC
|
||||
if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed)))
|
||||
update_tsc();
|
||||
|
||||
@@ -301,7 +301,7 @@ vid_write_1512(uint32_t addr, uint8_t val, void *priv)
|
||||
amsvid_t *vid = (amsvid_t *)priv;
|
||||
|
||||
egawrites++;
|
||||
sub_cycles(12);
|
||||
cycles -= 12;
|
||||
addr &= 0x3fff;
|
||||
|
||||
if ((vid->cgamode & 0x12) == 0x12) {
|
||||
@@ -320,7 +320,7 @@ vid_read_1512(uint32_t addr, void *priv)
|
||||
amsvid_t *vid = (amsvid_t *)priv;
|
||||
|
||||
egareads++;
|
||||
sub_cycles(12);
|
||||
cycles -= 12;
|
||||
addr &= 0x3fff;
|
||||
|
||||
if ((vid->cgamode & 0x12) == 0x12)
|
||||
|
||||
@@ -730,8 +730,8 @@ machine_at_4sa2_init(const machine_t *model)
|
||||
device_add(&sis_85c496_device);
|
||||
pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4);
|
||||
pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1);
|
||||
pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2);
|
||||
pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3);
|
||||
pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2);
|
||||
pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3);
|
||||
|
||||
device_add(&pc87332_device);
|
||||
device_add(&keyboard_ps2_pci_device);
|
||||
|
||||
@@ -204,7 +204,7 @@ void t3100e_write(uint32_t addr, uint8_t val, void *p)
|
||||
egawrites++;
|
||||
|
||||
t3100e->vram[addr & 0x7fff] = val;
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ uint8_t t3100e_read(uint32_t addr, void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
egareads++;
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
|
||||
return t3100e->vram[addr & 0x7fff];
|
||||
}
|
||||
|
||||
@@ -194,14 +194,14 @@ static void t1000_write(uint32_t addr, uint8_t val, void *p)
|
||||
egawrites++;
|
||||
|
||||
t1000->vram[addr & 0x3fff] = val;
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
}
|
||||
|
||||
static uint8_t t1000_read(uint32_t addr, void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
egareads++;
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
|
||||
return t1000->vram[addr & 0x3fff];
|
||||
}
|
||||
|
||||
214
src/mem/mem.c
214
src/mem/mem.c
@@ -274,7 +274,7 @@ mem_flush_write_page(uint32_t addr, uint32_t virt)
|
||||
#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK]
|
||||
#define rammap64(x) ((uint64_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 3) & MEM_GRANULARITY_PMASK]
|
||||
|
||||
static uint64_t
|
||||
static __inline uint64_t
|
||||
mmutranslatereal_normal(uint32_t addr, int rw)
|
||||
{
|
||||
uint32_t temp,temp2,temp3;
|
||||
@@ -297,7 +297,7 @@ mmutranslatereal_normal(uint32_t addr, int rw)
|
||||
|
||||
if ((temp & 0x80) && (cr4 & CR4_PSE)) {
|
||||
/*4MB page*/
|
||||
if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) {
|
||||
if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) {
|
||||
cr2 = addr;
|
||||
temp &= 1;
|
||||
if (CPL == 3)
|
||||
@@ -318,7 +318,7 @@ mmutranslatereal_normal(uint32_t addr, int rw)
|
||||
|
||||
temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc));
|
||||
temp3 = temp & temp2;
|
||||
if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) {
|
||||
if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) {
|
||||
cr2 = addr;
|
||||
temp &= 1;
|
||||
if (CPL == 3) temp |= 4;
|
||||
@@ -336,7 +336,7 @@ mmutranslatereal_normal(uint32_t addr, int rw)
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
static __inline uint64_t
|
||||
mmutranslatereal_pae(uint32_t addr, int rw)
|
||||
{
|
||||
uint64_t temp,temp2,temp3,temp4;
|
||||
@@ -429,7 +429,7 @@ mmutranslatereal32(uint32_t addr, int rw)
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
static __inline uint64_t
|
||||
mmutranslate_noabrt_normal(uint32_t addr, int rw)
|
||||
{
|
||||
uint32_t temp,temp2,temp3;
|
||||
@@ -462,7 +462,7 @@ mmutranslate_noabrt_normal(uint32_t addr, int rw)
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
static __inline uint64_t
|
||||
mmutranslate_noabrt_pae(uint32_t addr, int rw)
|
||||
{
|
||||
uint64_t temp,temp2,temp3,temp4;
|
||||
@@ -572,7 +572,7 @@ addreadlookup(uint32_t virt, uint32_t phys)
|
||||
readlookup[readlnext++] = virt >> 12;
|
||||
readlnext &= (cachesize-1);
|
||||
|
||||
sub_cycles(9);
|
||||
cycles -= 9;
|
||||
}
|
||||
|
||||
|
||||
@@ -625,7 +625,7 @@ addwritelookup(uint32_t virt, uint32_t phys)
|
||||
writelookup[writelnext++] = virt >> 12;
|
||||
writelnext &= (cachesize - 1);
|
||||
|
||||
sub_cycles(9);
|
||||
cycles -= 9;
|
||||
}
|
||||
|
||||
|
||||
@@ -665,15 +665,19 @@ uint8_t
|
||||
read_mem_b(uint32_t addr)
|
||||
{
|
||||
mem_mapping_t *map;
|
||||
uint8_t ret = 0xff;
|
||||
int old_cycles = cycles;
|
||||
|
||||
mem_logical_addr = addr;
|
||||
addr &= rammask;
|
||||
|
||||
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
|
||||
if (map && map->read_b)
|
||||
return map->read_b(addr, map->p);
|
||||
ret = map->read_b(addr, map->p);
|
||||
|
||||
return 0xff;
|
||||
resub_cycles(old_cycles);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -681,22 +685,26 @@ uint16_t
|
||||
read_mem_w(uint32_t addr)
|
||||
{
|
||||
mem_mapping_t *map;
|
||||
uint16_t ret = 0xffff;
|
||||
int old_cycles = cycles;
|
||||
|
||||
mem_logical_addr = addr;
|
||||
addr &= rammask;
|
||||
|
||||
if (addr & 1)
|
||||
return read_mem_b(addr) | (read_mem_b(addr + 1) << 8);
|
||||
ret = read_mem_b(addr) | (read_mem_b(addr + 1) << 8);
|
||||
else {
|
||||
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
|
||||
|
||||
map = read_mapping[addr >> MEM_GRANULARITY_BITS];
|
||||
if (map && map->read_w)
|
||||
ret = map->read_w(addr, map->p);
|
||||
else if (map && map->read_b)
|
||||
ret = map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8);
|
||||
}
|
||||
|
||||
if (map && map->read_w)
|
||||
return map->read_w(addr, map->p);
|
||||
resub_cycles(old_cycles);
|
||||
|
||||
if (map && map->read_b)
|
||||
return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8);
|
||||
|
||||
return 0xffff;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -704,6 +712,7 @@ void
|
||||
write_mem_b(uint32_t addr, uint8_t val)
|
||||
{
|
||||
mem_mapping_t *map;
|
||||
int old_cycles = cycles;
|
||||
|
||||
mem_logical_addr = addr;
|
||||
addr &= rammask;
|
||||
@@ -711,6 +720,8 @@ write_mem_b(uint32_t addr, uint8_t val)
|
||||
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
|
||||
if (map && map->write_b)
|
||||
map->write_b(addr, val, map->p);
|
||||
|
||||
resub_cycles(old_cycles);
|
||||
}
|
||||
|
||||
|
||||
@@ -718,6 +729,7 @@ void
|
||||
write_mem_w(uint32_t addr, uint16_t val)
|
||||
{
|
||||
mem_mapping_t *map;
|
||||
int old_cycles = cycles;
|
||||
|
||||
mem_logical_addr = addr;
|
||||
addr &= rammask;
|
||||
@@ -725,18 +737,19 @@ write_mem_w(uint32_t addr, uint16_t val)
|
||||
if (addr & 1) {
|
||||
write_mem_b(addr, val);
|
||||
write_mem_b(addr + 1, val >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
|
||||
if (map) {
|
||||
if (map->write_w)
|
||||
map->write_w(addr, val, map->p);
|
||||
else if (map->write_b) {
|
||||
map->write_b(addr, val, map->p);
|
||||
map->write_b(addr + 1, val >> 8, map->p);
|
||||
} else {
|
||||
map = write_mapping[addr >> MEM_GRANULARITY_BITS];
|
||||
if (map) {
|
||||
if (map->write_w)
|
||||
map->write_w(addr, val, map->p);
|
||||
else if (map->write_b) {
|
||||
map->write_b(addr, val, map->p);
|
||||
map->write_b(addr + 1, val >> 8, map->p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resub_cycles(old_cycles);
|
||||
}
|
||||
|
||||
|
||||
@@ -792,6 +805,55 @@ writemembl(uint32_t addr, uint8_t val)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rwmembl(uint32_t raddr, uint32_t waddr, uint8_t val)
|
||||
{
|
||||
uint64_t raddr64 = (uint64_t) raddr;
|
||||
uint64_t waddr64 = (uint64_t) waddr;
|
||||
mem_mapping_t *rmap, *wmap;
|
||||
uint8_t temp = 0xff;
|
||||
|
||||
mem_logical_addr = raddr;
|
||||
|
||||
if (cr0 >> 31) {
|
||||
raddr64 = mmutranslate_read(raddr);
|
||||
if (raddr64 == 0xffffffffffffffffULL)
|
||||
goto do_writebl;
|
||||
if (raddr64 > 0xffffffffULL)
|
||||
goto do_writebl;
|
||||
}
|
||||
raddr = (uint32_t) (raddr64 & rammask);
|
||||
|
||||
rmap = read_mapping[raddr >> MEM_GRANULARITY_BITS];
|
||||
if (rmap && rmap->read_b)
|
||||
temp = rmap->read_b(raddr, rmap->p);
|
||||
|
||||
do_writebl:
|
||||
if (cpu_state.abrt)
|
||||
return;
|
||||
|
||||
mem_logical_addr = waddr;
|
||||
|
||||
if (page_lookup[waddr >> 12] && page_lookup[waddr >> 12]->write_b) {
|
||||
page_lookup[waddr >> 12]->write_b(waddr, temp, page_lookup[waddr >> 12]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cr0 >> 31) {
|
||||
waddr64 = mmutranslate_write(waddr);
|
||||
if (waddr64 == 0xffffffffffffffffULL)
|
||||
return;
|
||||
if (waddr64 > 0xffffffffULL)
|
||||
return;
|
||||
}
|
||||
waddr = (uint32_t) (waddr64 & rammask);
|
||||
|
||||
wmap = write_mapping[waddr >> MEM_GRANULARITY_BITS];
|
||||
if (wmap && wmap->write_b)
|
||||
wmap->write_b(waddr, temp, wmap->p);
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_NEW_DYNAREC
|
||||
uint16_t
|
||||
readmemwl(uint32_t addr)
|
||||
@@ -803,7 +865,7 @@ readmemwl(uint32_t addr)
|
||||
|
||||
if (addr64 & 1) {
|
||||
if (!cpu_cyrix_alignment || (addr64 & 7) == 7)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr64 & 0xfff) > 0xffe) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_read(addr) == 0xffffffffffffffffULL)
|
||||
@@ -847,7 +909,7 @@ writememwl(uint32_t addr, uint16_t val)
|
||||
|
||||
if (addr & 1) {
|
||||
if (!cpu_cyrix_alignment || (addr & 7) == 7)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr & 0xFFF) > 0xFFE) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_write(addr) == 0xffffffff)
|
||||
@@ -900,7 +962,7 @@ readmemll(uint32_t addr)
|
||||
|
||||
if (addr & 3) {
|
||||
if (!cpu_cyrix_alignment || (addr & 7) > 4)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr & 0xfff) > 0xffc) {
|
||||
if (cr0>>31) {
|
||||
if (mmutranslate_read(addr) == 0xffffffffffffffffULL)
|
||||
@@ -950,7 +1012,7 @@ writememll(uint32_t addr, uint32_t val)
|
||||
|
||||
if (addr & 3) {
|
||||
if (!cpu_cyrix_alignment || (addr & 7) > 4)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr & 0xFFF) > 0xFFC) {
|
||||
if (cr0>>31) {
|
||||
if (mmutranslate_write(addr) == 0xffffffffffffffffULL)
|
||||
@@ -1006,7 +1068,7 @@ readmemql(uint32_t addr)
|
||||
mem_logical_addr = addr;
|
||||
|
||||
if (addr & 7) {
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr & 0xFFF) > 0xFF8) {
|
||||
if (cr0>>31) {
|
||||
if (mmutranslate_read(addr) == 0xffffffffffffffffULL)
|
||||
@@ -1046,7 +1108,7 @@ writememql(uint32_t addr, uint64_t val)
|
||||
mem_logical_addr = addr;
|
||||
|
||||
if (addr & 7) {
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr & 0xFFF) > 0xFF8) {
|
||||
if (cr0>>31) {
|
||||
if (mmutranslate_write(addr) == 0xffffffffffffffffULL)
|
||||
@@ -1100,30 +1162,16 @@ writememql(uint32_t addr, uint64_t val)
|
||||
}
|
||||
}
|
||||
#else
|
||||
uint8_t
|
||||
readmemb386l(uint32_t seg, uint32_t addr)
|
||||
{
|
||||
return readmembl(addr + seg);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
writememb386l(uint32_t seg, uint32_t addr, uint8_t val)
|
||||
{
|
||||
writemembl(addr + seg, val);
|
||||
}
|
||||
|
||||
|
||||
uint16_t
|
||||
readmemwl(uint32_t seg, uint32_t addr)
|
||||
readmemwl(uint32_t addr)
|
||||
{
|
||||
uint64_t addr64 = (uint64_t) addr;
|
||||
mem_mapping_t *map;
|
||||
uint32_t addr2 = mem_logical_addr = seg + addr;
|
||||
uint32_t addr2 = mem_logical_addr = addr;
|
||||
|
||||
if (addr2 & 1) {
|
||||
if (!cpu_cyrix_alignment || (addr2 & 7) == 7)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr2 & 0xfff) > 0xffe) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_read(addr2) == 0xffffffffffffffffULL)
|
||||
@@ -1131,8 +1179,7 @@ readmemwl(uint32_t seg, uint32_t addr)
|
||||
if (mmutranslate_read(addr2+1) == 0xffffffffffffffffULL)
|
||||
return 0xffff;
|
||||
}
|
||||
if (is386) return readmemb386l(seg,addr)|(((uint16_t) readmemb386l(seg,addr+1))<<8);
|
||||
else return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8);
|
||||
return readmembl(addr)|(((uint16_t) readmembl(addr+1))<<8);
|
||||
} else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV)
|
||||
return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2);
|
||||
}
|
||||
@@ -1154,12 +1201,8 @@ readmemwl(uint32_t seg, uint32_t addr)
|
||||
return map->read_w(addr2, map->p);
|
||||
|
||||
if (map && map->read_b) {
|
||||
if (AT)
|
||||
return map->read_b(addr2, map->p) |
|
||||
((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8);
|
||||
else
|
||||
return map->read_b(addr2, map->p) |
|
||||
((uint16_t) (map->read_b(seg + ((addr + 1) & 0xffff), map->p)) << 8);
|
||||
return map->read_b(addr2, map->p) |
|
||||
((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8);
|
||||
}
|
||||
|
||||
return 0xffff;
|
||||
@@ -1167,27 +1210,22 @@ readmemwl(uint32_t seg, uint32_t addr)
|
||||
|
||||
|
||||
void
|
||||
writememwl(uint32_t seg, uint32_t addr, uint16_t val)
|
||||
writememwl(uint32_t addr, uint16_t val)
|
||||
{
|
||||
uint64_t addr64 = (uint64_t) addr;
|
||||
mem_mapping_t *map;
|
||||
uint32_t addr2 = mem_logical_addr = seg + addr;
|
||||
uint32_t addr2 = mem_logical_addr = addr;
|
||||
|
||||
if (addr2 & 1) {
|
||||
if (!cpu_cyrix_alignment || (addr2 & 7) == 7)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr2 & 0xFFF) > 0xffe) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return;
|
||||
if (mmutranslate_write(addr2+1) == 0xffffffffffffffffULL) return;
|
||||
}
|
||||
if (is386) {
|
||||
writememb386l(seg,addr,val);
|
||||
writememb386l(seg,addr+1,val>>8);
|
||||
} else {
|
||||
writemembl(seg+addr,val);
|
||||
writemembl(seg+addr+1,val>>8);
|
||||
}
|
||||
writemembl(addr,val);
|
||||
writemembl(addr+1,val>>8);
|
||||
return;
|
||||
} else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) {
|
||||
*(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val;
|
||||
@@ -1227,21 +1265,21 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val)
|
||||
|
||||
|
||||
uint32_t
|
||||
readmemll(uint32_t seg, uint32_t addr)
|
||||
readmemll(uint32_t addr)
|
||||
{
|
||||
uint64_t addr64 = (uint64_t) addr;
|
||||
mem_mapping_t *map;
|
||||
uint32_t addr2 = mem_logical_addr = seg + addr;
|
||||
uint32_t addr2 = mem_logical_addr = addr;
|
||||
|
||||
if (addr2 & 3) {
|
||||
if (!cpu_cyrix_alignment || (addr2 & 7) > 4)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr2 & 0xfff) > 0xffc) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffff;
|
||||
if (mmutranslate_read(addr2+3) == 0xffffffffffffffffULL) return 0xffffffff;
|
||||
}
|
||||
return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16);
|
||||
return readmemwl(addr)|(readmemwl(addr+2)<<16);
|
||||
} else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV)
|
||||
return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2);
|
||||
}
|
||||
@@ -1277,22 +1315,22 @@ readmemll(uint32_t seg, uint32_t addr)
|
||||
|
||||
|
||||
void
|
||||
writememll(uint32_t seg, uint32_t addr, uint32_t val)
|
||||
writememll(uint32_t addr, uint32_t val)
|
||||
{
|
||||
uint64_t addr64 = (uint64_t) addr;
|
||||
mem_mapping_t *map;
|
||||
uint32_t addr2 = mem_logical_addr = seg + addr;
|
||||
uint32_t addr2 = mem_logical_addr = addr;
|
||||
|
||||
if (addr2 & 3) {
|
||||
if (!cpu_cyrix_alignment || (addr2 & 7) > 4)
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr2 & 0xfff) > 0xffc) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return;
|
||||
if (mmutranslate_write(addr2+3) == 0xffffffffffffffffULL) return;
|
||||
}
|
||||
writememwl(seg,addr,val);
|
||||
writememwl(seg,addr+2,val>>16);
|
||||
writememwl(addr,val);
|
||||
writememwl(addr+2,val>>16);
|
||||
return;
|
||||
} else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) {
|
||||
*(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val;
|
||||
@@ -1338,20 +1376,20 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val)
|
||||
|
||||
|
||||
uint64_t
|
||||
readmemql(uint32_t seg, uint32_t addr)
|
||||
readmemql(uint32_t addr)
|
||||
{
|
||||
uint64_t addr64 = (uint64_t) addr;
|
||||
mem_mapping_t *map;
|
||||
uint32_t addr2 = mem_logical_addr = seg + addr;
|
||||
uint32_t addr2 = mem_logical_addr = addr;
|
||||
|
||||
if (addr2 & 7) {
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr2 & 0xfff) > 0xff8) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL;
|
||||
if (mmutranslate_read(addr2+7) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL;
|
||||
}
|
||||
return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32);
|
||||
return readmemll(addr)|((uint64_t)readmemll(addr+4)<<32);
|
||||
} else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV)
|
||||
return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2);
|
||||
}
|
||||
@@ -1371,26 +1409,26 @@ readmemql(uint32_t seg, uint32_t addr)
|
||||
if (map && map->read_l)
|
||||
return map->read_l(addr2, map->p) | ((uint64_t)map->read_l(addr2 + 4, map->p) << 32);
|
||||
|
||||
return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32);
|
||||
return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
writememql(uint32_t seg, uint32_t addr, uint64_t val)
|
||||
writememql(uint32_t addr, uint64_t val)
|
||||
{
|
||||
uint64_t addr64 = (uint64_t) addr;
|
||||
mem_mapping_t *map;
|
||||
uint32_t addr2 = mem_logical_addr = seg + addr;
|
||||
uint32_t addr2 = mem_logical_addr = addr;
|
||||
|
||||
if (addr2 & 7) {
|
||||
sub_cycles(timing_misaligned);
|
||||
cycles -= timing_misaligned;
|
||||
if ((addr2 & 0xfff) > 0xff8) {
|
||||
if (cr0 >> 31) {
|
||||
if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return;
|
||||
if (mmutranslate_write(addr2+7) == 0xffffffffffffffffULL) return;
|
||||
}
|
||||
writememll(seg, addr, val);
|
||||
writememll(seg, addr+4, val >> 32);
|
||||
writememll(addr, val);
|
||||
writememll(addr+4, val >> 32);
|
||||
return;
|
||||
} else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) {
|
||||
*(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val;
|
||||
|
||||
@@ -162,6 +162,42 @@ rom_readl(uint32_t addr, void *priv)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rom_load_linear_oddeven(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
|
||||
{
|
||||
FILE *f = rom_fopen(fn, L"rb");
|
||||
int i;
|
||||
|
||||
if (f == NULL) {
|
||||
rom_log("ROM: image '%ls' not found\n", fn);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Make sure we only look at the base-256K offset. */
|
||||
if (addr >= 0x40000)
|
||||
addr = 0;
|
||||
else
|
||||
addr &= 0x03ffff;
|
||||
|
||||
if (ptr != NULL) {
|
||||
if (fseek(f, off, SEEK_SET) == -1)
|
||||
fatal("rom_load_linear(): Error seeking to the beginning of the file\n");
|
||||
for (i = 0; i < (sz >> 1); i++) {
|
||||
if (fread(ptr + (addr + (i << 1)), 1, 1, f) != 1)
|
||||
fatal("rom_load_linear(): Error reading even data\n");
|
||||
}
|
||||
for (i = 0; i < (sz >> 1); i++) {
|
||||
if (fread(ptr + (addr + (i << 1) + 1), 1, 1, f) != 1)
|
||||
fatal("rom_load_linear(): Error reading od data\n");
|
||||
}
|
||||
}
|
||||
|
||||
(void)fclose(f);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Load a ROM BIOS from its chips, interleaved mode. */
|
||||
int
|
||||
rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
|
||||
@@ -507,6 +543,36 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rom_init_oddeven(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags)
|
||||
{
|
||||
rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags);
|
||||
|
||||
/* Allocate a buffer for the image. */
|
||||
rom->rom = malloc(sz);
|
||||
memset(rom->rom, 0xff, sz);
|
||||
|
||||
/* Load the image file into the buffer. */
|
||||
if (! rom_load_linear_oddeven(fn, addr, sz, off, rom->rom)) {
|
||||
/* Nope.. clean up. */
|
||||
free(rom->rom);
|
||||
rom->rom = NULL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
rom->sz = sz;
|
||||
rom->mask = mask;
|
||||
|
||||
mem_mapping_add(&rom->mapping,
|
||||
addr, sz,
|
||||
rom_read, rom_readw, rom_readl,
|
||||
mem_write_null, mem_write_nullw, mem_write_nulll,
|
||||
rom->rom, flags | MEM_MAPPING_ROM, rom);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags)
|
||||
{
|
||||
|
||||
@@ -638,7 +638,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv)
|
||||
local_t *local = (local_t *)nvr->data;
|
||||
uint8_t addr_id = (addr & 0x0e) >> 1;
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (local->bank[addr_id] == 0xff)
|
||||
return;
|
||||
@@ -673,7 +673,7 @@ nvr_read(uint16_t addr, void *priv)
|
||||
uint8_t addr_id = (addr & 0x0e) >> 1;
|
||||
uint16_t i, checksum = 0x0000;
|
||||
|
||||
sub_cycles(ISA_CYCLES(8));
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (/* (addr & 1) && */(local->bank[addr_id] == 0xff))
|
||||
return 0xff;
|
||||
|
||||
10
src/pc.c
10
src/pc.c
@@ -141,7 +141,8 @@ int cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */
|
||||
fpu_type = 0; /* (C) fpu type */
|
||||
int time_sync = 0; /* (C) enable time sync */
|
||||
int confirm_reset = 1, /* (C) enable reset confirmation */
|
||||
confirm_exit = 1; /* (C) enable exit confirmation */
|
||||
confirm_exit = 1, /* (C) enable exit confirmation */
|
||||
confirm_save = 1; /* (C) enable save confirmation */
|
||||
#ifdef USE_DISCORD
|
||||
int enable_discord = 0; /* (C) enable Discord integration */
|
||||
#endif
|
||||
@@ -1131,6 +1132,13 @@ set_screen_size(int x, int y)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reset_screen_size(void)
|
||||
{
|
||||
set_screen_size(unscaled_size_x, efscrnsz_y);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
set_screen_size_natural(void)
|
||||
{
|
||||
|
||||
24
src/pic.c
24
src/pic.c
@@ -31,6 +31,10 @@
|
||||
#include <86box/pic.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/pit.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/apm.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/acpi.h>
|
||||
|
||||
|
||||
enum
|
||||
@@ -142,7 +146,7 @@ pic_cascade_mode(pic_t *dev)
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
static __inline uint8_t
|
||||
pic_slave_on(pic_t *dev, int channel)
|
||||
{
|
||||
pic_log("pic_slave_on(%i): %i, %02X, %02X\n", channel, pic_cascade_mode(dev), dev->icw4 & 0x0c, dev->icw3 & (1 << channel));
|
||||
@@ -152,7 +156,7 @@ pic_slave_on(pic_t *dev, int channel)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
static __inline int
|
||||
find_best_interrupt(pic_t *dev)
|
||||
{
|
||||
uint8_t b, s;
|
||||
@@ -184,7 +188,7 @@ find_best_interrupt(pic_t *dev)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static __inline void
|
||||
pic_update_pending(void)
|
||||
{
|
||||
int is_at = IS_AT(machine);
|
||||
@@ -321,7 +325,7 @@ pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate)
|
||||
|
||||
|
||||
/* Automatic non-specific EOI. */
|
||||
static void
|
||||
static __inline void
|
||||
pic_auto_non_specific_eoi(pic_t *dev)
|
||||
{
|
||||
uint8_t irq;
|
||||
@@ -520,6 +524,9 @@ picint_common(uint16_t num, int level, int set)
|
||||
return;
|
||||
}
|
||||
|
||||
if (num & 0x0100)
|
||||
acpi_rtc_status = !!set;
|
||||
|
||||
if (set) {
|
||||
if (num & 0xff00) {
|
||||
if (level)
|
||||
@@ -650,8 +657,13 @@ picinterrupt()
|
||||
pit_ctr_set_gate(&pit2->counters[0], 0);
|
||||
|
||||
/* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */
|
||||
for (i = 0; i < 2; i++)
|
||||
ret = pic_irq_ack();
|
||||
for (i = 0; i < 2; i++) {
|
||||
ret = pic_irq_ack_read(&pic, pic.ack_bytes);
|
||||
pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
|
||||
|
||||
if (pic.ack_bytes == 0)
|
||||
pic_update_pending();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
17
src/pit.c
17
src/pit.c
@@ -358,7 +358,7 @@ ctr_load(ctr_t *ctr)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static __inline void
|
||||
ctr_latch_status(ctr_t *ctr)
|
||||
{
|
||||
ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0) | (ctr->null_count ? 0x40 : 0);
|
||||
@@ -366,7 +366,7 @@ ctr_latch_status(ctr_t *ctr)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static __inline void
|
||||
ctr_latch_count(ctr_t *ctr)
|
||||
{
|
||||
int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count;
|
||||
@@ -459,8 +459,8 @@ pit_ctr_set_gate(ctr_t *ctr, int gate)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_clock(ctr_t *ctr, int clock)
|
||||
static __inline void
|
||||
pit_ctr_set_clock_common(ctr_t *ctr, int clock)
|
||||
{
|
||||
int old = ctr->clock;
|
||||
|
||||
@@ -491,6 +491,13 @@ pit_ctr_set_clock(ctr_t *ctr, int clock)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_clock(ctr_t *ctr, int clock)
|
||||
{
|
||||
pit_ctr_set_clock_common(ctr, clock);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pit_ctr_set_using_timer(ctr_t *ctr, int using_timer)
|
||||
{
|
||||
@@ -509,7 +516,7 @@ pit_timer_over(void *p)
|
||||
dev->clock ^= 1;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
pit_ctr_set_clock(&dev->counters[i], dev->clock);
|
||||
pit_ctr_set_clock_common(&dev->counters[i], dev->clock);
|
||||
|
||||
timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL);
|
||||
}
|
||||
|
||||
@@ -595,7 +595,6 @@ handle_satn_stop(void *priv)
|
||||
dev->rregs[ESP_RSEQ] = SEQ_CD;
|
||||
esp_log("ESP SCSI Command len = %d, raising IRQ\n", dev->cmdlen);
|
||||
esp_raise_irq(dev);
|
||||
timer_on_auto(&dev->timer, 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,6 +728,7 @@ esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val)
|
||||
dev->rregs[ESP_RINTR] = INTR_FC;
|
||||
dev->rregs[ESP_RSEQ] = 0;
|
||||
dev->rregs[ESP_RFLAGS] = 0;
|
||||
timer_on_auto(&dev->timer, 10.0);
|
||||
break;
|
||||
case CMD_RESET:
|
||||
esp_pci_soft_reset(dev);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#define CS4231 0x80
|
||||
|
||||
static int ad1848_vols_6bits[64];
|
||||
static uint32_t ad1848_vols_5bits_aux_gain[32];
|
||||
static double ad1848_vols_5bits_aux_gain[32];
|
||||
|
||||
|
||||
void ad1848_setirq(ad1848_t *ad1848, int irq)
|
||||
@@ -224,11 +224,11 @@ static void ad1848_poll(void *p)
|
||||
static void ad1848_filter_cd_audio(int channel, double *buffer, void *p)
|
||||
{
|
||||
ad1848_t *ad1848 = (ad1848_t *)p;
|
||||
int32_t c;
|
||||
uint32_t volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l;
|
||||
double c;
|
||||
double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l;
|
||||
|
||||
c = (((int32_t) *buffer) * volume) >> 16;
|
||||
*buffer = (double) c;
|
||||
c = ((*buffer) * volume) / 65536.0;
|
||||
*buffer = c;
|
||||
}
|
||||
|
||||
void ad1848_init(ad1848_t *ad1848, int type)
|
||||
@@ -292,12 +292,13 @@ void ad1848_init(ad1848_t *ad1848, int type)
|
||||
|
||||
attenuation = pow(10, attenuation / 10);
|
||||
|
||||
ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536);
|
||||
ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536);
|
||||
}
|
||||
|
||||
ad1848->type = type;
|
||||
|
||||
timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0);
|
||||
|
||||
sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848);
|
||||
if (ad1848->type != AD1848_TYPE_DEFAULT)
|
||||
sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848);
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ opl2_read(uint16_t port, void *priv)
|
||||
opl_t *dev = (opl_t *)priv;
|
||||
|
||||
if (dev->flags & FLAG_CYCLES)
|
||||
sub_cycles((int) (isa_timing * 8));
|
||||
cycles -= ((int) (isa_timing * 8));
|
||||
|
||||
opl2_update(dev);
|
||||
|
||||
@@ -277,7 +277,7 @@ opl3_read(uint16_t port, void *priv)
|
||||
opl_t *dev = (opl_t *)priv;
|
||||
|
||||
if (dev->flags & FLAG_CYCLES)
|
||||
sub_cycles((int)(isa_timing * 8));
|
||||
cycles -= ((int)(isa_timing * 8));
|
||||
|
||||
opl3_update(dev);
|
||||
|
||||
|
||||
@@ -1207,7 +1207,7 @@ sb_pro_v1_opl_read(uint16_t port, void *priv)
|
||||
{
|
||||
sb_t *sb = (sb_t *)priv;
|
||||
|
||||
sub_cycles((int)(isa_timing * 8));
|
||||
cycles -= ((int) (isa_timing * 8));
|
||||
|
||||
(void)opl2_read(port, &sb->opl2); // read, but ignore
|
||||
return(opl2_read(port, &sb->opl));
|
||||
|
||||
@@ -102,8 +102,10 @@ uhci_reg_writew(uint16_t addr, uint16_t val, void *p)
|
||||
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
if ((regs[0x00] & 0x0001) && !(val & 0x0001))
|
||||
regs[0x02] |= 0x20;
|
||||
if ((val & 0x0001) && !(regs[0x00] & 0x0001))
|
||||
regs[0x01] &= ~0x20;
|
||||
else if (!(val & 0x0001))
|
||||
regs[0x01] |= 0x20;
|
||||
regs[0x00] = (val & 0x00ff);
|
||||
break;
|
||||
case 0x06:
|
||||
|
||||
@@ -401,7 +401,7 @@ ati28800_recalctimings(svga_t *svga)
|
||||
case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 32000000.0; break;
|
||||
case 0x0A: svga->clock = (cpuclock * (double)(1ull << 32)) / 37500000.0; break;
|
||||
case 0x0B: svga->clock = (cpuclock * (double)(1ull << 32)) / 39000000.0; break;
|
||||
case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break;
|
||||
case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break;
|
||||
case 0x0D: svga->clock = (cpuclock * (double)(1ull << 32)) / 56644000.0; break;
|
||||
case 0x0E: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break;
|
||||
case 0x0F: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break;
|
||||
@@ -423,14 +423,6 @@ ati28800_recalctimings(svga_t *svga)
|
||||
svga->rowoffset <<= 1;
|
||||
}
|
||||
|
||||
if (svga->crtc[0x17] & 4) {
|
||||
svga->vtotal <<= 1;
|
||||
svga->dispend <<= 1;
|
||||
svga->vsyncstart <<= 1;
|
||||
svga->split <<= 1;
|
||||
svga->vblankstart <<= 1;
|
||||
}
|
||||
|
||||
if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) { /* Extended 256 colour modes */
|
||||
switch (svga->bpp) {
|
||||
case 8:
|
||||
|
||||
@@ -123,7 +123,7 @@ cga_waitstates(void *p)
|
||||
int ws;
|
||||
|
||||
ws = ws_array[cycles & 0xf];
|
||||
sub_cycles(ws);
|
||||
cycles -= ws;
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -100,7 +100,7 @@ void colorplus_write(uint32_t addr, uint8_t val, void *p)
|
||||
colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff];
|
||||
}
|
||||
egawrites++;
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
}
|
||||
|
||||
uint8_t colorplus_read(uint32_t addr, void *p)
|
||||
@@ -117,7 +117,7 @@ uint8_t colorplus_read(uint32_t addr, void *p)
|
||||
{
|
||||
addr &= 0x3FFF;
|
||||
}
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
if (colorplus->cga.snow_enabled)
|
||||
{
|
||||
int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc;
|
||||
|
||||
@@ -732,7 +732,7 @@ ega_write(uint32_t addr, uint8_t val, void *p)
|
||||
int writemask2 = ega->writemask;
|
||||
|
||||
egawrites++;
|
||||
sub_cycles(video_timing_write_b);
|
||||
cycles -= video_timing_write_b;
|
||||
|
||||
if (addr >= 0xB0000) addr &= 0x7fff;
|
||||
else addr &= 0xffff;
|
||||
@@ -859,7 +859,7 @@ ega_read(uint32_t addr, void *p)
|
||||
int readplane = ega->readplane;
|
||||
|
||||
egareads++;
|
||||
sub_cycles(video_timing_read_b);
|
||||
cycles -= video_timing_read_b;
|
||||
if (addr >= 0xb0000) addr &= 0x7fff;
|
||||
else addr &= 0xffff;
|
||||
|
||||
|
||||
@@ -245,6 +245,15 @@ et4000_out(uint16_t addr, uint8_t val, void *priv)
|
||||
svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000;
|
||||
} else
|
||||
svga->write_bank = svga->read_bank = 0;
|
||||
|
||||
old = svga->gdcreg[6];
|
||||
svga_out(addr, val, svga);
|
||||
if ((old & 0xc) != 0 && (val & 0xc) == 0)
|
||||
{
|
||||
/*override mask - ET4000 supports linear 128k at A0000*/
|
||||
svga->banked_mask = 0x1ffff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -454,7 +454,7 @@ void et4000w32p_recalcmapping(et4000w32p_t *et4000)
|
||||
case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/
|
||||
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
|
||||
mem_mapping_disable(&et4000->mmu_mapping);
|
||||
svga->banked_mask = 0xffff;
|
||||
svga->banked_mask = 0x1ffff;
|
||||
break;
|
||||
case 0x1: /*64k at A0000*/
|
||||
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
|
||||
|
||||
@@ -253,7 +253,7 @@ genius_waitstates(void)
|
||||
int ws;
|
||||
|
||||
ws = ws_array[cycles & 0xf];
|
||||
sub_cycles(ws);
|
||||
cycles -= ws;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ hercules_waitstates(void *p)
|
||||
int ws;
|
||||
|
||||
ws = ws_array[cycles & 0xf];
|
||||
sub_cycles(ws);
|
||||
cycles -= ws;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -729,7 +729,7 @@ ht216_write_common(ht216_t *ht216, uint32_t addr, uint8_t val)
|
||||
svga_t *svga = &ht216->svga;
|
||||
uint8_t bit_mask = 0, rop_select = 0;
|
||||
|
||||
sub_cycles(video_timing_write_b);
|
||||
cycles -= video_timing_write_b;
|
||||
|
||||
egawrites++;
|
||||
|
||||
@@ -911,7 +911,7 @@ ht216_read_common(ht216_t *ht216, uint32_t addr)
|
||||
|
||||
addr &= 0xfffff;
|
||||
|
||||
sub_cycles(video_timing_read_b);
|
||||
cycles -= video_timing_read_b;
|
||||
|
||||
egareads++;
|
||||
|
||||
|
||||
@@ -2132,7 +2132,7 @@ mystique_readb_linear(uint32_t addr, void *p)
|
||||
|
||||
egareads++;
|
||||
|
||||
sub_cycles(video_timing_read_b);
|
||||
cycles -= video_timing_read_b;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -2149,7 +2149,7 @@ mystique_readw_linear(uint32_t addr, void *p)
|
||||
|
||||
egareads += 2;
|
||||
|
||||
sub_cycles(video_timing_read_w);
|
||||
cycles -= video_timing_read_w;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -2166,7 +2166,7 @@ mystique_readl_linear(uint32_t addr, void *p)
|
||||
|
||||
egareads += 4;
|
||||
|
||||
sub_cycles(video_timing_read_l);
|
||||
cycles -= video_timing_read_l;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -2183,7 +2183,7 @@ mystique_writeb_linear(uint32_t addr, uint8_t val, void *p)
|
||||
|
||||
egawrites++;
|
||||
|
||||
sub_cycles(video_timing_write_b);
|
||||
cycles -= video_timing_write_b;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -2201,7 +2201,7 @@ mystique_writew_linear(uint32_t addr, uint16_t val, void *p)
|
||||
|
||||
egawrites += 2;
|
||||
|
||||
sub_cycles(video_timing_write_w);
|
||||
cycles -= video_timing_write_w;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -2219,7 +2219,7 @@ mystique_writel_linear(uint32_t addr, uint32_t val, void *p)
|
||||
|
||||
egawrites += 4;
|
||||
|
||||
sub_cycles(video_timing_write_l);
|
||||
cycles -= video_timing_write_l;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
|
||||
@@ -2697,7 +2697,7 @@ s3_accel_in(uint16_t port, void *p)
|
||||
if (FIFO_FULL && s3->chip >= S3_VISION964)
|
||||
temp |= 0xf8; /*FIFO full*/
|
||||
} else {
|
||||
if (s3->busy || s3->force_busy) {
|
||||
if (s3->force_busy) {
|
||||
temp |= 0x02; /*Hardware busy*/
|
||||
}
|
||||
s3->force_busy = 0;
|
||||
@@ -3343,10 +3343,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
dstbase >>= 2;
|
||||
}
|
||||
|
||||
if (((s3_cpu_src(s3) || s3_cpu_dest(s3))) && (s3->chip >= S3_86C928 && s3->chip < S3_TRIO64V)) {
|
||||
s3->busy = 1;
|
||||
}
|
||||
|
||||
if ((s3->accel.cmd & 0x100) && (s3_cpu_src(s3) || s3_cpu_dest(s3)) && !cpu_input) {
|
||||
s3->force_busy = 1;
|
||||
}
|
||||
@@ -3439,7 +3435,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
if (s3->bpp == 0) cpu_dat >>= 8;
|
||||
else cpu_dat >>= 16;
|
||||
if (!s3->accel.sy) {
|
||||
s3->busy = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3510,7 +3505,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
else cpu_dat >>= 16;
|
||||
|
||||
if (!s3->accel.sy) {
|
||||
s3->busy = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3682,10 +3676,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
s3->accel.dest = dstbase + s3->accel.cy * s3->width;
|
||||
s3->accel.sy--;
|
||||
|
||||
if (s3->accel.sy < 0) {
|
||||
s3->busy = 0;
|
||||
}
|
||||
|
||||
if (cpu_input) {
|
||||
if (s3_cpu_dest(s3))
|
||||
s3->data_available = 1;
|
||||
@@ -3766,7 +3756,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
s3->accel.sy--;
|
||||
|
||||
if (s3->accel.sy < 0) {
|
||||
s3->busy = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -3854,9 +3843,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
|
||||
s3->accel.sy--;
|
||||
|
||||
if (s3->accel.sy < 0)
|
||||
s3->busy = 0;
|
||||
|
||||
if (cpu_input)
|
||||
return;
|
||||
|
||||
@@ -3979,9 +3965,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
|
||||
s3->accel.sy--;
|
||||
|
||||
if (s3->accel.sy < 0)
|
||||
s3->busy = 0;
|
||||
|
||||
if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
|
||||
if (s3->accel.sy < 0)
|
||||
return;
|
||||
@@ -4061,7 +4044,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff;
|
||||
s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff;
|
||||
}
|
||||
s3->busy = 0;
|
||||
break;
|
||||
|
||||
case 11: /*Polygon Fill Pattern (Trio64 only)*/
|
||||
@@ -4150,7 +4132,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
|
||||
s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff;
|
||||
s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff;
|
||||
}
|
||||
s3->busy = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ sigma_write(uint32_t addr, uint8_t val, void *p)
|
||||
|
||||
sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)] = val;
|
||||
egawrites++;
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ sigma_read(uint32_t addr, void *p)
|
||||
{
|
||||
sigma_t *sigma = (sigma_t *)p;
|
||||
|
||||
sub_cycles(4);
|
||||
cycles -= 4;
|
||||
egareads++;
|
||||
return sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)];
|
||||
}
|
||||
|
||||
@@ -1015,7 +1015,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p)
|
||||
|
||||
egawrites++;
|
||||
|
||||
sub_cycles(video_timing_write_b);
|
||||
cycles -= video_timing_write_b;
|
||||
|
||||
if (!linear) {
|
||||
addr = svga_decode_addr(svga, addr, 1);
|
||||
@@ -1057,14 +1057,21 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p)
|
||||
if (svga->adv_flags & FLAG_LATCH8)
|
||||
count = 8;
|
||||
|
||||
/* Undocumented Cirrus Logic behavior: The datasheet says that, with EXT_WRITE and FLAG_ADDR_BY8, the write mask only
|
||||
changes meaning in write modes 4 and 5, as well as write mode 1. In reality, however, all other write modes are also
|
||||
affected, as proven by the Windows 3.1 CL-GD 5422/4 drivers in 8bpp modes. */
|
||||
switch (svga->writemode) {
|
||||
case 0:
|
||||
if (svga->gdcreg[3] & 7)
|
||||
val = svga_rotate[svga->gdcreg[3] & 7][val];
|
||||
val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7))));
|
||||
if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) {
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = val;
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = val;
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = val;
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
@@ -1078,8 +1085,13 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p)
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = svga->latch.b[i];
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = svga->latch.b[i];
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = svga->latch.b[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 2:
|
||||
@@ -1088,15 +1100,19 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p)
|
||||
|
||||
if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) {
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]);
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]);
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (svga->gdcreg[3] & 7)
|
||||
val = svga_rotate[svga->gdcreg[3] & 7][val];
|
||||
val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7))));
|
||||
wm = svga->gdcreg[8];
|
||||
svga->gdcreg[8] &= val;
|
||||
|
||||
@@ -1114,26 +1130,46 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p)
|
||||
switch (svga->gdcreg[3] & 0x18) {
|
||||
case 0x00: /* Set */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]);
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]);
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x08: /* AND */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i];
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i];
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x10: /* OR */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i];
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i];
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x18: /* XOR */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i];
|
||||
if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) {
|
||||
if (writemask2 & (0x80 >> i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i];
|
||||
} else {
|
||||
if (writemask2 & (1 << i))
|
||||
svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1156,7 +1192,7 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p)
|
||||
if (svga->adv_flags & FLAG_ADDR_BY8)
|
||||
readplane = svga->gdcreg[4] & 7;
|
||||
|
||||
sub_cycles(video_timing_read_b);
|
||||
cycles -= video_timing_read_b;
|
||||
|
||||
egareads++;
|
||||
|
||||
@@ -1182,6 +1218,9 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p)
|
||||
addr = svga->translate_address(addr, p);
|
||||
if (addr >= svga->vram_max)
|
||||
return 0xff;
|
||||
latch_addr = (addr & svga->vram_mask) & ~3;
|
||||
for (i = 0; i < count; i++)
|
||||
svga->latch.b[i] = svga->vram[latch_addr | i];
|
||||
return svga->vram[addr & svga->vram_mask];
|
||||
} else if (svga->chain2_read) {
|
||||
readplane = (readplane & 2) | (addr & 1);
|
||||
@@ -1381,7 +1420,7 @@ svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p)
|
||||
|
||||
egawrites += 2;
|
||||
|
||||
sub_cycles(video_timing_write_w);
|
||||
cycles -= video_timing_write_w;
|
||||
|
||||
if (!linear) {
|
||||
addr = svga_decode_addr(svga, addr, 1);
|
||||
@@ -1442,7 +1481,7 @@ svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p)
|
||||
|
||||
egawrites += 4;
|
||||
|
||||
sub_cycles(video_timing_write_l);
|
||||
cycles -= video_timing_write_l;
|
||||
|
||||
if (!linear) {
|
||||
addr = svga_decode_addr(svga, addr, 1);
|
||||
@@ -1526,7 +1565,7 @@ svga_readw_common(uint32_t addr, uint8_t linear, void *p)
|
||||
|
||||
egareads += 2;
|
||||
|
||||
sub_cycles(video_timing_read_w);
|
||||
cycles -= video_timing_read_w;
|
||||
|
||||
if (!linear) {
|
||||
addr = svga_decode_addr(svga, addr, 0);
|
||||
@@ -1579,7 +1618,7 @@ svga_readl_common(uint32_t addr, uint8_t linear, void *p)
|
||||
|
||||
egareads += 4;
|
||||
|
||||
sub_cycles(video_timing_read_l);
|
||||
cycles -= video_timing_read_l;
|
||||
|
||||
if (!linear) {
|
||||
addr = svga_decode_addr(svga, addr, 0);
|
||||
|
||||
@@ -71,9 +71,7 @@ video_cards[] = {
|
||||
{ "cl_gd5401_isa", &gd5401_isa_device },
|
||||
{ "cl_gd5402_isa", &gd5402_isa_device },
|
||||
{ "cl_gd5420_isa", &gd5420_isa_device },
|
||||
#if defined(DEV_BRANCH) && defined(USE_CL5422)
|
||||
{ "cl_gd5422_isa", &gd5422_isa_device },
|
||||
#endif
|
||||
{ "cl_gd5428_isa", &gd5428_isa_device },
|
||||
{ "cl_gd5429_isa", &gd5429_isa_device },
|
||||
{ "cl_gd5434_isa", &gd5434_isa_device },
|
||||
@@ -154,9 +152,7 @@ video_cards[] = {
|
||||
{ "voodoo3_3k_pci", &voodoo_3_3000_device },
|
||||
{ "mach64gx_vlb", &mach64gx_vlb_device },
|
||||
{ "et4000w32p_vlb", &et4000w32p_cardex_vlb_device },
|
||||
#if defined(DEV_BRANCH) && defined(USE_CL5422)
|
||||
{ "cl_gd5424_vlb", &gd5424_vlb_device },
|
||||
#endif
|
||||
{ "cl_gd5428_vlb", &gd5428_vlb_device },
|
||||
{ "cl_gd5429_vlb", &gd5429_vlb_device },
|
||||
{ "cl_gd5434_vlb", &gd5434_vlb_device },
|
||||
|
||||
@@ -798,7 +798,7 @@ static uint8_t tgui_ext_linear_read(uint32_t addr, void *p)
|
||||
tgui_t *tgui = (tgui_t *)svga->p;
|
||||
int c;
|
||||
|
||||
sub_cycles(video_timing_read_b);
|
||||
cycles -= video_timing_read_b;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -829,7 +829,7 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p)
|
||||
uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]};
|
||||
uint8_t mask = tgui->ext_gdc_regs[7];
|
||||
|
||||
sub_cycles(video_timing_write_b);
|
||||
cycles -= video_timing_write_b;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
@@ -898,7 +898,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p)
|
||||
uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]};
|
||||
uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8];
|
||||
|
||||
sub_cycles(video_timing_write_w);
|
||||
cycles -= video_timing_write_w;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= svga->vram_max)
|
||||
|
||||
@@ -127,6 +127,15 @@ void tvga_out(uint16_t addr, uint8_t val, void *p)
|
||||
case 0x3CF:
|
||||
switch (svga->gdcaddr & 15)
|
||||
{
|
||||
case 0x6:
|
||||
old = svga->gdcreg[6];
|
||||
svga_out(addr, val, svga);
|
||||
if ((old & 0xc) != 0 && (val & 0xc) == 0)
|
||||
{
|
||||
/*override mask - TVGA supports linear 128k at A0000*/
|
||||
svga->banked_mask = 0x1ffff;
|
||||
}
|
||||
return;
|
||||
case 0xE:
|
||||
svga->gdcreg[0xe] = val ^ 2;
|
||||
tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf;
|
||||
|
||||
@@ -151,7 +151,7 @@ static uint16_t voodoo_readw(uint32_t addr, void *p)
|
||||
|
||||
addr &= 0xffffff;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
cycles -= voodoo->read_time;
|
||||
|
||||
if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/
|
||||
{
|
||||
@@ -190,7 +190,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p)
|
||||
voodoo->rd_count++;
|
||||
addr &= 0xffffff;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
cycles -= voodoo->read_time;
|
||||
|
||||
if (addr & 0x800000) /*Texture*/
|
||||
{
|
||||
@@ -390,7 +390,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("voodoo_readl : bad addr %08X\n", addr);
|
||||
voodoo_log("voodoo_readl : bad addr %08X\n", addr);
|
||||
temp = 0xffffffff;
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ static void voodoo_writew(uint32_t addr, uint16_t val, void *p)
|
||||
voodoo->wr_count++;
|
||||
addr &= 0xffffff;
|
||||
|
||||
sub_cycles(voodoo->write_time);
|
||||
cycles -= voodoo->write_time;
|
||||
|
||||
if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/
|
||||
voodoo_queue_command(voodoo, addr | FIFO_WRITEW_FB, val);
|
||||
@@ -418,9 +418,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p)
|
||||
addr &= 0xffffff;
|
||||
|
||||
if (addr == voodoo->last_write_addr+4)
|
||||
sub_cycles(voodoo->burst_time);
|
||||
cycles -= voodoo->burst_time;
|
||||
else
|
||||
sub_cycles(voodoo->write_time);
|
||||
cycles -= voodoo->write_time;
|
||||
voodoo->last_write_addr = addr;
|
||||
|
||||
if (addr & 0x800000) /*Texture*/
|
||||
|
||||
@@ -181,6 +181,8 @@ enum
|
||||
#define VIDPROCCFG_CURSOR_MODE (1 << 1)
|
||||
#define VIDPROCCFG_HALF_MODE (1 << 4)
|
||||
#define VIDPROCCFG_OVERLAY_ENABLE (1 << 8)
|
||||
#define VIDPROCCFG_OVERLAY_CLUT_BYPASS (1 << 11)
|
||||
#define VIDPROCCFG_OVERLAY_CLUT_SEL (1 << 13)
|
||||
#define VIDPROCCFG_H_SCALE_ENABLE (1 << 14)
|
||||
#define VIDPROCCFG_V_SCALE_ENABLE (1 << 15)
|
||||
#define VIDPROCCFG_FILTER_MODE_MASK (3 << 16)
|
||||
@@ -658,7 +660,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
|
||||
|
||||
case Video_hwCurPatAddr:
|
||||
banshee->hwCurPatAddr = val;
|
||||
svga->hwcursor.addr = val & 0xfffff0;
|
||||
svga->hwcursor.addr = (val & 0xfffff0) + (svga->hwcursor.yoff * 16);
|
||||
break;
|
||||
case Video_hwCurLoc:
|
||||
banshee->hwCurLoc = val;
|
||||
@@ -671,6 +673,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
|
||||
}
|
||||
else
|
||||
svga->hwcursor.yoff = 0;
|
||||
svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16);
|
||||
svga->hwcursor.xsize = 64;
|
||||
svga->hwcursor.ysize = 64;
|
||||
// banshee_log("hwCurLoc %08x %i\n", val, svga->hwcursor.y);
|
||||
@@ -832,7 +835,7 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p)
|
||||
svga_t *svga = &banshee->svga;
|
||||
uint32_t ret = 0xffffffff;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
cycles -= voodoo->read_time;
|
||||
|
||||
switch (addr & 0xff)
|
||||
{
|
||||
@@ -1023,7 +1026,7 @@ static uint32_t banshee_reg_readl(uint32_t addr, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
uint32_t ret = 0xffffffff;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
cycles -= voodoo->read_time;
|
||||
|
||||
switch (addr & 0x1f00000)
|
||||
{
|
||||
@@ -1154,7 +1157,7 @@ static uint32_t banshee_reg_readl(uint32_t addr, void *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("banshee_reg_readl: 3D addr=%08x\n", addr);
|
||||
banshee_log("banshee_reg_readl: 3D addr=%08x\n", addr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1175,7 +1178,7 @@ static void banshee_reg_writew(uint32_t addr, uint16_t val, void *p)
|
||||
banshee_t *banshee = (banshee_t *)p;
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
|
||||
sub_cycles(voodoo->write_time);
|
||||
cycles -= voodoo->write_time;
|
||||
|
||||
// banshee_log("banshee_reg_writew: addr=%08x val=%04x\n", addr, val);
|
||||
switch (addr & 0x1f00000)
|
||||
@@ -1205,6 +1208,8 @@ static void banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val)
|
||||
voodoo->cmdfifo_size = val;
|
||||
voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12);
|
||||
voodoo->cmdfifo_enabled = val & 0x100;
|
||||
if (!voodoo->cmdfifo_enabled)
|
||||
voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/
|
||||
// banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end);
|
||||
break;
|
||||
|
||||
@@ -1248,9 +1253,9 @@ static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
|
||||
if (addr == voodoo->last_write_addr+4)
|
||||
sub_cycles(voodoo->burst_time);
|
||||
cycles -= voodoo->burst_time;
|
||||
else
|
||||
sub_cycles(voodoo->write_time);
|
||||
cycles -= voodoo->write_time;
|
||||
voodoo->last_write_addr = addr;
|
||||
|
||||
// banshee_log("banshee_reg_writel: addr=%08x val=%08x\n", addr, val);
|
||||
@@ -1346,7 +1351,7 @@ static uint8_t banshee_read_linear(uint32_t addr, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
svga_t *svga = &banshee->svga;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
cycles -= voodoo->read_time;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= voodoo->tile_base)
|
||||
@@ -1364,7 +1369,7 @@ static uint8_t banshee_read_linear(uint32_t addr, void *p)
|
||||
return 0xff;
|
||||
|
||||
egareads++;
|
||||
sub_cycles(video_timing_read_b);
|
||||
cycles -= video_timing_read_b;
|
||||
|
||||
// banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]);
|
||||
|
||||
@@ -1377,8 +1382,10 @@ static uint16_t banshee_read_linear_w(uint32_t addr, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
svga_t *svga = &banshee->svga;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
|
||||
if (addr & 1)
|
||||
return banshee_read_linear(addr, p) | (banshee_read_linear(addr+1, p) << 8);
|
||||
|
||||
cycles -= voodoo->read_time;
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= voodoo->tile_base)
|
||||
{
|
||||
@@ -1395,7 +1402,7 @@ static uint16_t banshee_read_linear_w(uint32_t addr, void *p)
|
||||
return 0xff;
|
||||
|
||||
egareads++;
|
||||
sub_cycles(video_timing_read_w);
|
||||
cycles -= video_timing_read_w;
|
||||
|
||||
// banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]);
|
||||
|
||||
@@ -1408,7 +1415,10 @@ static uint32_t banshee_read_linear_l(uint32_t addr, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
svga_t *svga = &banshee->svga;
|
||||
|
||||
sub_cycles(voodoo->read_time);
|
||||
if (addr & 3)
|
||||
return banshee_read_linear_w(addr, p) | (banshee_read_linear_w(addr+2, p) << 16);
|
||||
|
||||
cycles -= voodoo->read_time;
|
||||
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= voodoo->tile_base)
|
||||
@@ -1426,7 +1436,7 @@ static uint32_t banshee_read_linear_l(uint32_t addr, void *p)
|
||||
return 0xff;
|
||||
|
||||
egareads++;
|
||||
sub_cycles(video_timing_read_l);
|
||||
cycles -= video_timing_read_l;
|
||||
|
||||
// banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]);
|
||||
|
||||
@@ -1439,7 +1449,7 @@ static void banshee_write_linear(uint32_t addr, uint8_t val, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
svga_t *svga = &banshee->svga;
|
||||
|
||||
sub_cycles(voodoo->write_time);
|
||||
cycles -= voodoo->write_time;
|
||||
|
||||
// banshee_log("write_linear: addr=%08x val=%02x\n", addr, val);
|
||||
addr &= svga->decode_mask;
|
||||
@@ -1459,7 +1469,7 @@ static void banshee_write_linear(uint32_t addr, uint8_t val, void *p)
|
||||
|
||||
egawrites++;
|
||||
|
||||
sub_cycles(video_timing_write_b);
|
||||
cycles -= video_timing_write_b;
|
||||
|
||||
svga->changedvram[addr >> 12] = changeframecount;
|
||||
svga->vram[addr & svga->vram_mask] = val;
|
||||
@@ -1471,8 +1481,14 @@ static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p)
|
||||
voodoo_t *voodoo = banshee->voodoo;
|
||||
svga_t *svga = &banshee->svga;
|
||||
|
||||
sub_cycles(voodoo->write_time);
|
||||
|
||||
if (addr & 1)
|
||||
{
|
||||
banshee_write_linear(addr, val, p);
|
||||
banshee_write_linear(addr + 1, val >> 8, p);
|
||||
return;
|
||||
}
|
||||
|
||||
cycles -= voodoo->write_time;
|
||||
// banshee_log("write_linear: addr=%08x val=%02x\n", addr, val);
|
||||
addr &= svga->decode_mask;
|
||||
if (addr >= voodoo->tile_base)
|
||||
@@ -1491,7 +1507,7 @@ static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p)
|
||||
|
||||
egawrites++;
|
||||
|
||||
sub_cycles(video_timing_write_w);
|
||||
cycles -= video_timing_write_w;
|
||||
|
||||
svga->changedvram[addr >> 12] = changeframecount;
|
||||
*(uint16_t *)&svga->vram[addr & svga->vram_mask] = val;
|
||||
@@ -1504,11 +1520,18 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p)
|
||||
svga_t *svga = &banshee->svga;
|
||||
int timing;
|
||||
|
||||
if (addr & 3)
|
||||
{
|
||||
banshee_write_linear_w(addr, val, p);
|
||||
banshee_write_linear_w(addr + 2, val >> 16, p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr == voodoo->last_write_addr+4)
|
||||
timing = voodoo->burst_time;
|
||||
else
|
||||
timing = voodoo->write_time;
|
||||
sub_cycles(timing);
|
||||
cycles -= timing;
|
||||
voodoo->last_write_addr = addr;
|
||||
|
||||
// /*if (val) */banshee_log("write_linear_l: addr=%08x val=%08x %08x\n", addr, val, voodoo->tile_base);
|
||||
@@ -1530,7 +1553,7 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p)
|
||||
|
||||
egawrites += 4;
|
||||
|
||||
sub_cycles(video_timing_write_l);
|
||||
cycles -= video_timing_write_l;
|
||||
|
||||
svga->changedvram[addr >> 12] = changeframecount;
|
||||
*(uint32_t *)&svga->vram[addr & svga->vram_mask] = val;
|
||||
@@ -1670,7 +1693,12 @@ void banshee_hwcursor_draw(svga_t *svga, int displine)
|
||||
int g = (data >> 5) & 0x3f; \
|
||||
int b = data >> 11; \
|
||||
\
|
||||
buf[wp++] = (r << 3) | (g << 10) | (b << 19); \
|
||||
if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \
|
||||
buf[wp++] = (r << 3) | (g << 10) | (b << 19); \
|
||||
else \
|
||||
buf[wp++] = (clut[r << 3] & 0x0000ff) | \
|
||||
(clut[g << 2] & 0x00ff00) | \
|
||||
(clut[b << 3] & 0xff0000); \
|
||||
src += 2; \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -1680,7 +1708,7 @@ void banshee_hwcursor_draw(svga_t *svga, int displine)
|
||||
{ \
|
||||
int c; \
|
||||
int wp = 0; \
|
||||
uint32_t base_addr = buf ? src_addr2 : src_addr; \
|
||||
uint32_t base_addr = (buf == banshee->overlay_buffer[1]) ? src_addr2 : src_addr; \
|
||||
\
|
||||
for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \
|
||||
{ \
|
||||
@@ -1689,7 +1717,12 @@ void banshee_hwcursor_draw(svga_t *svga, int displine)
|
||||
int g = (data >> 5) & 0x3f; \
|
||||
int b = data >> 11; \
|
||||
\
|
||||
buf[wp++] = (r << 3) | (g << 10) | (b << 19); \
|
||||
if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \
|
||||
buf[wp++] = (r << 3) | (g << 10) | (b << 19); \
|
||||
else \
|
||||
buf[wp++] = (clut[r << 3] & 0x0000ff) | \
|
||||
(clut[g << 2] & 0x00ff00) | \
|
||||
(clut[b << 3] & 0xff0000); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -1957,6 +1990,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
|
||||
uint32_t src_x = 0;
|
||||
unsigned int y_coeff = (voodoo->overlay.src_y & 0xfffff) >> 4;
|
||||
int skip_filtering;
|
||||
uint32_t *clut = &svga->pallook[(banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_SEL) ? 256 : 0];
|
||||
|
||||
if (svga->render == svga_render_null &&
|
||||
!svga->changedvram[src_addr >> 12] && !svga->changedvram[src_addr2 >> 12] &&
|
||||
@@ -2323,11 +2357,11 @@ static uint8_t banshee_pci_read(int func, int addr, void *p)
|
||||
case 0x1a: ret = 0x00; break;
|
||||
case 0x1b: ret = 0x00; break;
|
||||
|
||||
/*Undocumented, but Voodoo 3 BIOS checks this*/
|
||||
case 0x2c: ret = 0x1a; break;
|
||||
case 0x2d: ret = 0x12; break;
|
||||
case 0x2e: ret = (banshee->type == TYPE_V3_3000) ? 0x3a : 0x30; break;
|
||||
case 0x2f: ret = 0x00; break;
|
||||
/*Subsystem vendor ID*/
|
||||
case 0x2c: ret = banshee->pci_regs[0x2c]; break;
|
||||
case 0x2d: ret = banshee->pci_regs[0x2d]; break;
|
||||
case 0x2e: ret = banshee->pci_regs[0x2e]; break;
|
||||
case 0x2f: ret = banshee->pci_regs[0x2f]; break;
|
||||
|
||||
case 0x30: ret = banshee->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/
|
||||
case 0x31: ret = 0x00; break;
|
||||
@@ -2633,6 +2667,37 @@ static void *banshee_init_common(const device_t *info, wchar_t *fn, int has_sgra
|
||||
banshee->i2c_ddc = i2c_gpio_init("ddc_voodoo_banshee");
|
||||
banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c_ddc));
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_BANSHEE:
|
||||
if (has_sgram) {
|
||||
banshee->pci_regs[0x2c] = 0x1a;
|
||||
banshee->pci_regs[0x2d] = 0x12;
|
||||
banshee->pci_regs[0x2e] = 0x04;
|
||||
banshee->pci_regs[0x2f] = 0x00;
|
||||
} else {
|
||||
banshee->pci_regs[0x2c] = 0x02;
|
||||
banshee->pci_regs[0x2d] = 0x11;
|
||||
banshee->pci_regs[0x2e] = 0x17;
|
||||
banshee->pci_regs[0x2f] = 0x10;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_V3_2000:
|
||||
banshee->pci_regs[0x2c] = 0x1a;
|
||||
banshee->pci_regs[0x2d] = 0x12;
|
||||
banshee->pci_regs[0x2e] = 0x30;
|
||||
banshee->pci_regs[0x2f] = 0x00;
|
||||
break;
|
||||
|
||||
case TYPE_V3_3000:
|
||||
banshee->pci_regs[0x2c] = 0x1a;
|
||||
banshee->pci_regs[0x2d] = 0x12;
|
||||
banshee->pci_regs[0x2e] = 0x3a;
|
||||
banshee->pci_regs[0x2f] = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee);
|
||||
|
||||
return banshee;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#define COMMAND_INITIATE (1 << 8)
|
||||
#define COMMAND_INC_X_START (1 << 10)
|
||||
#define COMMAND_INC_Y_START (1 << 11)
|
||||
#define COMMAND_STIPPLE_LINE (1 << 12)
|
||||
#define COMMAND_PATTERN_MONO (1 << 13)
|
||||
#define COMMAND_DX (1 << 14)
|
||||
#define COMMAND_DY (1 << 15)
|
||||
@@ -246,6 +247,50 @@ static void PLOT(voodoo_t *voodoo, int x, int y, int pat_x, int pat_y, uint8_t p
|
||||
}
|
||||
}
|
||||
|
||||
static void PLOT_LINE(voodoo_t *voodoo, int x, int y, uint8_t rop, uint32_t pattern, int src_colorkey)
|
||||
{
|
||||
switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK)
|
||||
{
|
||||
case DST_FORMAT_COL_8_BPP:
|
||||
{
|
||||
uint32_t addr = get_addr(voodoo, x, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
|
||||
uint32_t dest = voodoo->vram[addr];
|
||||
|
||||
voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_8);
|
||||
voodoo->changedvram[addr >> 12] = changeframecount;
|
||||
break;
|
||||
}
|
||||
case DST_FORMAT_COL_16_BPP:
|
||||
{
|
||||
uint32_t addr = get_addr(voodoo, x*2, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
|
||||
uint32_t dest = *(uint16_t *)&voodoo->vram[addr];
|
||||
|
||||
*(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_16);
|
||||
voodoo->changedvram[addr >> 12] = changeframecount;
|
||||
break;
|
||||
}
|
||||
case DST_FORMAT_COL_24_BPP:
|
||||
{
|
||||
uint32_t addr = get_addr(voodoo, x*3, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
|
||||
uint32_t dest = *(uint32_t *)&voodoo->vram[addr];
|
||||
|
||||
*(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000);
|
||||
voodoo->changedvram[addr >> 12] = changeframecount;
|
||||
break;
|
||||
}
|
||||
case DST_FORMAT_COL_32_BPP:
|
||||
{
|
||||
uint32_t addr = get_addr(voodoo, x*4, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask;
|
||||
uint32_t dest = *(uint32_t *)&voodoo->vram[addr];
|
||||
|
||||
*(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32);
|
||||
voodoo->changedvram[addr >> 12] = changeframecount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void update_src_stride(voodoo_t *voodoo)
|
||||
{
|
||||
int bpp;
|
||||
@@ -858,14 +903,24 @@ static void banshee_do_host_to_screen_stretch_blt(voodoo_t *voodoo, int count, u
|
||||
}
|
||||
}
|
||||
|
||||
static void banshee_do_line(voodoo_t *voodoo)
|
||||
static void step_line(voodoo_t *voodoo)
|
||||
{
|
||||
if (voodoo->banshee_blt.line_pix_pos == voodoo->banshee_blt.line_rep_cnt)
|
||||
{
|
||||
voodoo->banshee_blt.line_pix_pos = 0;
|
||||
if (voodoo->banshee_blt.line_bit_pos == voodoo->banshee_blt.line_bit_mask_size)
|
||||
voodoo->banshee_blt.line_bit_pos = 0;
|
||||
else
|
||||
voodoo->banshee_blt.line_bit_pos++;
|
||||
}
|
||||
else
|
||||
voodoo->banshee_blt.line_pix_pos++;
|
||||
}
|
||||
|
||||
|
||||
static void banshee_do_line(voodoo_t *voodoo, int draw_last_pixel)
|
||||
{
|
||||
clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0];
|
||||
uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern;
|
||||
int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.srcY);
|
||||
int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.srcX;
|
||||
int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) ==
|
||||
(COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO);
|
||||
uint8_t rop = voodoo->banshee_blt.command >> 24;
|
||||
int dx = ABS(voodoo->banshee_blt.dstX - voodoo->banshee_blt.srcX);
|
||||
int dy = ABS(voodoo->banshee_blt.dstY - voodoo->banshee_blt.srcY);
|
||||
@@ -874,27 +929,28 @@ static void banshee_do_line(voodoo_t *voodoo)
|
||||
int x = voodoo->banshee_blt.srcX;
|
||||
int y = voodoo->banshee_blt.srcY;
|
||||
int error;
|
||||
uint32_t stipple = (voodoo->banshee_blt.command & COMMAND_STIPPLE_LINE) ?
|
||||
voodoo->banshee_blt.lineStipple : ~0;
|
||||
|
||||
if (dx > dy) /*X major*/
|
||||
{
|
||||
error = dx/2;
|
||||
while (x != voodoo->banshee_blt.dstX)
|
||||
{
|
||||
uint8_t pattern_mask = pattern_mono[pat_y & 7];
|
||||
int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1;
|
||||
int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos);
|
||||
int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1;
|
||||
|
||||
if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans)
|
||||
PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32);
|
||||
PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32);
|
||||
|
||||
error -= dy;
|
||||
if (error < 0)
|
||||
{
|
||||
error += dx;
|
||||
y += y_inc;
|
||||
pat_y += y_inc;
|
||||
}
|
||||
x += x_inc;
|
||||
pat_x += x_inc;
|
||||
step_line(voodoo);
|
||||
}
|
||||
}
|
||||
else /*Y major*/
|
||||
@@ -902,24 +958,32 @@ static void banshee_do_line(voodoo_t *voodoo)
|
||||
error = dy/2;
|
||||
while (y != voodoo->banshee_blt.dstY)
|
||||
{
|
||||
uint8_t pattern_mask = pattern_mono[pat_y & 7];
|
||||
int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1;
|
||||
int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos);
|
||||
int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1;
|
||||
|
||||
if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans)
|
||||
PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32);
|
||||
PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32);
|
||||
|
||||
error -= dx;
|
||||
if (error < 0)
|
||||
{
|
||||
error += dy;
|
||||
x += x_inc;
|
||||
pat_x += x_inc;
|
||||
}
|
||||
y += y_inc;
|
||||
pat_y += y_inc;
|
||||
step_line(voodoo);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_last_pixel)
|
||||
{
|
||||
int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos);
|
||||
int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1;
|
||||
|
||||
if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans)
|
||||
PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32);
|
||||
}
|
||||
|
||||
voodoo->banshee_blt.srcXY = (x & 0xffff) | (y << 16);
|
||||
voodoo->banshee_blt.srcX = x;
|
||||
voodoo->banshee_blt.srcY = y;
|
||||
@@ -1057,8 +1121,12 @@ static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data)
|
||||
banshee_do_rectfill(voodoo);
|
||||
break;
|
||||
|
||||
case COMMAND_CMD_LINE:
|
||||
banshee_do_line(voodoo, 1);
|
||||
break;
|
||||
|
||||
case COMMAND_CMD_POLYLINE:
|
||||
banshee_do_line(voodoo);
|
||||
banshee_do_line(voodoo, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1141,6 +1209,16 @@ void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val)
|
||||
case 0x38:
|
||||
voodoo->banshee_blt.commandExtra = val;
|
||||
// bansheeblt_log("commandExtra=%08x\n", val);
|
||||
break;
|
||||
case 0x3c:
|
||||
voodoo->banshee_blt.lineStipple = val;
|
||||
break;
|
||||
case 0x40:
|
||||
voodoo->banshee_blt.lineStyle = val;
|
||||
voodoo->banshee_blt.line_rep_cnt = val & 0xff;
|
||||
voodoo->banshee_blt.line_bit_mask_size = (val >> 8) & 0x1f;
|
||||
voodoo->banshee_blt.line_pix_pos = (val >> 16) & 0xff;
|
||||
voodoo->banshee_blt.line_bit_pos = (val >> 24) & 0x1f;
|
||||
break;
|
||||
case 0x44:
|
||||
voodoo->banshee_blt.colorPattern[0] = val;
|
||||
@@ -1321,18 +1399,18 @@ void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val)
|
||||
banshee_do_rectfill(voodoo);
|
||||
break;
|
||||
|
||||
/* case COMMAND_CMD_LINE:
|
||||
case COMMAND_CMD_LINE:
|
||||
voodoo->banshee_blt.dstXY = val;
|
||||
voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19;
|
||||
voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19;
|
||||
banshee_do_line(voodoo);
|
||||
break;*/
|
||||
banshee_do_line(voodoo, 1);
|
||||
break;
|
||||
|
||||
case COMMAND_CMD_POLYLINE:
|
||||
voodoo->banshee_blt.dstXY = val;
|
||||
voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19;
|
||||
voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19;
|
||||
banshee_do_line(voodoo);
|
||||
banshee_do_line(voodoo, 0);
|
||||
break;
|
||||
|
||||
case COMMAND_CMD_POLYFILL:
|
||||
|
||||
@@ -155,16 +155,19 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo)
|
||||
static uint32_t cmdfifo_get(voodoo_t *voodoo)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr)
|
||||
{
|
||||
thread_wait_event(voodoo->wake_fifo_thread, -1);
|
||||
thread_reset_event(voodoo->wake_fifo_thread);
|
||||
}
|
||||
|
||||
if (!voodoo->cmdfifo_in_sub) {
|
||||
while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr)
|
||||
{
|
||||
thread_wait_event(voodoo->wake_fifo_thread, -1);
|
||||
thread_reset_event(voodoo->wake_fifo_thread);
|
||||
}
|
||||
}
|
||||
|
||||
val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask];
|
||||
|
||||
voodoo->cmdfifo_depth_rd++;
|
||||
if (!voodoo->cmdfifo_in_sub)
|
||||
voodoo->cmdfifo_depth_rd++;
|
||||
voodoo->cmdfifo_rp += 4;
|
||||
|
||||
// voodoo_fifo_log(" CMDFIFO get %08x\n", val);
|
||||
@@ -285,7 +288,7 @@ void voodoo_fifo_thread(void *param)
|
||||
voodoo->time += end_time - start_time;
|
||||
}
|
||||
|
||||
while (voodoo->cmdfifo_enabled && voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr)
|
||||
while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub))
|
||||
{
|
||||
uint64_t start_time = plat_timer_read();
|
||||
uint64_t end_time;
|
||||
@@ -308,6 +311,18 @@ void voodoo_fifo_thread(void *param)
|
||||
case 0: /*NOP*/
|
||||
break;
|
||||
|
||||
case 1: /*JSR*/
|
||||
// voodoo_fifo_log("JSR %08x\n", (header >> 4) & 0xfffffc);
|
||||
voodoo->cmdfifo_ret_addr = voodoo->cmdfifo_rp;
|
||||
voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc;
|
||||
voodoo->cmdfifo_in_sub = 1;
|
||||
break;
|
||||
|
||||
case 2: /*RET*/
|
||||
voodoo->cmdfifo_rp = voodoo->cmdfifo_ret_addr;
|
||||
voodoo->cmdfifo_in_sub = 0;
|
||||
break;
|
||||
|
||||
case 3: /*JMP local frame buffer*/
|
||||
voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc;
|
||||
// voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header);
|
||||
|
||||
@@ -36,6 +36,24 @@
|
||||
#include <86box/vid_voodoo_render.h>
|
||||
#include <86box/vid_voodoo_setup.h>
|
||||
|
||||
#ifdef ENABLE_VOODOO_SETUP_LOG
|
||||
int voodoo_setup_do_log = ENABLE_VOODOO_SETUP_LOG;
|
||||
|
||||
static void
|
||||
voodoo_setup_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (voodoo_setup_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define voodoo_setup_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
void voodoo_triangle_setup(voodoo_t *voodoo)
|
||||
{
|
||||
@@ -152,8 +170,10 @@ void voodoo_triangle_setup(voodoo_t *voodoo)
|
||||
voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff);
|
||||
voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff);
|
||||
|
||||
if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy)
|
||||
fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy);
|
||||
if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) {
|
||||
voodoo_setup_log("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (voodoo->sSetupMode & SETUPMODE_RGB)
|
||||
{
|
||||
|
||||
@@ -336,7 +336,7 @@ static png_infop info_ptr;
|
||||
|
||||
|
||||
static void
|
||||
video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h)
|
||||
video_take_screenshot(const wchar_t *fn, int startx, int starty, int y1, int y2, int w, int h)
|
||||
{
|
||||
int i, x, y;
|
||||
png_bytep *b_rgb = NULL;
|
||||
@@ -382,7 +382,7 @@ video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h)
|
||||
for (y = 0; y < h; ++y) {
|
||||
b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr));
|
||||
for (x = 0; x < w; ++x) {
|
||||
temp = render_buffer->line[y + starty][x + startx];
|
||||
temp = render_buffer->dat[(y * w) + x];
|
||||
|
||||
b_rgb[y][(x) * 3 + 0] = (temp >> 16) & 0xff;
|
||||
b_rgb[y][(x) * 3 + 1] = (temp >> 8) & 0xff;
|
||||
@@ -407,7 +407,7 @@ video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h)
|
||||
|
||||
|
||||
static void
|
||||
video_screenshot(int x, int y, int w, int h)
|
||||
video_screenshot(int x, int y, int y1, int y2, int w, int h)
|
||||
{
|
||||
wchar_t path[1024], fn[128];
|
||||
|
||||
@@ -426,7 +426,7 @@ video_screenshot(int x, int y, int w, int h)
|
||||
|
||||
video_log("taking screenshot to: %S\n", path);
|
||||
|
||||
video_take_screenshot((const wchar_t *) path, x, y, w, h);
|
||||
video_take_screenshot((const wchar_t *) path, x, y, y1, y2, w, h);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
}
|
||||
|
||||
@@ -449,20 +449,20 @@ video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h)
|
||||
{
|
||||
int yy;
|
||||
|
||||
if ((w > 0) && (h > 0)) {
|
||||
for (yy = 0; yy < h; yy++) {
|
||||
if (y2 > 0) {
|
||||
for (yy = y1; yy < y2; yy++) {
|
||||
if (((y + yy) >= 0) && ((y + yy) < buffer32->h)) {
|
||||
if (video_grayscale || invert_display)
|
||||
video_transform_copy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w);
|
||||
video_transform_copy(&(render_buffer->dat)[yy * w], &(buffer32->line[y + yy][x]), w);
|
||||
else
|
||||
memcpy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w << 2);
|
||||
memcpy(&(render_buffer->dat)[yy * w], &(buffer32->line[y + yy][x]), w << 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (screenshots) {
|
||||
if (render_buffer != NULL)
|
||||
video_screenshot(x, y, w, h);
|
||||
video_screenshot(x, y, y1, y2, w, h);
|
||||
screenshots--;
|
||||
video_log("screenshot taken, %i left\n", screenshots);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ vnc_blit(int x, int y, int y1, int y2, int w, int h)
|
||||
p = (uint32_t *)&(((uint32_t *)rfb->frameBuffer)[yy*VNC_MAX_X]);
|
||||
|
||||
if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y)
|
||||
memcpy(p, &(render_buffer->line[y+yy][x]), w*4);
|
||||
memcpy(p, &(render_buffer->dat[yy * w]), w*4);
|
||||
}
|
||||
|
||||
video_blit_complete();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user