Linux驱动开发 --- CCF时钟框架

news2024/11/27 18:43:04

0. CCF时钟框架概览

linux内核的CCF时钟框架可以分为三层,每一层的职责以及彼此的关系如下图所示
在这里插入图片描述
对CCF框架的分析也将以如下几个方向入手:

  1. consumer(也就是device driver)如何使用CCF
  2. provider如何借助CCF管理系统的时钟资源
  3. CCF内部的逻辑结构

1. provider如何借助CCF管理系统的时钟资源

1.1 系统中的时钟资源

Soc通过晶振和锁相环,提供硬件平台上所需的全部时钟,时钟之间往往具有复杂的继承关系,形成一个庞大的树状结构,如下图所示。
图1
在这里插入图片描述

clock相关的器件包括:

  1. 用于产生clock的Oscillator(有源振荡器,也称作谐振荡器)或者Crystal(无源振荡器,也称晶振)
  2. 用于倍频的PLL(锁相环,Phase Locked Loop);
  3. 用于分频的divider;
  4. 用于多路选择的Mux;
  5. 用于clock enable控制的与门;
  6. 使用clock的硬件模块等等。

1.2 如何组织时钟资源

SoC上的所有这些期间,在内核中都是用struct clk去抽象的。
在这里插入图片描述

一个系统的clock tree是固定的,因此clock的数目和用途也是固定的。为了处理所有clk对象的级联关系(如上图,hw2_clk和hw3_clk都关闭时,pll2_clk才能关闭),struct clk中必须有一个list_head字段来将所有clk对象关联起来。
系统启动时,clock driver会将所有的clk对象都初始化,当需要访问某个clock时,只需要通过某种方式去索引到对应clk对象即可。以前内核是通过名字作索引。
为了索引更加方便,可以利用设备和clk对象的一一对应性,通过在设备树中找到设备节点,进一步找到与它绑定的clk对象。

CCF以及provider的目标就是支持针对特定的时钟实现以下功能:
7. 使能/失能某个时钟
8. 设置clock的频率
9. 选择clock的parent,比如上图中的hw3_clk可以通过mux来选择使用osc/PLL3/PLL2来作为它的时钟源

1.3 如何描述时钟资源

provider的时钟资源在DTS中的描述

内核将clock provider的配置细节放在DTS中,两种典型的配置如下:
方式1:
将系统所有的clock,抽象为一个虚拟的设备(有一个算一个),用一个DTS node表示。
在这里插入图片描述
clock表示该clock设备的名称(phandle?),clock consumer可以根据该名称引用clock;
clock-cells字段表示这个clock是否有多个输出(0表示只有1个输出),如图1中,PLL1只有1个输出,PLL2有2个输出。

