Alice OS 2-Load Address

为了方便不同平台的演示,这次我们添加一个新的平台, 是ARM versatilepb 平台的arm926ej-s处理器, 这是一款比较老的ARM处理器 CPU是A9系列的ARM926EJ-S, ARMv5TE架构; 我们来看看这个CPU起始的地址,并且考虑如何给我们的Alice OS初始化一个临时的栈~

Alice-OS: Load Address

Versatilepb & ARM926EJ-S

我们仿照vexpress-a9建一个新的平台,并用类似的方式看看启动之后的LR地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Another shell:
alice@MacAlice ‹ 521074d ↑●● › : ~/Codes/alice-os
make PLAT=versatilepb qemu-telnet

alice@MacAlice ‹ 521074d ↑●● › : ~/Codes/alice-os
[0] % telnet localhost 1234
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
QEMU 4.2.0 monitor - type 'help' for more information
(qemu) info registers
R00=000000a3 R01=00000183 R02=00000100 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00010008 R15=00010004

可以发现,这次的LR (R14)是0x10008了, 说明启动是从0x10000开始执行的,

所以我们现在知道, vexpress-a9是从0x60010000开始执行, 而versatilepb是从0x00010000开始执行的

接下来让我们给他们都给一个初始的栈吧

Init Stack

我们在汇编里面声明一段空间,并把它当做我们的内核栈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.global entry
entry:
mov r0, pc
# R5 save PC
mov r5, r0

# make r0 4k aligned
mov r0, pc
bic r0, r0, #0xFF0
bic r0, r0, #0xF

# This is the .L_stack_start
add r0, #0x2000
mov sp, r0
ldr r1, =.L_stack_start
ldr r2, =#kernel_stack_start
mov r3, sp
push {r0}
mov r4, sp
.word 0xdeadbeef

.align
.section ".stack", "aw"
.L_stack: .space 4096
.L_stack_start:

我们在代码段的最下面声明一个4K大小的空间,并将它连接到”.stack”段里面:

1
2
3
4
5
6
7
.bss : { *(.bss COMMON) }
. = ALIGN(4096);

.stack : {
*(.stack);
}
kernel_stack_start = .;

我们可以看一下,r0到r5里面的值都是多少:

  • r0是我们计算出来并赋值给sp的栈;
  • r1是直接加载.L_stack_start这个tag得到的地址;
  • r2是从linker script中取得的kernel_stack_start这个symbol地址;
  • r3是赋值之后的sp;
  • r4是push一次之后的sp;
  • r5是程序一开始的PC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
alice@MacAlice ‹ 521074d ●● › : ~/Codes/alice-os
[0] % telnet localhost 1234
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
QEMU 4.2.0 monitor - type 'help' for more information
(qemu) info registers
R00=60012000 R01=80002000 R02=80002000 R03=60012000
R04=60011ffc R05=60010008 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=60010034 R15=016a8000
PSR=400001db -Z-- A S und32

(qemu) x /x 0x60011ffc
60011ffc: 0x60012000

我们计算栈的方式是这样: 假设启动这部分代码最长不超过4K大小, 那我空4K出来将当前PC后12位清零, 加上两个4K页就是我的栈底。

但是我们直接Load Symbol会发现, 无论是tag还是从linker script取出来的 地址都是0x80002000。这是由于我们linker一开始给的其实地址是80002000, 导致我们的栈变成了这样。

但是至少我们了解了,代码开始往后2个页就是栈底,所以我们使用 0x60012000作为栈底是没有问题的!

通过 x 命令我们也看到了,push一次之后,栈里确实存了我们要的数据。

那么接下来,我们就考虑如何更优雅并且正确的设置栈,尽快从汇编跳到C代码吧!