×ðÁú¿­Ê±¹ÙÍøµÇ¼

RISC-V LinuxÆô¶¯Ö®Ò³±í½¨ÉèÆÊÎö

ÉÏƪÆÊÎöÁËRISC-V LinuxµÄ»ã±àÆô¶¯Àú³Ì£¬ÆäÖн²µ½ÁËrelocateÖض¨ÏòÐèÒª¿ªÆôMMU£¬½ñÌìÆÊÎöRISC-V LinuxµÄÒ³±í½¨Éè¡£

×¢ÖØ£º±¾ÎÄ»ùÓÚlinux5.10.111ÄÚºË

sv39 mmu

RISC-V LinuxÖ§³Ösv32¡¢sv39¡¢sv48µÈÐéÄâµØµãÃûÌ㬻®·Ö´ú±í32ΪÐéÄâµØµã¡¢38λÐéÄâµØµãºÍ48λÐéÄâµØµã¡£RISC-V LinuxĬÈÏÒ²ÊÇʹÓÃsv39ÃûÌã¬sv39µÄÐéÄâµØµã¡¢ÎïÀíµØµã¡¢PTEÃûÌÃÈçÏ£º

ÐéÄâµØµãÃûÌãº

ÎïÀíµØµãÃûÌãº

PTE̞틼

ÐéÄâµØµãʹÓÃ39λÌåÏÖ£¬ÆäÖеÍ12λ´ú±ípage offset£¬¸ßλ»®·ÖΪÁËÈý²¿·Ö£ºVP N[0]¡¢VP N[1]ºÍVP N[2]£¬»®·Ö´ú±íÐéÄâµØµãVAÔÚPTE¡¢PMDºÍPGDÖеÄË÷Òý¡£

ÎïÀíµØµãʹÓÃ56λÌåÏÖ£¬µÍ12λ´ú±ípage offset£¬¸ßλÊÇÎïÀíÒ³PPN[0]¡¢PPN[1]ºÍPPN[2]

PTEÉúÑÄÁËÎïÀíÒ³PPN[0]¡¢PPN[1]ºÍPPN[2]£¬ºÍÎïÀíµØµãÖеÄPPNÏà¶ÔÓ¦£»PTEµÄµÍ10λ´ú±íÎïÀíµØµãµÄ»á¼ûȨÏÞ£¬µ±RWXȫΪ0ʱ£¬Ôò´ú±í¸ÃPTE´æ´¢µÄµØµãÊÇÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã£¬²»È»´ú±íÄ¿½ñÒ³±íÊÇ×îºóÒ»¼¶Ò³±í¡£

ÔÙ¿´¿´sv39 µÄÒ³±íÃûÌã¬sv39ʹÓõÄÊÇÈý¼¶Ò³±í£¬PGD¡¢PMDºÍPTE£¬Ã¿Ò»¸ö¼¶Ò³±íʹÓÃ9bitÌåÏÖ£¬¼´Ã¿Ò»¼¶Ò³±í¶¼ÓÐ512¸öÒ³±íÏî¡£

ÔÚ´úÂëÖУ¬½¨ÉèÒ»¸öÓÐ512¸öÔªËصÄÊý×é¼´´ú±íÒ»¸öÒ³±í¡£Ò»¸öPTEÓÐ512¸öÒ³±íÏÿһ¸öÒ³±íÏîÕ¼ÓÃ8×Ö½Ú£¬512*8=4096×Ö½Ú£¬ÒÔÊÇÒ»¸öPTE´ú±í4K¡£Ò»¸öPMDÒ²ÊÇ512¸öÒ³±íÏÿһÏî¿É´ú±íÒ»¸öPTE£¬512 *4 K=2M£¬ÒÔÊÇÒ»¸öPMD¾Í´ú±í2M¡£ÒÔ´ËÀàÍÆ£¬Ò»¸öPGD´ú±í512 * 2M=1G¡£

Ö÷Òª½áÂÛ£ºPGD´ú±í1G¡¢PMD´ú±í2M¡¢PTE´ú±í4K¡£sv39ĬÈϵÄÒ³¾ÞϸÊÇ4K¡£

Èý¼¶Ò³±íÐéÄâµØµãתΪÎïÀíµØµãÀú³ÌʾÒâͼ£º

sv39Èý¼¶Ò³±íÐéÄâµØµãתΪÎïÀíµØµãÀú³Ì£º