方式2:
每一个可输出clock的器件,如图一中Oscillator、PLL、Mux等等,都是一个设备,用一个DTS node表示。每一个器件,既是clock provider,也是clock consumer(根节点除外,如OSC),因为它需要接受clock输入,经过处理后,输出clock。

   1: /* arch/arm/boot/dts/sun4i-a10.dtsi */
   2: clocks {
   3:     #address-cells = <1>;
   4:     #size-cells = <1>;
   5:     ranges;
   6:  
   7:     /*
   8:      * This is a dummy clock, to be used as placeholder on
   9:      * other mux clocks when a specific parent clock is not
  10:      * yet implemented. It should be dropped when the driver
  11:      * is complete.
  12:      */
  13:     dummy: dummy {
  14:         #clock-cells = <0>;
  15:         compatible = "fixed-clock";
  16:         clock-frequency = <0>;
  17:     };
  18:  
  19:     osc24M: osc24M@01c20050 {
  20:         #clock-cells = <0>;
  21:         compatible = "allwinner,sun4i-osc-clk";
  22:         reg = <0x01c20050 0x4>;
  23:         clock-frequency = <24000000>;
  24:     };
  25:  
  26:     osc32k: osc32k {
  27:         #clock-cells = <0>;
  28:         compatible = "fixed-clock";
  29:         clock-frequency = <32768>;
  30:     };
  31:  
  32:     pll1: pll1@01c20000 {
  33:         #clock-cells = <0>;
  34:         compatible = "allwinner,sun4i-pll1-clk";
  35:         reg = <0x01c20000 0x4>;
  36:         clocks = <&osc24M>;

  54:     axi_gates: axi_gates@01c2005c {
  55:         #clock-cells = <1>;
  56:         compatible = "allwinner,sun4i-axi-gates-clk";
  57:         reg = <0x01c2005c 0x4>;
  58:         clocks = <&axi>;
  59:         clock-output-names = "axi_dram";
  60:     };
  61:  
  62:     ahb: ahb@01c20054 {
  63:         #clock-cells = <0>;
  64:         compatible = "allwinner,sun4i-ahb-clk";
  65:         reg = <0x01c20054 0x4>;
  66:         clocks = <&axi>;
  67:     };
  。。。。。。
 "ahb_de_fe1", "ahb_mp", "ahb_mali400";
  85:     };
  86:  
  87:     apb0: apb0@01c20054 {
  88:         #clock-cells = <0>;
  89:         compatible = "allwinner,sun4i-apb0-clk";
  90:         reg = <0x01c20054 0x4>;
  91:         clocks = <&ahb>;
  92:     };
  93:  
  94:     apb0_gates: apb0_gates@01c20068 {
  95:         #clock-cells = <1>;
  96:         compatible = "allwinner,sun4i-apb0-gates-clk";
  97:         reg = <0x01c20068 0x4>;
  98:         clocks = <&apb0>;
  99:         clock-output-names = "apb0_codec", "apb0_spdif",
 100:             "apb0_ac97", "apb0_iis", "apb0_pio", "apb0_ir0",
 101:             "apb0_ir1", "apb0_keypad";
 102:     };
 103:  
 104:     /* dummy is pll62 */
 105:     apb1_mux: apb1_mux@01c20058 {
 106:         #clock-cells = <0>;
 107:         compatible = "allwinner,sun4i-apb1-mux-clk";
 108:         reg = <0x01c20058 0x4>;
 109:         clocks = <&osc24M>, <&dummy>, <&osc32k>;
 110:     };
 111:  
 112:     apb1: apb1@01c20058 {
 113:         #clock-cells = <0>;
 114:         compatible = "allwinner,sun4i-apb1-clk";
 115:         reg = <0x01c20058 0x4>;
 116:         clocks = <&apb1_mux>;
 117:     };
 118:  
。。。。。

这些描述中既有只做clock provider工作的,也有既作provider也作consumer的
ahb_gates,它是clock provider(cell为1),通过clock-output-names关键字,描述所有的输出时钟。同时它也是clock consumer(由clocks关键字可知输入clock为“ahb”)。需要注意的是,clock-output-names关键字只为了方便clock provider编程方便

consumer在DTS中如何引用provider节点

clock consumer在dts中的描述一般有3种方式:
第一种对应provider描述中的第一种方式,一个clk对象对应一个dts节点。
clocks,指明该设备的clock列表,clk_get时,会以它为关键字,去device_node中搜索,以得到对应的struct clk指针;
clocks需要指明的信息,由clock provider的“#clock-cells”规定:为0时,只需要提供一个clock provider name(称作phandle);为1时,表示phandle有多个输出,则需要额外提供一个ID,指明具体需要使用那个输出。这个例子直接用立即数表示,更好的做法是,将系统所有clock的ID,定义在一个头文件中,而DTS可以包含这个头文件,如“clocks = <&clock CLK_SPI0>”;
clock-names,为clocks指定的那些clock分配一些易于使用的名字,driver可以直接以名字为参数
在这里插入图片描述
第二种:如果clock provider的“#clock-cells”为0,可直接引用该clock provider的名字
第三种:如果clock provider的节点中#clock-cells为1,并通过clock-output-names指定了所有的输出clock
consumer中的引用如下:
clocks字段引用所需provider的phandle,后面的数字为这个provider输出的ID号
一般来说不会直接用立即数,而是用一个头文件存储所有的ID号,provider和consumer节点甚至clk驱动都同时引用这个头文件,这样三者就很轻易地在ID号上达成了一致的协议。
在这里插入图片描述

Provider提供的API汇整

struct clk由CCF框架用于描述clock对象,对consumer和provider都是透明的。
在provider层,CCF为其提供了struct clk_hw(hw hardware,好吧,驱动不就是和硬件打交道)
struct clk_hw是对struct clk的继承

   1: struct clk_hw {
   2:         struct clk *clk;
   3:         const struct clk_init_data *init;
   4: };

clk,struct clk指针,由clock framework分配并维护,并在需要时提供给clock consumer使用;

**init,描述该clock的静态数据,clock provider负责把系统中每个clock的静态数据准备好,然后交给clock framework的核心逻辑,剩下的事情,clock provider就不用操心了。**这个过程,就是clock driver的编写过程,简单吧?该静态数据的数据结构如下。

   1: struct clk_init_data {
   2:         const char              *name;
   3:         const struct clk_ops    *ops;
   4:         const char              **parent_names;
   5:         u8                      num_parents;
   6:         unsigned long           flags;
   7: };

name,该clock的名称;
ops,该clock相关的操作函数集,具体参考下面的描述;
parent_names,该clock所有的parent clock的名称。这是一个字符串数组,保存了所有可能的parent;
num_parents,parent的个数;
flags,一些framework级别的flags,后面会详细说明。

clk_ops是clock的操作函数集,其中很多API的名字都将在介绍 给cousumer层使用的通用API 的名字是相同的

1: struct clk_ops {
   2:         int             (*prepare)(struct clk_hw *hw);
   3:         void            (*unprepare)(struct clk_hw *hw);
   4:         int             (*is_prepared)(struct clk_hw *hw);
   5:         void            (*unprepare_unused)(struct clk_hw *hw);
   6:         int             (*enable)(struct clk_hw *hw);
   7:         void            (*disable)(struct clk_hw *hw);
   8:         int             (*is_enabled)(struct clk_hw *hw);
   9:         void            (*disable_unused)(struct clk_hw *hw);
  10:         unsigned long   (*recalc_rate)(struct clk_hw *hw,
  11:                                         unsigned long parent_rate);
  12:         long            (*round_rate)(struct clk_hw *hw, unsigned long,
  13:                                         unsigned long *);
  14:         int             (*set_parent)(struct clk_hw *hw, u8 index);
  15:         u8              (*get_parent)(struct clk_hw *hw);
  16:         int             (*set_rate)(struct clk_hw *hw, unsigned long,
  17:                                     unsigned long);
  18:         void            (*init)(struct clk_hw *hw);
  19: };

is_prepared,判断clock是否已经prepared。可以不提供,clock framework core会维护一个prepare的计数(该计数在clk_prepare调用时加一,在clk_unprepare时减一),并依据该计数判断是否prepared;

unprepare_unused,自动unprepare unused clocks;

is_enabled,和is_prepared类似;

disable_unused,自动disable unused clocks;

注2:clock framework core提供一个clk_disable_unused接口,在系统初始化的late_call中调用,用于关闭unused clocks,这个接口会调用相应clock的.unprepare_unused和.disable_unused函数。

recalc_rate,以parent clock rate为参数,从新计算并返回clock rate;

注3:细心的读者可能会发现,该结构没有提供get_rate函数,因为会有一个rate变量缓存,另外可以使用recalc_rate。

round_rate,该接口有点特别,在返回rounded rate的同时,会通过一个指针,返回round后parent的rate。这和CLK_SET_RATE_PARENT flag有关,后面会详细解释;

init,clock的初始化接口,会在clock被register到内核时调用。

clock tree如何建立,CCF提供的API汇整:

系统中,每一个clock都有一个struct clk_hw变量描述,clock provider需要使用register相关的接口,将这些clock注册到kernel,clock framework的核心代码会把它们转换为struct clk变量,即
struct hw_clk --> struct clk
并以tree的形式组织起来。这些接口的原型如下:

struct clk *clk_register(struct device *dev, struct clk_hw *hw);
struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
void clk_unregister(struct clk *clk);
void devm_clk_unregister(struct device *dev, struct clk *clk);

这些接口比较好理解,传入填充好的struct clk_hw并将它转化为struct clk结构,根据parent的名字添加到clock tree中
不过,clock framework所做的远比这周到,它基于clk_register,又封装了其它接口,使clock provider在注册clock时,连struct clk_hw都不需要关心,而是直接使用类似人类语言的方式,下面继续。
根据clock的特点,clock framework将clock分为fixed rate、gate、devider、mux、fixed factor、composite六类,每一类clock都有相似的功能、相似的控制方式,因而可以使用相同的逻辑s,统一处理,这充分体现了面向对象的思想。分类有如下几种:

  1. fixed rate clock
    这一类clock具有固定的频率,不能开关、不能调整频率、不能选择parent、不需要提供任何的clk_ops回调函数,是最简单的一类clock。
    可以直接通过DTS配置的方式支持,clock framework core能直接从DTS中解出clock信息,并自动注册到kernel,不需要任何driver支持。
    clock framework使用struct clk_fixed_rate结构抽象这一类clock,另外提供了一个接口,可以直接注册fixed rate clock,如下:
   6: struct clk_fixed_rate {
   7:         struct          clk_hw hw;
   8:         unsigned long   fixed_rate;
   9:         u8              flags;
  10: };
  11:  
  12: extern const struct clk_ops clk_fixed_rate_ops;
  13: struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
  14:                 const char *parent_name, unsigned long flags,
  15:                 unsigned long fixed_rate);
clock provider一般不需要直接使用struct clk_fixed_rate结构,因为clk_register_fixed_rate接口是非常方便的;

clk_register_fixed_rate接口以clock name、parent name、fixed_rate为参数,创建一个具有固定频率的clock,该clock的clk_ops也是clock framework提供的,不需要provider关心;

如果使用DTS的话,clk_register_fixed_rate都不需要,直接在DTS中配置即可,后面会说明。
  1. gate clock
    这一类clock只可开关(会提供.enable/.disable回调),可使用下面接口注册:
  1: struct clk *clk_register_gate(struct device *dev, const char *name,
   2:                 const char *parent_name, unsigned long flags,
   3:                 void __iomem *reg, u8 bit_idx,
   4:                 u8 clk_gate_flags, spinlock_t *lock);
需要提供的参数包括:
name,clock的名称;
parent_name,parent clock的名称,没有的话可留空;
flags
reg,控制该clock开关的寄存器地址(虚拟地址);
bit_idx,控制clock开关的bit位(是1开,还是0开,可通过下面gate特有的flag指定);
clk_gate_flags,gate clock特有的flag,当前只有一种:CLK_GATE_SET_TO_DISABLE,clock开关控制的方式,如果置位,表示写1关闭clock,反之亦然;
lock,如果clock开关时需要互斥,可提供一个spinlock。
  1. divider clock
    这一类clock可以设置分频值(因而会提供.recalc_rate/.set_rate/.round_rate回调),可通过下面两个接口注册:
 1: struct clk *clk_register_divider(struct device *dev, const char *name,
   2:                 const char *parent_name, unsigned long flags,
   3:                 void __iomem *reg, u8 shift, u8 width,
   4:                 u8 clk_divider_flags, spinlock_t *lock);
