This commit is contained in:
RichardG867
2020-12-03 01:46:04 -03:00
111 changed files with 8720 additions and 2236 deletions

View File

@@ -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**

View File

@@ -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
View File

@@ -9,3 +9,4 @@ src/*.dmp
src/NUL
src/nvr/
src/roms/
/.vs

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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:*/
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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--;

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);

View File

@@ -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}
}
}, {

View File

@@ -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);

View File

@@ -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) */

View File

@@ -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;

View File

@@ -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

View File

@@ -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:

View File

@@ -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,

File diff suppressed because it is too large Load Diff

View 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
View 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

File diff suppressed because it is too large Load Diff

457
src/disk/minivhd/cwalk.h Normal file
View 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

View 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. */

View 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
View 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

View 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;
}

View 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 */
}

View 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

View 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

View 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;
}

View 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

View 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;
}

View 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);
}

View 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

View 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
}

View 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

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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

View File

@@ -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 {

View File

@@ -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));

View File

@@ -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));

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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*/

View File

@@ -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();

View File

@@ -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)

View File

@@ -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);

View File

@@ -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];
}

View File

@@ -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];
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -253,7 +253,7 @@ genius_waitstates(void)
int ws;
ws = ws_array[cycles & 0xf];
sub_cycles(ws);
cycles -= ws;
}

View File

@@ -212,7 +212,7 @@ hercules_waitstates(void *p)
int ws;
ws = ws_array[cycles & 0xf];
sub_cycles(ws);
cycles -= ws;
}

View File

@@ -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++;

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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)];
}

View File

@@ -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);

View File

@@ -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 },

View File

@@ -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)

View File

@@ -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;

View File

@@ -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*/

View File

@@ -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;

View File

@@ -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:

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);
}

View File

@@ -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