MMUͨ¹ýsatp¼Ä´æÆ÷»ñµÃPGDµÄÎïÀíµØµã£¬ÍŽáPGD index£¨¼´V PN[2]£©ÕÒµ½PMD£»ÕÒµ½PMDºó£¬ÔÙÍŽáPMD index£¨¼´V PN[1]£©ÕÒµ½PTE£¬È»ºóÍŽáPTE index£¨¼´V PN[0]£©»ñµÃVAÔÚPTEË÷ÒýÖеÄÖµ£¬´Ó¶ø»ñµÃÎïÀíµØµã¡£

×îºóÔÚPTEÖÐÈ¡³öPPN[2]¡¢PPN[1]ºÍPPN[0],ÔÙºÍÐéÄâµØµãµÄµÍ12λoffsetÏà¼Ó£¬»ñµÃ×îÖÕµÄÎïÀíµØµã¡£

ÔÝʱҳ±íÆÊÎö

MMU¿ªÆôÇ°£¬ÐèÒª½¨ÉèºÃkernel¡¢dtb¡¢trampolineµÈÒ³±í¡£ÒÔ±ãMMU¿ªÆôºó£¬²¢ÇÒÔÚÄÚ´æÖÎÀíÄ£¿éÔËÐÐ֮ǰ£¬kernel¿ÉÒÔÕý³£³õʼ»¯£¬dtb¿ÉÒÔÕý³£µØ±»ÆÊÎö¡£Õⲿ·ÖÒ³±í¶¼ÊÇÔÝʱҳ±í£¬×îÖÕµÄÒ³±íÔÚsetup_vm_final()½¨Éè¡£

ÔÝʱҳ±í½¨Éè˳Ðò£º

Ê×ÏÈΪfixmap½¨ÉèÔçÆÚµÄPGD¡¢PMD£¬ÕâʱPGDʹÓÃearly_pg_dir¡£È»ºó¶Ô´Ókernel×îÏȵÄÇ°2MÄڴ潨Éè¶þ¼¶Ò³±í£¬´ËʱPGDʹÓÃtrampoline_pg_dir£¬ÎªÕâ2M½¨ÉèµÄÒ³±íÒ²½Ð×÷superpage¡£ÔÙÈ»ºó£¬¶ÔÕû¸ökernel½¨Éè¶þ¼¶Ò³±í£¬´ËʱPGDʹÓÃearly_pg_dir¡£×îºóΪdtbÔ¤Áô4M¾Þϸ½¨Éè¶þ¼¶Ò³±í¡£

Ò³±í½¨É躯Êý

create_pgd_mapping()

void __init create_pgd_mapping(pgd_t *pgdp,
          uintptr_t va, phys_addr_t pa,
          phys_addr_t sz, pgprot_t prot)

µÇ¼ºó¸´ÖÆ

pgdp£ºPGDÒ³±í

va£ºÐéÄâµØµã

pa£ºÎïÀíµØµã

sz£ºÓ³Éä¾Þϸ£¬PGDIR_SIZE»òPMD_SIZE»òPTE_SIZE

prot£ºPAGE_KERNEL_EXEC/PAGE_KERNELÌåÏÖÄ¿½ñÊÇ×îºóÒ»¼¶Ò³±í£¬²»È»pa´ú±íÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã

create_pmd_mapping()

static void __init create_pmd_mapping(pmd_t *pmdp,
          uintptr_t va, phys_addr_t pa,
          phys_addr_t sz, pgprot_t prot)

µÇ¼ºó¸´ÖÆ

pmdp£ºPMDÒ³±í

va£ºÐéÄâµØµã

pa£ºÎïÀíµØµã

sz£ºÓ³Éä¾Þϸ£¬PMD_SIZE»òPAGE_SIZE

prot£ºÈ¨ÏÞ£¬PAGE_KERNEL_EXEC/PAGE_KERNELÌåÏÖÄ¿½ñÊÇ×îºóÒ»¼¶Ò³±í£¬²»È»pa´ú±íÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã

create_pte_mapping()

static void __init create_pte_mapping(pte_t *ptep,
          uintptr_t va, phys_addr_t pa,
          phys_addr_t sz, pgprot_t prot)

µÇ¼ºó¸´ÖÆ

ptep£ºPTEÒ³±í