该接口用于注册分频比规则的clock:

reg,控制clock分频比的寄存器;

shift,控制分频比的bit在寄存器中的偏移;

width,控制分频比的bit位数,默认情况下,实际的divider值是寄存器值加1。如果有其它例外,可使用下面的的flag指示;

clk_divider_flags,divider clock特有的flag,包括:

        CLK_DIVIDER_ONE_BASED,实际的divider值就是寄存器值(0是无效的,除非设置CLK_DIVIDER_ALLOW_ZERO flag);
        CLK_DIVIDER_POWER_OF_TWO,实际的divider值是寄存器值得2次方;
        CLK_DIVIDER_ALLOW_ZERO,divider值可以为0(不改变,视硬件支持而定)。

如有需要其他分频方式,就需要使用另外一个接口,如下:
  1. mux clock
  2. fixed factor clock
  3. composite clock

CCF如何帮助provider解析DTS

clock driver使用一个DTS node描述一个clock provider,而clock consumer则会使用类似“clocks = <&clock 32>, <&clock 45>;”的形式引用,clock framework会自行把这些抽象的数字转换成实际的struct clk结构,怎么做的呢?肯定离不开clock provider的帮助。
前面介绍的clk_register_xxx函数负责把clocks抽象为一个一个的struct clock,与此同时,clock provider需要把这些struct clk结构保存起来,并调用clock framework的接口,将这些对应信息告知framework的OF模块,这样才可以帮助将clock consumer的DTS描述转换为struct clk结构。

   1: int of_clk_add_provider(struct device_node *np,
   2:                         struct clk *(*clk_src_get)(struct of_phandle_args *args,
   3:                                                    void *data),
   4:                         void *data);

np,device_node指针,clock provider在和自己的DTS匹配时获得;
clk_src_get,获取struct clk指针的回调函数,由clock provider根据实际的逻辑实现,参数说明如下
args,struct of_phandle_args类型的指针,由DTS在解析参数时传递。例如上面的“clocks = <&clock 32>, <&clock 45>;”,32、45就是通过这个指针传进来的;
data,保存struct clk结构的指针,通常是一个数组,具体由provider决定。
data,和回调函数中的data意义相同,只是这里由provider提供,get时由clock framework core传递给回调函数。
对于常用的one cell clock provider(第2章的例子),clock framework core提供一个默认的会调用函数,如下:

   1: struct clk_onecell_data {
   2:         struct clk **clks;
   3:         unsigned int clk_num;
   4: };
   5: struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
  1. 使用clock framework编写clock驱动的步骤
    编写clock driver的步骤大概如下:

