create_mapping如何创建内存映射表

本文详细解析了ARM920T处理器MMU的工作原理及Linux内核中的内存映射实现。介绍了MMU地址转换流程,包括TLB、一级表项与二级表项的计算方法,并展示了create_mapping函数如何为物理地址创建静态映射。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 ARM920T的MMU工作原理

下图显示了MMU地址转化关系

 

一级表项的地址(pmd) = ( (TLB) & (0xFFFFC000) ) + ( (Table Index)<<2 );

注1:TLB(Translate table base),即转换表基地址

注2:由于每个表项占32位(4Bytes),因此(Table Index)<<2

一级表项的内容(*pmd) = ( (pte) & (0xFFFFFC00) ) + prot_l1;

-------------------------------------------------------------------------------------

二级表项的地址(pte) =  ( (pte) & (0xFFFFFC00) )  + ( (L2 table index) <<2 );

二级表项的内容(*pte) = ( (PA) & (0xFFFFF000) ) + prot_pte;

 

 

2 create_mapping分析

//利用该函数可以为物理地址创建内存的静态映射

static void __init create_mapping(struct map_desc *md)
{
     ...  

     pgd = pgd_offset_k(addr);

     //计算pgd的地址(64bits) = ((mm)->pgd+pgd_index(addr))

     //                              = ((mm)->pgd+((addr) >> 21) )

     //pmd地址(32bits)        = ((mm)->pgd+((addr) >> 20) )

     end = addr + length;

     //PGDIR_SIZE=(1UL << PGDIR_SHIFT)=2M

     //一次处理2个连续的一级表项:2*1M = 2M
     do {
            unsigned long next = pgd_addr_end(addr, end);

            alloc_init_section(pgd, addr, next, phys, type);

            phys += next - addr;
            addr = next;
      } while (pgd++, addr != end);
}

 

//尝试使用段映射

static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
          unsigned long end, unsigned long phys,
          const struct mem_type *type)
{
     pmd_t *pmd = pmd_offset(pgd, addr); //一级表指针

     //pmd地址(32bits)        = ((mm)->pgd+((addr) >> 20) )

     

     /*  当大小和地址1MB对齐时,使用段映射 */
     if (((addr | end | phys) & ~SECTION_MASK) == 0) {
         pmd_t *p = pmd;

         if (addr & SECTION_SIZE)
              pmd++;

         do {
             *pmd = __pmd(phys | type->prot_sect);
             phys += SECTION_SIZE;
         } while (pmd++, addr += SECTION_SIZE, addr != end);

         //2MB,循环2次

         flush_pmd_entry(p);
      } else {
          /*  使用small页映射,必须为二级表分配空间4Kb(1page) */
          alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
       }
}

 

//small页映射

static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
      unsigned long end, unsigned long pfn,
      const struct mem_type *type)
{
     pte_t *pte;  //二级表指针

     

     //当一级表项内容为空时,为二级表项分配空间2*512*4 = 4Kb(1Page)

     if (pmd_none(*pmd)) {
         pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
          __pmd_populate(pmd, __pa(pte) | type->prot_l1);

         //给一级表项赋值,pmd为指针,指向需赋值的地址

         //pmdp[0] = __pmd(pmdval);
         //pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));

 

      }

      pte = pte_offset_kernel(pmd, addr);
      do {
          set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
          pfn++;
      } while (pte++, addr += PAGE_SIZE, addr != end);

      //2MB,2Mb/4Kb = 512次(最多)
}

 

 

 

.macro armv3_set_pte_ext wc_disable=1
 str r1, [r0], #-2048  @ linux version  MMU看到的h/w pte0/1

 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY

 bic r2, r1, #PTE_SMALL_AP_MASK @ keep C, B bits
 bic r2, r2, #PTE_TYPE_MASK
 orr r2, r2, #PTE_TYPE_SMALL

 tst r3, #L_PTE_USER   @ user?
 orrne r2, r2, #PTE_SMALL_AP_URO_SRW  @设置SVC模式为读写,USR模式为READONLY

 tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ write and dirty?
 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW 

设置SVC模式为读写,USR模式为不能读,PTE_SMALL_AP_URO_SRW | PTE_SMALL_AP_UNO_SRW为SVC & USR可读写

#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \
     L_PTE_WRITE)

#define _L_PTE_READ L_PTE_USER | L_PTE_EXEC

PAGE_SHARED 使用PAGE_SHARE映射的空间USR模式也能进行读写

关于读写的权限,参考ARM V5 reference.pdf  协处理器的C3寄存器和PTE的APx(3~0),PMD的domain参数

 tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young?
 movne r2, #0

 .if /wc_disable
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
 tst r2, #PTE_CACHEABLE
 bicne r2, r2, #PTE_BUFFERABLE
#endif
 .endif
 str r2, [r0]   @ hardware version
 .endm

 

