你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

uboot的升级中比较有意思的两个问题

[复制链接]
gaosmile 发布时间:2020-9-11 15:02
背景- }( H' o. t+ c% [# u+ x+ |
: v& n- Q: r5 t& ~! b
之前做过一次uboot的升级,当时留下了一些记录,本文摘录其中比较有意思的两个问题。) f( R2 |# \" O& B  w
+ j9 K: Y% {( G1 ^/ u) I; ~

0 y2 U$ f- g8 K8 X+ c启动失败问题
- B% {9 e9 h; d' h% y  {问题简述
$ C; M! `  W$ v2 |! Y3 A& P# Kuboot代码中用到了一个库,考虑到库本身跟uboot版本没什么关系,就直接把旧的库文件拷贝过来使用。结果编译链接是没问题,启动却会卡住。
6 a7 X% _' \( `9 C* V1 Q  E* f. q) T) i/ o& ~6 s  L0 O
4 f% ^5 i9 d! z: y8 \2 u
消失的打印
6 O5 [# ~  f6 h9 e; E为了明确卡住的位置,就去修改了库的源码,添加一些打印(此时还是在旧版本uboot下编译的),结果发现卡住的位置或随着添加打印的变化而变化,且有些打印语句,添加后未打印出来。
- G9 a- c- Y+ P. Y2 ]1 J0 f  m我决定先从这些神秘消失的打印入手。
) A* r8 K0 N% Z& ~) k- v3 J% T分析下uboot中的printf实现,最底层就是写寄存器,是一个同步的函数,也没什么可疑的地方。) s1 z! `9 |1 ]" U( S
为了确认打印不出来的时候,到底有没有调用到printf,我决定给printf增加一个计数器,在gd结构体中,增加一个printf_count字段,初始化为0,每次打印时执行printf_count++并打印出值。
8 G2 @1 ]1 X. m6 D. L9 ]设计这个试验,本意是确认未打印出来时是否确实也调用到了printf,但却有了别的发现,实验结果中printf_count值会异常变化,不是按打印顺序递增,而是会突变成很大的异常值。! K6 r1 D0 G9 b3 J
printf_count是gd结构体的成员,那就是gd的问题了。进一步将uboot全局结构体gd的地址打印出来。确认了原因是gd结构体的指针变化了。  _& b. o* U! E; t( s7 F6 {
这也可以解释部分打印消失的现象,原因是我们在gd中有另一个字段,用于控制打印等级。当gd被改动了,printf就可能解析出错,误以为打印等级为0而提前返回。) j& ~1 _6 Y: s# N1 _
& `# t+ D3 u/ T

  g# j) M1 b9 s4 A8 ~gd的实现- {2 J( z2 S" N1 k7 h
那么好端端的,gd为什么会被改了呢?这就要先看看gd到底是怎么实现的了。uboot中维护了一个全局的结构体gd。在代码中加入DECLARE_GLOBAL_DATA_PTR;
4 b' I/ q* b$ r% }. ?, H" s  @2 @/ f6 P& }1 K
即可使用gd指针访问这个全局结构体,许多地方都会借助gd来保存传递信息。进一步看看这个宏的定义2 \, \5 y" l4 {6 a
旧版本uboot:
- F( ~% x, Q" P* n#define DECLARE_GLOBAL_DATA_PTR        register volatile gd_t *gd asm ("r8")
. e3 q3 S/ o0 X7 z; _
( o+ R6 E/ c) g) f* L: A新版本uboot:$ k! S7 A1 X9 {
#define DECLARE_GLOBAL_DATA_PTR        register volatile gd_t *gd asm ("r9")5 e% C5 J/ ~( r2 Q  T' `
居然不一样,一个是将gd的值放到r8寄存器,一个是放在r9寄存器。% d. |. G1 e  w3 ?, m  D) R$ u" f
那么就可以猜测到,库是在旧版本uboot中编译出来的,可能使用了r9,那么放到新版本uboot中去,就会破坏r9寄存器中保存的gd值,导致一系列依赖gd的代码不能正常工作。
$ F2 {9 K$ i; {2 `6 g, J/ U; ^& N3 E1 V& x/ m+ S& C. W

; }/ `) S4 u8 N验证改动- \. F+ s: P& c& X- g
为了求证,将库反汇编出来,发现确实避开了r8寄存器,但使用了r9寄存器。
2 \8 E2 O; a* ]8 S* ?- s. Q说明uboot在指定gd寄存器的同时,还有某种方法让其他代码不使用这个寄存器。
0 q  O' ?# M6 L4 Z那是不是把旧uboot中的这个r8改成r9,重新编译库就可以了呢?试一下,还是不行。0 |+ E% |5 H. V' |' ]0 c
那么禁止其他代码使用r8寄存器肯定就是通过别的方式实现的了。简单粗暴地在旧版本uboot下搜索r8,去掉.c .h等类型后,很容易发现了
+ R. U# M- Z! H* \. o) z  h./arch/arm/cpu/armv7/config.mk:24LATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-floa+ D; H" W1 \, s- h
将-ffixed-r8修改为-ffixed-r9,重新编译出库,这回就可以正常工作了,打印正常,启动正常。反汇编出来也可以看到,新编译出来的库用了r8没有用r9。
9 ], D9 ~# t: w5 J* C( M当然更好的改法,是直接在新版本的uboot中编译,这是最可靠的。9 \7 n3 g2 i0 q. I0 I& W" E

