Linux Kernel之flush_cache_all在ARM平台下是如何实现的【转】

简介:

转自:http://blog.csdn.net/u011461299/article/details/10199989

在驱动程序的设计中,我们可能会用到flush_cache_all将ARM cache的内容刷新到RAM,这是因为ARM Linux中cache一般会被设定为write back的。而通常象DMA是访问不了cache,所以如果我们需要启动DMA将RAM中的内容写到Flash中或LCD framebuffer,那么我们就需要调用flush_cache_all将cache中最新的内容刷新到RAM中。如果不这样做在LCD中可能会出现花屏。本文主要分析在ARM平台上到底如何实现的。

1.1                   flush_cache_all在ARM Linux中的实现

在include/asm-arm/cacheflush.h中:

#define flush_cache_all()             __cpuc_flush_kern_all()

#define __cpuc_flush_kern_all            cpu_cache.flush_kern_all

 

在setup_processor():

list = lookup_processor_type(processor_id);

//根据processor id找到对应ARM CPU(常见的如ARM926)相关的信息,存在list中。如果想把事情彻底搞清楚,必然要问processor_id是怎么来。它是在Linux Kernel启动时候从ARM chip中读出来。如果以后有机会大家一起讨论ARM Linux的启动全过程,可以详细分析。

      cpu_cache = *list->cache;

 

而lookup_processor_type定义在arch/arm/kernel/head-comman.S中:相应的assembler code如下:

     .type __lookup_processor_type, %function

__lookup_processor_type:

   adr   r3, 3f

   ldmda       r3, {r5 - r7}

   sub  r3, r3, r7                      @ get offset between virt&phys

   add  r5, r5, r3                      @ convert virt addresses to

   add  r6, r6, r3                      @ physical address space

1:         ldmia        r5, {r3, r4}                    @ value, mask

   and  r4, r4, r9                      @ mask wanted bits

   teq    r3, r4

   beq  2f

   add  r5, r5, #PROC_INFO_SZ            @ sizeof(proc_info_list)

   cmp r5, r6

   blo    1b

   mov  r5, #0                                    @ unknown processor

2:         mov  pc, lr

 

/*

 * This provides a C-API version of the above function.

 */

ENTRY(lookup_processor_type)

   stmfd        sp!, {r4 - r7, r9, lr}

   mov  r9, r0

   bl      __lookup_processor_type

   mov  r0, r5

   ldmfd        sp!, {r4 - r7, r9, pc}

 

/*

 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for

 * more information about the __proc_info and __arch_info structures.

 */

   .long          __proc_info_begin

   .long          __proc_info_end

3:         .long          .

   .long          __arch_info_begin

   .long          __arch_info_end

 

它其实就是到__proc_info_begin开始的section中去找到对应当前SOC中用的CPU Cache相关的operation list

再由arch/arm/kernel/vmlinux.lds.S可以__proc_info_begin就是section *(.proc.info.init)的开始地址。

            __proc_info_begin = .;

                   *(.proc.info.init)

            __proc_info_end = .;

而我们知道我们所用是ARM926,所以其定义在arch/arm/mm/proc-arm926.S:

     .section ".proc.info.init", #alloc, #execinstr

     .type       __arm926_proc_info,#object

__arm926_proc_info:

  .long       0x41069260                  @ ARM926EJ-S (v5TEJ)

  .long       0xff0ffff0

  .long   PMD_TYPE_SECT | \

         PMD_SECT_BUFFERABLE | \

         PMD_SECT_CACHEABLE | \

         PMD_BIT4 | \

         PMD_SECT_AP_WRITE | \

         PMD_SECT_AP_READ

  .long   PMD_TYPE_SECT | \

         PMD_BIT4 | \

         PMD_SECT_AP_WRITE | \

         PMD_SECT_AP_READ

  b     __arm926_setup

  .long       cpu_arch_name

  .long       cpu_elf_name

  .long         HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA

  .long       cpu_arm926_name

  .long       arm926_processor_functions

  .long       v4wbi_tlb_fns

  .long       v4wb_user_fns

  .long       arm926_cache_fns

     .size       __arm926_proc_info, . - __arm926_proc_info

arm926_cache_fns定义在同一个文件中,如下:

ENTRY(arm926_cache_fns)

  .long       arm926_flush_kern_cache_all

  .long       arm926_flush_user_cache_all

  .long       arm926_flush_user_cache_range

  .long       arm926_coherent_kern_range

  .long       arm926_coherent_user_range

  .long       arm926_flush_kern_dcache_page

  .long       arm926_dma_inv_range

  .long       arm926_dma_clean_range

  .long       arm926_dma_flush_range

 

它所对应的struct的定义:(include/asm-arm/cacheflush.h)

