I am trying to read kernel image and calculate a checksum value of this image. Firstly, I used a smc instruction to trigger a exception, and in the exception handler, I tried to read the first bytes of the image. I don't really know what the address is, but from some documents, I know the kernel image is decompressed in address like 0x20008000, 0x30008000 or 0xC0008000(they call this ZRELADDR, i don't really know whether this is the right address...). So I tried to read the memory like this:
uint32_t test;
test = * (uint32_t *)0x30008000;
DMSG("test : %x\n",test);
But the system crashed with a data abort exception,
core data-abort at address 0x30008000
fsr 0x00000005 ttbr0 0x7df7006a ttbr1 0x7df7006a cidr 0x0
cpu #0 cpsr 0x200001b3
r0 0x00000090 r4 0x7df4bf51 r8 0x00000000 r12 0x00000000
r1 0x09010000 r5 0x806665e0 r9 0x00000000 sp 0x7df77f50
r2 0x0000000d r6 0x7f002000 r10 0x00000000 lr 0x7df273ff
r3 0x30008000 r7 0x7df77f60 r11 0x00000000 pc 0x7df052f0
ERR TEE-CORE:tee_pager_handle_fault:602: Unexpected page fault! Trap CPU
PANIC: tee_pager_handle_fault core/arch/arm/mm/tee_pager.c:603
I guess I am on the wrong way. Does anyone know how to read the kernel image in runtime environment?
Thanks for your help!
EDIT:Thanks for your reply. I am talking about secure kernel. I am trying to check the integrity of the kernel under TrustZone, and to insure the kernel haven't be compromised. So I guess a checksum like hash value may help me. Also, I am a novice who is trying to be familiar with the memory system of arm, so I tried to start with simple read some certain memory address. I have tried to read 0xc0000000 as Artless Noise said, but the same error occurs again. Again I tried to find "_test" and "stext" address in System.map, which is 0x80008000, and error occurs again.
The beginning of the RAM is usually mapped at 0xC0000000. This depends on CONFIG_PAGE_OFFSET:
- VMSPLIT_3G: 0xC0000000
- VMSPLIT_2G: 0x80000000
- VMSPLIT_1G: 0x40000000
Note that this is a virtual address if you have an MMU (usual case), the physical address will depend on your actual architecture (it may or may not be 0x00000000). The kernel is loaded a few pages after that, at an offset of 0x8000.
So, you can probably find the (uncompressed) kernel at 0xC0008000 but it may as well be located somewhere else.
You can also try to ioremap() offset 0x8000 of your RAM.
Can you give us a bit more information on the particular SoC you are working on?
If you are in secure mode and you believe that in secure mode it access physical address then from below these macro you can deduce the physical address.
The physical address at which kernel loads is PHYS_OFFSET + TEXT_OFFSET (text offset is 0x8000),
PHYS_OFFSET definition will be depend on the CONFIG_ARM_PATCH_PHYS_VIRT patch.
if CONFIG_ARM_PATCH_PHYS_VIRT is defined, then PHYS_OFFSET will be equal to __pv_phys_offset otherwise PHYS_OFFSET will be defined as CONFIG_PHYS_OFFSET in your kernel config file.
Related
I want to translate a virtual user level address (EL0) to a physical address.
Arm provides an instruction AT to translate a virtual address to a physical address. This instruction should be called by privileged level (EL1), so I write a linux kernel module to execute this instruction. I pass a user level address (EL0) virt_addr through ioctl() to kernel module, and execute instruction AT.
According to the instruction manual, I execute the instruction by this way:
// S1E0R: S1 means stage 1, E0 means EL0 and R means read.
asm volatile("AT S1E0R, %[_addr_]" :: [_addr_]"r"(virt_addr));
// Register PAR_EL1 stores the translation result.
asm volatile("MRS %0, PAR_EL1": "=r"(phys_addr));
However, the value of register PAR_EL1, i.e. stored in phys_addr, is 0x80b (or 0b100000001011), which is not a correct result.
Then I found a manual about register PAR_EL1.
According to the manual, bit[0] is 1 means a fault occurs on the execution of an Address translation instruction.
bits[6:1] is Fault Status Code (FST). My FST is 0b000101. The manual tell me that the error information is: Translation fault, level 1.
I don't know the fault reason.
My cpu is Cortex-A53, and operating system is Linux-4.14.59.
Below is the code for reset vector as defined arm linux (arch/arm/kernel/entry-armv.S)
vector_rst:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
b vector_und
What does the instruction swi SYS_ERROR0 do ? When I checked, I found SYS_ERROR0 in arch/arm/kernel/asm-offsets.c
DEFINE(SYS_ERROR0, 0x9f0000);
I was unable to find anything related to it on internet. Can someone explain what does this instruction do ? What is SYS_ERROR0 ?
I was unable to find anything related to it on internet. Can someone explain what does this instruction do ? What is SYS_ERROR0 ?
DEFINE(SYS_ERROR0, 0x9f0000);
The swi instruction is typically a call from user mode to system mode. Ie, User space to the Linux kernel. Lower numbers are standard Linux system call such as open(), sbrk(), etc.
If you look at uapi/asm/unistd.h in arch/arm you can see some defines like __ARM_NR_BASE which is __NR_SYSCALL_BASE+0x0f0000. This can be 0x9f0000 for OABI systems. Basically, these are secret system calls that are ARM specific kernel calls. For instance, __ARM_NR_get_tls is only used for libc thread management on the ARM. Other CPUs may have different non-syscall mechanisms to do the same thing and/or the syscall interface may be different than on the ARM CPU.
So SYS_ERROR0 is a special ARM system call. By the way, asm-offset.c is never used directly. It is compiled and the object is scanned by a script to get assembler offsets to structures, etc. So if a compiler packs structures differently, then in theory, the assembler will be in-sync with the compiler version. We start here,
.L__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, .L__vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
The swi is a vector handled by W(ldr) pc, .L__vectors_start + 0x1000, so the code is 4k after the vector table. This is vector_swi and you can see the code in entry-common.S. There are two methods of making a syscall. The older one (OABI) encodes the call in the SWI instruction. This is bad as the ICACHE must be examined as data (DCACHE). The newer systems pass the syscall in r7. There are two jump tables; sys_call_table and sys_oabi_call_table to handle OABI and the newer mechanism. In both case, higher __NR_SYSCALL_BASE are special cased and use arm_syscall in traps.c. So SYS_ERROR0 is the case 0: /* branch through 0 */ code in traps.c. The message branch through zero is printed (because user space jump to the reset vector which can be at address 0) and the user space gets a signal.
I have problem flashing main program and SoftDevice on the nrf 51822 module. I have Keil version 5.24 and I am using SDK v12.3 .
I can flash SoftDevice easily but after that I can not flash the main program on the device. in the Keil it just shows the error erase failed, flash download failed - "cortex-m0" . But if i try to do this process by the nRFgo studio after that i flashed SoftDevice, when i try to flash the main program it shows the error : This hex file has data in SoftDevice region. Try programming using "Program SoftDevice", or erase all before programming.
Could it be cause because of ROM memory area configuration and addresses? If so how can i fix it?
Thank for your attention.
After a while, I finally found out where the problem was laid.
I tried to change the ROM memory allocation for SoftDevice and main program and it finally works.
Basically SoftDevice allocation must be bellow the main program in the memory. For example if we have memory form 0x00 to 0xff, The SoftDevice can be allocated from 0x00 to 0x2f and the remained area from 0x2f to the end must be reserved for main program.
Depending on which SoftDevice(SD) you use eg. S110, S130 etc. , The size of SDs can vary So the memory allocation of SDs start from 0x00 but the ending point depends on which SD you use, So I changed the memory allocation address in Kiel, And can get information about SDs compatibility with nRF devices and SDs features in the site :
https://infocenter.nordicsemi.com
Here is another helpful link :
https://devzone.nordicsemi.com/f/nordic-q-a/38067/ble_app_uart-can-not-be-loaded-completely-on-nrf-51822
I have a couple of doubts about how the kernel is loaded into memory. Upon inspecting /proc/kallsyms I'm able to find the address of various symbols in the kernel.
$ cat /proc/kallsyms | head -n 10
00000000 t __vectors_start
80008240 T asm_do_IRQ
80008240 T _stext
80008240 T __exception_text_start
80008244 T do_undefinstr
80008408 T do_IPI
8000840c T do_DataAbort
800084a8 T do_PrefetchAbort
80008544 t gic_handle_irq
800085a0 T secondary_startup
Is there any way I can find the base address at which the kernel is loaded?
In userspace, suppose I use a libc with say the puts function at an offset of 0x200. When loaded into memory at say the address 0x8048000, I would be able to find the resolved puts at 0x8048000 + 0x200. Would the same hold for the kernel? i.e. is the kernel image loaded up into memory as 1 contiguous .text section?
for MIPS architecture
file Platform contain the field/variable "load-..." assigned with the location in physical address space.
example:
openwrt/build_dir/target-mips_mips32_musl-1.1.16/linux-brcm63xx_smp/linux-4.4.14/arch/mips/bcm63xx/Platform
#
# Broadcom BCM63XX boards
#
platform-$(CONFIG_BCM63XX) += bcm63xx/
cflags-$(CONFIG_BCM63XX) += \
-I$(srctree)/arch/mips/include/asm/mach-bcm63xx/
load-$(CONFIG_BCM63XX) := 0xffffffff80010000
for ARM architecture
file Makefile.boot contain the field/variable "zreladdr-y" assigned with the location in physical address space.
example:
openwrt/build_dir/target-mips_mips32_musl-1.1.16/linux-brcm63xx_smp/linux-4.4.14/arch/arm/mach-omap1/Makefile.boot
zreladdr-y += 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x10800000
for Microblaze architecture
file Makefile contain the field/variable "UIMAGE_LOADADDR" assigned with the location in physical address space (exported from Xilinx ISE).
example:
openwrt/build_dir/target-mips_mips32_musl-1.1.16/linux-brcm63xx_smp/linux-4.4.14/arch/microblaze/boot/Makefile
UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR)
Kernel is loaded at physical address of 1MiB which is mapped on PAGE_OFFSET + 0x00100000 (virtual address). usually 8MiB of virtual space is reserved for kernel image starting from PAGE_OFFSET + 0x00100000
As other answer states that Kernel base address is fixed for particular architecture. But due to many security issues kernel development community decided to make it random. It is called ASLR (Address Space Layout Randomization).
By reading your question (or because I am reading it in 2017), you may be trying to find offset used in ASLR (or KASLR for kernel).
KASLR offset = address of symbol loaded in memory - address of symbol present in binary.
As your question states you already know address of symbol in memory from /proc/kallsyms.
We can find address of symbol in binary using nm utility and vmlinux file.
nm vmlinux | grep do_IPI
This will print address of symbol do_IPI in vmlinux file. Subtracting these two address will provide you KASLR offset.
If you are using u-boot then at boot time bootloader usually print the kernel load address and entry point.
Erase Group Size: 512 Bytes
reading uImage
4670784 bytes read in 469 ms (9.5 MiB/s)
reading devicetree.dtb
20597 bytes read in 17 ms (1.2 MiB/s)
Booting Linux kernel with ramdisk and devicetree
## Booting kernel from Legacy Image at 02004000 ...
Image Name: Linux-4.9.0-xilinx
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4670720 Bytes = 4.5 MiB
Load Address: 10000000
Entry Point: 10000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 04000000
Booting using the fdt blob at 0x4000000
Loading Kernel Image ... OK
Loading Device Tree to 1cb3d000, end 1cb45074 ... OK
Starting kernel ...
In the case of this ARM kernel the load address was at 0x80008000. Also, the kernel is loaded in a contiguous manner.
I'm porting u-boot to P2040 based board these days.
As u-boot/arch/powerpc/mpc85xx/start.s commented:
The processor starts at 0xffff_fffc and the code is first executed in the last 4K page in flash/rom.
In u-boot/arch/powerpc/mpc85xx/resetvec.S:
.section .resetvec,"ax"
b _start_e500
And in u-boot.lds linker script:
.resetvec RESET_VECTOR_ADDRESS :
{
KEEP(*(.resetvec))
} :text = 0xffff
The reset vector is at 0xffff_fffc, which contains a jump instruction to _start_e500.
The E500MCRM Chapter 6.6 mentioned:
This default TLB entry translates the first instruction fetch out of reset(at effective address 0xffff_fffc).
This instruction should be a branch to the beginning of this page.
So, if I configure the HCW to let powerpc boot from Nor Flash, why should I suppose that the Nor Flash's
last 4K is mapped to 0xffff_f000~0xffff_ffff? Since there're no LAW setup yet and the default BR0/OR0 of Local Bus
does not match that range. I’m confused about how Nor Flash be access at the very beginning of core startup.
Another question is:
Does P2040 always have MMU enabled so as to translate effective address to real address even at u-boot stage?
If so, beside accessing to CCSRBAR, all other memory access should have TLB entry setup first.
Best Regards,
Hook Guo