1)分析硬件的clock tree,按照上面所描述的分类,讲这些clock分类。

2)将clock tree在DTS中描述出来,需要注意以下几2点:

    a)对于fixed rate clocks,.compatible固定填充"fixed-clock",并提供"clock-frequency"和"clock-output-names"关键字。之后不需要再driver中做任何处理,clock framework core会帮我们搞定一切。

    b)同样,对于fixed factor clock,.compatible为"fixed-factor-clock",并提供"clock-div"、"clock-mult"和"clock-output-names"关键字。clock framework core会帮我们搞定一切。

    切记,尽量利用kernel已有资源,不要多写一行代码,简洁的就是美的!

3)对于不能由clock framework core处理的clock,需要在driver中使用struct of_device_id进行匹配,并在初始化时,调用OF模块,查找所有的DTS匹配项,并执行合适的regitser接口,注册clock。

4)注册clock的同时,将返回的struct clk指针,保存在一个数组中,并调用of_clk_add_provider接口,告知clock framework core。

5)最后,也是最重要的一点,多看kernel源代码,多模仿,多抄几遍,什么都熟悉了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/537975.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端BFC

一、首先我们要先了解常见的定位方案&#xff0c;总共3种&#xff08;普通流、浮动、绝对定位&#xff09; 而BFC是属于普通流的 我们可以把BFC看作为页面的一块渲染区域&#xff0c;他有着自己的渲染规则 简单来说BFC可以看作元素的一种属性&#xff0c;当元素拥有了BFC属性…

ChatGPT:2. 使用OpenAI创建自己的AI网站:1. 初探API

使用OpenAI创建自己的AI网站 如果你还是一个OpenAI的小白&#xff0c;有OpenAI的账号&#xff0c;但想调用OpenAI的API搞一些有意思的事&#xff0c;那么这一系列的教程将仔细的为你讲解如何使用OpenAI的API制作属于自己的AI网站。博主只能利用下班时间更新&#xff0c;进度慢…

自学spring个人笔记

目录 如何学习spring&#xff1f; 如何查看自己电脑是否安装了spring boot Spring Boot CLI安装成功 springboot的版本2.7.12(SNAPSHOT)与2.7.11有什么区别&#xff1f; 报错解决 Plugin org.springframework.boot:spring-boot-maven-plugin:not found 在maven pom.xml中…

【AFNetWorking源码(二)AFURLSessionManger和AFHTTPSessionManager】

前言 学习了Mananger的初始化和以GET请求为例的过程&#xff0c;发现整个过程离不开AFHTTPSessionManager和AFURLSessionManger的某些方法。这两个是AFN的重要的网络通信模块内容&#xff0c;对它们作揖详细的学习。 AFURLSessionManager和AFHTTPSessionManager都是AFNetwork…

chatgpt赋能Python-mac电脑安装python

在Mac电脑上轻松安装Python Python是一种高级编程语言&#xff0c;常用于数据科学、机器学习和Web开发等领域。如果你是一名Mac电脑用户&#xff0c;那么安装Python将会让你受益匪浅。本文将提供详细的操作步骤&#xff0c;让你轻松安装Python并开始学习编程。 第一步&#x…

【Linux】进程地址空间(带你认清内存的本质)

&#x1f525;&#x1f525; 欢迎来到小林的博客&#xff01;&#xff01;       &#x1f6f0;️博客主页&#xff1a;✈️小林爱敲代码       &#x1f6f0;️博客专栏&#xff1a;✈️Linux之路       &#x1f6f0;️社区 :✈️ 进步学堂       &a…

Linux:chmod chown 权限管理

基础权限有以下三个 r 读 4 w 写 2 x 执行 1 - 无此权限 0 开头的第一个字母是这个的类型 d 目录 - 普通文件 l 链接文件 常见的三种 只不过今天不讲这个 从第二个字母开始看起 三个字母为一组 一共…

【EfficientDet】《EfficientDet:Scalable and Efficient Object Detection》

CVPR-2020 文章目录 1 Background and Motivation2 Related Work3 Advantages / Contributions4 Method4.1 BiFPN4.2 EfficientDet 5 Experiments5.1 Datasets5.2 EfficientDet for Object Detection5.3 EfficientDet for Semantic Segmentation5.4 Ablation Study 6 Conclusio…