va£ºÐéÄâµØµã

pa£ºÎïÀíµØµã

sz£ºÓ³Éä¾Þϸ£¬PAGE_SIZE

prot£ºÈ¨ÏÞ£¬PAGE_KERNEL_EXEC/PAGE_KERNELÌåÏÖÄ¿½ñÊÇ×îºóÒ»¼¶Ò³±í£¬²»È»pa´ú±íÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã

ʹÓþÙÀý

ÀýÈ磬½«ÐéÄâµØµãPAGE_OFFSETÓ³Éäµ½ÎïÀíµØµãpa£¬Ó³Éä¾ÞϸΪ4K£¬½¨ÉèÈý¼¶Ò³±íPGD¡¢PMDºÍPTE£º

create_pgd_mapping(early_pg_dir£¬PAGE_OFFSET£¬
                   (uintptr_t)early_pmd£¬PGDIR_SIZE,PAGE_TABLE);
create_pmd_mapping(early_pmd£¬PAGE_OFFSET£¬
                   (uintptr_t)early_pte£¬PGDIR_SIZE,PAGE_TABLE);
create_pte_mapping(early_pte£¬PAGE_OFFSET£¬
                   (uintptr_t)pa£¬PAGE_SIZE,PAGE_KERNEL_EXEC);

µÇ¼ºó¸´ÖÆ

ÕâÑù½¨Éèºó£¬MMU¾Í»áƾ֤PAGE_OFFSETÔÚPGDÖÐÕÒµ½PMD£¬È»ºóÔÙPMDÖÐÕÒµ½PTE£¬×îºóÈ¡³öÎïÀíµØµã¡£

Ò³±í½¨ÉèÔ´ÂëÆÊÎö

RISC-V LinuxÆô¶¯£¬ÂÄÀúÁËÁ½´ÎÒ³±í½¨ÉèÀú³Ì£¬µÚÒ»´ÎʹÓÃCº¯Êýsetup_vm()½¨ÉèÔÝʱҳ±í£¬µÚ¶þ´ÎʹÓÃCº¯Êýsetup_vm_final()½¨Éè×îÖÕÒ³±í¡£

Ïêϸϸ½Ú²Î¿¼´úÂëÖеÄ×¢ÊÍ£¬ÏÂÃæµÄ´úÂëÊ¡ÂÔÁËһЩ²»Ö÷ÒªµÄ²¿·Ö¡£

setup_vm()

asmlinkage void __init setup_vm(uintptr_t dtb_pa)
{
 uintptr_t va, pa, end_va;
 uintptr_t load_pa = (uintptr_t)(&_start);
 uintptr_t load_sz = (uintptr_t)(&_end) - load_pa;
 uintptr_t map_size;
 //load_pa¾ÍÊÇkernel¼ÓÔصÄ×ÅʵÎïÀíµØµã
    //load_sz¾ÍÊÇkernelµÄÏÖʵ¾Þϸ

    //page_offset¾ÍÊÇkernelµÄÆðʼÎïÀíµØµã¶ÔÓ¦µÄÐéÄâµØµã£¬va_pa_offsetÊÇËûÃǵÄÆ«ÒÆÁ¿
 va_pa_offset = PAGE_OFFSET - load_pa;
    
    //ÅÌËã»ñµÃkernelÆðʼÎïÀíµØµãµÄÎïÀíÒ³£¬PFN_DOWNÊǽ«ÎïÀíµØµãÓÒÒÆ12룬ÓÉÓÚsv39µÄÎïÀíµØµãµÄµÍ12λÊÇpa_offset£¬ÒÔÊÇÓÒÒÆ12룬»ñµÃpfn
 pfn_base = PFN_DOWN(load_pa);

 map_size = PMD_SIZE;//PMD_SIZEΪ2M£¬ÔÚÄ¿½ñ£¬map_sizeÖ»ÄÜΪPGDIR_SIZE»òPMD_SIZE¡£ÕâʱkernelĬÈϲ»ÔÊÐí½¨ÉèPTE¡£

 //¼ì²éPAGE_OFFSETÊÇ·ñ1G¶ÔÆ룬ÒÔ¼°kernelÈë¿ÚµØµãÊÇ·ñ2M¶ÔÆë
 BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
 BUG_ON((load_pa % map_size) != 0);

    //allc_pte_earlyÄÚÀïÊÇBUG(),¹ØÓÚÔÝʱҳ±í£¬kernel²»ÔÊÐíÎÒÃǽ¨ÉèPTE
 pt_ops.alloc_pte = alloc_pte_early;
 pt_ops.get_pte_virt = get_pte_virt_early;
#ifndef __PAGETABLE_PMD_FOLDED
 pt_ops.alloc_pmd = alloc_pmd_early;
 pt_ops.get_pmd_virt = get_pmd_virt_early;
#endif
 /* ÉèÖÃ early PGD for fixmap */
 create_pgd_mapping(early_pg_dir, FIXADDR_START,
      (uintptr_t)fixmap_pgd_next, PGDIR_SIZE, PAGE_TABLE);


 /* ÉèÖÃ fixmap PMD */
 create_pmd_mapping(fixmap_pmd, FIXADDR_START,
      (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE);
 /* ÉèÖÃ trampoline PGD and PMD */
 create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET,
      (uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE);
 create_pmd_mapping(trampoline_pmd, PAGE_OFFSET,
      load_pa, PMD_SIZE, PAGE_KERNEL_EXEC);

 /*
  * ÉèÖÃÁýÕÖÕû¸öÄں˵ÄÔçÆÚPGD£¬Õ⽫ʹÎÒÃÇÄܹ»µÖ´ïpaging_init£¨£©¡£
  * ÉÔºóÔÚÏÂÃæµÄ setup_vm_final£¨£© ÖÐÓ³ÉäËùÓÐÄÚ´æ¡£
  */
 end_va = PAGE_OFFSET + load_sz;
 for (va = PAGE_OFFSET; va < end_va; va += map_size)
  create_pgd_mapping(early_pg_dir, va,
       load_pa + (va - PAGE_OFFSET),
       map_size, PAGE_KERNEL_EXEC);

 /* Ϊdtb½¨ÉèÔçÆÚµÄPMD */
 create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA,
      (uintptr_t)early_dtb_pmd, PGDIR_SIZE, PAGE_TABLE);
 /* Ϊ FDT ÔçÆÚɨÃ轨ÉèÁ½¸öÒ»Á¬µÄ PMD Ó³Éä */
 pa = dtb_pa & ~(PMD_SIZE - 1);
 create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA,
      pa, PMD_SIZE, PAGE_KERNEL);
 create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA + PMD_SIZE,
      pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL);
 dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PMD_SIZE - 1));
 ......

}

µÇ¼ºó¸´ÖÆ

setup_vm()ÔÚ×î×îÏȾ;ÙÐÐÁËkernelÈë¿ÚµØµãµÄ¶ÔÆë¼ì²é£¬ÒªÇóÈë¿ÚµØµã2M¶ÔÆë¡£¼ÙÉèÄÚ´æÆðʼµØµãΪ0x80000000£¬ÄÇôkernelÖ»ÄÜ·ÅÔÚ0x80000000¡¢0x80200000µÈ2M¶ÔÆë´¦¡£ÎªÊ²Ã´»áÓÐÕâÖÖ¶ÔÆëÒªÇóÄØ£¿

ÎÒÍƲⴿ´âÊÇΪ¸øopensbiÔ¤ÁôÁË2M¿Õ¼ä£¬ÓÉÓÚkernel֮ǰÉÐÓÐopensbi£¬¶øopensbiÔËÐÐÍêÖ®ºó£¬Ä¬ÈÏÌøתµØµã¾ÍÊÇÆ«ÒÆ2M£¬kernelÖ»ÊÇΪÁ˸úopensbi¶ÔÓ¦£¬ÒÔÊÇÉèÖÃÁË2M¶ÔÆë¡£

ÄÇopensbiÐèÒªÕ¼ÓÃ2MÕâô´ó£¿ÏÖʵÉÏÖ»ÐèÒª¼¸°ÙKB£¬Òò´ËopensbiºÍkernelÖÐÑëÓÐÒ»¶ÎÄÚ´æÊÇ¿ÕÏеÄ£¬Ã»ÓÐÈËʹÓá£Õâ¸öÎÊÌâÎÒÃÇÏÂƪÔÙ½²¡£

setup_vm_final()

Ôڸú¯ÊýÖÐ×îÏÈΪÕû¸öÎïÀíÄÚ´æ×öÄÚ´æÓ³É䣬ͨ¹ýswapperÒ³±íÀ´ÖÎÀí£¬²¢ÇÒɨ³ýµô»ã±à½×¶ÎµÄÒ³±í¡£

