📄 os-area.c
字号:
&& i->match_id.key != (int)i->idx->key) goto next; return 1;}static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id){ struct db_iterator i; for (i.db = NULL; db_for_each_64(db, id, &i); ) { pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, i.idx->owner, i.idx->key, (unsigned long long)*i.value_64); i.idx->owner = 0; i.idx->key = 0; *i.value_64 = 0; } return 0;}static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id, uint64_t value){ struct db_iterator i; pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__, id->owner, id->key, (unsigned long long)value); if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY || id->key == OS_AREA_DB_KEY_ANY) { pr_debug("%s:%d: bad id: (%d:%d)\n", __func__, __LINE__, id->owner, id->key); return -1; } db_delete_64(db, id); i.db = NULL; if (db_for_each_64(db, &os_area_db_id_empty, &i)) { pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, i.idx->owner, i.idx->key, (unsigned long long)*i.value_64); i.idx->owner = id->owner; i.idx->key = id->key; *i.value_64 = value; pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__, i.idx->owner, i.idx->key, (unsigned long long)*i.value_64); return 0; } pr_debug("%s:%d: database full.\n", __func__, __LINE__); return -1;}static int db_get_64(const struct os_area_db *db, const struct os_area_db_id *id, uint64_t *value){ struct db_iterator i; i.db = NULL; if (db_for_each_64(db, id, &i)) { *value = *i.value_64; pr_debug("%s:%d: found %lld\n", __func__, __LINE__, (long long int)*i.value_64); return 0; } pr_debug("%s:%d: not found\n", __func__, __LINE__); return -1;}static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff){ return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff);}#define dump_db(a) _dump_db(a, __func__, __LINE__)static void _dump_db(const struct os_area_db *db, const char *func, int line){ char str[sizeof(db->magic_num) + 1]; dump_field(str, db->magic_num, sizeof(db->magic_num)); pr_debug("%s:%d: db.magic_num: '%s'\n", func, line, str); pr_debug("%s:%d: db.version: %u\n", func, line, db->version); pr_debug("%s:%d: db.index_64: %u\n", func, line, db->index_64); pr_debug("%s:%d: db.count_64: %u\n", func, line, db->count_64); pr_debug("%s:%d: db.index_32: %u\n", func, line, db->index_32); pr_debug("%s:%d: db.count_32: %u\n", func, line, db->count_32); pr_debug("%s:%d: db.index_16: %u\n", func, line, db->index_16); pr_debug("%s:%d: db.count_16: %u\n", func, line, db->count_16);}static void os_area_db_init(struct os_area_db *db){ enum { HEADER_SIZE = offsetof(struct os_area_db, _db_data), INDEX_64_COUNT = 64, VALUES_64_COUNT = 57, INDEX_32_COUNT = 64, VALUES_32_COUNT = 57, INDEX_16_COUNT = 64, VALUES_16_COUNT = 57, }; memset(db, 0, sizeof(struct os_area_db)); memcpy(db->magic_num, OS_AREA_DB_MAGIC_NUM, sizeof(db->magic_num)); db->version = 1; db->index_64 = HEADER_SIZE; db->count_64 = VALUES_64_COUNT; db->index_32 = HEADER_SIZE + INDEX_64_COUNT * sizeof(struct db_index) + VALUES_64_COUNT * sizeof(u64); db->count_32 = VALUES_32_COUNT; db->index_16 = HEADER_SIZE + INDEX_64_COUNT * sizeof(struct db_index) + VALUES_64_COUNT * sizeof(u64) + INDEX_32_COUNT * sizeof(struct db_index) + VALUES_32_COUNT * sizeof(u32); db->count_16 = VALUES_16_COUNT; /* Rules to check db layout. */ BUILD_BUG_ON(sizeof(struct db_index) != 1); BUILD_BUG_ON(sizeof(struct os_area_db) != 2 * OS_AREA_SEGMENT_SIZE); BUILD_BUG_ON(INDEX_64_COUNT & 0x7); BUILD_BUG_ON(VALUES_64_COUNT > INDEX_64_COUNT); BUILD_BUG_ON(INDEX_32_COUNT & 0x7); BUILD_BUG_ON(VALUES_32_COUNT > INDEX_32_COUNT); BUILD_BUG_ON(INDEX_16_COUNT & 0x7); BUILD_BUG_ON(VALUES_16_COUNT > INDEX_16_COUNT); BUILD_BUG_ON(HEADER_SIZE + INDEX_64_COUNT * sizeof(struct db_index) + VALUES_64_COUNT * sizeof(u64) + INDEX_32_COUNT * sizeof(struct db_index) + VALUES_32_COUNT * sizeof(u32) + INDEX_16_COUNT * sizeof(struct db_index) + VALUES_16_COUNT * sizeof(u16) > sizeof(struct os_area_db));}/** * update_flash_db - Helper for os_area_queue_work_handler. * */static void update_flash_db(void){ int result; int file; off_t offset; ssize_t count; static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; const struct os_area_header *header; struct os_area_db* db; /* Read in header and db from flash. */ file = sys_open("/dev/ps3flash", O_RDWR, 0); if (file < 0) { pr_debug("%s:%d sys_open failed\n", __func__, __LINE__); goto fail_open; } header = kmalloc(buf_len, GFP_KERNEL); if (!header) { pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); goto fail_malloc; } offset = sys_lseek(file, 0, SEEK_SET); if (offset != 0) { pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); goto fail_header_seek; } count = sys_read(file, (char __user *)header, buf_len); result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; if (result) { pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); dump_header(header); goto fail_header; } /* Now got a good db offset and some maybe good db data. */ db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; result = db_verify(db); if (result) { printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " "formatting.\n", __func__, __LINE__); dump_db(db); os_area_db_init(db); } /* Now got good db data. */ db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, SEEK_SET); if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) { pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); goto fail_db_seek; } count = sys_write(file, (const char __user *)db, sizeof(struct os_area_db)); if (count < sizeof(struct os_area_db)) { pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); }fail_db_seek:fail_header:fail_header_seek: kfree(header);fail_malloc: sys_close(file);fail_open: return;}/** * os_area_queue_work_handler - Asynchronous write handler. * * An asynchronous write for flash memory and the device tree. Do not * call directly, use os_area_queue_work(). */static void os_area_queue_work_handler(struct work_struct *work){ struct device_node *node; pr_debug(" -> %s:%d\n", __func__, __LINE__); node = of_find_node_by_path("/"); if (node) { os_area_set_property(node, &property_rtc_diff); of_node_put(node); } else pr_debug("%s:%d of_find_node_by_path failed\n", __func__, __LINE__);#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) update_flash_db();#else printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", __func__, __LINE__);#endif pr_debug(" <- %s:%d\n", __func__, __LINE__);}static void os_area_queue_work(void){ static DECLARE_WORK(q, os_area_queue_work_handler); wmb(); schedule_work(&q);}/** * ps3_os_area_save_params - Copy data from os area mirror to @saved_params. * * For the convenience of the guest the HV makes a copy of the os area in * flash to a high address in the boot memory region and then puts that RAM * address and the byte count into the repository for retrieval by the guest. * We copy the data we want into a static variable and allow the memory setup * by the HV to be claimed by the lmb manager. * * The os area mirror will not be available to a second stage kernel, and * the header verify will fail. In this case, the saved_params values will * be set from flash memory or the passed in device tree in ps3_os_area_init(). */void __init ps3_os_area_save_params(void){ int result; u64 lpar_addr; unsigned int size; struct os_area_header *header; struct os_area_params *params; struct os_area_db *db; pr_debug(" -> %s:%d\n", __func__, __LINE__); result = ps3_repository_read_boot_dat_info(&lpar_addr, &size); if (result) { pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n", __func__, __LINE__); return; } header = (struct os_area_header *)__va(lpar_addr); params = (struct os_area_params *)__va(lpar_addr + OS_AREA_SEGMENT_SIZE); result = verify_header(header); if (result) { /* Second stage kernels exit here. */ pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); dump_header(header); return; } db = (struct os_area_db *)__va(lpar_addr + header->db_area_offset * OS_AREA_SEGMENT_SIZE); dump_header(header); dump_params(params); dump_db(db); result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff); if (result) saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff : SECONDS_FROM_1970_TO_2000; saved_params.av_multi_out = params->av_multi_out; saved_params.valid = 1; memset(header, 0, sizeof(*header)); pr_debug(" <- %s:%d\n", __func__, __LINE__);}/** * ps3_os_area_init - Setup os area device tree properties as needed. */void __init ps3_os_area_init(void){ struct device_node *node; pr_debug(" -> %s:%d\n", __func__, __LINE__); node = of_find_node_by_path("/"); if (!saved_params.valid && node) { /* Second stage kernels should have a dt entry. */ os_area_get_property(node, &property_rtc_diff); os_area_get_property(node, &property_av_multi_out); } if(!saved_params.rtc_diff) saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000; if (node) { os_area_set_property(node, &property_rtc_diff); os_area_set_property(node, &property_av_multi_out); of_node_put(node); } else pr_debug("%s:%d of_find_node_by_path failed\n", __func__, __LINE__); pr_debug(" <- %s:%d\n", __func__, __LINE__);}/** * ps3_os_area_get_rtc_diff - Returns the rtc diff value. */u64 ps3_os_area_get_rtc_diff(void){ return saved_params.rtc_diff;}/** * ps3_os_area_set_rtc_diff - Set the rtc diff value. * * An asynchronous write is needed to support writing updates from * the timer interrupt context. */void ps3_os_area_set_rtc_diff(u64 rtc_diff){ if (saved_params.rtc_diff != rtc_diff) { saved_params.rtc_diff = rtc_diff; os_area_queue_work(); }}/** * ps3_os_area_get_av_multi_out - Returns the default video mode. */enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void){ return saved_params.av_multi_out;}EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -