aboutsummaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
* Fixed FSMC in the registry for F1 devices.Giovanni Di Sirio2016-04-281-2/+8
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9373 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed STM32F303xE memory setup.Giovanni Di Sirio2016-04-281-1/+1
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9371 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Moved VTOS initialization in startup files.Giovanni Di Sirio2016-04-255-12/+35
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9364 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed bug #734.Giovanni Di Sirio2016-04-252-4/+18
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9363 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed bug #735.Giovanni Di Sirio2016-04-252-0/+7
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9360 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed readme files for STM32L1 demos.Giovanni Di Sirio2016-04-252-2/+2
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9356 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Reversed switch for STM32F4 revision A workaround, now the fix is included ↵Giovanni Di Sirio2016-04-251-1/+1
| | | | | | by default. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9355 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Updated Makefile including ChibiOS license inclusion.Rocco Marco Guglielmi2016-04-241-1/+1
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9354 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Updated Makefile including ChibiOS license inclusion.Rocco Marco Guglielmi2016-04-241-1/+2
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9353 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added support for LSM6DS0, improved hal_accelerometer and hal_gyroscope, ↵Rocco Marco Guglielmi2016-04-2313-79/+2221
| | | | | | added a new demo git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9349 35acf78f-673a-0410-8e92-d51de3d6d3f4
* L3GD20 documentation fixes,Rocco Marco Guglielmi2016-04-232-12/+20
| | | | | | Improved get_temperature() implementation. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9348 35acf78f-673a-0410-8e92-d51de3d6d3f4
* GCC asm files extension changed from .s to .S.Giovanni Di Sirio2016-04-23187-192/+345
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9345 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Makefiles mass update.Giovanni Di Sirio2016-04-23165-173/+313
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9344 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9343 ↵Giovanni Di Sirio2016-04-231-0/+2
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Updated broken CMSIS files with updated broken CMSIS files. Fixes applied.Giovanni Di Sirio2016-04-2315-7192/+11740
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9342 35acf78f-673a-0410-8e92-d51de3d6d3f4
* EX: added get temperature for L3GD20, improved related demosRocco Marco Guglielmi2016-04-225-55/+57
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9341 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9326 ↵Giovanni Di Sirio2016-04-203-12/+12
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9323 ↵Giovanni Di Sirio2016-04-202-1/+3
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9317 ↵Giovanni Di Sirio2016-04-181-1/+0
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9316 ↵Giovanni Di Sirio2016-04-187-7/+0
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9315 ↵Giovanni Di Sirio2016-04-183-0/+0
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9314 ↵Giovanni Di Sirio2016-04-182-0/+2
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added ST_STM32L053_DISCOVERY board filesRocco Marco Guglielmi2016-04-1715-0/+3519
| | | | | | Added RT-STM32L053-DISCOVERY demo git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9313 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Changed linked folder path from Absolute to RelativeRocco Marco Guglielmi2016-04-171-1/+1
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9312 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Changed linked folder path from Absolute to RelativeRocco Marco Guglielmi2016-04-176-6/+6
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9311 35acf78f-673a-0410-8e92-d51de3d6d3f4
* RoccoMarco take note of this commit.Giovanni Di Sirio2016-04-172-2/+1
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9310 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9309 ↵Giovanni Di Sirio2016-04-176-56/+32
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added linker script for STM32L053x6Rocco Marco Guglielmi2016-04-171-0/+85
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9308 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added linker script for STM32F446xC and STM32F446xERocco Marco Guglielmi2016-04-1716-2/+5377
| | | | | | | | Improved STM32F4xx/stm32_registry.h completing STM32F446 support Added ST_NUCLEO144_F446ZE board files Added RT-STM32F446ZE-NUCLEO144 demo git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9307 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added linker script for STM32F303xERocco Marco Guglielmi2016-04-1714-0/+5077
| | | | | | | Added board files for ST_NUCLEO144_F303ZE Added demo RT-STM32F303ZE-NUCLEO144 git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9306 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added board linked folder to RT-STM32F303-DISCOVERY demoRocco Marco Guglielmi2016-04-171-0/+5
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9305 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixes to the heap allocator.Giovanni Di Sirio2016-04-171-2/+2
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9304 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Small fixes in some xml board.chcfgRocco Marco Guglielmi2016-04-172-2/+2
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9303 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed invalid EOL in generated files.Giovanni Di Sirio2016-04-1754-1194/+1194
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9301 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9300 ↵Giovanni Di Sirio2016-04-171-2/+1
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added board files for STM32 Nucleo-144 F429ZIRocco Marco Guglielmi2016-04-1715-19/+5220
| | | | | | | Added demo RT-STM32F429ZI-NUCLEO144 Still small fixes on Nucleo144 F7 board files git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9299 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9298 ↵Rocco Marco Guglielmi2016-04-163-7/+7
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed last commit file namesRocco Marco Guglielmi2016-04-1614-12/+12
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9297 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added board files for STM32 Nucleo-144 F746ZERocco Marco Guglielmi2016-04-1613-0/+5203
| | | | | | Added demo RT-STM32F746ZE-NUCLEO144 git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9296 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed copyright date in recently generated board files.Rocco Marco Guglielmi2016-04-1625-26/+28
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9295 35acf78f-673a-0410-8e92-d51de3d6d3f4
* IAR support restored.Giovanni Di Sirio2016-04-163-264/+316
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9294 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9293 ↵Giovanni Di Sirio2016-04-161-1/+8
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* More infos in chtypes.h.Giovanni Di Sirio2016-04-169-50/+158
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9292 35acf78f-673a-0410-8e92-d51de3d6d3f4
* git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9291 ↵Giovanni Di Sirio2016-04-162-0/+10
| | | | 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Fixed bug #731 related to RT-STM32F334-DISCOVERYRocco Marco Guglielmi2016-04-161-2/+2
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9290 35acf78f-673a-0410-8e92-d51de3d6d3f4
* Added licensing checks to ports.Giovanni Di Sirio2016-04-1612-1/+85
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9289 35acf78f-673a-0410-8e92-d51de3d6d3f4
* More licensing checks.Giovanni Di Sirio2016-04-163-4/+54
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9288 35acf78f-673a-0410-8e92-d51de3d6d3f4
* New licensing headers.Giovanni Di Sirio2016-04-161-0/+107
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9287 35acf78f-673a-0410-8e92-d51de3d6d3f4
* New licensing headers.Giovanni Di Sirio2016-04-167-74/+120
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9286 35acf78f-673a-0410-8e92-d51de3d6d3f4
* More shell enhancements.Giovanni Di Sirio2016-04-162-10/+31
| | | | git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9285 35acf78f-673a-0410-8e92-d51de3d6d3f4
>; sysctl.u.page_offline.start = start; sysctl.u.page_offline.cmd = sysctl_page_online; sysctl.u.page_offline.end = end; set_xen_guest_handle(sysctl.u.page_offline.status, status); ret = xc_sysctl(xc, &sysctl); unlock_pages(status, sizeof(uint32_t)*(end - start + 1)); return ret; } int xc_mark_page_offline(int xc, unsigned long start, unsigned long end, uint32_t *status) { DECLARE_SYSCTL; int ret = -1; if ( !status || (end < start) ) return -EINVAL; if (lock_pages(status, sizeof(uint32_t)*(end - start + 1))) { ERROR("Could not lock memory for xc_mark_page_offline"); return -EINVAL; } sysctl.cmd = XEN_SYSCTL_page_offline_op; sysctl.u.page_offline.start = start; sysctl.u.page_offline.cmd = sysctl_page_offline; sysctl.u.page_offline.end = end; set_xen_guest_handle(sysctl.u.page_offline.status, status); ret = xc_sysctl(xc, &sysctl); unlock_pages(status, sizeof(uint32_t)*(end - start + 1)); return ret; } int xc_query_page_offline_status(int xc, unsigned long start, unsigned long end, uint32_t *status) { DECLARE_SYSCTL; int ret = -1; if ( !status || (end < start) ) return -EINVAL; if (lock_pages(status, sizeof(uint32_t)*(end - start + 1))) { ERROR("Could not lock memory for xc_query_page_offline_status\n"); return -EINVAL; } sysctl.cmd = XEN_SYSCTL_page_offline_op; sysctl.u.page_offline.start = start; sysctl.u.page_offline.cmd = sysctl_query_page_offline; sysctl.u.page_offline.end = end; set_xen_guest_handle(sysctl.u.page_offline.status, status); ret = xc_sysctl(xc, &sysctl); unlock_pages(status, sizeof(uint32_t)*(end - start + 1)); return ret; } /* * There should no update to the grant when domain paused */ static int xc_is_page_granted(int xc_handle, xen_pfn_t gpfn, struct grant_entry *gnttab, int gnt_num) { int i = 0; if (!gnttab) return 0; for (i = 0; i < gnt_num; i++) if ( ((gnttab[i].flags & GTF_type_mask) != GTF_invalid) && (gnttab[i].frame == gpfn) ) break; return (i != gnt_num); } static xen_pfn_t pfn_to_mfn(xen_pfn_t pfn, xen_pfn_t *p2m, int gwidth) { return ((xen_pfn_t) ((gwidth==8)? (((uint64_t *)p2m)[(pfn)]): ((((uint32_t *)p2m)[(pfn)]) == 0xffffffffU ? (-1UL) : (((uint32_t *)p2m)[(pfn)])))); } static int get_pt_level(int xc_handle, uint32_t domid, unsigned int *pt_level, unsigned int *gwidth) { DECLARE_DOMCTL; xen_capabilities_info_t xen_caps = ""; if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) return -1; memset(&domctl, 0, sizeof(domctl)); domctl.domain = domid; domctl.cmd = XEN_DOMCTL_get_address_size; if ( do_domctl(xc_handle, &domctl) != 0 ) return -1; *gwidth = domctl.u.address_size.size / 8; if (strstr(xen_caps, "xen-3.0-x86_64")) /* Depends on whether it's a compat 32-on-64 guest */ *pt_level = ( (*gwidth == 8) ? 4 : 3 ); else if (strstr(xen_caps, "xen-3.0-x86_32p")) *pt_level = 3; else if (strstr(xen_caps, "xen-3.0-x86_32")) *pt_level = 2; else return -1; return 0; } static int close_mem_info(int xc_handle, struct domain_mem_info *minfo) { if (minfo->pfn_type) free(minfo->pfn_type); munmap(minfo->m2p_table, M2P_SIZE(minfo->max_mfn)); munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE); minfo->p2m_table = minfo->m2p_table = NULL; return 0; } static int init_mem_info(int xc_handle, int domid, struct domain_mem_info *minfo, xc_dominfo_t *info) { uint64_aligned_t shared_info_frame; shared_info_any_t *live_shinfo = NULL; int i, rc; /* Only be initialized once */ if (minfo->pfn_type || minfo->m2p_table || minfo->p2m_table) return -EINVAL; if ( get_pt_level(xc_handle, domid, &minfo->pt_level, &minfo->guest_width) ) { ERROR("Unable to get PT level info."); return -EFAULT; } guest_width = minfo->guest_width; shared_info_frame = info->shared_info_frame; live_shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ, shared_info_frame); if ( !live_shinfo ) { ERROR("Couldn't map live_shinfo"); return -EFAULT; } if ( (rc = xc_core_arch_map_p2m_writable(xc_handle, minfo->guest_width, info, live_shinfo, &minfo->p2m_table, &minfo->p2m_size)) ) { ERROR("Couldn't map p2m table %x\n", rc); goto failed; } munmap(live_shinfo, PAGE_SIZE); live_shinfo = NULL; p2m_size = minfo->p2m_size; minfo->max_mfn = xc_memory_op(xc_handle, XENMEM_maximum_ram_page, NULL); if ( !(minfo->m2p_table = xc_map_m2p(xc_handle, minfo->max_mfn, PROT_READ, NULL)) ) { ERROR("Failed to map live M2P table"); goto failed; } /* Get pfn type */ minfo->pfn_type = malloc(sizeof(uint32_t) * minfo->p2m_size); if (!minfo->pfn_type) { ERROR("Failed to malloc pfn_type\n"); goto failed; } memset(minfo->pfn_type, 0, sizeof(uint32_t) * minfo->p2m_size); for (i = 0; i < minfo->p2m_size; i++) minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table, minfo->guest_width); if ( lock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(uint32_t)) ) { ERROR("Unable to lock pfn_type array"); goto failed; } for (i = 0; i < minfo->p2m_size ; i+=1024) { int count = ((p2m_size - i ) > 1024 ) ? 1024: (p2m_size - i); if ( ( rc = xc_get_pfn_type_batch(xc_handle, domid, count, minfo->pfn_type + i)) ) { ERROR("Failed to get pfn_type %x\n", rc); goto unlock; } } return 0; unlock: unlock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(uint32_t)); failed: if (minfo->pfn_type) { minfo->pfn_type = NULL; free(minfo->pfn_type); } if (live_shinfo) munmap(live_shinfo, PAGE_SIZE); munmap(minfo->m2p_table, M2P_SIZE(minfo->max_mfn)); munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE); minfo->p2m_table = minfo->m2p_table = NULL; return -1; } static int backup_ptes(xen_pfn_t table_mfn, int offset, struct pte_backup *backup) { if (!backup) return -EINVAL; if (backup->max == backup->cur) { backup->entries = realloc(backup->entries, backup->max * 2 * sizeof(struct pte_backup_entry)); if (backup->entries == NULL) return -1; else backup->max *= 2; } backup->entries[backup->cur].table_mfn = table_mfn; backup->entries[backup->cur++].offset = offset; return 0; } /* * return: * 1 when MMU update is required * 0 when no changes * <0 when error happen */ typedef int (*pte_func)(uint64_t pte, uint64_t *new_pte, unsigned long table_mfn, int table_offset, struct pte_backup *backup, unsigned long no_use); static int __clear_pte(uint64_t pte, uint64_t *new_pte, unsigned long table_mfn, int table_offset, struct pte_backup *backup, unsigned long mfn) { /* If no new_pte pointer, same as no changes needed */ if (!new_pte || !backup) return -EINVAL; if ( !(pte & _PAGE_PRESENT)) return 0; /* XXX Check for PSE bit here */ /* Hit one entry */ if ( ((pte >> PAGE_SHIFT_X86) & MFN_MASK_X86) == mfn) { *new_pte = pte & ~_PAGE_PRESENT; if (!backup_ptes(table_mfn, table_offset, backup)) return 1; } return 0; } static int __update_pte(uint64_t pte, uint64_t *new_pte, unsigned long table_mfn, int table_offset, struct pte_backup *backup, unsigned long new_mfn) { int index; if (!new_pte) return 0; for (index = 0; index < backup->cur; index ++) if ( (backup->entries[index].table_mfn == table_mfn) && (backup->entries[index].offset == table_offset) ) break; if (index != backup->cur) { if (pte & _PAGE_PRESENT) ERROR("Page present while in backup ptes\n"); pte &= ~MFN_MASK_X86; pte |= (new_mfn << PAGE_SHIFT_X86) | _PAGE_PRESENT; *new_pte = pte; return 1; } return 0; } static int change_pte(int xc_handle, int domid, struct domain_mem_info *minfo, struct pte_backup *backup, struct xc_mmu *mmu, pte_func func, unsigned long data) { int pte_num, rc; uint64_t i; void *content = NULL; pte_num = PAGE_SIZE / ((minfo->pt_level == 2) ? 4 : 8); for (i = 0; i < minfo->p2m_size; i++) { xen_pfn_t table_mfn = pfn_to_mfn(i, minfo->p2m_table, minfo->guest_width); uint64_t pte, new_pte; int j; if ( table_mfn == INVALID_P2M_ENTRY ) continue; if ( minfo->pfn_type[i] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK ) { content = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ, table_mfn); if (!content) goto failed; for (j = 0; j < pte_num; j++) { if ( minfo->pt_level == 2 ) pte = ((const uint32_t*)content)[j]; else pte = ((const uint64_t*)content)[j]; rc = func(pte, &new_pte, table_mfn, j, backup, data); switch (rc) { case 1: if ( xc_add_mmu_update(xc_handle, mmu, table_mfn << PAGE_SHIFT | j * ( (minfo->pt_level == 2) ? sizeof(uint32_t): sizeof(uint64_t)) | MMU_PT_UPDATE_PRESERVE_AD, new_pte) ) goto failed; break; case 0: break; default: goto failed; } } } munmap(content, PAGE_SIZE); content = NULL; } if ( xc_flush_mmu_updates(xc_handle, mmu) ) goto failed; return 0; failed: /* XXX Shall we take action if we have fail to swap? */ if (content) munmap(content, PAGE_SIZE); return -1; } static int update_pte(int xc_handle, int domid, struct domain_mem_info *minfo, struct pte_backup *backup, struct xc_mmu *mmu, unsigned long new_mfn) { return change_pte(xc_handle, domid, minfo, backup, mmu, __update_pte, new_mfn); } static int clear_pte(int xc_handle, int domid, struct domain_mem_info *minfo, struct pte_backup *backup, struct xc_mmu *mmu, xen_pfn_t mfn) { return change_pte(xc_handle, domid, minfo, backup, mmu, __clear_pte, mfn); } static int exchange_page(int xc_handle, xen_pfn_t mfn, xen_pfn_t *new_mfn, int domid) { int rc; xen_pfn_t out_mfn; struct xen_memory_exchange exchange = { .in = { .nr_extents = 1, .extent_order = 0, .domid = domid }, .out = { .nr_extents = 1, .extent_order = 0, .domid = domid } }; set_xen_guest_handle(exchange.in.extent_start, &mfn); set_xen_guest_handle(exchange.out.extent_start, &out_mfn); rc = xc_memory_op(xc_handle, XENMEM_exchange, &exchange); if (!rc) *new_mfn = out_mfn; return rc; } /* * Check if a page can be exchanged successfully */ static int is_page_exchangable(int xc_handle, int domid, xen_pfn_t mfn, xc_dominfo_t *info) { uint32_t status; int rc; /* domain checking */ if ( !domid || (domid > DOMID_FIRST_RESERVED) ) { DPRINTF("Dom0's page can't be LM"); return 0; } if (info->hvm) { DPRINTF("Currently we can only live change PV guest's page\n"); return 0; } /* Check if pages are offline pending or not */ rc = xc_query_page_offline_status(xc_handle, mfn, mfn, &status); if ( rc || !(status & PG_OFFLINE_STATUS_OFFLINE_PENDING) ) { ERROR("Page %lx is not offline pending %x\n", mfn, status); return 0; } return 1; } /* The domain should be suspended when called here */ int xc_exchange_page(int xc_handle, int domid, xen_pfn_t mfn) { xc_dominfo_t info; struct domain_mem_info minfo; struct xc_mmu *mmu = NULL; struct pte_backup old_ptes = {NULL, 0, 0}; struct grant_entry *gnttab = NULL; struct mmuext_op mops; int gnt_num, unpined = 0; void *old_p, *backup = NULL; int rc, result = -1; uint32_t status; xen_pfn_t new_mfn, gpfn; if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 ) { ERROR("Could not get domain info"); return -EFAULT; } if (!info.shutdown || info.shutdown_reason != SHUTDOWN_suspend) { ERROR("Can't exchange page unless domain is suspended\n"); return -EINVAL; } if (!is_page_exchangable(xc_handle, domid, mfn, &info)) { ERROR("Could not exchange page\n"); return -EINVAL; } /* Get domain's memory information */ memset(&minfo, 0, sizeof(minfo)); init_mem_info(xc_handle, domid, &minfo, &info); gpfn = minfo.m2p_table[mfn]; /* Don't exchange CR3 for PAE guest in PAE host environment */ if (minfo.guest_width > sizeof(long)) { if ( (minfo.pfn_type[gpfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) == XEN_DOMCTL_PFINFO_L3TAB ) goto failed; } gnttab = xc_gnttab_map_table(xc_handle, domid, &gnt_num); if (!gnttab) { ERROR("Failed to map grant table\n"); goto failed; } if (xc_is_page_granted(xc_handle, mfn, gnttab, gnt_num)) { ERROR("Page %lx is granted now\n", mfn); goto failed; } /* allocate required data structure */ backup = malloc(PAGE_SIZE); if (!backup) { ERROR("Failed to allocate backup pages pointer\n"); goto failed; } old_ptes.max = DEFAULT_BACKUP_COUNT; old_ptes.entries = malloc(sizeof(struct pte_backup_entry) * DEFAULT_BACKUP_COUNT); if (!old_ptes.entries) { ERROR("Faield to allocate backup\n"); goto failed; } old_ptes.cur = 0; /* Unpin the page if it is pined */ if (minfo.pfn_type[gpfn] & XEN_DOMCTL_PFINFO_LPINTAB) { mops.cmd = MMUEXT_UNPIN_TABLE; mops.arg1.mfn = mfn; if ( xc_mmuext_op(xc_handle, &mops, 1, domid) < 0 ) { ERROR("Failed to unpin page %lx", mfn); goto failed; } mops.arg1.mfn = mfn; unpined = 1; } /* backup the content */ old_p = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ, mfn); if (!old_p) { ERROR("Failed to map foreign page %lx\n", mfn); goto failed; } memcpy(backup, old_p, PAGE_SIZE); munmap(old_p, PAGE_SIZE); mmu = xc_alloc_mmu_updates(xc_handle, domid); if ( mmu == NULL ) { ERROR("%s: failed at %d\n", __FUNCTION__, __LINE__); goto failed; } /* Firstly update all pte to be invalid to remove the reference */ rc = clear_pte(xc_handle, domid, &minfo, &old_ptes, mmu, mfn); if (rc) { ERROR("clear pte failed\n"); goto failed; } rc = exchange_page(xc_handle, mfn, &new_mfn, domid); if (rc) { ERROR("Exchange the page failed\n"); /* Exchange fail means there are refere to the page still */ rc = update_pte(xc_handle, domid, &minfo, &old_ptes, mmu, mfn); if (rc) result = -2; goto failed; } rc = update_pte(xc_handle, domid, &minfo, &old_ptes, mmu, new_mfn); if (rc) { ERROR("update pte failed guest may be broken now\n"); /* No recover action now for swap fail */ result = -2; goto failed; } /* Check if pages are offlined already */ rc = xc_query_page_offline_status(xc_handle, mfn, mfn, &status); if (rc) { ERROR("Fail to query offline status\n"); }else if ( !(status & PG_OFFLINE_STATUS_OFFLINED) ) { ERROR("page is still online or pending\n"); goto failed; } else { void *new_p; IPRINTF("Now page is offlined %lx\n", mfn); /* Update the p2m table */ minfo.p2m_table[gpfn] = new_mfn; new_p = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ|PROT_WRITE, new_mfn); memcpy(new_p, backup, PAGE_SIZE); munmap(new_p, PAGE_SIZE); mops.arg1.mfn = new_mfn; result = 0; } failed: if (unpined && (minfo.pfn_type[mfn] & XEN_DOMCTL_PFINFO_LPINTAB)) { switch ( minfo.pfn_type[mfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK ) { case XEN_DOMCTL_PFINFO_L1TAB: mops.cmd = MMUEXT_PIN_L1_TABLE; break; case XEN_DOMCTL_PFINFO_L2TAB: mops.cmd = MMUEXT_PIN_L2_TABLE; break; case XEN_DOMCTL_PFINFO_L3TAB: mops.cmd = MMUEXT_PIN_L3_TABLE; break; case XEN_DOMCTL_PFINFO_L4TAB: mops.cmd = MMUEXT_PIN_L4_TABLE; break; default: ERROR("Unpined for non pate table page\n"); break; } if ( xc_mmuext_op(xc_handle, &mops, 1, domid) < 0 ) { ERROR("failed to pin the mfn again\n"); result = -2; } } if (mmu) free(mmu); if (old_ptes.entries) free(old_ptes.entries); if (backup) free(backup); if (gnttab) munmap(gnttab, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry))); close_mem_info(xc_handle, &minfo); return result; }