static void __init setup_vm_final(void)
{
 uintptr_t va, map_size;
 phys_addr_t pa, start, end;
 u64 i;

 /**
  * ´ËʱMMUÒѾ­¿ªÆô£¬¿ÉÊÇÒ³±í»¹Ã»ÍêÈ«½¨Éè¡£
  */
 pt_ops.alloc_pte = alloc_pte_fixmap;
 pt_ops.get_pte_virt = get_pte_virt_fixmap;
#ifndef __PAGETABLE_PMD_FOLDED
 pt_ops.alloc_pmd = alloc_pmd_fixmap;
 pt_ops.get_pmd_virt = get_pmd_virt_fixmap;
#endif
 /* Setup swapper PGD for fixmap */
 create_pgd_mapping(swapper_pg_dir, FIXADDR_START,
      __pa_symbol(fixmap_pgd_next),
      PGDIR_SIZE, PAGE_TABLE);

 /* ΪÕû¸öÎïÀíÄڴ潨ÉèÒ³±í */
 for_each_mem_range(i, &start, &end) {
  if (start >= end)
   break;
  if (start <= __pa(PAGE_OFFSET) &&
      __pa(PAGE_OFFSET) < end)
   start = __pa(PAGE_OFFSET);

        //best_map_sizeÊÇÑ¡ÔñºÏÊʵÄÓ³Éä¾Þϸ£¬kernelÈë¿ÚµØµã2M¶ÔÆë»òÕßkernel¾ÞϸÄܱ»2MÕû³ýʱ£¬map_size¾ÍÊÇ2M£¬²»È»¾ÍÊÇ4K¡£
  map_size = best_map_size(start, end - start);
  for (pa = start; pa < end; pa += map_size) {
   va = (uintptr_t)__va(pa);
   create_pgd_mapping(swapper_pg_dir, va, pa,
        map_size, PAGE_KERNEL_EXEC);
  }
 }

 /* ɨ³ýfixmapµÄPMDºÍPTE */
 clear_fixmap(FIX_PTE);
 clear_fixmap(FIX_PMD);

 /* Çл»µ½swapperÒ³±í£¬Õâ¸öÊÇ×îÖÕµÄÒ³±í£¬»ã±à½×¶Îrelocate¿ªÆôMMUµÄ²Ù×÷£¬¸úÏÂÃæÕâ¾äÊÇÒ»ÑùµÄ¡£ */
 csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE);
 local_flush_tlb_all();//Ë¢ÐÂTLB

 ......
}

µÇ¼ºó¸´ÖÆ

˵Ã÷£º

ÔÚsetup_vm_final()º¯ÊýÖУ¬Í¨¹ýswapper_pg_dirÒ³±íÀ´ÖÎÀíÕû¸öÎïÀíÄÚ´æµÄ»á¼û¡£²¢ÇÒɨ³ý»ã±à½×¶ÎµÄÒ³±ífixmap_pteºÍearly_pg_dir¡££¨ÊµÖÊÉϾÍÊǰѸÃÒ³±íÏîµÄÄÚÈÝÇå0£¬¼´¸³ÖµÎª0£©

×îÖÕ°Ñswapper_pg_dirÒ³±íµÄÎïÀíµØµã¸³Öµ¸øSATP¼Ä´æÆ÷¡£ÕâÑùCPU¾Í¿ÉÒÔͨ¹ý¸ÃÒ³±í»á¼ûÕû¸öÎïÀíÄÚ´æ¡£

Çл»Ò³±íͨ¹ýÈçÏÂʵÏÖ£º

csr_write(CSR_SATP,PFN_DOWN(_pa(swapper_pg_dir))|SATP_MODE);

ÔÚswapper_pg_dirÖÎÀíµÄkernel spaceÖУ¬ÆäÐéÄâµØµãÓëÎïÀíµØµã¿Õ¼äµÄÆ«ÒÆÊÇÀο¿µÄ£¬Îªva_pa_offset£¨½ç˵ÔÚarch/riscv/mm/init.cÖеÄÒ»¸öÈ«¾Ö±äÁ¿£©

