11e8a1faeSThomas Huth /* 21e8a1faeSThomas Huth * Boot order test cases. 31e8a1faeSThomas Huth * 41e8a1faeSThomas Huth * Copyright (c) 2013 Red Hat Inc. 51e8a1faeSThomas Huth * 61e8a1faeSThomas Huth * Authors: 71e8a1faeSThomas Huth * Markus Armbruster <armbru@redhat.com>, 81e8a1faeSThomas Huth * 91e8a1faeSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later. 101e8a1faeSThomas Huth * See the COPYING file in the top-level directory. 111e8a1faeSThomas Huth */ 121e8a1faeSThomas Huth 131e8a1faeSThomas Huth #include "qemu/osdep.h" 141e8a1faeSThomas Huth #include "libqos/fw_cfg.h" 15*907b5105SMarc-André Lureau #include "libqtest.h" 161e8a1faeSThomas Huth #include "qapi/qmp/qdict.h" 171e8a1faeSThomas Huth #include "standard-headers/linux/qemu_fw_cfg.h" 181e8a1faeSThomas Huth 191e8a1faeSThomas Huth /* TODO actually test the results and get rid of this */ 201e8a1faeSThomas Huth #define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__)) 211e8a1faeSThomas Huth 221e8a1faeSThomas Huth typedef struct { 231e8a1faeSThomas Huth const char *args; 241e8a1faeSThomas Huth uint64_t expected_boot; 251e8a1faeSThomas Huth uint64_t expected_reboot; 261e8a1faeSThomas Huth } boot_order_test; 271e8a1faeSThomas Huth 281e8a1faeSThomas Huth static void test_a_boot_order(const char *machine, 291e8a1faeSThomas Huth const char *test_args, 301e8a1faeSThomas Huth uint64_t (*read_boot_order)(QTestState *), 311e8a1faeSThomas Huth uint64_t expected_boot, 321e8a1faeSThomas Huth uint64_t expected_reboot) 331e8a1faeSThomas Huth { 341e8a1faeSThomas Huth uint64_t actual; 351e8a1faeSThomas Huth QTestState *qts; 361e8a1faeSThomas Huth 37d6a3dd74SThomas Huth if (machine && !qtest_has_machine(machine)) { 38d6a3dd74SThomas Huth g_test_skip("Machine is not available"); 39d6a3dd74SThomas Huth return; 40d6a3dd74SThomas Huth } 41d6a3dd74SThomas Huth 421e8a1faeSThomas Huth qts = qtest_initf("-nodefaults%s%s %s", machine ? " -M " : "", 431e8a1faeSThomas Huth machine ?: "", test_args); 441e8a1faeSThomas Huth actual = read_boot_order(qts); 451e8a1faeSThomas Huth g_assert_cmphex(actual, ==, expected_boot); 461e8a1faeSThomas Huth qmp_discard_response(qts, "{ 'execute': 'system_reset' }"); 471e8a1faeSThomas Huth /* 481e8a1faeSThomas Huth * system_reset only requests reset. We get a RESET event after 491e8a1faeSThomas Huth * the actual reset completes. Need to wait for that. 501e8a1faeSThomas Huth */ 511e8a1faeSThomas Huth qtest_qmp_eventwait(qts, "RESET"); 521e8a1faeSThomas Huth actual = read_boot_order(qts); 531e8a1faeSThomas Huth g_assert_cmphex(actual, ==, expected_reboot); 541e8a1faeSThomas Huth qtest_quit(qts); 551e8a1faeSThomas Huth } 561e8a1faeSThomas Huth 571e8a1faeSThomas Huth static void test_boot_orders(const char *machine, 581e8a1faeSThomas Huth uint64_t (*read_boot_order)(QTestState *), 591e8a1faeSThomas Huth const boot_order_test *tests) 601e8a1faeSThomas Huth { 611e8a1faeSThomas Huth int i; 621e8a1faeSThomas Huth 631e8a1faeSThomas Huth for (i = 0; tests[i].args; i++) { 641e8a1faeSThomas Huth test_a_boot_order(machine, tests[i].args, 651e8a1faeSThomas Huth read_boot_order, 661e8a1faeSThomas Huth tests[i].expected_boot, 671e8a1faeSThomas Huth tests[i].expected_reboot); 681e8a1faeSThomas Huth } 691e8a1faeSThomas Huth } 701e8a1faeSThomas Huth 711e8a1faeSThomas Huth static uint8_t read_mc146818(QTestState *qts, uint16_t port, uint8_t reg) 721e8a1faeSThomas Huth { 731e8a1faeSThomas Huth qtest_outb(qts, port, reg); 741e8a1faeSThomas Huth return qtest_inb(qts, port + 1); 751e8a1faeSThomas Huth } 761e8a1faeSThomas Huth 771e8a1faeSThomas Huth static uint64_t read_boot_order_pc(QTestState *qts) 781e8a1faeSThomas Huth { 791e8a1faeSThomas Huth uint8_t b1 = read_mc146818(qts, 0x70, 0x38); 801e8a1faeSThomas Huth uint8_t b2 = read_mc146818(qts, 0x70, 0x3d); 811e8a1faeSThomas Huth 821e8a1faeSThomas Huth return b1 | (b2 << 8); 831e8a1faeSThomas Huth } 841e8a1faeSThomas Huth 851e8a1faeSThomas Huth static const boot_order_test test_cases_pc[] = { 861e8a1faeSThomas Huth { "", 871e8a1faeSThomas Huth 0x1230, 0x1230 }, 881e8a1faeSThomas Huth { "-no-fd-bootchk", 891e8a1faeSThomas Huth 0x1231, 0x1231 }, 901e8a1faeSThomas Huth { "-boot c", 911e8a1faeSThomas Huth 0x0200, 0x0200 }, 921e8a1faeSThomas Huth { "-boot nda", 931e8a1faeSThomas Huth 0x3410, 0x3410 }, 941e8a1faeSThomas Huth { "-boot order=", 951e8a1faeSThomas Huth 0, 0 }, 961e8a1faeSThomas Huth { "-boot order= -boot order=c", 971e8a1faeSThomas Huth 0x0200, 0x0200 }, 981e8a1faeSThomas Huth { "-boot once=a", 991e8a1faeSThomas Huth 0x0100, 0x1230 }, 1001e8a1faeSThomas Huth { "-boot once=a -no-fd-bootchk", 1011e8a1faeSThomas Huth 0x0101, 0x1231 }, 1021e8a1faeSThomas Huth { "-boot once=a,order=c", 1031e8a1faeSThomas Huth 0x0100, 0x0200 }, 1041e8a1faeSThomas Huth { "-boot once=d -boot order=nda", 1051e8a1faeSThomas Huth 0x0300, 0x3410 }, 1061e8a1faeSThomas Huth { "-boot once=a -boot once=b -boot once=c", 1071e8a1faeSThomas Huth 0x0200, 0x1230 }, 1081e8a1faeSThomas Huth {} 1091e8a1faeSThomas Huth }; 1101e8a1faeSThomas Huth 1111e8a1faeSThomas Huth static void test_pc_boot_order(void) 1121e8a1faeSThomas Huth { 1131e8a1faeSThomas Huth test_boot_orders(NULL, read_boot_order_pc, test_cases_pc); 1141e8a1faeSThomas Huth } 1151e8a1faeSThomas Huth 1161e8a1faeSThomas Huth static uint64_t read_boot_order_pmac(QTestState *qts) 1171e8a1faeSThomas Huth { 11877c24259SPan Nengyuan g_autoptr(QFWCFG) fw_cfg = mm_fw_cfg_init(qts, 0xf0000510); 1191e8a1faeSThomas Huth 1201e8a1faeSThomas Huth return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); 1211e8a1faeSThomas Huth } 1221e8a1faeSThomas Huth 1231e8a1faeSThomas Huth static const boot_order_test test_cases_fw_cfg[] = { 1241e8a1faeSThomas Huth { "", 'c', 'c' }, 1251e8a1faeSThomas Huth { "-boot c", 'c', 'c' }, 1261e8a1faeSThomas Huth { "-boot d", 'd', 'd' }, 1271e8a1faeSThomas Huth { "-boot once=d,order=c", 'd', 'c' }, 1281e8a1faeSThomas Huth {} 1291e8a1faeSThomas Huth }; 1301e8a1faeSThomas Huth 1311e8a1faeSThomas Huth static void test_pmac_oldworld_boot_order(void) 1321e8a1faeSThomas Huth { 1331e8a1faeSThomas Huth test_boot_orders("g3beige", read_boot_order_pmac, test_cases_fw_cfg); 1341e8a1faeSThomas Huth } 1351e8a1faeSThomas Huth 1361e8a1faeSThomas Huth static void test_pmac_newworld_boot_order(void) 1371e8a1faeSThomas Huth { 1381e8a1faeSThomas Huth test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg); 1391e8a1faeSThomas Huth } 1401e8a1faeSThomas Huth 1411e8a1faeSThomas Huth static uint64_t read_boot_order_sun4m(QTestState *qts) 1421e8a1faeSThomas Huth { 14377c24259SPan Nengyuan g_autoptr(QFWCFG) fw_cfg = mm_fw_cfg_init(qts, 0xd00000510ULL); 1441e8a1faeSThomas Huth 1451e8a1faeSThomas Huth return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); 1461e8a1faeSThomas Huth } 1471e8a1faeSThomas Huth 1481e8a1faeSThomas Huth static void test_sun4m_boot_order(void) 1491e8a1faeSThomas Huth { 1501e8a1faeSThomas Huth test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg); 1511e8a1faeSThomas Huth } 1521e8a1faeSThomas Huth 1531e8a1faeSThomas Huth static uint64_t read_boot_order_sun4u(QTestState *qts) 1541e8a1faeSThomas Huth { 15577c24259SPan Nengyuan g_autoptr(QFWCFG) fw_cfg = io_fw_cfg_init(qts, 0x510); 1561e8a1faeSThomas Huth 1571e8a1faeSThomas Huth return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); 1581e8a1faeSThomas Huth } 1591e8a1faeSThomas Huth 1601e8a1faeSThomas Huth static void test_sun4u_boot_order(void) 1611e8a1faeSThomas Huth { 1621e8a1faeSThomas Huth test_boot_orders("sun4u", read_boot_order_sun4u, test_cases_fw_cfg); 1631e8a1faeSThomas Huth } 1641e8a1faeSThomas Huth 1651e8a1faeSThomas Huth int main(int argc, char *argv[]) 1661e8a1faeSThomas Huth { 1671e8a1faeSThomas Huth const char *arch = qtest_get_arch(); 1681e8a1faeSThomas Huth 1691e8a1faeSThomas Huth g_test_init(&argc, &argv, NULL); 1701e8a1faeSThomas Huth 1711e8a1faeSThomas Huth if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 1721e8a1faeSThomas Huth qtest_add_func("boot-order/pc", test_pc_boot_order); 1731e8a1faeSThomas Huth } else if (strcmp(arch, "ppc") == 0 || strcmp(arch, "ppc64") == 0) { 1741e8a1faeSThomas Huth qtest_add_func("boot-order/pmac_oldworld", 1751e8a1faeSThomas Huth test_pmac_oldworld_boot_order); 1761e8a1faeSThomas Huth qtest_add_func("boot-order/pmac_newworld", 1771e8a1faeSThomas Huth test_pmac_newworld_boot_order); 1781e8a1faeSThomas Huth } else if (strcmp(arch, "sparc") == 0) { 1791e8a1faeSThomas Huth qtest_add_func("boot-order/sun4m", test_sun4m_boot_order); 1801e8a1faeSThomas Huth } else if (strcmp(arch, "sparc64") == 0) { 1811e8a1faeSThomas Huth qtest_add_func("boot-order/sun4u", test_sun4u_boot_order); 1821e8a1faeSThomas Huth } 1831e8a1faeSThomas Huth 1841e8a1faeSThomas Huth return g_test_run(); 1851e8a1faeSThomas Huth } 186