2 S% u( ?, Z  L; r2 C4 O" U  h1 ~

8 j0 D/ h3 S0 \1 Y% E% a1 E追本溯源) {' a5 _1 w. u, g- n
话说回来,为什么两个版本的uboot,会使用不同的寄存器呢?难道有什么坑?这就得去翻一下git记录了。5 j! M3 w8 e. Y4 n! a' e& S
commit fe1378a961e508b31b1f29a2bb08ba1dac063155& g$ H' L# d- j6 ]2 J* i; m$ Z) X
Author: Jeroen Hofstee <jeroen@myspectrum.nl>
$ E) J- c8 T- ~Date:   Sat Sep 21 14:04:41 2013 +0200# N* P$ W; t( T0 J$ ?- l; w  Y
; |' x" O. p+ [9 A
    ARM: use r9 for gd
$ @; k8 s1 u- q   
) |9 |! A1 Q0 L' }+ }% C; }6 Z    To be more EABI compliant and as a preparation for building
, v. Q/ g( b& k  S- I2 e! U    with clang, use the platform-specific r9 register for gd
8 I$ m# z) K4 `3 p$ U# p    instead of r8.5 q% {5 R' ^  l, p6 [
    9 f+ j! z4 w% |# E; x3 d9 Y+ t7 X9 l
    note: The FIQ is not updated since it is not used in u-boot,$ N4 m$ U* D5 a& s" K
    and under discussion for the time being.
$ E9 D3 x6 }8 ~. o. V# L5 \- O    ) n4 z% A) S8 @: T
    The following checkpatch warning is ignored:
% X9 I. @  t& D    WARNING: Use of volatile is usually wrong: see
1 Q( _& S- }* B% N5 A' G6 L1 L    Documentation/volatile-considered-harmful.txt' j4 `( N% b5 |* p0 q4 U
   
# D9 H+ \8 c( l! w    Signed-off-by: Jeroen Hofstee <jeroen@myspectrum.nl>2 A. M; m9 a# Q% o+ y
    cc: Albert ARIBAUD <albert.u.boot@aribaud.net>

, }3 [2 d" `- z) N" g3 Y# a+ |+ p# s9 v- l
从git记录中,也可以确认完整地将r8切换到r9,都需要做哪些修改  A, g! z+ @6 ]. d+ v5 J
diff --git a/arch/arm/config.mk b/arch/arm/config.mk2 v  C) v& I7 W; F5 g/ F8 y$ ]6 T
index 16c2e3d1e0..d0cf43ff41 100644
. d4 J2 T. K2 t) U--- a/arch/arm/config.mk3 e! M9 F6 M% x. q$ R
+++ b/arch/arm/config.mk
4 m5 X! ?  e9 `* q' m8 f& j@@ -17,7 +17,7 @@ endif
: p8 Y& x$ m7 ?% t2 X9 z9 g, L : |5 I, T; q( Q+ \
LDFLAGS_FINAL += --gc-sections& r+ A& O4 c: \: i- q; Q
PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections \0 F2 s1 X% w* O( V' j& |  S
-                     -fno-common -ffixed-r8 -msoft-float
0 f, `9 v+ z" x) z+                     -fno-common -ffixed-r9 -msoft-float
0 P$ @: l1 ?: w9 C# r
4 \% l2 z% b7 [  p- y: U- t # Support generic board on ARM% j4 n6 O5 {! u$ h+ h) Q
__HAVE_ARCH_GENERIC_BOARD := y) |4 V- n% U8 S3 A
diff --git a/arch/arm/cpu/armv7/lowlevel_init.S b/arch/arm/cpu/armv7/lowlevel_init.S
8 S' c* A9 t' `) F; y  J+ kindex 82b2b86520..69e3053a42 100644
0 V3 D* `. J+ L+ X" T7 a--- a/arch/arm/cpu/armv7/lowlevel_init.S
' J3 w" @; F  ]/ q5 I+++ b/arch/arm/cpu/armv7/lowlevel_init.S
; S- W+ H0 V! C! i4 B' _" O@@ -22,11 +22,11 @@ ENTRY(lowlevel_init)8 \) t3 R* Q  P" J% g  d3 i" L
        ldr     sp, =CONFIG_SYS_INIT_SP_ADDR
5 e6 C3 G$ x* c" y2 E        bic     sp, sp, #7 /* 8-byte alignment for ABI compliance */  m; l4 U: P# R" U! C. _
#ifdef CONFIG_SPL_BUILD
# Q3 {# H: p5 n: {) C8 @; G-       ldr     r8, =gdata5 H1 U, Q7 E, @
+       ldr     r9, =gdata
+ F$ [' a4 G6 ?. j& d #else2 y4 u% \1 Q& C4 g, k  _
        sub     sp, #GD_SIZE& j; j) \1 k/ r% E
        bic     sp, sp, #72 k/ [2 U9 I- l6 T; y# k4 x# d+ h
-       mov     r8, sp
+ I8 Y  Q9 O# u' W" X+       mov     r9, sp; X! L3 D+ {: F( [, j1 d
#endif
* O) d7 a) |6 w, X7 F9 ?        /*
$ W" l  I- D) Q% M         * Save the old lr(passed in ip) and the current lr to stack
* ]+ ?0 l7 O* c* cdiff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
) u! m( I" f8 }& f' H  }3 Vindex 79a9597419..e126436093 100644
9 w( [+ |- w- w1 |7 Z) B: `--- a/arch/arm/include/asm/global_data.h' J7 {) l3 b2 G8 g! ^# R
+++ b/arch/arm/include/asm/global_data.h7 `# m5 Z; M, |9 R
@@ -47,6 +47,6 @@ struct arch_global_data {
9 k$ D/ B. `: Q7 f
! q. q( s8 X8 { #include <asm-generic/global_data.h>
& d/ B; X; j" l3 U2 J; |# U , n* }8 R/ f) c
-#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
) D7 e5 O; C6 B9 T" T+#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r9")
6 `( K; _4 F+ |. d# V- c" ^
* n* T3 b# m, G  H! o& }% @ #endif /* __ASM_GBL_DATA_H */

6 ?: v8 p! o/ S) Ydiff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S# e0 [( @) a9 \& w, J
index 960d12e732..ac54b9359a 100644  k" @) ~  J' l  v9 M7 `
--- a/arch/arm/lib/crt0.S. a# j, H8 @  `" }  w8 k& i, ?
+++ b/arch/arm/lib/crt0.S
& S" x1 n& Z; x& ~) K* a@@ -69,7 +69,7 @@ ENTRY(_main)
, m4 a+ g% q9 V) ]        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
1 E+ m) N& k/ G        sub     sp, #GD_SIZE    /* allocate one GD above SP */9 V  }, {* u* o, Q! q
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */1 T9 ?( \. b& e
-       mov     r8, sp          /* GD is above SP */
0 ]( Q  G4 g6 P+       mov     r9, sp          /* GD is above SP */! H7 N) |! o* B6 l/ ]0 r" c, S; Y
        mov     r0, #08 H& |( g7 S( p/ e6 `+ b
        bl      board_init_f9 f$ r# z5 f* R+ [8 ]

7 N; \1 p# l3 {6 S9 Z; B@@ -81,15 +81,15 @@ ENTRY(_main)8 w' k6 j. q2 R% M
  * 'here' but relocated.
" l% _. R2 o. w! X  */& }) I1 E' Y' ]

  E$ {. I0 F" m9 y( [) R$ n* B; z-       ldr     sp, [r8, #GD_START_ADDR_SP]     /* sp = gd->start_addr_sp */
8 t- e" z7 M6 K1 O+       ldr     sp, [r9, #GD_START_ADDR_SP]     /* sp = gd->start_addr_sp */6 m+ B% t4 e) r/ e/ f8 X
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
5 L: B1 d7 e! L-       ldr     r8, [r8, #GD_BD]                /* r8 = gd->bd */
9 f$ P" b  p& r( N+ W/ }-       sub     r8, r8, #GD_SIZE                /* new GD is below bd */( k) e8 [6 Y0 Q2 W3 ]- M- f4 Y
+       ldr     r9, [r9, #GD_BD]                /* r9 = gd->bd */; c' j5 V$ e1 O: ~" e! p
+       sub     r9, r9, #GD_SIZE                /* new GD is below bd */
( B0 v+ G2 \- v5 g$ T6 F 1 P7 l% ]8 W, P3 B) w( X  I: l. X8 P
        adr     lr, here
) F; F1 X9 T. y* E# A1 u-       ldr     r0, [r8, #GD_RELOC_OFF]         /* r0 = gd->reloc_off */. E3 \( l" q8 e  ]; n: |1 c, U( t
+       ldr     r0, [r9, #GD_RELOC_OFF]         /* r0 = gd->reloc_off */  W; N8 E- n$ L  [9 q% a
        add     lr, lr, r0
4 c9 a6 e2 F4 m6 O& ]-       ldr     r0, [r8, #GD_RELOCADDR]         /* r0 = gd->relocaddr */
+ ^2 K( h* P# Z4 b+ v7 ~* m3 a+       ldr     r0, [r9, #GD_RELOCADDR]         /* r0 = gd->relocaddr */; ?* S/ |4 _( L9 ~- j% {
        b       relocate_code2 _9 ]" F( M2 u" T
here:
; _% i: n' `4 |+ S! X- k 6 D4 ~% O7 X3 ~
@@ -111,8 +111,8 @@ clbss_l:cmp r0, r1                  /* while not at end of BSS */
4 a6 ]. w4 G/ U6 n        bl red_led_on/ d3 x3 N* I4 F7 r! N
. W9 r3 {# y$ U1 H& c6 G
        /* call board_init_r(gd_t *id, ulong dest_addr) */
5 g, z& r, g& Y-       mov     r0, r8                  /* gd_t */6 w4 r0 L: \7 n% ^4 c9 h) _  t
-       ldr     r1, [r8, #GD_RELOCADDR] /* dest_addr */6 t$ d; N3 C2 I* @
+       mov     r0, r9                  /* gd_t */) o- \. `& I- P. e& o9 @
+       ldr     r1, [r9, #GD_RELOCADDR] /* dest_addr */6 J# ~/ ]2 [/ P/ c
        /* call board_init_r */
, ^6 {( {. N. W0 `, ~        ldr     pc, =board_init_r       /* this is auto-relocated! */

6 x0 m% b% _4 Y9 D) n启动慢问题
1 f% G# S# M% E问题简述( ~$ o+ _/ i+ L
填了几个坑之后,新的uboot可以启动到内核了,但发现启动速度非常慢,内核启动速度慢了接近10倍!明明是同一个内核,为什么差异这么大。
( j. G) }0 X9 l5 s- C' g
) V1 E$ q- x4 n8 A$ `

! V2 _. V7 f2 i% {( M排查寄存器" \( |( Z2 U9 C, ?$ |+ x
初步排查了下设备树配置,以及uboot跳转内核前的一些关键寄存器,确实在两个版本的uboot中有所不同,但具体去看这些不同,发现都不会影响速度,将一些驱动对齐之后寄存器差异基本就消失了。
" N* r: e0 H& p* N
0 {( T$ f! |4 W! ?5 [

2 Z9 T: ?' C, H! b, o0 H6 p& P差异的分界
+ \* B0 d$ u' z& Y0 ^9 p) @1 {' p那再细看,kernel的速度有差异,uboot呢?在哪个时间点之后,速度开始产生差异?
' Q# ]8 r8 L- s6 h5 x+ f尝试在两个版本的uboot中插入一些操作,对比时间戳,发现两个uboot在某个节点之后的速度确实有区别。
  o) [$ U0 @/ a5 V进一步排查,原来是在打开cache操作之后,旧uboot的速度就会比新uboot快。尝试将旧uboot的cache关掉,则二者基本一致。尝试将旧uboot操作cache的代码,移植到新uboot,未发生改变。2 q+ {# I$ y9 I/ [5 }; C7 m' h7 @
此时可确认新uboot的开cache有问题。但觉得这个跟kernel启动慢没关系。因为uboot进入kernel之前都会关cache,由kernel自己去重新打开。
# E+ `: S# j. g# k) {7 p& c: N( I$ G也就是不管是用哪份uboot,也不管uboot中是否开了cache,对kernel阶段都应该没有影响才对。' `: r+ s( b% q* m& a# }5 E5 u
于是记录下来uboot的这个问题,待后续修复。先继续找kernel启动慢的原因。(注:现在看来当时的做法是有问题的,这里的异常这么明显,应该设法追踪下去找出原因才对); v. }& V3 X& r8 A; x

1 `/ q$ w* S5 @6 u* S5 |( ?7 Y6 Z8 R
. D% {( B/ }! R$ d; ]
锁定uboot1 p' q, ]! K- w) ]; Y0 ]
uboot的嫌疑非常大,但还不能完全确认,因为uboot之前还有一级spl。是否会是spl的问题呢?8 j+ l8 [9 a* `7 B7 ]
尝试改用新spl+旧uboot,启动速度正常。而新spl+新uboot的启动速度则很慢,其他因素都不变,说明问题确实出在uboot阶段。
/ Q$ g0 F, B1 ]/ @0 a2 s7 w/ n; q5 O$ A
3 D4 I$ s4 g- o. S3 w

; m: p5 h) B4 F6 f多做or少做
$ x" X' V/ s1 `. ^- b当时到这一步就卡住了,直接比较两份uboot的代码不太现实,差异太大了。
9 f7 V! s9 J6 p9 s! _) d后来我就给自己提了个问题,到底新uboot是多做了某件事情,还是少做了某件事情?
- P9 M" H- h3 ?+ Y5 M换个说法,目前已知  B1 v$ H2 I% i1 O; x# o& E9 B
spl --> 旧uboot --> kernel(速度快)1 s6 a0 k5 [4 [/ E, M# P5 P
spl --> 新uboot --> kernel(速度快); s* k2 @, z$ i# K! N: v
但到底是以下的情况A还是情况B呢?+ |$ m- w$ T: j( K- m4 d
A: spl(速度慢) --> 旧uboot(做了某个会提升速度的操作) --> kernel(速度快)
! E" M0 v3 D, }, z8 f; h; Y, r   spl(速度慢) --> 新uboot(少做了某个会提升速度的操作) --> kernel(速度慢)! ]6 [  V2 i( \
( j. G0 l+ S9 v, H2 f3 f
B: spl(速度快) --> 旧uboot(没做特殊操作) --> kernel(速度快)( h. I) a8 B' n& r( j
   spl(速度快) --> 新uboot(多做了某个会限制速度的操作) --> kernel(速度慢)
3 k$ S& u3 ~  g: y* g
为了验证,我决定让spl直接启动内核,看看内核到底是快是慢。
/ K& m2 J) j+ B7 t支持过程碰到了一些小问题9 [2 Y0 `6 c& |" G/ `
1.spl没有能力加载这么大的kernel
  W: ?& K9 }& m0 j5 c解决:此时不需要kernel能完全启动,只需要能加载启动一段,足以体现出启动速度是否正常即可,于是裁剪出一个非常小kernel来辅助实验。
3 |& T* k+ M' z4 L4 I( r8 M& o; T! Z8 T2.kernel需要dtb2 M; \- e; M2 s: S
解决:内核有一个CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE选项。选上重新编译。编译后再用dd将kernel和dtb拼接到一起,作为新的kernel。这样,spl就只需要加载一个文件并跳转过去即可。9 V8 u% m. Z4 O9 O$ o
试验结果,spl启动的kernel和使用新uboot启动的kernel速度一致,均比旧uboot启动的kernel慢。说明,旧uboot中做了某个关键操作,而新uboot没做。" Q2 @5 t8 R: ~3 ]" p; L

$ w, j- g+ J  @5 b+ \* a0 \" h
9 K2 j  `) b2 w7 U0 r
找出关键操作
- n) O5 E1 \6 M$ x那接下来的任务就是,找出旧uboot中的这个关键操作了。: ?/ ?0 w5 \2 \! m# w
怎么找呢?有了上一步的成果,我们可以使用以下方法来排查
  • spl加载kernel和旧uboot

  • spl跳转到旧uboot,此时kernel其实已经在dram中准备好了,随时可以启动

  • 在旧uboot的启动流程各个阶段,尝试直接跳转到kernel,观察启动速度

  • 如果在旧uboot的A点跳转kernel启动慢,B点跳转启动快,则说明关键操作位于AB点之间。

    ) J" n  @; W5 O. {8 e
方法有了,很快就锁定到start.S,进一步在start.S中揪出了这段代码" F, ?  h- Y, z; k- l5 ^* g
#if defined(CONFIG_ARM_A7)' F2 z2 e2 W9 M0 w- `& F
@set SMP bit
4 C' o0 z. ^. j9 M# W1 w- {    mrc     p15, 0, r0, c1, c0, 1
& D4 [+ F5 F) r2 C" y9 P    orr        r0, r0, #(1<<6)
8 Y  O6 Z7 u6 o9 B: M) L    mcr        p15, 0, r0, c1, c0, 1
$ ~1 V5 U: u0 ]0 @- R#endif& Z# w$ T8 u! q: Y
新uboot的start.S中没有这段代码,尝试在新uboot的start.S中添加此操作,速度立马恢复正常了。
" |9 l6 `- F% _1 b. ]再全局搜索下,原来这个新版本uboot中,套路是在board_init中进行此项设置的,而这个平台从旧版本移植过来,就没有设置 SMP bit, 补上即可。
; @: F- O/ q2 }
" j% S1 x. a5 P6 m
5 B. K! u) \+ @' w$ i* i; z7 q
SMP bit是什么7 i: v+ q: f; w
SMP 是指对称多处理器,看起来这个 bit 会影响多核的 cache一致性,此处没有再深入研究。
6 |7 r7 q3 q: \0 c但可以知道,对于单处理器的情况,也需要设置这个bit才能正常使用cache。贴下arm的图和描述: 微信图片_20200911150031.png . ^1 o6 ~% c) u' C; z9 d# M; K/ J
[6] SMP # A, N* ~& u  r6 m, c' M3 z+ b/ {0 |
/ R! @. @4 u& D# ^* ?2 l) r. T
Signals if the Cortex-A9 processor is taking part in coherency or not.0 o5 Y. r9 H. |