struct cpu_cache_fns {

  void (*flush_kern_all)(void);

  void (*flush_user_all)(void);

  void (*flush_user_range)(unsigned long, unsigned long, unsigned int);

 

  void (*coherent_kern_range)(unsigned long, unsigned long);

  void (*coherent_user_range)(unsigned long, unsigned long);

  void (*flush_kern_dcache_page)(void *);

 

  void (*dma_inv_range)(const void *, const void *);

  void (*dma_clean_range)(const void *, const void *);

  void (*dma_flush_range)(const void *, const void *);

};

所以其实flush_cache_all 在我们的项目中就是arm926_flush_kern_cache_all:其实现在同一个文件中:

/*

 *   flush_kern_cache_all()

*  Clean and invalidate the entire cache.

 */

ENTRY(arm926_flush_kern_cache_all)

  mov r2, #VM_EXEC

  mov ip, #0

__flush_whole_cache:

#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH

  mcr  p15, 0, ip, c7, c6, 0              @ invalidate D cache

#else

1:      mrc  p15, 0, r15, c7, c14, 3   @ test,clean,invalidate

  bne  1b

#endif

  tst   r2, #VM_EXEC

  mcrne     p15, 0, ip, c7, c5, 0              @ invalidate I cache

  mcrne     p15, 0, ip, c7, c10, 4            @ drain WB

  mov pc, lr

 

最后我们它不仅仅flush 所有的cache(包括ICache和DCache),也flush了Write Buffer。

















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5896366.html ,如需转载请自行联系原作者

相关文章
|
4月前
|
Ubuntu Linux
查看Linux系统架构的命令,查看linux系统是哪种架构:AMD、ARM、x86、x86_64、pcc 或 查看Ubuntu的版本号
查看Linux系统架构的命令,查看linux系统是哪种架构:AMD、ARM、x86、x86_64、pcc 或 查看Ubuntu的版本号
996 3
|
1月前
|
监控 Oracle 关系型数据库
Linux平台Oracle开机自启动设置
【11月更文挑战第8天】在 Linux 平台设置 Oracle 开机自启动有多种方法,本文以 CentOS 为例,介绍了两种常见方法:使用 `rc.local` 文件(较简单但不推荐用于生产环境)和使用 `systemd` 服务(推荐)。具体步骤包括编写启动脚本、赋予执行权限、配置 `rc.local` 或创建 `systemd` 服务单元文件,并设置开机自启动。通过 `systemd` 方式可以更好地与系统启动过程集成,更规范和可靠。
120 2
|
1月前
|
Oracle Ubuntu 关系型数据库
Linux平台Oracle开机自启动设置
【11月更文挑战第7天】本文介绍了 Linux 系统中服务管理机制,并详细说明了如何在使用 systemd 和 System V 的系统上设置 Oracle 数据库的开机自启动。包括创建服务单元文件、编辑启动脚本、设置开机自启动和启动服务的具体步骤。最后建议重启系统验证设置是否成功。
|
2月前
|
NoSQL Ubuntu Linux
Linux平台安装MongoDB
10月更文挑战第11天
79 5
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
116 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
3月前
|
存储 缓存 编译器
Linux kernel memory barriers 【ChatGPT】
Linux kernel memory barriers 【ChatGPT】
60 11
|
3月前
|
编解码 Linux 开发工具
Linux平台x86_64|aarch64架构RTMP推送|轻量级RTSP服务模块集成说明
支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。
|
4月前
|
Linux 网络安全 开发工具
内核实验(二):自定义一个迷你Linux ARM系统,基于Kernel v5.15.102, Busybox,Qemu
本文介绍了如何基于Linux Kernel 5.15.102版本和BusyBox创建一个自定义的迷你Linux ARM系统,并使用QEMU进行启动和调试,包括内核和BusyBox的编译配置、根文件系统的制作以及运行QEMU时的命令和参数设置。
405 0
内核实验(二):自定义一个迷你Linux ARM系统,基于Kernel v5.15.102, Busybox,Qemu
|
4月前
|
编解码 算法 Linux
Linux平台下RTSP|RTMP播放器如何跟python交互投递RGB数据供视觉算法分析
在对接Linux平台的RTSP播放模块时,需将播放数据同时提供给Python进行视觉算法分析。技术实现上,可在播放时通过回调函数获取视频帧数据,并以RGB32格式输出。利用`SetVideoFrameCallBackV2`接口设定缩放后的视频帧回调,以满足算法所需的分辨率。回调函数中,每收到一帧数据即保存为bitmap文件。Python端只需读取指定文件夹中的bitmap文件,即可进行视频数据的分析处理。此方案简单有效,但应注意控制输出的bitmap文件数量以避免内存占用过高。

热门文章

最新文章