×¢ÖØ£ºswapper_pg_dirÖÎÀíµÄÊÇkernel spaceµÄÒ³±í£¬¼´Ëü°ÑÎïÀíÄÚ´æÓ³Éäµ½µÄÐéÄâµØµã¿Õ¼äÊÇÖ»ÄÜkernel»á¼ûµÄ¡£user space²»¿É»á¼û£¬Óû§¿Õ¼äÈôÊÇ»á¼û£¬±ØÐè×ÔÐн¨ÉèÒ³±í£¬°ÑÎïÀíµØµãÓ³Éäµ½user spaceµÄÐéÄâµØµã¿Õ¼ä¡£kernelÏ̹߳²ÏíÕâ¸öswapper_pg_dirÒ³±í¡£

×ܽá

RISC-V LinuxÆô¶¯Ê±µÄÒ³±í½¨ÉèÏà¶ÔÀ´ËÃ÷ÈÕվɽÏÁ¿ÈÝÒ×Ã÷È·µÄ£¬¶¼ÊÇCÓïÑÔ½¨ÉèµÄ£¬´úÂëÒ²½ÏÁ¿ÉÙ¡£Ö÷Òª¾ÍÊÇsetup_vm()ºÍsetup_vm_final()Á½¸öÒ³±í½¨É躯Êý¡£Ã÷È·ÁËsv39µÄһЩµØµãÃûÌúó£¬ÔÙÈ¥ÆÊÎöÔ´Âë¾Í½ÏÁ¿ÈÝÒס£²»¹ý²î±ðkernel°æ±¾´úÂ붼·×ÆçÑù£¬ÐèÒªÏêϸÇéÐÎÏêϸÆÊÎö¡£

±¾ÆªÌáµ½ÁËsetup_vm()»á¼ì²ékernelÈë¿ÚµØµãÊÇ·ñ2M¶ÔÆ룬ÈôÊDzî³ØÆëkernelÎÞ·¨Æô¶¯£¬µ«×ÅʵÎÒÃÇ¿ÉÒÔɨ³ýÕâ¸ö2M¶ÔÆëÏÞÖÆ£¬½«Õⲿ·Ö¿Õ¼äʹÓÃÆðÀ´£¬ÏÂƪ½Ì¸÷ÈËÓÅ»¯Õⲿ·ÖÄÚ´æ¡£

ÒÔÉϾÍÊÇRISC-V LinuxÆô¶¯Ö®Ò³±í½¨ÉèÆÊÎöµÄÏêϸÄÚÈÝ£¬¸ü¶àÇë¹Ø×¢±¾ÍøÄÚÆäËüÏà¹ØÎÄÕ£¡

ÃâÔð˵Ã÷£ºÒÔÉÏչʾÄÚÈÝȪԴÓÚÏàÖúýÌå¡¢ÆóÒµ»ú¹¹¡¢ÍøÓÑÌṩ»òÍøÂçÍøÂçÕûÀí£¬°æȨÕùÒéÓë±¾Õ¾Î޹أ¬ÎÄÕÂÉæ¼°¿´·¨Óë¿´·¨²»´ú±í×ðÁú¿­Ê±¹ÙÍøµÇ¼ÂËÓÍ»úÍø¹Ù·½Ì¬¶È£¬Çë¶ÁÕß½ö×ö²Î¿¼¡£±¾ÎĽӴýתÔØ£¬×ªÔØÇë˵Ã÷À´ÓÉ¡£ÈôÄúÒÔΪ±¾ÎÄÇÖÕ¼ÁËÄúµÄ°æȨÐÅÏ¢£¬»òÄú·¢Ã÷¸ÃÄÚÈÝÓÐÈκÎÉæ¼°ÓÐÎ¥¹«µÂ¡¢Ã°·¸Ö´·¨µÈÎ¥·¨ÐÅÏ¢£¬ÇëÄúÁ¬Ã¦ÁªÏµ×ðÁú¿­Ê±¹ÙÍøµÇ¼ʵʱÐÞÕý»òɾ³ý¡£

Ïà¹ØÐÂÎÅ

ÁªÏµ×ðÁú¿­Ê±¹ÙÍøµÇ¼

18523999891

¿É΢ÐÅÔÚÏß×Éѯ

ÊÂÇéʱ¼ä£ºÖÜÒ»ÖÁÖÜÎ壬9:30-18:30£¬½ÚãåÈÕÐÝÏ¢

QR code
ÍøÕ¾µØͼ