entry() get into the different address from the entry point I set in the Elf - operating-system

Recently I'm learning about the OS. And I want to write a simple bootloader, which change the real mode to protect mode and then load the simple kernel.
But I can't figure out the entry address problem.
At first I put the bootloader in the first sector of the OS.img(qemu), and then the kernel begin at the second sector.
Here's readelf result of my kernel:
The entry point address is 0x800c.
And the LMA and VMA are below:
A part of the bootloader which read elf-type kernel and then get into the entry(),which is the entry point address.
However, when I disassemble the bootloader, the entry() is below:
Call *0x8018, not *0x800c.
I don't know why this happen.
Could you please help me?

call *0x8018 performs a call to an address that is stored at 0x8018, that's correct since ELFHDR is 0x8000 and offset of e_entry in the header is 0x18.
The real problem is in the way you load segments into memory. Each segment should be loaded at address p_vaddr from file offset p_offset. Notice that in your case p_vaddr is 0x8000, that the same place in memory you loaded elf header to and that's why ELFHDR->e_entry gets overwritten. The easiest solution would be to load elf header at different address.
Source: http://www.skyfree.org/linux/references/ELF_Format.pdf

Related

Question about Message Signaled Interrupts (MSI) on x86 LAPIC system

Hi I'm writing a kernel and plan to use MSI interrupt for PCI devices.
However, I'm also quite confused by the documentations.
My understanding about MSI are as follow:
From PCI device point of view:
Documentations indicate that I
need to find Capabillty ID = 0x05 to locate 3 registers: Message control (MCR), Message Address (MAR) and Message Data (MDR) registers
MCR provide control functionality for MSI interrupt,
MAR provide the physical address the PCI device
will write once interrupt occurs
MDR forms out the actual data it will write into the physical address
From CPU point of view:
Documentation shows that Message Address register contains fixed top of 0xFEE, and following by destination ID (LAPIC ID) and other controlling bits as follow:
The Message Data register will contain the following information, including the interrupt vector:
After reading all of these, I am thinking if the APIC_ID is 0x0h would the Message Address conflict with the Local APIC memory mapping? Although the address of FEE00000~FEE00010 are reserved.
In addition, is it true that the vector number in MDR is corresponding to the IDT vector number. In other words, if I put MAR = 0xFEE0000C (Destination ID = 0, Using logical APIC ID) and MDR = 0x0032 (edge trigger, Vector = 50) and enable the MSI interrupt, then once the device issues an interrupt CPU would correspondingly run the function pointed by IDT[50]? After that I write 0h to EOI register to end it?
Finally, according to the documentation, the upper 32 bit of MAR is not used? Can anyone help on this?
Thanks a lot!
Your understanding of how to detect and program MSI in a PCI (or PCIe) device is correct.*
The message address controls the destination (which CPU the interrupt is sent to), while the message data contains the vector number. For normal interrupts, all bits of the message data should be 0 except for the low 8 bits, which contain the vector.
The vector is an index into the IDT, so if the message data is 0x0032, the interrupt is delivered through entry 50 of the IDT.**
If the Destination ID in an interrupt message is 0, the Message Address of the MSI does match the default address of the local APIC, but they do not conflict, because the APIC can only be written by the CPU and MSIs can only be written by devices.
On x86 platforms, the upper 32 bits of the message address must be 0. This can be done by setting the upper part of the message address to 0 or by programming the device to use a 32-bit message address (in which case the upper message address register is not used). The PCI spec was designed to work with systems where 64-bit MSI addresses are used, but x86 systems never use the upper 32 bits of the message address.
Reprogramming the APIC base address by writing to the APIC_BASE MSR does not affect the address range used for MSI; it is always 0xFEExxxxx.
* You should also look at the MSI-X capability, because some devices support MSI-X but not MSI. MSI-X is a bit more flexible, which inevitably makes it a bit more complicated.
** When using the MSI capability, the message data isn't exactly the value in the Message Data Register (MDR). The MSI capability allows the device to use several contiguous vectors. When the device sends an interrupt message, it replaces the low bits of the MDR with a different value depending on the interrupt cause within the device.

"HelloWorld" program on MIPS is not working when loaded by linux core to another core

A program "HelloWorld" running on Mips Interaptive core0 VPE1, including crt0.S (which I wrote), main.c files creates an ELF in which the symbols are relative to 0x0:
0x0 - _core_reset (this is part of crt0.S)
...
0x460 - fw_reset (this is called from main)
...
0x484 - main (this is the main function)
(-) my ELF undergoes stripping of sections to create a binary file of instructions only, starting in _core_reset
(-) the binary image from last step is loaded to virtual address 0xADB00000, which is physical 0x2DB00000
(-) the first problem is that in _core_reset we do:
la t0,main
mtc0 t0,C0_ERRPC //store it as return address
but main has the address relative to 0x0, which causes memory exception,
what I need is main to be in address loaded + (offset relative to zero),
How do I do that? we can say that the address the image is loaded to and run from is constant
I tried to write in the crt0.S file, hardcoded to change the jump to main address:
lui t0, 0xa6b0 /* Assumtion the FW is loaded to 0xa6b00000 */
addiu t0, t0, main
and it worked an I reached main(), but later when tried to call fw_reset() from main, the address of fw_reset() was again relative to 0x0 and I got a memory exception
I tried from the makefile to add that the .text section of ELF will start from the address loaded, but then I get an issue that my image is loaded to:
(value i provide) + (actual loading address) and so it also doesn't work
I expected my code to reach main() and be stuck in the endless while loop, instead I get memory exceptions since the functions are relative to 0x0, while the code is loaded to another address not zero

In Application Programming issue

