@samitouri / QOSamiQemu / commits / 0905ef5b6d

tests/qtest/ide-test: cover a CHS translation with zero sectors

Ask for zero sectors per logical track via INITIALIZE DEVICE PARAMETERS and check that the command is aborted, that IDENTIFY DEVICE still reports the translation that was in effect before, and that a CHS read then completes normally rather than killing QEMU with SIGFPE. Cc: John Snow <jsnow@redhat.com> Cc: Peter Maydell <peter.maydell@linaro.org> Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Denis V. Lunev <den@openvz.org>

Denis V. Lunev committed Aug 4, 2026 at 18:34 UTC 0905ef5b6d483da0e27831152fdde059595244b9
1 file changed +62
tests/qtest/ide-test.c
+62
@@ -95,6 +95,7 @@ enum {
95
96 enum {
97 CMD_DSM = 0x06,
98 + CMD_READ = 0x20, /* READ SECTOR(S) */
99 CMD_DIAGNOSE = 0x90,
100 CMD_INIT_DP = 0x91, /* INITIALIZE DEVICE PARAMETERS */
101 CMD_READ_DMA = 0xc8,
@@ -1194,6 +1195,66 @@ static void cdrom_read_impl(int nblocks, unsigned flags)
1195 free_pci_device(dev);
1196 }
1197
1198 +/* Zero sectors per track has to abort (ATA-5 8.16.6), not divide by zero */
1199 +static void test_specify_zero_sectors(void)
1200 +{
1201 + QTestState *qts;
1202 + QPCIDevice *dev;
1203 + QPCIBar bmdma_bar, ide_bar;
1204 + uint16_t buf[256];
1205 + uint8_t data;
1206 + int i;
1207 +
1208 + qts = ide_test_start(
1209 + "-blockdev driver=file,node-name=hda,filename=%s "
1210 + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ",
1211 + tmp_path[0]);
1212 +
1213 + dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
1214 +
1215 + qpci_io_writeb(dev, ide_bar, reg_nsectors, 0);
1216 + qpci_io_writeb(dev, ide_bar, reg_device, 0);
1217 + qpci_io_writeb(dev, ide_bar, reg_command, CMD_INIT_DP);
1218 +
1219 + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), ERR);
1220 + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_error), ABRT);
1221 +
1222 + /* The refused request has to leave the default translation in effect */
1223 + qpci_io_writeb(dev, ide_bar, reg_device, 0);
1224 + qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY);
1225 + for (i = 0; i < 256; i++) {
1226 + buf[i] = qpci_io_readw(dev, ide_bar, reg_data);
1227 + }
1228 + g_assert_cmpint(buf[55], ==, 16);
1229 + g_assert_cmpint(buf[56], ==, 63);
1230 +
1231 + /* READ SECTOR(S) of CHS 0/0/1, which used to crash QEMU */
1232 + qpci_io_writeb(dev, ide_bar, reg_nsectors, 1);
1233 + qpci_io_writeb(dev, ide_bar, reg_lba_low, 1);
1234 + qpci_io_writeb(dev, ide_bar, reg_lba_middle, 0);
1235 + qpci_io_writeb(dev, ide_bar, reg_lba_high, 0);
1236 + qpci_io_writeb(dev, ide_bar, reg_device, 0);
1237 + qpci_io_writeb(dev, ide_bar, reg_command, CMD_READ);
1238 +
1239 + data = ide_wait_clear(qts, BSY);
1240 + assert_bit_set(data, DRQ);
1241 + assert_bit_clear(data, ERR | DF);
1242 + for (i = 0; i < 256; i++) {
1243 + buf[i] = qpci_io_readw(dev, ide_bar, reg_data);
1244 + }
1245 + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), ERR | DF | DRQ);
1246 +
1247 + /* A supported translation is still accepted */
1248 + qpci_io_writeb(dev, ide_bar, reg_nsectors, 32);
1249 + qpci_io_writeb(dev, ide_bar, reg_device, 7);
1250 + qpci_io_writeb(dev, ide_bar, reg_command, CMD_INIT_DP);
1251 +
1252 + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), ERR);
1253 +
1254 + ide_test_quit(qts);
1255 + free_pci_device(dev);
1256 +}
1257 +
1258 static void test_cdrom_pio(void)
1259 {
1260 cdrom_read_impl(1, CDROM_PIO);
@@ -1265,6 +1326,7 @@ int main(int argc, char **argv)
1326 g_test_init(&argc, &argv, NULL);
1327
1328 qtest_add_func("/ide/read_native", test_specify);
1329 + qtest_add_func("/ide/specify/zero_sectors", test_specify_zero_sectors);
1330
1331 qtest_add_func("/ide/identify", test_identify);
1332