8 u* L. }2 y% ?: W0 T/ i, lIn uniprocessor configurations, if this bit is set, then Inner Cacheable Shared is treated as Cacheable. The reset value is zero.
6 q+ i' F( }& v! U
搜下kernel的代码,发现也是有地方调用了的。不过这个芯片是单核的,根本就没配置CONFIG_SMP。
: H. B* u& L& V8 C" x& V#ifdef CONFIG_SMP
) l6 w. n5 P% ?# t ALT_SMP(mrc p15, 0, r0, c1, c0, 1)* w- B/ U5 z5 |/ c+ T- {8 s* H5 X
ALT_UP(mov r0, #(1 << 6))  @ fake it for UP
9 f8 ~, x3 T+ H$ @7 Q tst r0, #(1 << 6)   @ SMP/nAMP mode enabled?& b0 |* E+ L# B) S$ o
orreq r0, r0, #(1 << 6)  @ Enable SMP/nAMP mode- O; s7 {& Z$ S/ o8 ?, [
orreq r0, r0, r10   @ Enable CPU-specific SMP bits
1 ~5 N: D; @% u  i mcreq p15, 0, r0, c1, c0, 1
8 T) R, R0 h' I2 P9 u#endif
# G/ C  f; ^2 Q+ `; w
总结: _2 b7 Q/ I+ c' l( `$ a2 N
整理出来一方面是记录这两个bug,另一方面也是想记录下当时的一些操作。毕竟同样的bug可能以后都不会碰到了,但解bug的方法和思路却是可以积累复用的。
5 h6 P5 ~2 k; }- `# `7 H5 w5 V) f  H5 e& b% u
赞 收藏 评论0 发布时间:2020-9-11 15:02

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版