I'm working on project on STM32L152RCT6, where i have to build a mechanism to self update the code from the newly gated file(HEX file).
For that i have implemented such mechanism like boot loader where it checks for the new firmware if there it it has to cross verify and if found valid it has to store on "Application location".
I'm taking following steps.
Boot loader address = 0x08000000
Application address = 0x08008000
Somewhere on specified location it has to check for new file through Boot loader program.
If found valid it has to be copy all the HEX on location(as per the guide).
Than running the application code through jump on that location.
Now problem comes from step 5, all the above steps I've done even storing of data has been done properly(verify in STM32 utility), but when i'm jump to the application code it won't work.
Is there i have to cross check or something i'm missing?
Unlike other ARM controllers that directly jump to address 0 at reset, the Cortex-M series takes the start address from a vector table. If the program is loaded directly (without a bootloader), the vector table is at the start of the binary (loaded or mapped to address 0). First entry at offset 0 is the initial value of the stack pointer, second entry at address 4 is called the reset vector, it contains the address of the first instruction to be executed.
Programs loaded with a bootloader usually preserve this arrangement, and put the vector table at the start of the binary, 0x08008000 in your case. Then the reset vector would be at 0x08008004. But it's your application, you should check where did you put your vector table. Hint: look at the .map file generated by the linker to be sure. If it's indeed at 0x08008000, then you can transfer control to the application reset vector so:
void (*app)(void); // declare a pointer to a function
app = *(void (**)(void))0x08008004; // see below
app(); // invoke the function through the pointer
The complicated cast in the second line converts the physical address to a pointer to a pointer to a function, takes the value pointed to it, which is now a pointer to a function, and assigns it to app.
Then you should manage the switchover to the application vector table. You can do it either in the bootloader or in the application, or divide the steps between them.
Disable all interrupts and stop SysTick. Note that SysTick is not an interrupt, don't call NVIC_DisableIRQ() on it. I'd do this step in the bootloader, so it gets responsible to disable whatever it has enabled.
Assign the new vector table address to SCB->VTOR. Beware that the boilerplate SystemInit() function in system_stm32l1xx.c unconditionally changes SCB->VTOR back to the start of the flash, i.e. to 0x08000000, you should edit it to use the proper offset.
You can load the stack pointer value from the vector table too, but it's tricky to do it properly, and not really necessary, the application can just continue to use the stack that was set up in the bootloader. Just check it to make sure it's reasonable.
Have you changed the application according to the new falsh position?
For example the Vector Table has to be set correctl via
SCB->VTOR = ...
When your bootloader starts the app it has to configure everything back to the reset state as the application may relay on the default reset values. Espessially you need to:
Return values of all hardware registers to its reset values
Switch off all peripheral clocks (do not forget about the SysTick)
Disable all enabled interrupts
Return all clock domains to its reset values.
Set the vector table address
Load the stack pointer from the beginning of the APP vector table.
Call the APP entry point.(vertor table start + 4)
Your app has to be compiled and linked using the custom linker script where the FLASH start point is 0x8008000
for example:
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
where FLASH_BASE's value must be equal to the address of your IROM's value in KEIL
example:
#define FLASH_BASE 0x08004000
Keil configuration

How to find the number of data mapped by mmap()?

if mmap() was used to read a file, how can I find the number of data mapped by mmap().
float *map = (float *)mmap(NULL, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);
The mmap system call does not read data. It just maps the data in your virtual address space (by indirectly configuring your MMU), and that virtual address space is changed by a successful mmap. Later, your program will read that data (or not). In your example, your program might later read map[356] if mmap has succeeded (and you should test against its failure).
Read carefully the documentation of mmap(2). The second argument (in your code, FILESIZE) defines the size of the mapping (in bytes). You might check that it is a multiple of sizeof(float) and divide it by sizeof(float) to get the number of elements in map that are meaningful and obtained from the file. The size of the mapping is rounded up to a multiple of pages. The man page of mmap(2) says:
A file is mapped in multiples of the page size. For a file that is
not a multiple of the page size, the remaining memory is zeroed when
mapped, and writes to that region are not written out to the file.
Data is mapped in pages. A page is usually 4096 bytes. Read more about paging.
The page size is returned by getpagesize(2) or by sysconf(3) with _SC_PAGESIZE (which usually gives 4096).
Consider reading some book like Operating Systems: Three Easy Pieces (freely downloadable) to understand how virtual memory works and what is a memory mapped file.
On Linux, the /proc/ filesystem (see proc(5)) is very useful to understand the virtual address space of some process: try cat /proc/$$/maps in your terminal, and read more to understand its output. For a process of pid 1234, try also cat /proc/1234/maps
From inside your process, you could even read sequentially the /proc/self/maps pseudo-file to understand its virtual address space, like here.

Device tree address and reg and property

I'm struggling to understand where to get the address of a device on a device tree? As an example how do I know that I should set <0x00900000 0x20000> in here.
Is memory mapped IO done in the hardware (the processor itself) or in software and do I just have to pass the right address in the device tree?
Is the address hardcoded on the processor or can I just set an arbitrary address? I cannot find anything in my reference manual about setting a certain address in the device tree
These kind of addresses can be found in the Reference Manual of the processor.
You can find the link here.
Take a look at the chapter 48 (OCRAM On-chip RAM Memory Controller) and more specifically at the section 48.2.1 (page 4118):
The total on-chip RAM size for the chip is 128 Kbytes, organized as 16K x 64 bits,mapped from 0x00900000 to 0x0091FFFF
This is where come from the values <0x00900000 0x20000> from the dtsi file, corresponding to the base address and the offset.
These values are in dts/dtsi file provided by the chip maker.