RocketMQ你不得不了解的 Rebalance机制源码分析

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 RocketMQ版本 version: 5.1.0 RocketMQ中consumer消费模型 在了解RocketMQ的Rebalance机制之前&#xff0c;我们必须先简单了解下rocketmq的消费模型 我们知道…

chatgpt赋能Python-left函数_python

Left 函数在Python中的使用及其优点 在Python编程语言中&#xff0c;字符串处理是不可避免的任务。Python提供了许多内置函数来处理字符串&#xff0c;其中left()函数是其中一个非常重要的函数。本文将介绍left()函数的用法、优点和一些实例&#xff0c;以便更好的理解该函数。…

redis高级篇(2)---主从

一)搭建主从架构: 单节点Redis的并发能力是有限的&#xff0c;所以说要想进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离&#xff0c;因为对于Redis来说大部分都是读多写少的场景&#xff0c;更多的要进行读的压力&#xff0c;最基本都要是…

【Android学习专题】java基本语法和概念(学习记录)

学习记录来自菜鸟教程 Java 变量 Java 中主要有如下几种类型的变量 局部变量 在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中&#xff0c;方法结束后&#xff0c;变量就会自动销毁类变量&#xff08;静态变量&#xff09; 类变量也声…

chatgpt赋能Python-libreoffice_python宏

介绍 LibreOffice是一套免费开源的办公软件&#xff0c;其中包含一个强大的Python宏系统&#xff0c;可以使用Python编写脚本来增强办公软件的功能。本文将介绍LibreOffice Python宏是什么&#xff0c;如何使用Python编写宏&#xff0c;并提供一些示例&#xff0c;以便读者可以…

去付款--支付宝沙箱的简单测试

alipay-demo 进入开发者中心–开发工具–沙箱–设置公钥 搜索电脑网上支付–查看Demo–查看配置类–查看业务逻辑 我们的基础配置类主要是初始化我们的alipay客户端 真正去付款的时候是提交了一个form表单达到一个真正的支付jsp,java代码首先初始化我买的Alipay客户端&#xf…

瑞吉外卖 - 新增分类功能(11)

某马瑞吉外卖单体架构项目完整开发文档&#xff0c;基于 Spring Boot 2.7.11 JDK 11。预计 5 月 20 日前更新完成&#xff0c;有需要的胖友记得一键三连&#xff0c;关注主页 “瑞吉外卖” 专栏获取最新文章。 相关资料&#xff1a;https://pan.baidu.com/s/1rO1Vytcp67mcw-PD…

网安学习踩坑经验篇

回想学习网络安全一年来&#xff0c;踩了不少坑走了不少弯路&#xff0c;在此稍作总结&#xff0c;希望可以帮助那些想要入门 web 安全或者是想打CTF的同学们一些建议 坑点 先总结一下&#xff0c;我在学习中遇到的坑点 只看视频&#xff0c;眼高手低&#xff0c;不练习&…

【嵌入式Linux】设备树基本语法

设备树基本语法 1_总领-本期设备树视频要怎么讲&#xff1f;讲什么&#xff1f;_哔哩哔哩_bilibili 基本的 特殊的 中断控制 描述GIC控制器 时钟 CPU GPIO 个数&#xff0c;保留范围&#xff08;起始、长度&#xff09;&#xff0c;个数对应的名字 GPIO映射-这个脚被用了换一…

chatgpt赋能Python-numpy_归一化

NumPy归一化&#xff1a;理解数据规范化的重要性 什么是归一化&#xff1f; 在数据科学和机器学习中&#xff0c;归一化是预处理数据的一种常用技术。归一化是指将数据缩放到一个特定的范围内&#xff0c;通常是0到1或-1到1之间。 例如&#xff0c;我们可能比较一家医院的三…

渗透测试--5.3.使用john破解密码

前言 由于Linux是Internet最流行的服务器操作系统&#xff0c;因此它的安全性备受关注。这种安全主要靠口令实现。 Linux使用一个单向函数crypt&#xff08;&#xff09;来加密用户口令。单向函数crypt&#xff08;&#xff09;从数学原理上保证了从加密的密文得到加密前的明…

Java笔记_22(反射和动态代理)

Java笔记_22 一、反射1.1、反射的概述1.2、获取class对象的三种方式1.3、反射获取构造方法1.4、反射获取成员变量1.5、反射获取成员方法1.6、综合练习1.6.1、保存信息1.6.2、跟配置文件结合动态创建 一、反射 1.1、反射的概述 什么是反射? 反射允许对成员变量&#xff0c;成…