3 Linux MMU

#define PTRS_PER_PTE512 { (h/w + s/w )  *  4byte = 4096 }
#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 2048

4 9260EK 内存映射情况

Author: WoodPecker <Pecker.hu@gmail.com>

 

import pymysql import pandas as pd import os import csv from sqlalchemy import create_engine, text from sqlalchemy.exc import SQLAlchemyError def import_csv_to_mysql(config): """ 将CSV文件数据导入MySQL数据库 参数: config (dict): 包含数据库连接和文件信息的配置字典 返回: bool: 导入成功返回True,失败返回False """ try: # 检查CSV文件是否存在 if not os.path.exists(config['csv_path']): raise FileNotFoundError(f"CSV文件不存在: {config['csv_path']}") # 创建数据库连接 connection_str = f"mysql+pymysql://{config['user']}:{config['password']}@{config['host']}/{config['database']}" engine = create_engine(connection_str, echo=False) # 获取目标表结构 with engine.connect() as conn: result = conn.execute(text(f"DESCRIBE `{config['table']}`")) table_columns = [row[0] for row in result] print(f"目标表 '{config['table']}' 的列: {table_columns}") # 读取CSV文件 with open(config['csv_path'], 'r', encoding=config.get('encoding', 'utf-8')) as f: csv_reader = csv.reader(f, delimiter=config.get('delimiter', ',')) headers = next(csv_reader) # 列映射检查 missing_columns = set(table_columns) - set(headers) if missing_columns: print(f"⚠️ 警告: CSV中缺少表列: {missing_columns}") column_mapping = {header: header for header in headers if header in table_columns} print(f"列映射: {column_mapping}") data_rows = [] for row in csv_reader: # 跳过空行 if not any(row): continue # 创建映射行 mapped_row = {} for csv_col, value in zip(headers, row): if csv_col in column_mapping: db_col = column_mapping[csv_col] mapped_row[db_col] = value data_rows.append(mapped_row) # 检查是否有有效数据 if not data_rows: print("❌ CSV文件中未找到有效数据") return False # 分批导入参数 chunk_size = 1000 total_rows = len(data_rows) success_count = 0 # 创建临时表 temp_table = f"temp_{config['table'].lower()}_{os.getpid()}" with engine.begin() as conn: # 创建临时表 conn.execute(text(f"CREATE TEMPORARY TABLE `{temp_table}` LIKE `{config['table']}`")) # 分批处理数据 for i in range(0, total_rows, chunk_size): # 获取当前批次数据 chunk = data_rows[i:i + chunk_size] # 转换为DataFrame并处理空值 df_chunk = pd.DataFrame(chunk) df_chunk = df_chunk.where(pd.notnull(df_chunk), None) try: # 导入到临时表 df_chunk.to_sql( name=temp_table, con=conn, if_exists='append', index=False ) success_count += len(chunk) print(f"✅ 已插入 {success_count}/{total_rows} 条记录") except Exception as e: print(f"❌ 批量插入失败: {e}") print(f"问题数据示例: {chunk[0] if chunk else '无数据'}") return False # 从临时表导入目标表 try: cols = ', '.join([f'`{col}`' for col in column_mapping.values()]) insert_sql = f""" INSERT INTO `{config['table']}` ({cols}) SELECT {cols} FROM `{temp_table}` """ conn.execute(text(insert_sql)) print(f"🎉 成功导入 {success_count} 条记录到表 '{config['table']}'") # 清理临时表 conn.execute(text(f"DROP TEMPORARY TABLE IF EXISTS `{temp_table}`")) return True except SQLAlchemyError as e: print(f"❌ 最终导入失败: {e}") return False except Exception as e: print(f"❌ 导入过程出错: {e}") return False # 使用示例 if __name__ == "__main__": # 配置参数 IMPORT_CONFIG = { 'host': 'localhost', # 数据库主机 'user': 'root', # 数据库用户名 'password': '123456', # 数据库密码 'database': 'bdpd_rmv', # 数据库名称 'table': 'RMV_KDSQ_MODEL_MODEL_INFO', # 目标表名 'csv_path': r'D:\历史项目留存2\诺褀2025\python加工浦发模型模拟\底层表模拟\RMV_KDSQ_MODEL_MODEL_INFO.csv', # CSV文件路径 'delimiter': ',', # CSV分隔符 'encoding': 'gbk' # 文件编码 } print("=== CSV数据导入MySQL ===") print(f"源文件: {IMPORT_CONFIG['csv_path']}") print(f"目标表: {IMPORT_CONFIG['table']}") # 执行导入 result = import_csv_to_mysql(IMPORT_CONFIG) # 输出结果 if result: print("✅ 数据导入完成") else: print("❌ 数据导入失败") 逐步解析这边的代码我是小白,第一次接触
最新发布
07-23
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值